From e33ffc7bda2f3f3dec2785b1bdefaf1e60449c16 Mon Sep 17 00:00:00 2001 From: che cheng Date: Fri, 14 Aug 2026 05:18:54 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20/idd-plan=20=E5=88=B0=E4=B8=8D?= =?UTF-8?q?=E4=BA=86=E3=80=81in:body=20=E9=9D=9E=E7=B2=BE=E7=A2=BA?= =?UTF-8?q?=E6=AF=94=E5=B0=8D=E3=80=81residue=20=E9=A0=90=E8=A8=AD?= =?UTF-8?q?=EF=BC=9B=E4=B8=A6=E6=8A=8A=E8=A8=AD=E8=A8=88=E7=9B=B2=E9=BB=9E?= =?UTF-8?q?=E5=AF=AB=E9=80=B2=20MANIFESTO=20(#292,=20#293,=20#305,=20#304,?= =?UTF-8?q?=20#144)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #292 報的是「兩份文件互相矛盾」,但矛盾只是徵狀:EnterPlanMode 住在 /idd-plan, idd-implement 收到 Plan tier 只會印一句警告,而 grep "idd-plan" idd-all/SKILL.md 在修正前沒有任何命中 —— /idd-plan 從 /idd-all 根本到不了。結果是 Plan tier 的 approval checkpoint 在 orchestrated 路徑上整個消失,而三處文件都宣稱它在。 #293/#305 同根因:GitHub 對 #N 做 tokenize,引號不會讓它變精確。實測 in:body "#7" 命中 body 內只有 codex-pro#7 的 PR、in:body "#10" 命中 body 內根本沒有 #10 的 PR。 兩張 issue 點名兩處,實際有七處。新增 references/pr-issue-matching.md 契約: search 只當粗篩、判定在 client 端做(排除跨 repo 形式),並加上 #305 的時序檢查。 #304 Step 3.6 預設改為 file-as-follow-up。原本的理由是為 Step 3.5 寫的(那一步撈的 是散文裡可能只是順口提到的 mention),但 residue 是 diagnose 時明確宣告的實體,且 依定義是「接不進任何機制」的那部分 —— 除了 follow-up issue 沒有東西會再碰它。 實測三個 residue 使用者三次都偏離預設。 #144 把「設計階段的抽象度,作者自己看不出來」寫進 MANIFESTO,附兩次量到的證據 (#135 連四輪、PR #297 連七輪),以及第七輪示範的遞迴形式:為防分岔而加的機器檢查 本身帶著同一個盲點,且新加的三個機制全部沒有測試重量。 43/43 suites 綠。 --- plugins/issue-driven-dev/CHANGELOG.md | 44 +++++++++++++++ plugins/issue-driven-dev/MANIFESTO.md | 19 +++++++ .../references/external-agent-delegation.md | 3 ++ .../issue-driven-dev/references/pr-flow.md | 3 ++ .../references/pr-issue-matching.md | 53 +++++++++++++++++++ .../references/usecase-routing.md | 3 ++ .../issue-driven-dev/skills/idd-all/SKILL.md | 10 ++-- .../skills/idd-close/SKILL.md | 21 ++++++-- .../skills/idd-report/SKILL.md | 3 ++ .../skills/idd-verify/SKILL.md | 3 ++ 10 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 plugins/issue-driven-dev/references/pr-issue-matching.md diff --git a/plugins/issue-driven-dev/CHANGELOG.md b/plugins/issue-driven-dev/CHANGELOG.md index da9674d..81a53f6 100644 --- a/plugins/issue-driven-dev/CHANGELOG.md +++ b/plugins/issue-driven-dev/CHANGELOG.md @@ -5,6 +5,50 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.104.0] - 2026-08-14 + +### Fixed + +- **`/idd-plan` was unreachable from `/idd-all` (#292)** — the issue reported "two skill docs contradict each other"; + the contradiction was the symptom. `EnterPlanMode` lives in `/idd-plan` (Step 4 `enter_plan_mode_for_approval`). + `/idd-implement` says so itself and, when handed a Plan-tier issue, prints a *warning* suggesting `/idd-plan` — it has + no gate. And `grep "idd-plan" idd-all/SKILL.md` returned **nothing**: the orchestrator never routed there. So under + `/idd-all`, Plan tier's entire approval checkpoint silently vanished while three separate places claimed it fired — + under attended mode the user got a warning telling them to use a skill the orchestrator would not call, and under + unattended mode the injected directive told the sub-skill to "skip the EnterPlanMode approval gate" it never had. + Routing table now sends attended Plan tier to **Phase 3p `/idd-plan`**; unattended is stated as a deliberate downgrade + rather than skipping a gate that does not exist. + +- **`in:body "#N"` is not exact matching, in seven places (#293, #305)** — GitHub tokenizes `#N`; quoting does not make + it precise. Measured on `PsychQuant/perspective-writer`: `in:body "#7"` matched a PR whose body contains only + `codex-pro#7`, and `in:body "#10"` matched a PR whose body contains no `#10` at all. Every call site took `.[0]` as + the answer. The two issues named two sites; the pattern was in **seven** — the close gate (blocks a legitimate close), + branch resolution (verifies the wrong branch), verify's input auto-detect (reviews the wrong PR), the report stats, + and three reference files that get copied. New contract `references/pr-issue-matching.md`: search is a coarse filter, + the decision is made client-side with a regex that excludes cross-repo forms, plus #305's orthogonal check that a PR + predating the issue cannot be its feature branch. It is documented as a pragmatic answer, not an authoritative one — + GraphQL's `CrossReferencedEvent` is closer but not semantically identical. + +- **`idd-close` Step 3.6 now files residue by default (#304)** — the default was `acknowledge as-is`, whose stated + rationale ("closure is a wrap-up moment, not a deliberation moment") was written for **Step 3.5**, a keyword scan over + prose that may have surfaced an offhand mention. Residue is not surfaced — it is *declared* at diagnose time, with the + template requiring an explicit `(none)` when empty. And residue is by definition the part that cannot be + operationalized, so nothing but a follow-up issue will ever touch it again: leaving it in the closing summary reopens + the write-only loop #105 was created to close. Empirically the default was on the wrong side — three residues in one + batch, the user deviated all three times. Aligned with IC_R011 §1.1; skip still requires a reason. + +### Added + +- **MANIFESTO: 設計階段的抽象度,作者自己看不出來 (#144)** — codified with the evidence that produced it: #135's design + phase went four rounds over-abstract before a third party named it, and PR #297 needed **seven** verify rounds where + every round the author believed it was fixed and every round external review found real defects. The heaviest one — + `gh` returning only the oldest 100 comments, so a real closing summary is truncated away and the issue is classified + `missing`, inviting a duplicate post — surfaced only after round six, because it was never in the layer the author + kept re-reading. Round seven then demonstrated the recursive form: the machine check added to prevent prose drift + carried the same blind spot, and all three of that round's new mechanisms had zero test weight. Hence the three rules: + third-party surfacing of design shape, a positive control for every guard, and "I enumerated exhaustively" is not + evidence. + ## [2.102.2] - 2026-08-01 ### Added diff --git a/plugins/issue-driven-dev/MANIFESTO.md b/plugins/issue-driven-dev/MANIFESTO.md index 066ba62..eed6bf5 100644 --- a/plugins/issue-driven-dev/MANIFESTO.md +++ b/plugins/issue-driven-dev/MANIFESTO.md @@ -338,3 +338,22 @@ Ad-hoc analysis script 同理:當 question 答完,script 進 archive,不會被 f 維護者:Che Cheng 首次版本:2026-04-28(針對 issue-driven-dev v2.32.0 的方法論論述) + +## 設計階段的抽象度,作者自己看不出來 + +AI 在設計階段會**穩定地過度抽象**,而且**當事人審不出來** —— 這不是偶發失誤,是可預期的系統性偏差,所以流程要對它有安排,不能靠「這次多想一下」。 + +證據不是印象,是兩次量到的: + +- **#135 的 design 階段連四輪過度抽象**(每一輪都獨立提出「做成獨立 skill」的更抽象版本),直到第三方點出才收斂。 +- **PR #297 連七輪 verify**:每一輪作者都認為修好了,每一輪外部審查都找到真缺陷。最重的一個(`gh` 只回最舊 100 則 comment,導致真 summary 被截、判 `missing`、觸發重複貼文)**直到第六輪之後才浮出來**,因為它根本不在作者反覆檢視的那一層。同一個 PR 裡,「散文與實作分岔」這個缺陷連續四輪復發,而作者每一輪都做過「完整枚舉」。 + +共同結構:**自審能驗「我打算做的有沒有做到」,驗不了「我做出來的東西自己有沒有矛盾」** —— 矛盾正是作者看不見的那部分。第七輪甚至示範了它的遞迴形式:作者為了防止分岔而新增的機器檢查,本身也帶著同一個盲點(清單只認作者記得加進去的東西),而且新加的三個機制**全部沒有測試重量**,還原任何一個測試都不會紅。 + +因此: + +1. **設計輪廓要由第三方 surface**,不是由作者自評。可以是 ensemble、可以是人,但不能是同一個腦袋再讀一遍。 +2. **每個新加的防護機制都要有 positive control** —— 證明它在被破壞時會失敗。不會失敗的檢查不是檢查。 +3. **「我已經完整枚舉過了」不是證據。** 四輪的枚舉都是誠實的,也都漏了東西。要嘛讓枚舉機械化,要嘛承認它會漏並安排第二雙眼睛。 + +(#144;證據來自 #135 與 PR #297。) diff --git a/plugins/issue-driven-dev/references/external-agent-delegation.md b/plugins/issue-driven-dev/references/external-agent-delegation.md index ba09540..600e49c 100644 --- a/plugins/issue-driven-dev/references/external-agent-delegation.md +++ b/plugins/issue-driven-dev/references/external-agent-delegation.md @@ -77,6 +77,9 @@ idd-verify #98 --branch # diff against origin/ N>0 → local mode HEAD~N..HEAD N=0 → continue b. Search open PRs ref'ing #N: gh pr list --search "#N in:body" --state open + +> ⚠ **`in:body "#N"` 不是精確比對**(#293 / #305)——它會誤中跨 repo 引用(`codex-pro#7` → `#7`)與無關的 PR。search 只能當粗篩,判定必須照 [`references/pr-issue-matching.md`](pr-issue-matching.md) 在 client 端精篩,並檢查 PR 不早於 issue。 + 1 PR found → AskUserQuestion "Verify PR #X or local diff?" 2+ PRs → AskUserQuestion list all 0 PRs → fall back HEAD~1 (preserves v2.36 behavior) diff --git a/plugins/issue-driven-dev/references/pr-flow.md b/plugins/issue-driven-dev/references/pr-flow.md index 3776b2f..14ce067 100644 --- a/plugins/issue-driven-dev/references/pr-flow.md +++ b/plugins/issue-driven-dev/references/pr-flow.md @@ -221,6 +221,9 @@ Identical to PR path: `: (#NNN)`, no auto-close trailers. ```bash OPEN_PRS=$(gh pr list --repo "$GITHUB_REPO" --state open \ --search "in:body \"#${N}\" OR in:body \"Refs #${N}\"" \ + +> ⚠ **`in:body "#N"` 不是精確比對**(#293 / #305)——它會誤中跨 repo 引用(`codex-pro#7` → `#7`)與無關的 PR。search 只能當粗篩,判定必須照 [`references/pr-issue-matching.md`](pr-issue-matching.md) 在 client 端精篩,並檢查 PR 不早於 issue。 + --json number,url,headRefName) ``` diff --git a/plugins/issue-driven-dev/references/pr-issue-matching.md b/plugins/issue-driven-dev/references/pr-issue-matching.md new file mode 100644 index 0000000..c9d06d5 --- /dev/null +++ b/plugins/issue-driven-dev/references/pr-issue-matching.md @@ -0,0 +1,53 @@ +# 找「引用某 issue 的 PR」——精確比對契約(#293 / #305) + +## 問題 + +GitHub 的 issue/PR search **對 `#N` 做 tokenize 後的比對,不是 issue-reference 解析**。加引號也不會變成精確比對。實測(`PsychQuant/perspective-writer`): + +``` +$ gh pr list --state merged --search 'in:body "#7"' --json number +[{"number":2}] # PR #2 body 內實際出現的是 codex-pro#7,不是 #7 + +$ gh pr list --state merged --search 'in:body "#10"' --json number +[{"number":2}] # PR #2 body 內根本沒有 #10 +``` + +所有呼叫點都直接把 `.[0]` 當答案用,所以誤配會安靜地變成錯誤的 gate 判定、錯誤的 branch、錯誤的 verify 目標。 + +## 契約 + +**search 只當粗篩,判定一律在 client 端做。** + +```bash +# 1. 粗篩(縮小結果集,允許誤中) +CANDIDATES=$(gh pr list --repo "$REPO" --state "$STATE" \ + --search "in:body \"#${N}\"" \ + --json number,body,createdAt,headRefOid,mergedAt) + +# 2. 精篩:#N 前面不得緊鄰 [A-Za-z0-9_/-],後面不得緊鄰數字 +# —— 這一條同時排除 owner/repo#N 與 repo#N 的跨 repo 形式,以及 #12 誤中 #123 +MATCHED=$(printf '%s' "$CANDIDATES" | jq --argjson n "$N" ' + map(select((.body // "") | test("(^|[^A-Za-z0-9_/-])#\($n)([^0-9]|$)")))') + +# 3. 時序檢查(#305):PR 若在 issue 開立之前就建立,不可能是它的 feature branch +ISSUE_CREATED=$(gh issue view "$N" --repo "$REPO" --json createdAt --jq .createdAt) +MATCHED=$(printf '%s' "$MATCHED" | jq --arg t "$ISSUE_CREATED" 'map(select(.createdAt >= $t))') +``` + +**多筆命中時不得預設取 `.[0]`** —— 依呼叫點的語意決定(最新 merge、或提示使用者),並把「有多筆」這件事印出來。 + +## 為什麼不用 GraphQL 的 `CrossReferencedEvent` + +那是最接近權威的來源,但語意不完全一致(它包含任何 cross-reference,不限於「這個 PR 要修這個 issue」),且需要 GraphQL 分頁。**本契約是務實解,不是權威解** —— 這一點要留在實作註解裡,免得後人以為問題已從根解決。 + +## 呼叫點(全部七處) + +| 位置 | 用途 | 誤配後果 | +|---|---|---| +| `skills/idd-close/SKILL.md` Step 1.5 | PR gate | 誤以為有未 merge 的 PR → **擋住合法的 close** | +| `skills/idd-close/SKILL.md` Step 1.55 | branch resolution | 拿到別的 PR 的 headRefOid → merge-completeness 比對錯的 branch | +| `skills/idd-verify/SKILL.md` Step 0.5 | auto-detect input source | 對錯的 PR 跑 verify | +| `skills/idd-report/SKILL.md` | 統計 | 數字偏誤 | +| `references/pr-flow.md` | 文件範例 | 會被照抄 | +| `references/usecase-routing.md` | 文件範例 | 會被照抄 | +| `references/external-agent-delegation.md` | 文件範例 | 會被照抄 | diff --git a/plugins/issue-driven-dev/references/usecase-routing.md b/plugins/issue-driven-dev/references/usecase-routing.md index ceee57c..024cb18 100644 --- a/plugins/issue-driven-dev/references/usecase-routing.md +++ b/plugins/issue-driven-dev/references/usecase-routing.md @@ -100,6 +100,9 @@ 2. N=0 → 查 open PRs ref'ing #98: gh pr list --search "#98 in:body" --state open + +> ⚠ **`in:body "#N"` 不是精確比對**(#293 / #305)——它會誤中跨 repo 引用(`codex-pro#7` → `#7`)與無關的 PR。search 只能當粗篩,判定必須照 [`references/pr-issue-matching.md`](pr-issue-matching.md) 在 client 端精篩,並檢查 PR 不早於 issue。 + 找到 1 PR → AskUserQuestion「Verify PR #X 還是本地 diff?」 找到 2+ PR → AskUserQuestion 列全部 找不到 → fall back HEAD~1(保留 v2.36 行為) diff --git a/plugins/issue-driven-dev/skills/idd-all/SKILL.md b/plugins/issue-driven-dev/skills/idd-all/SKILL.md index d59d72b..f59601f 100644 --- a/plugins/issue-driven-dev/skills/idd-all/SKILL.md +++ b/plugins/issue-driven-dev/skills/idd-all/SKILL.md @@ -530,7 +530,7 @@ print(m.group(1).strip() if m else 'UNKNOWN') | Complexity 值 | 下一步 | |--------------|--------| | `Simple` | Phase 3a: idd-implement | -| `Plan` | Phase 3a: idd-implement(unattended → Plan deliberation 跳過;attended → Plan tier `EnterPlanMode` approval gate 自然 fire) | +| `Plan` | **attended → Phase 3p: `/idd-plan`**(該 skill 擁有 `EnterPlanMode` 閘門,approve 後自己 chain 到 idd-implement);**unattended → Phase 3a: idd-implement**,並在 final report 標記 `[Plan tier deliberation skipped under unattended mode]` | | `Plan via Layer V` (v2.50+) | 視同 `Plan` 處理 — verdict 是 user 在 idd-diagnose Step 3.4 選 escalate 觸發,routing 行為跟 bare `Plan` 一致 | | `Spectra` | Phase 3b: spectra-discuss → spectra-propose → spectra-apply(unattended → 一輪收斂;attended → multi-turn 對話自然進行) | | `SDD-warranted` (legacy alias) | 視同 `Spectra` 處理(v2.36.0+ backward compat) | @@ -542,7 +542,9 @@ print(m.group(1).strip() if m else 'UNKNOWN') > > **Plan tier under (PR, unattended)**: Plan tier 的核心價值是 user approval via `EnterPlanMode`/`ExitPlanMode`。unattended 沒有 user 在 review plan,所以 Plan path 直接跳到 idd-implement,**在 final report 標記 `[Plan tier deliberation skipped under unattended mode]`**。 > -> **Plan tier under (direct-commit, attended)**: 不傳 unattended hint,idd-implement 進 Plan tier、`EnterPlanMode` 呈現 plan 給 user,user `ExitPlanMode` approve 後才繼續。這是 attended mode 的設計目的之一。 +> **Plan tier under (direct-commit, attended)**: 路由到 **`/idd-plan`**,由它 `EnterPlanMode` 呈現 plan 給 user,user `ExitPlanMode` approve 後由 `/idd-plan` 自己 chain 到 `/idd-implement`。這是 attended mode 的設計目的之一。 +> +> **修正紀錄(#292)**:本表過去把 Plan tier 直送 `idd-implement`,並宣稱該 skill 的 `EnterPlanMode` 閘門會「自然 fire」。**那個閘門不在 `idd-implement` 裡** —— 它住在 `/idd-plan`(見該 skill Step 4 `enter_plan_mode_for_approval`)。`idd-implement` 收到 Plan tier 時做的是**印一句警告**並用 AskUserQuestion 問要不要繼續(見其 SKILL.md 的 Complexity 表)。而 `grep "idd-plan" idd-all/SKILL.md` 在修正前**沒有任何命中** —— `/idd-plan` 從 `/idd-all` 根本到不了。結果是 Plan tier 的 approval checkpoint 在 orchestrated 路徑上整個消失,而三處文件都宣稱它在。 > > **SDD path under (PR, unattended)**: 三步 chain `spectra-discuss → spectra-propose → spectra-apply`,每步傳 `UNATTENDED MODE` directive 抑制 `AskUserQuestion`,一輪收斂、不停 Park。 > @@ -567,7 +569,7 @@ if [ "$INTERACTION" = "unattended" ]; then # Inline directive — sub-skill suppresses AskUserQuestion / EnterPlanMode prompts IMPL_ARGS="$IMPL_ARGS -UNATTENDED MODE — called by /idd-all orchestrator. Suppress AskUserQuestion. If complexity is Plan, skip the EnterPlanMode approval gate and proceed straight to TDD; mark in your final comment that Plan deliberation was skipped." +UNATTENDED MODE — called by /idd-all orchestrator. Suppress AskUserQuestion. If complexity is Plan, this is a DELIBERATE DOWNGRADE to the Simple path — there is no approval gate in this skill to skip (it lives in /idd-plan); proceed straight to TDD and mark in your final comment that Plan deliberation was skipped." fi Skill(skill="issue-driven-dev:idd-implement", args="$IMPL_ARGS") @@ -1086,7 +1088,7 @@ Next: review PR https://github.com/owner/repo/pull/87, merge after acceptance, t Phase 0.5 印 `→ Path: direct-commit (attended) — pr_policy=never`,sub-skill args **不帶** unattended hint。 中間流程: -- Phase 2 diagnose 判定 `Plan` → Phase 3a `idd-implement` 進 Plan tier、`EnterPlanMode` 把 plan 呈現給 user → user `ExitPlanMode` approve 後才繼續 TDD +- Phase 2 diagnose 判定 `Plan` → Phase 3p `/idd-plan` 用 `EnterPlanMode` 把 plan 呈現給 user → user `ExitPlanMode` approve → `/idd-plan` chain 到 `/idd-implement` 跑 TDD - Phase 4 verify 找到 1 個 P3 finding → 不 auto-fix(attended mode trade-off),直接 surface 給 user ``` diff --git a/plugins/issue-driven-dev/skills/idd-close/SKILL.md b/plugins/issue-driven-dev/skills/idd-close/SKILL.md index 1e61703..bea84b0 100644 --- a/plugins/issue-driven-dev/skills/idd-close/SKILL.md +++ b/plugins/issue-driven-dev/skills/idd-close/SKILL.md @@ -282,6 +282,9 @@ Exit code: ```bash OPEN_PRS=$(gh pr list --repo "$GITHUB_REPO" --state open \ --search "in:body \"#${NUMBER}\"" \ + +> ⚠ **`in:body "#N"` 不是精確比對**(#293 / #305)——它會誤中跨 repo 引用(`codex-pro#7` → `#7`)與無關的 PR。search 只能當粗篩,判定必須照 [`references/pr-issue-matching.md`](../../references/pr-issue-matching.md) 在 client 端精篩,並檢查 PR 不早於 issue。 + --json number,url,headRefName,mergeable) ``` @@ -558,10 +561,20 @@ When `RESIDUE_TRIGGER == "true"`, AskUserQuestion per IC_R011 canonical pattern. > > 該 residue 在 #${NUMBER} 完成期間有變動嗎?" > -> Options (default = first): -> - **`still residue — acknowledge as-is`** — record acknowledgement in closing summary that residue stayed as residue. No new issue. Audit trail: `Acknowledged as still residue (text quoted in audit block).` -> - **`file as follow-up issue(s)`** — surface candidate decompositions if residue has multiple distinct items; user picks which to file. Each filed issue gets `**Source**: residue from #${NUMBER} at /idd-close time` for traceability. -> - **`skip — record in audit trail only`** — no new issue, no acknowledgement; just log the user's choice. Audit trail: `Skipped per user choice (residue not addressed).` +> Options (default = first, flipped in #304): +> - **`file as follow-up issue(s)`** — **預設**。surface candidate decompositions if residue has multiple distinct items; user picks which to file. Each filed issue gets `**Source**: residue from #NNN` footer. Audit trail: `Filed as follow-up: #XXX`. +> - **`still residue — acknowledge as-is`** — record acknowledgement in closing summary that residue stayed as residue. No new issue. Audit trail: `Acknowledged as still-residue`. +> - **`skip — record in audit trail only`** — no new issue, no acknowledgement; just log the user's choice. Audit trail: `Skipped per user choice (residue not addressed)`. + +**為什麼預設是 file,不是 acknowledge(#304)**:三個理由,第三個是決定性的。 + +1. **原本的理由是從別處借來的。** Step 3.6 過去寫著「closure 是 wrap-up moment 非 deliberation moment」—— 那句話是為 **Step 3.5**(closing-summary keyword scan)寫的。那一步撈的是散文裡的 orphan mention,可能只是順口提到,預設不 file 合理。但 residue 不是撈出來的:它是 `idd-diagnose` 時**被明確宣告過的實體**,模板還強制無殘留要寫 `(none)`。對一個已經正式宣告的東西,預設「不追蹤」說不通。 + +2. **residue 的定義本身就指向它最容易被遺忘。** Foresay §4.6 的 residue = issue 意圖中*無法 operationalize* 的部分。無法 operationalize 就是接不進 checklist、接不進 commit、接不進測試 —— 除了 follow-up issue,**沒有任何機制會再碰它**。停在 closing summary 的散文裡等於宣告完就丟,而 #103 F3 指認的 write-only loop 正是這件事,#105 建本 step 就是要關掉它。 + +3. **實測與預設系統性相反。** 同一批 close 的三個 residue,使用者三次全部偏離預設(Akashic-Library #235/#219/#224,2026-08-13)。一次是偏好,三次同向是預設站錯邊 —— 而代價不對稱:多開一張 follow-up 的成本是三十秒與一次關票,漏追一個 residue 的成本是三個月後重新考古。 + +與 [`references/ic-r011-checkpoint.md`](../../references/ic-r011-checkpoint.md) §1.1 的 file-by-default 對齊;skip 需比照 §1.4 給理由。 #### File issues (if user picks `file`) diff --git a/plugins/issue-driven-dev/skills/idd-report/SKILL.md b/plugins/issue-driven-dev/skills/idd-report/SKILL.md index 2d1633d..95b95e2 100644 --- a/plugins/issue-driven-dev/skills/idd-report/SKILL.md +++ b/plugins/issue-driven-dev/skills/idd-report/SKILL.md @@ -137,6 +137,9 @@ git log --all --oneline --grep="#$NUMBER" | head -5 # 找對應 PR gh pr list --repo $GITHUB_REPO --state merged --search "#$NUMBER" \ + +> ⚠ **`in:body "#N"` 不是精確比對**(#293 / #305)——它會誤中跨 repo 引用(`codex-pro#7` → `#7`)與無關的 PR。search 只能當粗篩,判定必須照 [`references/pr-issue-matching.md`](../../references/pr-issue-matching.md) 在 client 端精篩,並檢查 PR 不早於 issue。 + --json number,title,mergedAt,additions,deletions ``` diff --git a/plugins/issue-driven-dev/skills/idd-verify/SKILL.md b/plugins/issue-driven-dev/skills/idd-verify/SKILL.md index 0e6e5f7..89e713f 100644 --- a/plugins/issue-driven-dev/skills/idd-verify/SKILL.md +++ b/plugins/issue-driven-dev/skills/idd-verify/SKILL.md @@ -336,6 +336,9 @@ TaskCreate(name="triage_followup_issues", description="Step 5b: 分類 non-block N>0 → 本地 mode HEAD~N..HEAD N=0 → b b. PRS=$(gh pr list --search "#$NUMBER in:body" --state open --json number,headRefName,author) + +> ⚠ **`in:body "#N"` 不是精確比對**(#293 / #305)——它會誤中跨 repo 引用(`codex-pro#7` → `#7`)與無關的 PR。search 只能當粗篩,判定必須照 [`references/pr-issue-matching.md`](../../references/pr-issue-matching.md) 在 client 端精篩,並檢查 PR 不早於 issue。 + 1 PR → AskUserQuestion「Verify PR #X 還是本地 diff?」 2+ PR → AskUserQuestion 列全部 0 PR → fall back HEAD~1(保留 v2.36 行為) From f008a4e7e5cd8b86a5400a54285e4f825bec09c3 Mon Sep 17 00:00:00 2001 From: che cheng Date: Fri, 14 Aug 2026 05:28:47 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E4=BF=AE=E6=8E=89=E6=88=91=E4=B8=8A?= =?UTF-8?q?=E4=B8=80=E5=80=8B=20commit=20=E8=AA=A4=E7=95=99=E5=9C=A8=20CHA?= =?UTF-8?q?NGELOG=20=E7=9A=84=E8=A1=9D=E7=AA=81=E6=A8=99=E8=A8=98=EF=BC=88?= =?UTF-8?q?=E5=85=A9=E5=81=B4=E6=A2=9D=E7=9B=AE=E9=83=BD=E4=BF=9D=E7=95=99?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/issue-driven-dev/CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/issue-driven-dev/CHANGELOG.md b/plugins/issue-driven-dev/CHANGELOG.md index f2d7da6..9614d1a 100644 --- a/plugins/issue-driven-dev/CHANGELOG.md +++ b/plugins/issue-driven-dev/CHANGELOG.md @@ -5,7 +5,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -<<<<<<< HEAD ## [2.104.0] - 2026-08-14 ### Fixed @@ -49,7 +48,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 carried the same blind spot, and all three of that round's new mechanisms had zero test weight. Hence the three rules: third-party surfacing of design shape, a positive control for every guard, and "I enumerated exhaustively" is not evidence. -======= ## [2.103.1] - 2026-08-14 ### Fixed @@ -75,7 +73,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Renamed in all four tables in `idd-clarify`, plus the copy `idd-issue` emits on the deferred path and the emit rule in `references/terminology-canonical.md` — that library keeps its own `Suggested canonical` field, which is a different layer, and now states that the canonical term is the *basis* of the question rather than the cell contents. ->>>>>>> main ## [2.102.2] - 2026-08-01