Problem
#301 提議在 target resolution 加入 residual clause——未列舉事項依「事務性質」歸屬。但那條判準要能執行,需要先知道哪些層級實際存在:判準說「這件事屬 project 層」時,若該 project 根本沒有自己的 tracker,往下歸就會落空。
目前 IDD 完全沒有 global 層,也沒有任何跨 repo 的階層知識。每次 target resolution 只看得到 cwd 往上第一個 config,看不到「這台機器上有哪些 repo、誰是誰的上層」。
Original text(使用者,2026-08-12 對話逐字):
「我在想可能如果要考慮idd repo的話要考慮有沒有地方政府,如果最下層的repo已經沒了的話就不要往下,所以可能要有一個repo的地圖,是不是存在~/.idd (當idd的global setting如何? 你可以參考其他的repo)」
「好,照你的建議好,上收其實通常會到我現在正在開起的專案的git,要跨過的話通常會需要特別指定」
「地方政府在不在」是核心比喻:階層可以缺席,事務要歸給實際存在的最近層級,而不是歸給一個不存在的層。
Type
feature
Priority
P1(本週)— #301 的前置基礎設施
現況調查
1. walk-up 其實已經會經過 $HOME/.claude/.idd/
references/config-protocol.md 的 walk-up 終止條件寫著「don't go above $HOME」,但檢查在 break 之前:
while [ "$dir" != "/" ] && [ "$dir" != "$HOME/.." ]; do
if [ -f "$dir/.claude/.idd/local.json" ]; then ... return 0; fi # ← 先檢查
[ "$dir" = "$HOME" ] && break # ← 才 break
dir=$(dirname "$dir")
done
所以 $HOME/.claude/.idd/ 這個路徑已經在讀取路徑上,只是:
- 沒有 global 語意——它會被當成「
$HOME 這個目錄的 local config」,而 $HOME 不是 repo
- 實測該目錄存在但為空(0 檔案),是某次在 home 執行留下的空殼
2. 沒有任何 global / registry / 階層概念
grep -niE 'global|XDG|user-level|machine-wide' 掃 config-protocol.md 只命中 walk-up 的 $HOME 邊界描述。六機制全部是單點解析(解出一個 repo),沒有一個機制看得到 repo 之間的關係。
3. 兩種 config 格式並存(掃描器必須兩種都認)
實測一台機器上的分布:
| 格式 |
數量 |
.claude/.idd/local.json(新,#195 規定新裝一律用此) |
20+ |
.claude/issue-driven-dev.local.json(legacy,walk-up 仍 fallback 解析) |
17 |
任何掃描實作若只認新格式,會漏掉近半數 repo——而漏掉的那些會被判成「該層不存在」,觸發錯誤的上收。
Expected
A. Global config:~/.claude/.idd/global.json
位置決定(考慮過 ~/.idd/,不採用):
- walk-up 已經會經過
$HOME/.claude/.idd/ — 零新增掃描邏輯,只要多認一個檔名
- 與 project 層
.claude/.idd/local.json 完全對稱,只差 local / global
- IDD 是 Claude Code plugin,
~/.claude/ 是其生態家(settings.json / rules/ / plugins/ 皆在此);~/.idd/ 等於在 home 再開一個 dotdir
- 檔名用
global.json 而非 local.json 是必要的——後者會讓 $HOME 被誤讀成「一個 repo」,語意汙染既有的 repo-boundary 判定
生態先例:同一套工具鏈中,codex-pro 已採 ~/.codex-pro/profile.yaml(global)+ <project>/.codex-pro/profile.yaml(project)雙層 resolve。本案是同一模式,但寄生在 ~/.claude/ 之下而非另開 dotdir。
B. 地圖:自動推導,不手寫
手寫 registry 會 stale,而 stale 正是本問題的病因——#301 記錄的那條分散案例,成因就是某 project 中途被 extract 成獨立 repo 而沒有任何地方被更新。手寫地圖只是把同一種病從 walk-up 搬到 registry。
地圖可以完全自動推導:每個 repo 的 .claude/.idd/local.json(或 legacy)已經自我宣告了它的 tracker。掃描即得圖。因此 global.json 存的不是 repo 清單,而是掃描參數與快取控制:
{
"scan_roots": ["~/<work-root-a>", "~/<work-root-b>"],
"cache_ttl_seconds": 86400
}
single source of truth 仍在各 repo 自己的 config,global 只是索引 + 快取。實測規模:一個工作根 7 個 repo、另一個 30+ 個,全掃成本可接受(配 TTL 快取後更低)。
C. 缺層上收:階層可以缺席
判準與地圖必須分開——「判準說該歸哪一層」和「那一層是否存在」是兩種不同的失敗,混在一起會 debug 不出來。
D. 上收天花板:當前 git repo boundary,跨越需明示
這是安全約束,不是最佳化。 上收預設停在 cwd 所在的 git repo 邊界;要把 issue 開到該 repo 之外的上層,必須明示(--target,或 config 中顯式宣告的上層關係)。
理由:repo 邊界即「轄區」。事務移出轄區若可以默默發生,就會出現「以為開在自己專案、其實開到上層」的靜默錯誤——而這種錯誤事後極難察覺(issue 就在別的 tracker 躺著,沒有任何訊號)。
實作上可直接沿用既有的邊界語彙,不必新造:
E. 上收到頂仍無解 → 問,不要猜
一路上收會停在 global,但 global 不是 tracker,不能開 issue。兩條路:
- 規定「最上層必須指定一個 catch-all general repo」(憲政類比:中央永遠存在)
- 上收到頂仍無解 →
AskUserQuestion 交使用者裁決
建議取 (2)。取 (1) 會要求使用者指定一個 catch-all,而那個 repo 在實務上會變成垃圾桶——所有判不出來的東西都往那裡倒,久了失去分類意義。(2) 也與 #301 引用的憲法第 111 條後段「遇有爭議時,由立法院解決之」一致:判不出來時交裁決,而非塞給預設。
Actual
- 無 global config 層(
~/.claude/.idd/ 目錄存在但空)
- 無 repo 地圖、無階層知識;六機制皆為單點解析
- 缺層無偵測:判準若指向一個沒有 tracker 的層,行為未定義
- 上收無邊界概念(因為根本沒有上收機制)
Impact
Out-of-scope
相關
Current Status
Problem
#301 提議在 target resolution 加入 residual clause——未列舉事項依「事務性質」歸屬。但那條判準要能執行,需要先知道哪些層級實際存在:判準說「這件事屬 project 層」時,若該 project 根本沒有自己的 tracker,往下歸就會落空。
目前 IDD 完全沒有 global 層,也沒有任何跨 repo 的階層知識。每次 target resolution 只看得到
cwd往上第一個 config,看不到「這台機器上有哪些 repo、誰是誰的上層」。「地方政府在不在」是核心比喻:階層可以缺席,事務要歸給實際存在的最近層級,而不是歸給一個不存在的層。
Type
feature
Priority
P1(本週)— #301 的前置基礎設施
現況調查
1. walk-up 其實已經會經過
$HOME/.claude/.idd/references/config-protocol.md的 walk-up 終止條件寫著「don't go above$HOME」,但檢查在 break 之前:所以
$HOME/.claude/.idd/這個路徑已經在讀取路徑上,只是:$HOME這個目錄的 local config」,而$HOME不是 repo2. 沒有任何 global / registry / 階層概念
grep -niE 'global|XDG|user-level|machine-wide'掃config-protocol.md只命中 walk-up 的$HOME邊界描述。六機制全部是單點解析(解出一個 repo),沒有一個機制看得到 repo 之間的關係。3. 兩種 config 格式並存(掃描器必須兩種都認)
實測一台機器上的分布:
.claude/.idd/local.json(新,#195 規定新裝一律用此).claude/issue-driven-dev.local.json(legacy,walk-up 仍 fallback 解析)任何掃描實作若只認新格式,會漏掉近半數 repo——而漏掉的那些會被判成「該層不存在」,觸發錯誤的上收。
Expected
A. Global config:
~/.claude/.idd/global.json位置決定(考慮過
~/.idd/,不採用):$HOME/.claude/.idd/— 零新增掃描邏輯,只要多認一個檔名.claude/.idd/local.json完全對稱,只差local/global~/.claude/是其生態家(settings.json/rules//plugins/皆在此);~/.idd/等於在 home 再開一個 dotdirglobal.json而非local.json是必要的——後者會讓$HOME被誤讀成「一個 repo」,語意汙染既有的 repo-boundary 判定生態先例:同一套工具鏈中,
codex-pro已採~/.codex-pro/profile.yaml(global)+<project>/.codex-pro/profile.yaml(project)雙層 resolve。本案是同一模式,但寄生在~/.claude/之下而非另開 dotdir。B. 地圖:自動推導,不手寫
手寫 registry 會 stale,而 stale 正是本問題的病因——#301 記錄的那條分散案例,成因就是某 project 中途被 extract 成獨立 repo 而沒有任何地方被更新。手寫地圖只是把同一種病從 walk-up 搬到 registry。
地圖可以完全自動推導:每個 repo 的
.claude/.idd/local.json(或 legacy)已經自我宣告了它的 tracker。掃描即得圖。因此global.json存的不是 repo 清單,而是掃描參數與快取控制:{ "scan_roots": ["~/<work-root-a>", "~/<work-root-b>"], "cache_ttl_seconds": 86400 }single source of truth 仍在各 repo 自己的 config,global 只是索引 + 快取。實測規模:一個工作根 7 個 repo、另一個 30+ 個,全掃成本可接受(配 TTL 快取後更低)。
C. 缺層上收:階層可以缺席
判準與地圖必須分開——「判準說該歸哪一層」和「那一層是否存在」是兩種不同的失敗,混在一起會 debug 不出來。
D. 上收天花板:當前 git repo boundary,跨越需明示
這是安全約束,不是最佳化。 上收預設停在
cwd所在的 git repo 邊界;要把 issue 開到該 repo 之外的上層,必須明示(--target,或 config 中顯式宣告的上層關係)。理由:repo 邊界即「轄區」。事務移出轄區若可以默默發生,就會出現「以為開在自己專案、其實開到上層」的靜默錯誤——而這種錯誤事後極難察覺(issue 就在別的 tracker 躺著,沒有任何訊號)。
實作上可直接沿用既有的邊界語彙,不必新造:
.git/AND either config file (treat as repo boundary)」E. 上收到頂仍無解 → 問,不要猜
一路上收會停在 global,但 global 不是 tracker,不能開 issue。兩條路:
AskUserQuestion交使用者裁決建議取 (2)。取 (1) 會要求使用者指定一個 catch-all,而那個 repo 在實務上會變成垃圾桶——所有判不出來的東西都往那裡倒,久了失去分類意義。(2) 也與 #301 引用的憲法第 111 條後段「遇有爭議時,由立法院解決之」一致:判不出來時交裁決,而非塞給預設。
Actual
~/.claude/.idd/目錄存在但空)Impact
idd-list等只能看單一 repo,看不到跨 repo 的工作全貌Out-of-scope
相關
.claude/.idd/local.json新路徑規定。本案的掃描器必須同時認 legacy 格式,否則近半數 repo 會被誤判為不存在Current Status
references/config-protocol.md、scripts/lib/resolve-submodule-route.sh)/spectra-discuss(Spectra 預設;opt-out 走/spectra-propose需零 open questions —— 本案 Residue 與 R3 cache 去留尚未拍板,不符 opt-out 條件)