Problem
idd-close Step 1.55(merge-completeness gate)解析 issue 的 feature branch 時用:
BRANCH_REF=$(gh pr list --repo "$GITHUB_REPO" --state merged \
--search "in:body \"#${NUMBER}\"" --json headRefOid -q '.[0].headRefOid')
in:body "#N" 不是精確比對。GitHub 的 search 會做 tokenize,"#10" 命中了一個 body 內根本沒有 #10 的 PR。
Type
bug
Actual
實測於 PsychQuant/perspective-writer,close issue #10 時:
|
|
| 搜尋 |
gh pr list --state merged --search 'in:body "#10"' |
| 命中 |
PR #2(feat: EXTERNAL-CONSUMER CONTRACT — programmatic calibration…),headRefOid d1c6dfe2 |
| PR #2 body 內實際出現的 issue ref |
#1、#7、#20、#269、#272 —— 沒有 #10 |
| 時序 |
PR #2 merged 2026-08-02;issue #10 created 2026-08-10 |
於是 gate 拿到一個比 issue 早 8 天合併的無關 PR 的 branch SHA,準備對它跑 check-merge-completeness.sh。#10 走的是 direct-commit path、根本沒有 feature branch,正確行為應該是印那行 no merged PR / feature branch → direct-commit path 的 skip note。
實際後果有限(gate 是 warn-only,最壞是產生一則假 orphan 警告),但它污染的正是 gate 用來判斷的輸入,而使用者看到 orphan 警告時無從分辨真假。
Expected
Branch resolution 至少要排除結構上不可能的候選。兩道都便宜:
- 時序守衛(強烈建議) —— PR 的
mergedAt 早於 issue 的 createdAt → 不可能是該 issue 的 branch,直接排除。一次 gh issue view --json createdAt 即可,且完全不依賴 search 的精確度
- 精確 ref 比對 —— 取回候選 PR 的 body 後,用
grep -E "#${NUMBER}\b" 二次過濾(word-boundary),濾掉 #100/#1 這類 tokenize 假命中
兩道並用可涵蓋不同失效:(1) 擋掉時序不可能者(本案例),(2) 擋掉同期但編號相近的誤命中。
Impact
- 檔案:
skills/idd-close/SKILL.md Step 1.55 的 branch resolution 區塊
- 影響對象:所有走
/idd-close 且 repo 內有 merged PR 的 issue。direct-commit path 的 issue 最容易中招 —— 它們應該走 skip note,卻可能被塞一個無關 branch
- 嚴重度:低(warn-only gate,不硬擋 close),但錯誤方向是製造假訊號。一個會誤報的 gate,人會學會忽略它 —— 那等於沒有 gate。這正是 Step 1.55 自己的註解在講的事:「a checker whose output makes a passing check look like a skipped one is a checker people stop trusting」
附帶觀察
Step 1.55 的設計已經很小心處理過一個相關陷阱(#184 DA-1:用 headRefOid 而非 branch name,因為 GitHub merge 後會刪 branch)。時序守衛是同一類的「便宜且方向永遠正確」的加固 —— 建議一併補上。
Source: surfaced while running /idd-close #10 on PsychQuant/perspective-writer(2026-08-13);判定為 mis-detection 後跳過,已記入該 issue 的 closing summary ### Merge-completeness 段
Problem
idd-closeStep 1.55(merge-completeness gate)解析 issue 的 feature branch 時用:in:body "#N"不是精確比對。GitHub 的 search 會做 tokenize,"#10"命中了一個 body 內根本沒有#10的 PR。Type
bug
Actual
實測於
PsychQuant/perspective-writer,close issue #10 時:gh pr list --state merged --search 'in:body "#10"'feat: EXTERNAL-CONSUMER CONTRACT — programmatic calibration…),headRefOidd1c6dfe2#1、#7、#20、#269、#272—— 沒有#10於是 gate 拿到一個比 issue 早 8 天合併的無關 PR 的 branch SHA,準備對它跑
check-merge-completeness.sh。#10 走的是 direct-commit path、根本沒有 feature branch,正確行為應該是印那行no merged PR / feature branch → direct-commit path的 skip note。實際後果有限(gate 是 warn-only,最壞是產生一則假 orphan 警告),但它污染的正是 gate 用來判斷的輸入,而使用者看到 orphan 警告時無從分辨真假。
Expected
Branch resolution 至少要排除結構上不可能的候選。兩道都便宜:
mergedAt早於 issue 的createdAt→ 不可能是該 issue 的 branch,直接排除。一次gh issue view --json createdAt即可,且完全不依賴 search 的精確度grep -E "#${NUMBER}\b"二次過濾(word-boundary),濾掉#100/#1這類 tokenize 假命中兩道並用可涵蓋不同失效:(1) 擋掉時序不可能者(本案例),(2) 擋掉同期但編號相近的誤命中。
Impact
skills/idd-close/SKILL.mdStep 1.55 的 branch resolution 區塊/idd-close且 repo 內有 merged PR 的 issue。direct-commit path 的 issue 最容易中招 —— 它們應該走 skip note,卻可能被塞一個無關 branch附帶觀察
Step 1.55 的設計已經很小心處理過一個相關陷阱(#184 DA-1:用
headRefOid而非 branch name,因為 GitHub merge 後會刪 branch)。時序守衛是同一類的「便宜且方向永遠正確」的加固 —— 建議一併補上。Source: surfaced while running
/idd-close #10onPsychQuant/perspective-writer(2026-08-13);判定為 mis-detection 後跳過,已記入該 issue 的 closing summary### Merge-completeness段