Repository navigation
idd-issue --blocked-by:GraphQL mutation 名稱錯誤(addBlockedByDependency 不存在,應為 addBlockedBy / blockingIssueId),且失敗訊息誤指原因、原生 dependency 從未建立 #353
Description
Problem
Original text:
「兩張 issue 都開」
— Source: 使用者,2026-09-24(+08:00)對話——同意開「idd-issue的 GraphQL mutation 名稱錯誤」這張 issue
idd-issue 的 --blocked-by 三層 fallback 中,Layer 1(GitHub 原生 dependency)用的 mutation 在 GitHub GraphQL schema 裡不存在:
mutation($i:ID!,$b:ID!){addBlockedByDependency(input:{issueId:$i,blockedByIssueId:$b}){issue{id}}}實際名稱(2026-09-24 introspection 查證):
$ gh api graphql -f query='{__schema{mutationType{fields{name}}}}' --jq '...name' | grep -i block
addBlockedBy
removeBlockedBy
$ gh api graphql -f query='{__type(name:"AddBlockedByInput"){inputFields{name}}}'
clientMutationId / issueId / blockingIssueId
正確寫法:
mutation($i:ID!,$b:ID!){addBlockedBy(input:{issueId:$i,blockingIssueId:$b}){issue{number}}}照文件原樣執行的回應是 Variable $b is declared by anonymous mutation but not used;改用 addBlockedBy 後在 PsychQuant/Akashic-Library#620、#621 實測成功(原生 blocked-by 已建立)。
Type
bug
為什麼一直沒被發現(安靜的失敗)
SKILL.md 的呼叫是 if ! gh api graphql … 2>/dev/null; then echo "⚠ … failed (repo not enabled / API error / permission); body blockquote already in place":
2>/dev/null吞掉了 GraphQL 的錯誤訊息;- 失敗訊息把原因歸給「repo 沒啟用/API 錯誤/權限」——三個都不是真因,讀的人會以為是環境問題;
- Layer 2(body blockquote)照樣成功,所以結果看起來「大致可用」。
依 CHANGELOG,這條 fallback 自 v2.52.0(#21)起就在;原生 dependency 很可能從未成功建立過。
受影響檔案(v3.1.0 原始碼)
plugins/issue-driven-dev/skills/idd-issue/SKILL.md(第 110、772、774 行附近:TaskCreate 描述、mutation、失敗訊息)plugins/issue-driven-dev/references/bundle-flags.md(Fallback Chain 段)README.md、CHANGELOG.md的相關敘述
Expected
- mutation 改為
addBlockedBy(input:{issueId, blockingIssueId}) - 失敗時印出 GraphQL 回傳的錯誤,不要吞掉、不要猜原因
- 加一個會打到真 schema 的檢查(或至少 introspection 斷言 mutation 名稱存在),讓 schema 改名時會被發現,而不是安靜地退回 Layer 2
Actual
Layer 1 永遠失敗,訊息誤導;只有 Layer 2 的 body blockquote 生效。
Impact
--blocked-by 與 --bundle-mode ordered 建的依賴在 GitHub UI 上沒有原生的 blocked 標示與側欄關聯,只剩內文一行註記。
Current Status
Phase: closed
Last updated: 2026-10-09 by idd-close
Closing summary: #353 (comment)
Dashboard: #353 (comment)
Verify: #353 (comment)
Key Decisions
- 驗證 2 輪 PASS、0 blocking;follow-up [bug] idd-issue --blocked-by handler:Layer 2 字面 \n、不去重、stdout 被佔用、目標編號與 node ID 未檢查 (follow-up from #353 verify) #359–[bug] SKILL.md 程式碼裡的 $0/$1/$2 會被 skill 參數替換改掉 (follow-up from #353 verify) #362;verified tag
idd-353-verified=68779cc - 「已存在」只比對整句
Target issue has already been taken,並印出該句作依據;其他has already been taken照常警告(取代下方第 6 條的寬鬆寫法) - Layer 1 訊息全走 stderr(bundle 用
CHILD_NUM=$(…)擷取 stdout);node ID 用-f傳 - live schema 檢查另由每週 workflow
live-schema.yml執行(週一 09:00 臺北時間+手動;merge 後才會跑) - 主規格的直接修改超出診斷原訂界線(多了已存在判定與 stderr 兩條 SHALL),決定保留在主規格,理由見驗證報告
Layer 1 改用(比對已收窄,見上)addBlockedBy(issueId, blockingIssueId),GitHub 錯誤原樣印出;already been taken視為已存在(實測)- 根因:mutation 與欄位名稱都不在現行 schema,且規格條文寫了同一錯名
- Complexity = Simple(現行帶錯名的檔案 4 個 < 5,呼叫點單一)
- 測試採離線守衛為主,真 schema introspection 做成 opt-in(repo 測試皆不打網路)
- 直接更正
openspec/specs/idd-issue-bundle/spec.md(先例a4f0723、e6cd7da),不動 archive
Scope Changes
- 新增
.github/workflows/live-schema.yml(驗證第 1 輪:live 檢查原本只能手動 opt-in) --blocked-byhandler 的其餘缺陷(Layer 2、--parent、目標驗證)不在本 issue 範圍,移到 [bug] idd-issue --blocked-by handler:Layer 2 字面 \n、不去重、stdout 被佔用、目標編號與 node ID 未檢查 (follow-up from #353 verify) #359
Blocking
- (none) — 下一步:merge PR idd-issue --blocked-by:改用 addBlockedBy 並原樣印出 GitHub 錯誤 (#353) #358 → 手動跑一次
gh workflow run live-schema.yml確認綠燈 →/idd-close #353
Commits
44c9691fix: idd-issue --blocked-by uses addBlockedBy and shows GitHub's error (idd-issue --blocked-by:GraphQL mutation 名稱錯誤(addBlockedByDependency 不存在,應為 addBlockedBy / blockingIssueId),且失敗訊息誤指原因、原生 dependency 從未建立 #353)b433021chore: release 3.0.1 — native dependency for --blocked-by (idd-issue --blocked-by:GraphQL mutation 名稱錯誤(addBlockedByDependency 不存在,應為 addBlockedBy / blockingIssueId),且失敗訊息誤指原因、原生 dependency 從未建立 #353)7d71b15fix: harden --blocked-by Layer 1 after verify round 168779ccfix: apply verify round 2 in-scope items for --blocked-by- PR idd-issue --blocked-by:改用 addBlockedBy 並原樣印出 GitHub 錯誤 (#353) #358
Activity
kiki830621 commentedon Oct 2, 2026
Diagnosis
Type
bug
Root Cause / Analysis
我認為 root cause 是:Layer 1 呼叫的 mutation 名稱與欄位名稱在 GitHub GraphQL schema 中都不存在——
addBlockedByDependency/blockedByIssueId,正確的是addBlockedBy/blockingIssueId。依據如下。重現(2026-10-02,兩方向各一次):
idd-issue/SKILL.md:772原樣執行(在 入庫端照收來源給的姓名結構與語言:Zotero 匯入目前把 family/given 壓成 literal Akashic-Library#719 ← #717 上):addBlockedBy(input:{issueId:$i,blockingIssueId:$b})後成功,blockedBy讀回717, 718。Mutation中與依賴相關的欄位只有addBlockedBy、removeBlockedBy(另有addSubIssue等);AddBlockedByInput的欄位是clientMutationId, issueId, blockingIssueId。這個名稱過去是否曾經存在,無法從現行 schema 查證;能確定的是現行 schema 沒有它。
為什麼一直沒被看見(三層):
SKILL.md:771的2>/dev/null吞掉了 GraphQL 回傳的錯誤。SKILL.md:774的失敗訊息寫死三個原因(repo not enabled / API error / permission),三個都不是真因,讀的人會往環境方向查。openspec/specs/idd-issue-bundle/spec.md的 Requirement 第 2 條是「SHALL attempt the GitHub GraphQLaddBlockedByDependencymutation」,失敗情境也列了同樣三個猜測原因。實作與規格一致地錯,照規格審查不會抓到。錯名的分布(worktree 實測
grep):plugins/issue-driven-dev/skills/idd-issue/SKILL.mdplugins/issue-driven-dev/references/bundle-flags.mdopenspec/specs/idd-issue-bundle/spec.mddocs/commands.mdplugins/issue-driven-dev/CHANGELOG.md:1602、README.md:178openspec/changes/archive/2026-05-05-add-bundle-flags-to-idd-issue/整個 plugin 只有
idd-issue這一個呼叫點;沒有其他 skill 使用依賴類 mutation。Impact
idd-issue --blocked-by與--bundle-mode ordered建立的依賴,GitHub UI 上從未出現原生 blocked 標示與側欄關聯,只剩內文的> Blocked by #MStrategy
SKILL.md:772改為addBlockedBy(input:{issueId:$i,blockingIssueId:$b}){issue{number}}SKILL.md:771-775不再2>/dev/null:保留 GraphQL 回傳的錯誤,失敗時原樣印出,移除寫死的三個猜測原因SKILL.md:110、:1008的名稱同步更正references/bundle-flags.md五處同步更正(含 mutation 範例與失敗情境表)openspec/specs/idd-issue-bundle/spec.md:Requirement 第 2 條改名;失敗情境改為「warning SHALL 包含 GraphQL 回傳的錯誤」,不再列猜測原因(直接修改主規格有先例:a4f0723、e6cd7da)docs/commands.md:153更正scripts/tests/blocked-by-mutation/:(a) 現行檔案不得出現addBlockedByDependency/blockedByIssueId(排除 CHANGELOG 歷史段與 archive);(b) Layer 1 使用addBlockedBy與blockingIssueId;(c) graphql 呼叫不得接2>/dev/null。另加一段 opt-in 的真 schema introspection 斷言(環境變數開啟才跑,否則明確印 SKIP),對應 Expected 第 3 點Conflict Class
A_parallel_safe
編輯限於
idd-issueSKILL.md、bundle-flags.md、一份 spec、docs/commands.md 與一個新測試目錄;與其他工作共享的只有 CHANGELOG/版本號這類純文字合併點,沒有共享的執行期資源。Complexity
Simple
Hard-gate: not triggered — 帶此錯名的現行檔案為 4 個(
idd-issue/SKILL.md、references/bundle-flags.md、openspec/specs/idd-issue-bundle/spec.md、docs/commands.md),未達 5;呼叫點只有idd-issue/SKILL.md:770-775一處,非共用抽象Layer 1 未命中(不是敘述文件);Layer 2 未命中(不新增對外介面,
--blocked-by的三層契約不變,只更正其中寫錯的識別名稱);Layer P 未命中(各檔獨立的文字更正,無順序依賴;測試做法依 repo 慣例決定,見 Risks)。Risks
run-all-tests.sh。所以主要防線是離線文字守衛;真 schema 的斷言做成 opt-in,避免 CI 因為沒有網路或 token 而變紅。opt-in 段在預設情況下只會印 SKIP,不能把它算成「schema 已驗證」。Residue
(none)
Vagueness Pre-check
Recommended Agent: codex-xhigh
Confidence: 0.5
Data source: static_heuristic(四個候選的 routing 資料皆為 0 筆,冷啟動規則)
Reasoning: Static heuristic (cold start): codex score 4 vs claude score 0.
Sister Concerns Filed (mid-diagnose, v2.47.0+ #528)
Filed: #356, #357
未開(與既定方向衝突):bundle 的 Epic 加上原生 sub-issue 連結(
addSubIssue)——#83 已定調跨票追蹤用 milestone,替 Epic 加功能與該方向相反;是否保留 Epic 由 #357 裁決。kiki830621 commentedon Oct 2, 2026
📊 For Reviewer / Collaborator
現在:已結案。根因是 Layer 1 呼叫的 mutation 名稱與欄位都不在 GitHub schema(應為
addBlockedBy/blockingIssueId),且錯誤被吞掉;已改用正確 mutation、原樣印出 GitHub 錯誤,隨 3.1.1 發布。merge 後手動跑的 live schema 檢查綠燈(2026-10-09)。Blocking:無
你該做什麼:無
last-updated by idd-close at → closed, 2026-10-09
kiki830621 commentedon Oct 2, 2026
Implementation Plan
plugins/issue-driven-dev/scripts/tests/blocked-by-mutation/test.sh(先寫,先看它失敗):(a) 所有 tracked 檔案不得出現addBlockedByDependency/blockedByIssueId,例外是封閉清單——CHANGELOG、README 的版本歷史列、openspec/changes/archive/、本測試目錄;(b) Layer 1 使用addBlockedBy與blockingIssueId;(c) graphql 呼叫不接2>/dev/null、不再寫死猜測原因;(d) 每條檢查都有陽性對照(對突變副本必須失敗);(e)IDD_LIVE_GH=1時對真 schema 做 introspection,否則明確印 SKIPskills/idd-issue/SKILL.md:Layer 1 改用addBlockedBy(input:{issueId, blockingIssueId});捕捉 GraphQL 輸出,失敗時原樣印出;has already been taken視為已存在(2026-10-02 實測:重複建立回 rc=1、Validation failed: Target issue has already been taken,狀態不變);第 110、1008 行同步更正references/bundle-flags.md:五處名稱、mutation 範例、失敗情境表同步更正openspec/specs/idd-issue-bundle/spec.md:Requirement 第 2 條改名;失敗情境改為「warning SHALL 包含 GraphQL 回傳的錯誤」;新增「依賴已存在」情境docs/commands.md:153plugin.json、.claude-plugin/marketplace.json)+ CHANGELOG 3.0.1 條目不改:CHANGELOG 舊條目、README 版本歷史列、已封存的 spectra change——都是當時的紀錄。
kiki830621 commentedon Oct 2, 2026
Implementation Complete
Checklist (synced from TaskList)
scripts/tests/blocked-by-mutation/test.sh(先紅後綠;17 項,陽性對照齊備;IDD_LIVE_GH=1時 20 項)→ commit 44c9691skills/idd-issue/SKILL.mdLayer 1:addBlockedBy(issueId, blockingIssueId)、GitHub 錯誤原樣印出、already been taken視為已存在;第 110、1018 行同步 → commit 44c9691references/bundle-flags.md五處與失敗情境改寫(移除猜測原因)→ commit 44c9691openspec/specs/idd-issue-bundle/spec.md:Requirement 第 2 條、失敗情境、新增「Dependency already exists」情境;spectra validate --specs24/24 valid → commit 44c9691docs/commands.md:153→ commit 44c9691Changes
Verification evidence(皆於 committed HEAD b433021 上新跑)
run-all-tests.sh:53/53 PASS(原 52 + 新 1)IDD_LIVE_GH=1:真 schema introspection 3 項通過(^addBlockedBy$、^issueId$、^blockingIssueId$,整行比對)Validation failed: Target issue has already been taken、狀態不變Files Changed
Scope Compliance
無超出範圍的改動。CHANGELOG 舊條目、README 版本歷史列、已封存的 spectra change 刻意未改(歷史紀錄)。bundle 區段的另外兩個缺陷已在診斷時分出為 #356、#357,未混入本 PR。
Next: verification pending
Sister Bugs Filed (mid-impl, v2.44.0+ #526)
(none surfaced) — 實作中唯一發現的問題是新測試 live 段的子字串斷言(
issueId會被blockingIssueId滿足),已在本 PR 內改為整行比對;bundle 區段的兩個缺陷已於診斷時分出為 #356、#357。更正(verify 第 2 輪後,2026-10-02)
Target issue has already been taken,並把那一句印到 stderr 當判讀依據。上方 Checklist 寫的already been taken是第 1 輪驗證前的寬鬆比對,已在 7d71b15 收窄。IDD_LIVE_GH=1時 46 項);PR 改動 9 個檔案,新增.github/workflows/live-schema.yml(每週一 09:00 臺北時間)。--parent寫 stdout、Layer 2 用字面\n、不去重、目標編號與 node ID 未檢查,兩輪驗證時才發現,已開 [bug] idd-issue --blocked-by handler:Layer 2 字面 \n、不去重、stdout 被佔用、目標編號與 node ID 未檢查 (follow-up from #353 verify) #359。驗證另開 [bug] idd-report:Discussions 的 GraphQL 呼叫照抄會失敗(query 變數撞名、mutation 沒傳變數)(follow-up from #353 verify) #360、[enhancement] run-all-tests.sh:通過的 suite 印出的 SKIP 在摘要裡看不到 (follow-up from #353 verify) #361、[bug] SKILL.md 程式碼裡的 $0/$1/$2 會被 skill 參數替換改掉 (follow-up from #353 verify) #362。fix: harden --blocked-by Layer 1 after verify round 1
fix: apply verify round 2 in-scope items for --blocked-by
kiki830621 commentedon Oct 2, 2026
Verify: #353
Engine
pai-ensemble 2.23.0 (canonical #207) — 4 IDD lenses (requirements / logic / security / regression) + DA + Codex (gpt-6.1-sol, effort medium), model: opus
Rounds
Aggregate
PASS — 0 blocking, 4 follow-ups (#359–#362).
No finding in either round violated an issue requirement or was a security hole. Round 2's two MEDIUMs were the same doc inconsistency (the DA rated it LOW). The round-2 in-scope fixes in 68779cc were not re-reviewed by the ensemble (Step 5c); they are covered by the test runs below.
要求覆蓋率
3 / 3 requirements addressed
addBlockedBy(input:{issueId, blockingIssueId}), in SKILL.md, the spec,references/bundle-flags.mdanddocs/commands.md.Target issue has already been taken, exact sentence) counts as success and prints that sentence as evidence. All Layer 1 messages go to stderr.IDD_LIVE_GH=1. It introspects the mutation, the input fields and the payload, and it ran green locally on 2026-10-02..github/workflows/live-schema.ymlruns it every Monday 09:00 Taipei and on demand. The CI run has not happened yet: a scheduled or dispatched workflow can only run from the default branch, so the first run comes after merge (see Post-merge).Findings (round 2, merged)
bundle-flags.mdLayer 1 example printed GitHub's reply to stdout (bare2>&1), against the stderr rule written under itGQL_OUTand points to SKILL.md; a test checks its shapebreakpassed all checksbreakcontrol--parentstill print to stdout insideCHILD_NUM=$(…), Layer 2 builds a literal\n, there is no dedup, and M /CHILD_NUMare not validated as integerschangelog/persist-credentials: falserun-all-tests.shhides SKIP lines from passing suitesRound-1 items deferred as out of scope: #360 (idd-report GraphQL), #361 (SKIP visibility), #362 (skill
$Nsubstitution). The node-ID guard went into #359.Decision: spec boundary
The diagnosis said a direct edit of the main spec would only correct the name and remove the guessed causes. The implementation went further. Requirement 2 now also says:
Target issue has already been takencounts as success, and any other "has already been taken" still warns;It also adds the Scenario "Dependency already exists" and two rows to the example table. These stay in the main spec, not in a Spectra change. They are the smallest contract that describes the corrected behaviour; without them the spec would still describe a layer that drops GitHub's error. The repo has precedent for direct corrections to a main spec (a4f0723, e6cd7da). This note corrects the boundary the diagnosis stated.
Scope Check
9 files: SKILL.md, the spec,
bundle-flags.md,docs/commands.md, the new suite, the new workflow, CHANGELOG,plugin.json,marketplace.json. Each change traces to #353. Version 3.0.1.Tests (at 68779cc, 2026-10-02)
scripts/run-all-tests.sh: 53 suites, 0 failedblocked-by-mutationwithIDD_LIVE_GH=1against github.com: 46 PASS / 0 FAILspectra validate --specs:idd-issue-bundlevalidFollow-up Findings Filed (v2.72.0+ #148)
--blocked-byhandler: Layer 2 literal\n, no dedup, stdout channel, unvalidated targets and node IDs$0/$1/$2in SKILL.md code are rewritten by skill argument substitutionPost-merge
gh workflow run live-schema.ymlonce and confirm it is green; cite the run in the closing summarychore: record #353 attachments manifest and verify routing outcome
Merge origin/main into idd/353-graphql-blocked-by; renumber the relea…
fix: idd-issue --blocked-by calls addBlockedBy and prints GitHub's er…
docs: sync README.md with the 3.1.1–3.3.0 releases (#331)
kiki830621 commentedon Oct 9, 2026
Closing Summary
Problem
從 2.52.0(#21)起,
/idd-issue --blocked-by與--bundle-mode ordered的 Layer 1 送出的 GraphQL mutation 在 GitHub schema 裡不存在。原生 dependency 從來沒有建立過,每一次都悄悄退回 body 的 blockquote。失敗訊息又寫死了三個無關的原因,讀的人會往環境方向查。Root Cause
Layer 1 呼叫的是
addBlockedByDependency(input:{issueId, blockedByIssueId}),GitHub schema 實際的名稱是addBlockedBy(input:{issueId, blockingIssueId})。2026-10-02 的 introspection 與兩個方向的重現都確認了這一點。有三層讓它一直沒被看見:
2>/dev/null吞掉了 GraphQL 回傳的錯誤。Solution
addBlockedBy,node ID 以-f綁定(-F遇到@開頭的值會去讀本機檔案)。失敗時原樣印出 GitHub 的輸出,不再猜原因。Target issue has already been taken視為已連結,不發警告。只認這一句,其他的「already been taken」照常警告。CHILD_NUM=$(…)裡,訊息若印在 stdout,會被當成下一張的--blocked-by值。references/bundle-flags.md、openspec/specs/idd-issue-bundle/spec.md、docs/commands.md。blocked-by-mutation用 stubgh跑四種模式,加上兩個目標的情境。另有.github/workflows/live-schema.yml,每週一 09:00(臺北時間)以IDD_LIVE_GH=1對真實 schema 做 introspection。Verification
/idd-verify(2026-10-02,兩輪): PASS,0 blocking。4 個 follow-up 已開成 [bug] idd-issue --blocked-by handler:Layer 2 字面 \n、不去重、stdout 被佔用、目標編號與 node ID 未檢查 (follow-up from #353 verify) #359、[bug] idd-report:Discussions 的 GraphQL 呼叫照抄會失敗(query 變數撞名、mutation 沒傳變數)(follow-up from #353 verify) #360、[enhancement] run-all-tests.sh:通過的 suite 印出的 SKIP 在摘要裡看不到 (follow-up from #353 verify) #361、[bug] SKILL.md 程式碼裡的 $0/$1/$2 會被 skill 參數替換改掉 (follow-up from #353 verify) #362。round 2 的 in-scope 修正(68779cc)沒有再經 ensemble 重審,改由下面的測試涵蓋。IDD_LIVE_GH=1對真實 schema 做 introspection,3 項通過。3be157e上 success。Changes
7acac5c,發布為 3.1.1。原本準備為 3.0.1,因為在 3.1.0 之後才 merge 而改號。Implementation Complete 的 Checklist 裡寫的「版本 3.0.0 → 3.0.1」,實際以 3.1.1 發布。44c9691、b433021、7d71b15、68779cc,以及 merge commit3be157e。Merge-completeness
Step 1.55 回 rc=3,列出 4 個 orphan(
44c9691、b433021、7d71b15、68779cc),判定為誤判:3be157e的 tree 與 squash7acac5c完全相同。另外,Step 1.55 的片段本身有兩處反斜線多了一個,照原樣執行永遠會跳過。這次是手動修正後才真的跑起來,這個問題另開 #375 追蹤。
Residue Acknowledgement
residue declared as
(none)at diagnose time — no acknowledgement neededDoc-sync 檢查
→ doc-sync: 8 files checked.
README.md已同步(1890012):plugin 表改為 3.3.0、19 skills / 8 rules / 28 references。plugins/issue-driven-dev/README.md第 184 行提到addBlockedByDependency。那一行是 v2.52.0 當時行為的歷史紀錄,所以保留不改。Distribution Sync
Live schema check(merge 後)
live-schema.yml在 merge 後一直沒有跑過(排程是每週一)。結案時手動觸發一次:run 37917817720 在94d1368上 success,blocked-by-mutation46 passed、0 failed,其中三項 live introspection 確認了addBlockedBy、issueId、blockingIssueId(2026-10-09T18:28+08:00)。chore: record the merged routing outcome for #353 (#353)