Problem
Original text :
「Codex 其實已完成(12:37 寫入 19KB — 剛才的 glob 失敗讓 ls 整條 abort 看不到)。讀 Codex verdict,等 4 個 lens agents」
— Source: /idd-all #182 run(PsychQuant/che-ical-mcp,2026-08-31)的 verify phase 現場觀察
idd-verify 執行中,coordinator 用一條命令同時檢查 lens findings glob 與 codex 輸出檔:
ls -la "$VERIFY_DIR"/findings_*.md "$VERIFY_DIR"/codex.md 2>/dev/null
當時 4 個 lens agents 尚未寫檔(findings_*.md 零 match),但 codex.md 已存在 (codex-call 已完成並寫入 19KB)。zsh 的預設 nomatch 行為對無 match 的 glob 會讓整條命令 abort (no matches found),2>/dev/null 又吞掉了那行錯誤 → 存在的 codex.md 也沒被列出。搭配 pgrep 顯示 codex-call 程序已退出(實為正常完成),coordinator 得到兩個相互印證的假訊號,誤判「codex-call 死亡且沒寫輸出」。
本次靠 launcher 的 task output file 留有 [codex-call] wrote 13723 chars 一行才排除誤判。若沒有這條旁證,這個 false negative 的下游是:把已完成的 Codex lens 當 failure 標進 master report(「cross-model pass incomplete」process gap)、或觸發不必要的 retry — 都是靜默方向的錯。
Type
bug
Root cause 歸屬(skill 文件層)
臨場命令是 executor 寫的,但 idd-verify/SKILL.md 至少兩處樣板性地 教這個寫法:
鐵律段:「必須 ls $VERIFY_DIR/findings_*.md 確認 5 個檔案 + non-empty」
Step 0 bootstrap task wait_for_claude_agents:「4 lens Agent calls return 後 ls $VERIFY_DIR/findings_*.md 確認 4 檔 non-empty」
Claude Code 的 Bash 跑在 zsh;zsh 對 no-match glob 的 abort 行為是這個 plugin 生態已踩過的坑家族(safari-browser 的 unquoted-variable 教訓同源:zsh 與 bash 的字串/glob 語意差異)。glob 檢查在「檔案還沒生出來」的等待場景是常態路徑,不是 edge case — 樣板本身站在 footgun 上。
對照:Step 2.5a 的 bash 範例(EXPECTED_FILES array + [ -s "$f" ] 逐一檢查)是正確 寫法 — 問題只在鐵律段與 task 描述的 shorthand 樣板與它不一致。
Expected
檔案存在性檢查在 zsh 下對「部分檔案尚未存在」給出正確的 per-file 結果,不因單一 glob no-match 而讓其他存在的檔案也顯示為缺失。
SKILL.md 的鐵律段/task 樣板與 Step 2.5a 的正確寫法一致。
Actual
鐵律段樣板誘導 glob 合併檢查 → zsh nomatch abort → 存在的檔案被誤報為不存在 → 誤導 coordinator 判斷(本例:誤判 Codex 死亡;同構風險:Step 2.5 Recovery Protocol 被 false trigger,浪費一輪 agent spawn 或誤標 process gap)。
修法建議
鐵律段與 wait_for_claude_agents task 描述改為顯式路徑迴圈(即 Step 2.5a 既有樣板),或至少改寫為 zsh-safe 形式(每個 pattern 分開跑、或 setopt null_glob / ls ... 2>/dev/null || true 並明注「zsh nomatch 防禦」)。
可考慮在 SKILL.md 的 scratch-file 段(idd-verify 的 /tmp/verify_${NUMBER}_* 檔名跨 session 碰撞 — 不同 repo 的同號 issue 互踩 findings 檔 #288 附近)加一行環境註記:Claude Code Bash = zsh,glob no-match 會 abort 整條命令 — 與 idd-verify 的 /tmp/verify_${NUMBER}_* 檔名跨 session 碰撞 — 不同 repo 的同號 issue 互踩 findings 檔 #288 同屬「檢查樣板的靜默失敗方向」家族。
Impact
Problem
idd-verify執行中,coordinator 用一條命令同時檢查 lens findings glob 與 codex 輸出檔:當時 4 個 lens agents 尚未寫檔(
findings_*.md零 match),但codex.md已存在(codex-call 已完成並寫入 19KB)。zsh 的預設nomatch行為對無 match 的 glob 會讓整條命令 abort(no matches found),2>/dev/null又吞掉了那行錯誤 → 存在的codex.md也沒被列出。搭配pgrep顯示 codex-call 程序已退出(實為正常完成),coordinator 得到兩個相互印證的假訊號,誤判「codex-call 死亡且沒寫輸出」。本次靠 launcher 的 task output file 留有
[codex-call] wrote 13723 chars一行才排除誤判。若沒有這條旁證,這個 false negative 的下游是:把已完成的 Codex lens 當 failure 標進 master report(「cross-model pass incomplete」process gap)、或觸發不必要的 retry — 都是靜默方向的錯。Type
bug
Root cause 歸屬(skill 文件層)
臨場命令是 executor 寫的,但
idd-verify/SKILL.md至少兩處樣板性地教這個寫法:ls $VERIFY_DIR/findings_*.md確認 5 個檔案 + non-empty」wait_for_claude_agents:「4 lens Agent calls return 後ls $VERIFY_DIR/findings_*.md確認 4 檔 non-empty」Claude Code 的 Bash 跑在 zsh;zsh 對 no-match glob 的 abort 行為是這個 plugin 生態已踩過的坑家族(safari-browser 的 unquoted-variable 教訓同源:zsh 與 bash 的字串/glob 語意差異)。glob 檢查在「檔案還沒生出來」的等待場景是常態路徑,不是 edge case — 樣板本身站在 footgun 上。
對照:Step 2.5a 的 bash 範例(
EXPECTED_FILESarray +[ -s "$f" ]逐一檢查)是正確寫法 — 問題只在鐵律段與 task 描述的 shorthand 樣板與它不一致。Expected
Actual
鐵律段樣板誘導 glob 合併檢查 → zsh nomatch abort → 存在的檔案被誤報為不存在 → 誤導 coordinator 判斷(本例:誤判 Codex 死亡;同構風險:Step 2.5 Recovery Protocol 被 false trigger,浪費一輪 agent spawn 或誤標 process gap)。
修法建議
wait_for_claude_agentstask 描述改為顯式路徑迴圈(即 Step 2.5a 既有樣板),或至少改寫為 zsh-safe 形式(每個 pattern 分開跑、或setopt null_glob/ls ... 2>/dev/null || true並明注「zsh nomatch 防禦」)。Impact