diff --git a/openspec/changes/reshape-plan-preimpl-tier/.openspec.yaml b/openspec/changes/reshape-plan-preimpl-tier/.openspec.yaml new file mode 100644 index 0000000..9d911e3 --- /dev/null +++ b/openspec/changes/reshape-plan-preimpl-tier/.openspec.yaml @@ -0,0 +1,4 @@ +schema: spec-driven +created: 2026-07-07 +created_by: che cheng +created_with: claude diff --git a/openspec/changes/reshape-plan-preimpl-tier/design.md b/openspec/changes/reshape-plan-preimpl-tier/design.md new file mode 100644 index 0000000..da24aac --- /dev/null +++ b/openspec/changes/reshape-plan-preimpl-tier/design.md @@ -0,0 +1,126 @@ +## Context + +IDD 的 Plan / pre-implementation tier 由三個 2026-07-07 使用者裁決收斂而來(issues #129 / #57 / #111,Cluster C 三決策): + +- **#129**:`/idd-diagnose` Step 3.5 的 Layer P(複雜度路由)目前是純建議性的 disjunctive any-match,大型多檔 / 動到共用抽象的改動可能靜默落 Simple 而被 under-plan。實證:#44 / #47 —— 同一 conceptual 改動散落三個量表,單次 Plan 未一次涵蓋,兩次 close 才補齊。 +- **#57**:meeting / 審議型 issue 被迫走 code-centric pipeline(Strategy = Files & Changes、closing = TDD verify),與「使用者驅動的決策工作」形狀不符。 +- **#111**:pre-implementation staging(brainstorm → written plan)在 IDD 沒有落點;而 #209 已把 superpowers 設為 install-time hard dependency,故正解是委派而非自建。 + +三者共通面:都重塑 Plan / pre-implementation tier,且 #129 與 #57 同碰 Step 3.5 routing,必須一起設計避免雙重判準。 + +## Goals / Non-Goals + +**Goals:** + +- 在 Layer P 之上疊一層 MUST-trigger 硬閘,讓 ≥ N 檔 / 共用抽象改動一定升級 Plan,同時保住其餘情況的 Simple 預設。 +- 讓 `meeting` 成為 first-class issue type,有專屬的 diagnose Strategy 模板、meeting-adapted plan body(跳過對 `/idd-implement` 的 chain)、與 decision→action 的 closing 語意。 +- 把 pre-implementation staging 委派給 superpowers(README 階段對照表 + diagnose/issue hand-off 指標),不自建對等 skill。 +- 統一 Step 3.5 的 routing 順序,讓 #129 硬閘與 #57 type 分支在同一判定流程裡有明確先後、互不衝突。 + +**Non-Goals:** + +- **不**反轉複雜度預設為 Default-Plan(#129 明確排除 —— 只升級、不改預設)。 +- **不**自建 idd-brainstorm / idd-write-plan skill(#111:依 deep-integration-over-hardcode,自建 = 禁止的 vendored fork)。 +- **不**對 meeting type 套用 `/idd-verify` TDD verify pass。 +- **不**改動 Layer V(vagueness)的**評分邏輯 / anchors**;既有 non-meeting issue 的 Layer V 行為完全不變。但 `type=meeting` 因最優先分流而**不經過** Layer V(round-1 verify HIGH-8:這是刻意的 —— 審議 issue 的模糊性由 Phase A/B/C 議程釐清,非 V1/V4 Likert;meeting 是新增 type,過去不存在,故非「改動既有行為」)。 +- **不**改動 `/idd-implement` 本身;meeting 分支只是在上游跳過對它的 chain。 + +## Decisions + +### 硬閘疊加於 Layer P 之上,不反轉 Simple 預設 + +保留 Layer P 現行的 disjunctive any-match「may trigger」語意;在其上新增一層 MUST-trigger 硬閘。硬閘命中 → 強制 Plan;未命中 → 維持既有 Layer P + Simple 預設。**替代方案(反轉為 Default-Plan)已被使用者否決**:那會把大量小改也拖進 plan-mode approval gate,over-trigger 的成本高於 under-plan 的殘餘風險。硬閘是「加法」不是「換底」。 + +### 硬閘判準用 diagnose-time 的 AI scope 估計,門檻 N=5 檔 + shared-abstraction 述詞 + +`/idd-diagnose` 在 implementation 之前執行,**沒有實際 diff**可 grep,故硬閘的觸發是 AI 對「本 issue 預期改動範圍」的**估計**,而非 diff-time 機械比對。判準(OR,任一即命中): + +1. **單一概念散佈 ≥ N 檔**,預設 **N = 5**。**判準是「同一 conceptual 改動散佈到 ≥ N 檔」,不是純檔數**:genuinely 各自獨立、無共享概念的多檔由 Layer 1「Multi-file but each file independent」保持 Simple、**不**觸發硬閘(round-1 verify HIGH-7:消解硬閘 vs Layer 1 對 5-independent-file 的矛盾)。取 5 而非 3/4 是為保護 Simple 預設:impl + test + doc 這類合法小改常觸及 3 檔,門檻設 3 會過度觸發;5 檔才是「單一概念散佈多處」的可靠訊號(對齊 #44/#47 的 failure class —— CR/PTSR/PCQ 三量表共用一 scoring helper 即散佈的單一概念)。N 是本設計唯一真正可調的旋鈕(見 Open Questions)。 +2. **動到 shared abstraction**:被多個 caller 使用的 data structure / helper interface / constants set。diagnose 以「issue 描述 + 對現有程式碼的引用查找」估計某個待改符號是否有 ≥ 2 個跨檔 caller;有 → 命中。 + +估計必須依 `attribute-assessment` 紀律揭露:在 Diagnosis comment 寫一行 `Hard-gate: `,與 Layer V 同等的 audit trail。認識論地位與 Layer P/V 的 AI 判斷一致 —— 是有理由、有錨點的估計,不是黑箱。 + +### 硬閘觸發後,Plan 必涵蓋 family-wide 影響 + +硬閘因 shared-abstraction 命中時,產出的 Plan **必須列舉該抽象的所有已知 call site / family 成員為 in-scope**,而非只覆蓋觸發當下那個檔案的最小修改。這正是 #44 的教訓:miss 不在於沒開 Plan,而在於 Plan 只覆蓋一個量表、沒涵蓋同 family 的 sibling(CR + PTSR + PCQ)。family-wide enumeration 是硬閘的產出契約的一部分。 + +### meeting 作為 first-class type:diagnose Strategy 模板 + plan skip-chain + closing 語意 + +`meeting` 加入 type taxonomy(與 bug / feature / refactor / docs 並列)。三段行為改變: + +- **diagnose**:對 `type=meeting` emit **Phase A/B/C Strategy 模板**(審議 deliverables:議程 / 決策點 / 行動項),取代 code-centric 的 Files & Changes。 +- **plan**:偵測 `type=meeting` → 用 meeting-adapted Plan body schema,且**跳過** Step 6 對 `/idd-implement` 的 chain(meeting 是 user-driven deliberation,不是 TDD loop)。 +- **closing**:無 `/idd-verify` TDD pass;closing summary = decision → action mapping。 + +**替代方案(issue 自身推薦的 Option C:doc-only 漸進過渡)已被使用者否決** —— 那把 adaptation 複雜度推遲進每個 agent 的臨場判斷,非本質正確形式;explicit 邊界 > implicit 判斷。過渡期沿用 `ai_martech_global_scripts` #615 的 Plan body 範本。 + +### Step 3.5 統一 routing 順序(消解 #129×#57 耦合) + +Step 3.5 內明定判定順序,讓兩個新機件不衝突(**忠實 7-step,含 Spectra,不省略任何 gate**):**(1) type=meeting 分支(走 meeting Strategy,最優先 —— type 是確定性欄位,先於任何內容啟發式)→ (2) Layer 1 disqualifier(narrative/ad-hoc → 強制 Simple)→ (3) Layer V vagueness(Step 3.4 既有)→ (4) Spectra(Layer 2+3;published API contract)→ (5) #129 硬閘(MUST-trigger)→ (6) Layer P any-match → (7) Simple 預設**。**meeting 最優先分流**(round-1 verify HIGH-2 修正:原設計把 Layer 1 放最前,會讓 meeting 的 Phase A/B/C 審議內容被 Layer 1 的 narrative disqualifier 攔成 Simple、永遠到不了 meeting 分支)。硬閘只作用於非 meeting 的 code-centric issue,兩者不會對同一 issue 同時給出衝突 verdict。(round-3 verify HIGH 修正:本段原為漏列 Spectra 的 5-step,與同檔 Acceptance Criteria + Risks 自我矛盾。) + +### pre-implementation staging 委派 superpowers,不自建 + +README 加 IDD ↔ superpowers 階段對照表(idd-issue / brainstorming / writing-plans / idd-implement / idd-verify / idd-close),明標 verify ensemble 與 close audit trail 為 IDD 獨有;design-heavy issue 在 `/idd-issue` Step 5 與 `/idd-diagnose` 加一行指向 `superpowers:brainstorming` 的 hand-off hint。**不**新增任何 staging skill。依 deep-integration-over-hardcode:superpowers 既是 hard dependency,hand-off 指標必然可解析,自建即 vendored fork。這是三個 requirement 中最輕的一塊,可在本 change 內先落地。 + +## Implementation Contract + +**Behavior(可觀察行為):** + +- diagnose 對「估計 ≥5 檔 或 動到 shared abstraction」的非 meeting issue → Complexity 欄輸出 `Plan`,且 Diagnosis comment 含一行 `Hard-gate: triggered — `;未命中則輸出 `Hard-gate: not triggered — ` 並回落既有 Layer P 判定。 +- diagnose 對 `type=meeting` → 輸出 Phase A/B/C Strategy 模板(非 Files & Changes)。 +- plan 對 `type=meeting` → 產出 meeting-adapted Plan body,且不 chain 到 `/idd-implement`。 +- idd-issue 接受 `meeting` 為合法 type 值;Step 5 與 diagnose 對 design-heavy issue 印出 `superpowers:brainstorming` hand-off hint。 +- plugin README 含 IDD ↔ superpowers 階段對照表。 + +**Interface / data shape:** + +- type taxonomy 值集由 `{bug, feature, refactor, docs}` 擴為 `{bug, feature, refactor, docs, meeting}`。 +- Diagnosis audit line 格式:`Hard-gate: `(單行,PATCH 進 Diagnosis comment,與 Layer V 的 audit line 並列)。 +- 硬閘 shared-abstraction 命中時,Plan body 含一個 `Family-wide scope` 小節,列舉所有已知 call site。 + +**Failure modes:** + +- diagnose 無法估計檔數 / caller 數(issue 描述過稀)→ 硬閘**不**命中(fail-open 到 Layer P + Simple 預設),並在 audit line 註明 `insufficient signal`。理由:硬閘是「加保護」,訊號不足時不應誤升級;漏升級由既有 Layer P 兜底。 +- superpowers 未安裝 → 已由 #209 hard dependency + pre-flight gate 處理,本 change 不新增 failure mode。 + +**Acceptance criteria:** + +- 新增 test.sh 案例:餵一個「issue 描述明示改 ≥5 檔」的 fixture → 斷言 diagnose 輸出 Complexity=Plan + `Hard-gate: triggered`。 +- 新增 test.sh 案例:餵 `type=meeting` fixture → 斷言 diagnose emit Phase A/B/C 模板、plan 不 chain 到 implement。 +- drift-guard / analyzer:斷言 type taxonomy 值集含 `meeting`;README 含階段對照表;Step 3.5 routing 順序文字含 **meeting-first 忠實 7-step 序列**(不省略 Spectra);Step 3.4 對 `type=meeting` short-circuit;tasks.md / spec.md 的 routing 順序與硬閘 qualifier 與 SKILL 一致(round-2 verify:normative artifact 亦納入 drift-guard)。 +- 以上皆以可觀察輸出斷言,不綁定 source line number。 + +**Scope boundaries:** + +- **In scope**:7 個 SKILL/rule/README/CLAUDE.md 編輯(idd-diagnose、idd-plan、idd-issue、**idd-close**、sdd-integration、README、**plugin CLAUDE.md**)+ 2 個新 spec(complexity-hard-gate、meeting-issue-type)+ 1 個 modified spec(superpowers-integration delta)+ 對應 test 案例。(idd-close 承載 meeting 的 decision→action closing + meeting-specific gate;CLAUDE.md 的 Checklist Conventions 加 meeting 例外註記 —— round-1/round-4 verify regression finding:原 Impact 漏列 idd-close 與 CLAUDE.md。) +- **Out of scope**:N 門檻在預設值 5 之外的進一步 calibration(見 Open Questions)、**既有 non-meeting issue 的 Layer V 評分邏輯/anchors**(meeting 因最優先分流而短路跳過 Layer V,屬本 change 範圍;改動的是 non-meeting 行為才 out of scope)、任何新 skill、`/idd-implement` 內部。 + +## Risks / Trade-offs + +- [N 設太低把 impl+test+doc 三件組拖進 Plan(over-trigger)] → 預設 N=5 保守;shared-abstraction 述詞作為更精準的 OR 條件補位;N 作為唯一旋鈕外顯供 calibrate。 +- [diagnose 無 diff,scope 估計可能失準] → 依 attribute-assessment 揭露估計 + 理由 + 錨點;認識論地位等同 Layer P/V 判斷;訊號不足時 fail-open 不誤升級。 +- [#129 硬閘與 #57 meeting 分支在 Step 3.5 給出雙重 verdict] → 統一 routing 順序決策把 meeting 分流置於複雜度評估之前,硬閘只作用於 code-centric issue,precedence 明確。 +- [meeting type 無 TDD verify,品質保證減弱] → 這是刻意的:meeting 是審議非 code,closing 的 decision→action mapping + 人工 review 是其對應的品質閘,非 TDD。 +- [Layer 1 narrative disqualifier 攔截 meeting(round-1 verify HIGH-2)] → meeting 分支移到**最優先**(step 1,先於 Layer 1);type 是確定性欄位,先分流即免疫於內容啟發式。 +- [硬閘 ≥5 檔 vs Layer 1「獨立多檔→Simple」矛盾(round-1 verify HIGH-7)] → 硬閘判準改為「單一概念散佈 ≥5 檔」;獨立多檔留給 Layer 1,兩機制不對同輸入給衝突 verdict。 +- [meeting 永久豁免 Layer V vagueness(round-1 verify HIGH-8)] → 接受為刻意設計:meeting 的模糊性由 Phase A/B/C 議程釐清;已在 Non-Goals 明述、非「改動既有 Layer V 行為」。 +- [string-only drift-guard = false assurance(round-1 verify HIGH-6)] → drift-guard 補強:新增 sdd-integration 內部一致性斷言(meeting 分支存在、無 stale「5-layer」、truth table 有 Hard-gate 欄)、Step 1 type recognition、Next Step meeting row、idd-close TaskCreate 分支 —— 讓「executor 與 canonical rule 漂移」這類可被機械斷言的內部矛盾被鎖住。 +- [meeting-first 排序在 Step 3.5 內,但 Step 3.4 Layer V 更早跑,形同虛設(round-2 verify HIGH)] → 於 Step 3.4 頂端加 `type=meeting` short-circuit(跳過整個 Layer V),並在 meeting spec 加對應 Scenario;drift-guard 斷言「跳過整個 Layer V」token。 +- [meeting Phase C 行動項無 downstream 打勾者,checklist gate 永久 deadlock close(round-2 verify HIGH)] → idd-close meeting 段改為 close 時經 decision→action mapping 為每個行動項標 `- [x]`/`- [~] tracked in #N`/`- [-]` disposition(依 Checklist Conventions 三者皆不擋);bare `- [ ]` 無 disposition 仍擋。 +- [normative artifact(tasks.md / 兩份 spec.md)仍載 disproven 舊規,且 archive 後成 canonical(round-2 verify CRITICAL + HIGH)] → 修正三檔至 meeting-first + interdependent qualifier + full bypass;drift-guard 擴至 change dir artifact(present 才斷言,downstream/archive 後 graceful skip),把「executor 修了但 spec 沒修」鎖住。 +- [5-stage 摘要漏列 Spectra,與 7-step operational list 歧義,且被 design acceptance criterion 鎖死(round-2 verify HIGH)] → 摘要改為忠實 7-step 序列(含 Spectra)與 list 一一對應;acceptance criterion 同步改「7-step 序列」。 +- [Spectra-omission 復發於 siblings:design.md Decisions 段、meeting spec Requirement/Scenario 仍是漏 Spectra 的短序(round-3 verify HIGH ×3)] → 全類掃除:design.md line 59 + meeting spec bypass 清單 + test 註解全部補上 Spectra;drift-guard 擴至讀 design.md 並斷言 Spectra 在 routing seq / bypass 清單(點修改成類修)。 +- [checklist gate 白名單不認得 meeting 標題 → Phase C 掃不到(round-3 verify HIGH ×2);且 round-3 的 whitelist bolt-on 其實是 prose-only —— `authoritative_source` resolution 無 meeting 分支、supersession 宣稱未實作,pure-meeting issue 會 deadlock 或完全不 gate(round-4 verify CRITICAL ×2)] → **改採 meeting-specific gate**(使用者裁決,取代 whitelist bolt-on):`type=meeting` 於 idd-close Step 0 分流、**不走** generic checklist gate / authoritative_source,改跑自足 meeting gate —— 掃 authoritative meeting deliverable(approved Meeting Plan Phase C,退回 diagnose Strategy deliberation Phase C;兩者並存只掃 Meeting Plan),precedence 就地判定、disposition 三態(`[x]`/`[~]`/`[-]`)、bare `- [ ]` 擋 close。revert round-3 加的 whitelist rows;plugin CLAUDE.md 副本改為 meeting 例外註記(兩處同步);meeting spec 加 gate Requirement + Scenario;drift-guard 斷言 meeting gate 分支存在(機制而非字串)。 +- [diagnose_by_type bootstrap TaskCreate 漏 docs/meeting(round-3 verify MEDIUM)] → 補齊 docs/meeting;drift-guard 斷言 meeting 在該行。 +- [meeting gate 的「approved Meeting Plan」是 prose 裝飾,真正條件是 existence 非 approval;且 no-deliverable / disposition 時序 / heading 前綴未定義(round-5 verify HIGH ×多)] → source resolution 改為可機械判定:**最新 `## Meeting Plan` comment(prefix 比對)→ 最新 `### Strategy (meeting deliberation)` → 兩者皆無則擋 close(不 vacuous pass)**;明訂執行順序(先 PATCH disposition 再跑 blocking check);掃 `- [ ]` 行不論 Phase C 是 heading 或粗體。drift-guard 鎖 no-deliverable block + 順序 + 移除「approved」誤導語。 +- [`type=meeting` 判定的「type 是確定性欄位」前提無解析程序(round-5 verify HIGH)] → idd-diagnose Step 1 補 type 解析序:GitHub label > body `## Type` heading > 衝突取 label > 皆無則預設非 meeting。drift-guard 斷言解析序存在。 +- [Pile B:hard gate「interdependent concept」、shared-abstraction lookup、Layer V prompt 時序、meeting clarity gate、mixed-mode detection 要求把 AI-judgment predicate 完全 deterministic(round-5 verify)] → 判定為 **by-design**:IDD 全部 complexity routing(Layer 1/V/P + 硬閘)皆 AI estimate + audit-trail 揭露(N=5 為使用者裁決);操作化到完全 deterministic 等於重設計已定案決策 + 大幅擴 scope。以 audit line 揭露為既有解;如需 operational checklist 留作 follow-up issue,不阻擋本 change。 + +## Migration Plan + +純加法,無 breaking change。既有非 meeting issue 不受影響;Layer P 既有 advisory 行為保留(硬閘是疊加層);meeting close 走**自足 meeting gate**,不改動 code-issue 的 generic checklist gate / `authoritative_source` resolution。type taxonomy 擴充向後相容(舊 issue 無 type=meeting)。Rollback = revert 7 個 SKILL/rule/README/CLAUDE.md 編輯(idd-diagnose、idd-plan、idd-issue、idd-close、sdd-integration、README、plugin CLAUDE.md)+ 移除 3 個新 test suite(complexity-hard-gate / meeting-issue-type / superpowers-staging)+ 移除整個 openspec change dir(proposal / design / tasks / specs,含 complexity-hard-gate、meeting-issue-type 新 spec 與 superpowers-integration delta);無資料遷移。 + +## Open Questions + +- **N 門檻最終值**:預設 5,於 apply 階段請使用者確認 / 微調(可調旋鈕;3 = 激進、5 = 保守)。 +- **shared-abstraction 偵測的機械形式**:diagnose-time 以「符號跨檔 caller 數 ≥ 2」為估計啟發式;實際啟發式細節(如何 grep、要不要限定 helper/constants 目錄)於 apply 階段細化。此為估計非精確判定,接受一定誤差。 diff --git a/openspec/changes/reshape-plan-preimpl-tier/proposal.md b/openspec/changes/reshape-plan-preimpl-tier/proposal.md new file mode 100644 index 0000000..0c00cfb --- /dev/null +++ b/openspec/changes/reshape-plan-preimpl-tier/proposal.md @@ -0,0 +1,38 @@ +## Why + +IDD's Plan / pre-implementation tier has three ratified gaps (user decisions 2026-07-07, issues #129 / #57 / #111). (1) Complexity routing's Layer P is purely advisory disjunctive any-match — large multi-file / shared-abstraction changes can silently route Simple and be under-planned (empirically #44 / #47: one conceptual change scattered across three artifacts, missed by a single Plan pass, needing two closes to fully cover). (2) Meeting / deliberation issues are forced through a code-centric pipeline (Strategy = Files & Changes, closing = TDD verify) that does not fit user-driven decision work. (3) Pre-implementation staging (brainstorm → written plan) has no home in IDD, and #209 already made superpowers a hard dependency — so the correct move is delegation, not a self-built equivalent. + +## What Changes + +- **#129 — complexity hard gate**: Layer P keeps its current disjunctive any-match "may trigger" behavior; on top of it, a **MUST-trigger hard gate** forces Plan tier when a change touches ≥ N files or modifies a shared abstraction (a data structure / helper interface / constants set used by multiple callers). The Simple default is preserved for everything else — the gate escalates, it does NOT invert the default to Default-Plan. +- **#57 — explicit meeting issue type**: add `meeting` to the issue-type taxonomy alongside bug / feature / refactor / docs. `/idd-diagnose` emits a Phase A/B/C Strategy template (deliberation deliverables, not code Files & Changes) for `type=meeting`; `/idd-plan` detects `type=meeting`, uses a meeting-adapted Plan body, and skips the Step 6 chain to `/idd-implement`; closing semantics become a decision→action mapping with no `/idd-verify` TDD pass. +- **#111 — delegate pre-implementation staging to superpowers**: add an IDD ↔ superpowers stage-mapping table to the plugin README (marking the verify ensemble and close audit trail as IDD-unique), and a hand-off hint in `/idd-issue` Step 5 and `/idd-diagnose` pointing design-heavy issues at superpowers:brainstorming. No new idd-brainstorm / idd-write-plan skill is created — self-building would be a forbidden vendored fork under the deep-integration-over-hardcode rule. + +Coupling: #129's hard gate and #57's meeting branch both alter `/idd-diagnose` Step 3.5 routing, so they are designed together in this one change to avoid a double or conflicting verdict path. + +## Capabilities + +### New Capabilities + +- `complexity-hard-gate`: MUST-trigger escalation layered above Layer P that forces Plan tier on ≥ N-file or shared-abstraction changes, while preserving the Simple default elsewhere. +- `meeting-issue-type`: first-class `meeting` issue type with a deliberation-shaped diagnose Strategy template, a meeting-adapted plan body that skips the implement chain, and decision→action closing semantics. + +### Modified Capabilities + +- `superpowers-integration`: add a pre-implementation staging hand-off requirement — README stage-mapping table plus diagnose / issue hand-off pointers to superpowers:brainstorming, with no self-built staging skill. + +## Impact + +- Affected specs: `complexity-hard-gate` (new), `meeting-issue-type` (new), `superpowers-integration` (modified) +- Affected code: + - Modified: + - plugins/issue-driven-dev/skills/idd-diagnose/SKILL.md (Step 3.5 routing — #129 hard gate + #57 meeting Strategy template branch) + - plugins/issue-driven-dev/skills/idd-plan/SKILL.md (#57 meeting-adapted Plan body + skip Step 6 chain to implement) + - plugins/issue-driven-dev/skills/idd-issue/SKILL.md (#57 add meeting to the type taxonomy; #111 hand-off hint at Step 5) + - plugins/issue-driven-dev/skills/idd-close/SKILL.md (#57 meeting decision→action closing semantics — no /idd-verify TDD pass) + - plugins/issue-driven-dev/rules/sdd-integration.md (#129 Layer P hard-gate definition) + - plugins/issue-driven-dev/README.md (#111 IDD ↔ superpowers stage-mapping table) + - New: + - openspec/specs/complexity-hard-gate/spec.md (on archive) + - openspec/specs/meeting-issue-type/spec.md (on archive) + - Removed: (none) diff --git a/openspec/changes/reshape-plan-preimpl-tier/specs/complexity-hard-gate/spec.md b/openspec/changes/reshape-plan-preimpl-tier/specs/complexity-hard-gate/spec.md new file mode 100644 index 0000000..2bb03a5 --- /dev/null +++ b/openspec/changes/reshape-plan-preimpl-tier/specs/complexity-hard-gate/spec.md @@ -0,0 +1,53 @@ +## ADDED Requirements + +### Requirement: MUST-trigger complexity hard gate layered above Layer P + +`/idd-diagnose` Step 3.5 SHALL evaluate a MUST-trigger hard gate that forces the `Plan` complexity tier when the diagnosed change is estimated to touch at least N files (default N = 5) **that belong to one interdependent concept**, OR to modify a shared abstraction. A shared abstraction is a data structure, helper interface, or constants set estimated to be referenced by at least 2 distinct files other than the one under change. The file-count trigger is scoped to *one interdependent concept scattered across files*, NOT raw file count: genuinely-independent multi-file changes (parallel doc updates, independent script tweaks) SHALL NOT trigger the hard gate — they remain `Simple` via the Layer 1 "Multi-file but each file independent" disqualifier. The hard gate SHALL only escalate: when it does not trigger, routing SHALL fall through to the existing Layer P disjunctive any-match evaluation with the `Simple` default preserved. The hard gate SHALL NOT invert the default tier to `Plan`. + +#### Scenario: Multi-file change of one interdependent concept forces Plan + +- **WHEN** `/idd-diagnose` estimates a change will touch 5 or more files that belong to one interdependent concept +- **THEN** the Complexity verdict is `Plan`, set by the hard gate before Layer P is consulted + +#### Scenario: Shared-abstraction change forces Plan + +- **WHEN** `/idd-diagnose` estimates the change modifies a helper interface referenced by 2 or more other files +- **THEN** the Complexity verdict is `Plan`, set by the hard gate + +##### Example: gate decisions by estimated scope + +| Estimated scope | Shared abstraction touched | Hard gate | Complexity verdict | +| --------------- | -------------------------- | --------- | ------------------ | +| 1 file (impl only) | no | not triggered | Simple (default) | +| 3 files (impl + test + doc) | no | not triggered | Simple (default), unless Layer P any-match fires | +| 5 files of one interdependent concept | no | triggered | Plan | +| 5 genuinely-independent files (parallel doc / script edits) | no | not triggered | Simple (Layer 1 disqualifier) | +| 2 files | yes (constants set used by 4 callers) | triggered | Plan | + +#### Scenario: Small isolated change preserves the Simple default + +- **WHEN** `/idd-diagnose` estimates a change touches 1 file and no shared abstraction, and no Layer P signal fires +- **THEN** the hard gate does not trigger and the Complexity verdict is `Simple` + +### Requirement: Hard-gate estimate is disclosed in the audit trail + +The hard-gate evaluation SHALL be an AI scope estimate, because `/idd-diagnose` runs before implementation and no diff exists yet. The evaluation SHALL be disclosed as a single audit line of the form `Hard-gate: ` in the Diagnosis comment, placed alongside the Layer V audit line. The reason SHALL cite concrete anchors (estimated file names or symbol names), not style words. When the issue provides insufficient signal to estimate file count or caller count, the hard gate SHALL NOT trigger and the audit line SHALL state `insufficient signal`. + +#### Scenario: Triggered gate discloses reason and anchors + +- **WHEN** the hard gate triggers because the issue names four scale-family modules plus a shared scoring helper +- **THEN** the Diagnosis comment contains a line `Hard-gate: triggered — ` + +#### Scenario: Insufficient signal fails open to Layer P + +- **WHEN** the issue body is too sparse to estimate file count or caller count +- **THEN** the hard gate does not trigger, the audit line reads `Hard-gate: not triggered — insufficient signal`, and routing falls through to Layer P with the `Simple` default + +### Requirement: Shared-abstraction trigger forces family-wide Plan scope + +When the hard gate triggers because of a shared-abstraction estimate, the resulting Plan SHALL enumerate all known call sites and family members of that abstraction as in-scope, not only the triggering file. + +#### Scenario: Plan enumerates family members + +- **WHEN** the hard gate triggers on a change to a scoring helper shared by three sibling scale modules +- **THEN** the Plan lists all three sibling modules as in-scope, not just the one module named in the issue title diff --git a/openspec/changes/reshape-plan-preimpl-tier/specs/meeting-issue-type/spec.md b/openspec/changes/reshape-plan-preimpl-tier/specs/meeting-issue-type/spec.md new file mode 100644 index 0000000..4795e43 --- /dev/null +++ b/openspec/changes/reshape-plan-preimpl-tier/specs/meeting-issue-type/spec.md @@ -0,0 +1,52 @@ +## ADDED Requirements + +### Requirement: meeting is a first-class issue type + +The IDD issue-type taxonomy SHALL include `meeting` alongside `bug`, `feature`, `refactor`, and `docs`. `/idd-issue` SHALL accept `meeting` as a valid type value when creating an issue. + +#### Scenario: idd-issue accepts the meeting type + +- **WHEN** a user creates an issue and selects type `meeting` +- **THEN** `/idd-issue` records the type as `meeting` without falling back to `feature` or rejecting the value + +### Requirement: Diagnose emits a deliberation Strategy for meeting issues + +For an issue with `type=meeting`, `/idd-diagnose` SHALL emit a Phase A/B/C deliberation Strategy template (Phase A agenda, Phase B decision points, Phase C action items) instead of the code-centric Files & Changes Strategy. The `meeting` branch SHALL be evaluated FIRST in routing — before the Layer 1 disqualifier, before the Layer V vagueness pre-check (which SHALL short-circuit at Step 3.4 for `type=meeting`), before the Spectra (Layer 2+3) evaluation, before the complexity hard gate, and before Layer P — so a `meeting` issue SHALL NOT be assigned a `Simple`, `Plan`, or `Spectra` complexity verdict by any of them. Evaluating meeting first is required because a meeting's deliberation content would otherwise match the Layer 1 narrative disqualifier and be forced to `Simple`. + +#### Scenario: meeting issue gets a Phase A/B/C Strategy + +- **WHEN** `/idd-diagnose` runs on an issue with `type=meeting` +- **THEN** the emitted Strategy contains Phase A / Phase B / Phase C deliberation sections and contains no Files & Changes section + +#### Scenario: meeting issue bypasses the complexity hard gate + +- **WHEN** `/idd-diagnose` reaches Step 3.5 routing for an issue with `type=meeting` +- **THEN** the meeting branch is taken before complexity scoring, so none of Spectra (Layer 2+3), the hard gate, or Layer P assigns a `Simple` / `Plan` / `Spectra` verdict to the issue + +#### Scenario: meeting issue skips the Layer V vagueness gate + +- **WHEN** `/idd-diagnose` reaches Step 3.4 (Layer V) for an issue with `type=meeting` whose body would otherwise score V1/V4 ≥ 4 +- **THEN** Step 3.4 short-circuits without scoring V1/V4 or raising the vagueness AskUserQuestion, and routing proceeds directly to the Step 3.5 meeting branch + +### Requirement: Plan for meeting issues skips the implement chain + +For an issue with `type=meeting`, `/idd-plan` SHALL produce a meeting-adapted Plan body and SHALL NOT chain to `/idd-implement`. + +#### Scenario: meeting plan does not chain to implement + +- **WHEN** `/idd-plan` completes for an issue with `type=meeting` +- **THEN** the Plan body uses the meeting-adapted schema and the skill does not invoke or prompt to invoke `/idd-implement` + +### Requirement: Meeting closing maps decisions to actions without a TDD verify pass + +Closing an issue with `type=meeting` SHALL use a decision-to-action mapping as the closing summary and SHALL NOT require an `/idd-verify` TDD verification pass. `/idd-close` SHALL gate a `type=meeting` issue with a **meeting-specific gate** — NOT the generic code-issue checklist gate / `authoritative_source` resolution. The meeting gate SHALL scan the authoritative meeting deliverable — the approved Meeting Plan's Phase C action items, falling back to the diagnose Strategy deliberation's Phase C when no plan stage ran (when both exist, only the Meeting Plan Phase C is scanned) — and each action item SHALL carry a disposition marker (`[x]` done / `[~]` tracked in a follow-up / `[-]` dropped). A bare undispositioned `- [ ]` action item SHALL block close. + +#### Scenario: meeting close needs no TDD verify + +- **WHEN** an issue with `type=meeting` is closed +- **THEN** the closing summary records each decision mapped to its follow-up action, and no `/idd-verify` TDD pass is required as a precondition of closing + +#### Scenario: meeting gate blocks on an undispositioned Phase C action item + +- **WHEN** a `type=meeting` issue with an approved Meeting Plan whose Phase C contains a bare `- [ ]` action item (no owner / no disposition) is closed +- **THEN** the meeting-specific gate blocks close until that item is marked `[x]`, `[~] — tracked in #NNN`, or `[-] — ` (mirroring the generic checklist markers), and the generic `authoritative_source` resolution is not consulted for the meeting issue diff --git a/openspec/changes/reshape-plan-preimpl-tier/specs/superpowers-integration/spec.md b/openspec/changes/reshape-plan-preimpl-tier/specs/superpowers-integration/spec.md new file mode 100644 index 0000000..a34965e --- /dev/null +++ b/openspec/changes/reshape-plan-preimpl-tier/specs/superpowers-integration/spec.md @@ -0,0 +1,36 @@ +## MODIFIED Requirements + +### Requirement: Kept disciplines are excluded from delegation + +`idd-verify` ensemble backend resolution, worktree isolation, and planning disciplines (idd-plan / Spectra — explicitly including the `brainstorming` and `writing-plans` counterparts) SHALL NOT delegate to `superpowers`. A non-binding hand-off pointer surfaced by `idd-issue` or `idd-diagnose` that names `superpowers:brainstorming` as an optional pre-implementation staging destination for the user is NOT delegation — IDD's own planning flow does not invoke it, and the user chooses whether to follow the pointer — and it is permitted; that pointer is governed by the "Pre-implementation staging hand-off to superpowers" requirement. + +#### Scenario: Verify backend unaffected + +- **WHEN** `idd-verify` resolves its ensemble backend +- **THEN** resolution follows the existing `idd-verify` spec chain (pai canonical → vendored fallback → manual fan-out) with no `superpowers` involvement + +#### Scenario: Planning disciplines remain superpowers-free + +- **WHEN** `idd-plan` or the Spectra planning skills execute +- **THEN** their skill definitions contain no `superpowers:` invocation (mechanical check: `grep -rn 'superpowers:' plugins/issue-driven-dev/skills/idd-plan/` returns zero hits) + +## ADDED Requirements + +### Requirement: Pre-implementation staging hand-off to superpowers + +The IDD plugin README SHALL contain an IDD-to-superpowers stage-mapping table that maps each IDD pipeline stage to its superpowers counterpart and marks the `idd-verify` ensemble and the `idd-close` audit trail as IDD-unique (no superpowers counterpart). For a design-heavy issue, `idd-issue` (at its issue-creation summary step) and `idd-diagnose` SHALL surface a non-binding hand-off pointer naming `superpowers:brainstorming` as the pre-implementation staging destination. IDD SHALL NOT add a self-built brainstorming or plan-writing skill; no skill named `idd-brainstorm` or `idd-write-plan` SHALL exist. + +#### Scenario: README documents the stage mapping + +- **WHEN** a reader opens the IDD plugin README +- **THEN** a stage-mapping table maps IDD pipeline stages to superpowers counterparts and explicitly marks the verify ensemble and close audit trail as having no superpowers counterpart + +#### Scenario: Design-heavy issue surfaces the brainstorming pointer + +- **WHEN** `idd-diagnose` classifies an issue as design-heavy (Plan tier or Spectra tier) +- **THEN** the emitted output contains a non-binding pointer naming `superpowers:brainstorming` as the pre-implementation staging destination, and the pointer does not cause IDD to invoke that skill itself + +#### Scenario: No self-built staging skill is added + +- **WHEN** the IDD plugin skill set is enumerated +- **THEN** no skill named `idd-brainstorm` or `idd-write-plan` exists (mechanical check: the `plugins/issue-driven-dev/skills/` directory contains neither) diff --git a/openspec/changes/reshape-plan-preimpl-tier/tasks.md b/openspec/changes/reshape-plan-preimpl-tier/tasks.md new file mode 100644 index 0000000..c274db4 --- /dev/null +++ b/openspec/changes/reshape-plan-preimpl-tier/tasks.md @@ -0,0 +1,28 @@ + + +## 1. 硬閘(#129,complexity-hard-gate) + +- [x] 1.1 為 **MUST-trigger complexity hard gate layered above Layer P** 先寫 drift-guard fixture(TDD RED):給定「估計 ≥5 檔」與「動到 shared abstraction」兩組 diagnose 輸入,斷言 Complexity verdict = `Plan`;給定「1 檔、無 shared abstraction、無 Layer P 訊號」斷言 verdict = `Simple`。落實 design 決策 **硬閘疊加於 Layer P 之上,不反轉 Simple 預設**。驗證:新增 fixture 在實作前執行為 RED(斷言失敗)。 +- [x] 1.2 在 `plugins/issue-driven-dev/skills/idd-diagnose/SKILL.md` Step 3.5 與 `plugins/issue-driven-dev/rules/sdd-integration.md` Layer P 段落實作硬閘:`Plan` 只升級不反轉,門檻 N=5、shared-abstraction 述詞 =「符號跨檔 caller 數 ≥ 2」。落實 design 決策 **硬閘判準用 diagnose-time 的 AI scope 估計,門檻 N=5 檔 + shared-abstraction 述詞**。驗證:1.1 fixture 由 RED 轉 GREEN,且 Simple-default fixture 仍 GREEN。 +- [x] 1.3 實作 **Hard-gate estimate is disclosed in the audit trail**:diagnose 於 Diagnosis comment 印出單行 `Hard-gate: `,訊號不足時印 `insufficient signal` 且不觸發(fail-open 回 Layer P)。驗證:新增 fixture 斷言三種情境(triggered/not triggered/insufficient signal)各自輸出對應 audit line 字串。 +- [x] 1.4 實作 **Shared-abstraction trigger forces family-wide Plan scope**:shared-abstraction 觸發時,產出的 Plan 列舉該抽象的所有已知 call site / family member 為 in-scope。落實 design 決策 **硬閘觸發後,Plan 必涵蓋 family-wide 影響**。驗證:fixture 給定「scoring helper 被三個 sibling 量表共用」,斷言 Plan 列出三個 sibling(非僅 issue 標題點名的單檔)。 + +## 2. meeting 型別(#57,meeting-issue-type) + +- [x] 2.1 [P] 實作 **meeting is a first-class issue type**:在 `plugins/issue-driven-dev/skills/idd-issue/SKILL.md` 的 type taxonomy 加入 `meeting`(與 `bug` / `feature` / `refactor` / `docs` 並列),idd-issue 接受 `meeting` 為合法 type 值。驗證:drift-guard 斷言 taxonomy 行含 `meeting`;以 `meeting` 建 issue 不 fallback 成 `feature`、不被拒。 +- [x] 2.2 實作 **Diagnose emits a deliberation Strategy for meeting issues**:`type=meeting` 時 idd-diagnose emit Phase A/B/C 審議 Strategy 模板(agenda / decision points / action items),不 emit code-centric 的 Files & Changes。驗證:fixture 斷言 meeting issue 的 Strategy 含 Phase A/B/C 段、且不含 Files & Changes 段。 +- [x] 2.3 實作 **Plan for meeting issues skips the implement chain**:`plugins/issue-driven-dev/skills/idd-plan/SKILL.md` 對 `type=meeting` 用 meeting-adapted Plan body schema,且不 chain 到 `/idd-implement`。驗證:fixture 斷言 meeting plan 用 meeting schema 且輸出不含對 `/idd-implement` 的邀請/呼叫。 +- [x] 2.4 實作 **Meeting closing maps decisions to actions without a TDD verify pass**:closing meeting issue 以 decision→action mapping 作 closing summary,不要求 `/idd-verify` TDD pass 為前置。落實 design 決策 **meeting 作為 first-class type:diagnose Strategy 模板 + plan skip-chain + closing 語意**。驗證:fixture 斷言 meeting close 路徑產出 decision→action 對照且不 gate 於 idd-verify。 + +## 3. 耦合收斂(#129 × #57) + +- [x] 3.1 於 idd-diagnose Step 3.5 建立統一 **meeting-first** routing 順序:(1) `type=meeting` 分支 →(2) Layer 1 disqualifier →(3) Layer V vagueness →(4) Spectra(Layer 2+3)→(5) #129 hard gate →(6) Layer P →(7) Simple default,確保 meeting issue 最優先分流(先於 Layer 1 / Layer V,含 Step 3.4 short-circuit)、不被硬閘或 Layer P 雙重判定。落實 design 決策 **Step 3.5 統一 routing 順序(消解 #129×#57 耦合)**。驗證:fixture 斷言 meeting issue 走 meeting 分支(無 Simple/Plan complexity verdict)、非 meeting 的 code issue 才進硬閘與 Layer P。(round-2 verify CRITICAL fix:此 task 文字原本仍是 disproven 的 Layer-1-first 序,與 SKILL/rule/design 全部矛盾。) + +## 4. superpowers 委派(#111,superpowers-integration) + +- [x] 4.1 [P] 實作 **Pre-implementation staging hand-off to superpowers**:在 `plugins/issue-driven-dev/README.md` 加 IDD↔superpowers 階段對照表(標明 verify ensemble 與 close audit trail 為 IDD 獨有、無 superpowers 對應),並於 idd-issue 建立摘要步驟與 idd-diagnose 對 design-heavy issue 印非綁定 hand-off pointer 指向 `superpowers:brainstorming`;不新增 `idd-brainstorm` / `idd-write-plan`。落實 design 決策 **pre-implementation staging 委派 superpowers,不自建**。驗證:README 表格內容審查通過;fixture 斷言 design-heavy diagnose 輸出含 `superpowers:brainstorming` pointer 字串;`ls plugins/issue-driven-dev/skills/` 不含 `idd-brainstorm` / `idd-write-plan`。 +- [x] 4.2 更新 **Kept disciplines are excluded from delegation**:在 superpowers-integration 契約區分「delegation(IDD flow 內部呼叫,仍禁止)」與「hand-off pointer(idd-issue/idd-diagnose 對使用者的非綁定建議,允許)」,並保留 idd-plan 無 superpowers 呼叫的機械檢查。驗證:`grep -rn 'superpowers:' plugins/issue-driven-dev/skills/idd-plan/` 回傳零命中;契約文字明述 pointer ≠ delegation。 + +## 5. 迴歸防護與驗證 + +- [x] 5.1 彙整三條決策的 drift-guard 覆蓋並跑全套 plugin 測試 + `spectra validate "reshape-plan-preimpl-tier"`:確保硬閘 fixtures、meeting fixtures、superpowers pointer/grep 檢查全 GREEN,Simple 預設未回歸。驗證:plugin test suite 全綠、spectra validate 通過。 diff --git a/plugins/issue-driven-dev/CLAUDE.md b/plugins/issue-driven-dev/CLAUDE.md index 8557f12..1527df5 100644 --- a/plugins/issue-driven-dev/CLAUDE.md +++ b/plugins/issue-driven-dev/CLAUDE.md @@ -348,6 +348,8 @@ IDD 把 checkbox 當成**契約**,不是願望清單。`idd-implement` 會 boo | `Problem` / `Repro` / `Workaround` / `Expected` / `Actual` | ❌ | | _其他未列出的標題_ | ❌(保守:只掃白名單)| +> **`type=meeting` 例外(#57)**:meeting issue **不走**本 generic checklist gate;改由 `idd-close` 的 **meeting-specific gate** 掃 authoritative meeting deliverable(approved Meeting Plan 的 Phase C,退回 diagnose Strategy deliberation 的 Phase C),每個 `- [ ]` 行動項需 disposition。詳見 `idd-close` SKILL.md「Meeting close」段。 + ### 去重規則 同一個 issue 可能有多個 comments 含相同 source 標題(例如 re-run `idd-implement` 後發了兩個 `## Implementation Complete`)。Gate check **只看最後一個**(按 comment `createdAt` desc),那是最新的 source of truth。 diff --git a/plugins/issue-driven-dev/README.md b/plugins/issue-driven-dev/README.md index de13dcb..190c597 100644 --- a/plugins/issue-driven-dev/README.md +++ b/plugins/issue-driven-dev/README.md @@ -268,6 +268,26 @@ Install:`claude plugin marketplace add anthropics/claude-plugins-official` 然 > **Native alternative — `/goal`(v2.1.139+,#138)**:以上「outer driver for verify-fix loop」的角色,也可改用 Claude Code **內建**的 [`/goal`](https://code.claude.com/docs/en/goal.md) —— 設一個 completion condition(例如「verify 通過、blocking findings = 0」),它每個 turn 後用 small fast model 檢查、未達成就自動再跑下一個 turn,直到條件滿足。`/goal` 是 native(無需安裝第三方 plugin),`ralph-loop` 是 `claude-plugins-official` 的 plugin —— 兩者都能驅動 loop,擇一即可。**目前 `idd-all` / `idd-verify --loop` 的 gate 偵測的是 `ralph-loop` plugin**;若偏好 native,可手動以 `/goal` 驅動(是否把 gate 改為支援 `/goal` 為更大設計題,見 #138 residue)。 +### IDD ↔ superpowers stage mapping (#111) + +IDD pipeline stage 對照 superpowers counterpart。**pre-implementation staging(brainstorm → written plan)委派 superpowers,IDD 不自建對等 skill**(依 deep-integration-over-hardcode:superpowers 既是 hard dependency,hand-off pointer 必然可解析,自建 = vendored fork)。verify ensemble 與 close audit trail 標為 **IDD 獨有 — 無 superpowers 對應**。 + +| IDD stage | superpowers counterpart | 說明 | +|-----------|-------------------------|------| +| `idd-issue`(問題框定)| (無 — issue framing 是 IDD 入口)| well-documented issue | +| `idd-diagnose`(bug RCA)| `superpowers:systematic-debugging` | RCA 執行框架(delegate,#209)| +| pre-implementation staging(brainstorm)| `superpowers:brainstorming` | design-heavy issue 的**非綁定 hand-off pointer**(idd-issue summary step + idd-diagnose 印出;使用者自選是否跟進,IDD 自身不 invoke)| +| written plan | `superpowers:writing-plans` | 同上 staging;IDD 的 `idd-plan` 是 approval-gate 版、不 delegate | +| `idd-implement`(TDD)| `superpowers:test-driven-development` | TDD 執行紀律(delegate,#209)| +| `idd-verify` | **IDD 獨有 — 無 superpowers 對應** | 6-AI ensemble cross-verify | +| `idd-close` | **IDD 獨有 — 無 superpowers 對應** | closing summary audit trail + two-tier gate | + +> **hand-off pointer ≠ delegation(#111 契約)**:上表的 `superpowers:brainstorming` / `writing-plans` 是 **hand-off pointer**,不是 delegation。界線: +> - **delegation**(IDD flow **內部**呼叫 superpowers skill):僅 `idd-implement` TDD 與 `idd-diagnose` RCA 的 process-discipline 走 delegation(#209)。planning discipline(`idd-plan` / Spectra,含對應的 `brainstorming` / `writing-plans`)**禁止** delegation。 +> - **hand-off pointer**(idd-issue / idd-diagnose **印給使用者**的非綁定建議,**允許**):IDD 自身**不** invoke 該 skill,使用者自選是否跟進。 +> +> 機械檢查(drift-guard 硬鎖,見 `scripts/tests/superpowers-staging/`):`grep -rn 'superpowers:' plugins/issue-driven-dev/skills/idd-plan/` **零命中** —— `idd-plan` 內不得出現任何 superpowers 呼叫;pointer 只活在 idd-issue / idd-diagnose 的 prose 建議裡。 + ### Sister plugins - [`idd-route`](../idd-route) — Data-driven agent routing (Codex / Claude Opus / Sonnet / Haiku) per IDD issue。`idd-diagnose` Step 3.7 偵測到 `idd-route` 已裝就會自動呼叫做 enrichment;沒裝則 silently skip。**非必要**,純粹增強 routing 建議品質。Install: `claude plugin install idd-route@issue-driven-development` diff --git a/plugins/issue-driven-dev/rules/sdd-integration.md b/plugins/issue-driven-dev/rules/sdd-integration.md index 63beb85..d965767 100644 --- a/plugins/issue-driven-dev/rules/sdd-integration.md +++ b/plugins/issue-driven-dev/rules/sdd-integration.md @@ -9,15 +9,17 @@ description: When to route IDD to Plan-mode or Spectra (formerly SDD), with back > > **v2.50.0+ Layer V**: a 5th evaluation layer (Vagueness Pre-check) sits between Layer 1 and Layer 2. See "Layer V" section below. Existing diagnoses written before v2.50 are not retroactively re-evaluated. -`idd-diagnose` is the single decision point. After diagnosis, evaluate in order (5 layers as of v2.50): +`idd-diagnose` is the single decision point. After diagnosis, evaluate in order: -1. **Disqualifiers (Layer 1)** — any one yes → force `Simple`, ignore everything below -2. **Vagueness Pre-check (Layer V, v2.50+)** — `max(V1, V4) ≥ 4` triggers a 3-option AskUserQuestion gate; user choice determines whether routing continues, body is clarified first, or verdict is force-set to `Plan via Layer V` -3. **Spectra-warranting condition (Layer 2 + Layer 3)** — both must be yes → `Spectra` -4. **Plan signals (Layer P)** — at least one yes → `Plan` -5. Otherwise → `Simple` (default) +1. **`type=meeting` branch (#57)** — if the issue type is `meeting`, route to the deliberation Strategy (Phase A/B/C: agenda / decision points / action items) and STOP. A meeting issue is NOT scored by Layer 1 / Layer V / Spectra (Layer 2+3) / the hard gate / Layer P. Checked FIRST because type is a deterministic field, and a meeting's deliberation content would otherwise be swallowed by Layer 1's narrative disqualifier. +2. **Disqualifiers (Layer 1)** — any one yes → force `Simple`, ignore everything below +3. **Vagueness Pre-check (Layer V, v2.50+)** — `max(V1, V4) ≥ 4` triggers a 3-option AskUserQuestion gate; user choice determines whether routing continues, body is clarified first, or verdict is force-set to `Plan via Layer V` +4. **Spectra-warranting condition (Layer 2 + Layer 3)** — both must be yes → `Spectra` +5. **Hard gate (#129, MUST-trigger)** — estimated ≥ 5 files of one interdependent concept OR a shared abstraction → force `Plan`; layered above Layer P, escalate-only. Genuinely-independent multi-file changes stay Simple via Layer 1's disqualifier. +6. **Plan signals (Layer P)** — at least one yes → `Plan` +7. Otherwise → `Simple` (default) -This 5-layer evaluation replaces the v2.36 4-layer order by inserting Layer V right after Layer 1 disqualifier. Plan exists for "I want to think before I leap, but no spec contract is needed" — the most common case where Simple is too thin (multi-step / multi-file / decision-heavy) but Spectra is overkill (no published API contract for future callers). Layer V exists for the orthogonal case: **the change shape is small, but the request itself is unclear** — Simple's direct TDD loop would pattern-match a wrong direction. +This routing has 7 evaluation steps (as of the #129/#57 change): the `type=meeting` branch and the MUST-trigger hard gate were layered onto the v2.50 order (which itself inserted Layer V right after the Layer 1 disqualifier). Plan exists for "I want to think before I leap, but no spec contract is needed" — the most common case where Simple is too thin (multi-step / multi-file / decision-heavy) but Spectra is overkill (no published API contract for future callers). Layer V exists for the orthogonal case: **the change shape is small, but the request itself is unclear** — Simple's direct TDD loop would pattern-match a wrong direction. ## Layer 1: Simple-required disqualifiers (any one = force Simple) @@ -28,6 +30,10 @@ If any of these match, the work is `Simple` regardless of other signals. Plan / - **Primary deliverable is updating existing prose without changing behavior** — typo fixes, wording cleanup, restructuring documents - **Multi-file but each file is independent** — parallel doc updates, parallel script tweaks; multi-file count without interdependent contract is not a routing signal +> **`type=meeting` is evaluated BEFORE Layer 1** (see the ordered list above): a meeting issue's deliberation deliverable would otherwise match this section's narrative disqualifier and be force-`Simple`'d, so Layer 1 never sees a meeting issue (round-1 verify HIGH-2 fix). +> +> **Interaction with the #129 hard gate**: this "multi-file but each file independent → Simple" rule and the hard gate's "≥ 5 files" trigger are reconciled by scoping the hard gate to *one interdependent concept scattered across files*. Genuinely independent files (this bullet) stay Simple; a single concept spread across ≥ 5 files escalates to Plan. The two never fire on the same input with opposite verdicts. + **Rationale**: Plan's value is the approval checkpoint; Spectra's value is the spec contract. Narrative is fluid by design (evolves with reviewer feedback). Ad-hoc analysis is similar — once the question is answered, the script is archived. IDD's checklist + closing summary already provide sufficient audit trail. ## Layer V: Vagueness Pre-check (v2.50.0+) @@ -73,18 +79,21 @@ Whether Layer V triggers or not, Step 3.4 PATCHes the just-posted Diagnosis comm When `idd-diagnose` runs under `idd-all` UNATTENDED MODE directive, Layer V still scores but does not present `AskUserQuestion`. It auto-applies `proceed anyway` and records `[Layer V: V1=N V4=M, clarify-default skipped under unattended mode, defaulting to proceed]` in the audit trail. Same pattern as Plan tier under unattended mode (`/idd-plan` EnterPlanMode is also skipped). -### Layer evaluation order (5-layer) +**`type=meeting` exception**: a meeting issue skips Layer V entirely (the Step 3.4 `type=meeting` short-circuit runs in both attended and unattended mode), so no V1/V4 scoring and no Layer V audit line apply — meeting-first routing precedes Layer V regardless of mode. + +### Layer evaluation order (7-step, meeting-first) -| Layer 1 hit | Layer V hit | Layer 2 hit | Layer 3 hit | Layer P hit | Verdict | -|-------------|-------------|-------------|-------------|-------------|---------------------| -| yes | (skipped) | (skipped) | (skipped) | (skipped) | Simple | -| no | yes (escalate) | (skipped) | (skipped) | (skipped) | `Plan via Layer V` | -| no | yes (proceed/clarify) | yes | yes | (any) | Spectra | -| no | yes (proceed/clarify) | no | (any) | yes | Plan | -| no | yes (proceed/clarify) | no | (any) | no | Simple | -| no | no (≤3) | yes | yes | (any) | Spectra | -| no | no (≤3) | no | (any) | yes | Plan | -| no | no (≤3) | no | (any) | no | Simple | +Columns are evaluated left→right; the first decisive column wins. **Hard gate hit** = the #129 MUST-trigger fired (≥ 5 files of one interdependent concept OR a shared abstraction). `(skipped)` = an earlier column already decided the verdict. + +| type=meeting | Layer 1 hit | Layer V hit | Layer 2+3 hit | Hard gate hit | Layer P hit | Verdict | +|--------------|-------------|-------------|---------------|---------------|-------------|----------------------------------| +| yes | (skipped) | (skipped) | (skipped) | (skipped) | (skipped) | meeting Strategy (no Simple/Plan verdict) | +| no | yes | (skipped) | (skipped) | (skipped) | (skipped) | Simple | +| no | no | yes (escalate) | (skipped) | (skipped) | (skipped) | `Plan via Layer V` | +| no | no | (proceed/≤3) | yes | (any) | (any) | Spectra | +| no | no | (proceed/≤3) | no | yes | (any) | Plan (hard gate) | +| no | no | (proceed/≤3) | no | no | yes | Plan | +| no | no | (proceed/≤3) | no | no | no | Simple (default) | ### Backward compatibility @@ -138,9 +147,20 @@ The single discriminator is **"published API/protocol for future callers"**: When in doubt, ask: **"Will a future engineer / future caller check the spec to know how to use this?"** Yes → Spectra. No → Plan. +## Hard Gate (#129, MUST-trigger, layered above Layer P) + +A MUST-trigger hard gate is evaluated above Layer P. `/idd-diagnose` runs before implementation, so no diff exists yet — the hard gate is an **AI scope estimate** (disclosed with reasons + concrete anchors per [`attribute-assessment`](../../../.claude/rules/attribute-assessment.md)), not a diff-time mechanical count. + +It forces the `Plan` tier when EITHER holds (OR): + +1. **≥ 5 files of one interdependent concept** — threshold **N = 5**. The trigger is "one conceptual change scattered across ≥ 5 files", NOT a raw file count: genuinely-independent multi-file changes (parallel doc updates / independent script tweaks) stay Simple via Layer 1's "Multi-file but each file independent" disqualifier and do NOT fire the hard gate (round-1 verify HIGH-7 fix — resolves the hard-gate-vs-Layer-1 contradiction). Conservative to protect the `Simple` default (`3 = aggressive, 5 = conservative`); N is the design's one tunable knob. 5 rather than 3: a legitimate small change (impl + test + doc) commonly touches 3 files, so N = 3 over-triggers; 5 is the reliable "one concept scattered across many places" signal (aligns with the #44/#47 failure class — CR/PTSR/PCQ sharing one scoring helper is a scattered single concept, not independent files). +2. **Modifies a shared abstraction** — a data structure, helper interface, or constants set estimated to be **referenced by ≥ 2 other files**. Estimated from the issue description plus reference lookups in existing code. + +The hard gate **only escalates**: it **does not invert** the `Simple` default. When it fires → force `Plan`. When it does not fire → routing **falls through to Layer P** and the `Simple` default is preserved. The gate is additive, not a new baseline — it lifts large multi-file / shared-abstraction changes from Simple to Plan without dragging small changes into the plan-mode approval gate (the rejected alternative — inverting to Default-Plan — was declined by the user; over-trigger cost exceeds the residual under-plan risk). The gate evaluates only **non-meeting, code-centric issues**; Layer 1 has already forced narrative / independent-multi-file work to Simple before this point. + ## Layer P: Plan signals (at least one = `Plan`) -If Layer 1 didn't fire AND Layer 2 didn't qualify for Spectra, evaluate Plan signals: +If Layer 1 didn't fire AND Layer 2 didn't qualify for Spectra AND the hard gate didn't fire, evaluate Plan signals: - **2+ files with sequence dependency** — file A's changes affect what file B's changes must do; can't parallelize the edits - **Strategy has 5+ ordered steps** — sequential complexity benefits from explicit checkpoint before execution @@ -219,7 +239,7 @@ New diagnosis comments (v2.36.0+) MUST emit `Spectra` — `SDD-warranted` is rea 4. **Close triggers archive (Spectra only)** — `idd-close` should also `spectra-archive` for Spectra changes 5. **Discuss-first for Spectra** — `idd-diagnose` must route Spectra issues to `spectra-discuss` by default; only bypass when the user explicitly opts out during the Step 4 routing prompt 6. **Plan-mode approval gate** — `idd-plan` MUST use `EnterPlanMode` + present full Implementation Plan + `ExitPlanMode` for user approval BEFORE any tool that modifies state. No silent fallthrough to TDD. -7. **Disqualifiers are evaluated first** — narrative / ad-hoc / no-caller deliverables route to `Simple` even if Plan signals or Spectra signals technically match. The disqualifier protects against pattern-matching scope hints into the heavier tiers. +7. **`type=meeting` is evaluated first, then Layer 1 disqualifiers** — the `type=meeting` branch splits before any complexity scoring (deterministic type field). For non-meeting issues, Layer 1 disqualifiers are next: narrative / ad-hoc / no-caller deliverables route to `Simple` even if Plan signals or Spectra signals technically match. The disqualifier protects against pattern-matching scope hints into the heavier tiers. ## Retrospective check (motivating examples) diff --git a/plugins/issue-driven-dev/scripts/tests/complexity-hard-gate/test.sh b/plugins/issue-driven-dev/scripts/tests/complexity-hard-gate/test.sh new file mode 100755 index 0000000..1ed0337 --- /dev/null +++ b/plugins/issue-driven-dev/scripts/tests/complexity-hard-gate/test.sh @@ -0,0 +1,156 @@ +#!/usr/bin/env bash +# test.sh — drift-guard for the #129 MUST-trigger complexity hard gate +# (change reshape-plan-preimpl-tier, spec complexity-hard-gate). +# +# WHY A CONTENT DRIFT-GUARD (not an execution harness): `/idd-diagnose` is a +# prose SKILL.md — an AI prompt, not executable code. "Feed a ≥5-file issue → +# assert Complexity=Plan" cannot be run. The falsifiable equivalent is asserting +# the prompt text (idd-diagnose Step 3.5) AND the canonical rule (Layer P section +# of sdd-integration.md) both encode the hard-gate routing contract. Assertions +# are on canonical tokens, non-line-bound (design acceptance: "不綁定 source line +# number"). Token alignment across BOTH files mirrors the session-start-commit- +# rule suite: the executor (SKILL.md) and the canonical rule must not drift apart. +# +# Usage: bash test.sh (exit 0 = all pass, 1 = any fail) + +set -u + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PLUGIN_ROOT="$HERE/../../.." +DIAGNOSE="$PLUGIN_ROOT/skills/idd-diagnose/SKILL.md" +SDD="$PLUGIN_ROOT/rules/sdd-integration.md" + +HELPERS="$HERE/../../lib/assert-helpers.sh" +[ -f "$HELPERS" ] || { echo "✗ missing $HELPERS — cannot run suite" >&2; exit 1; } +. "$HELPERS" + +assert_file_exists "idd-diagnose SKILL.md exists" "$DIAGNOSE" +assert_file_exists "sdd-integration.md exists" "$SDD" +D="$(cat "$DIAGNOSE" 2>/dev/null || echo "")" +S="$(cat "$SDD" 2>/dev/null || echo "")" + +# ── Task 1.1 — hard-gate verdict mapping (design: 硬閘疊加於 Layer P 之上,不反轉 Simple 預設) ── +# Three verdict cases from spec "MUST-trigger complexity hard gate layered above +# Layer P": (a) estimated ≥ 5 files → Plan; (b) shared abstraction (≥ 2 cross-file +# callers) → Plan; (c) escalate-only — the gate does NOT invert the Simple default, +# and a non-firing gate falls through to Layer P with Simple preserved. + +# (mechanism exists — MUST-trigger hard gate, in both the executor and the rule) +assert_grep "diagnose: names the 硬閘 (hard gate) mechanism" "硬閘" "$D" +assert_grep "diagnose: hard gate is MUST-trigger" "MUST-trigger" "$D" +assert_grep "sdd: names the hard gate mechanism" "hard gate" "$S" +assert_grep "sdd: hard gate is MUST-trigger" "MUST-trigger" "$S" + +# (a) estimated ≥ 5 files OF ONE INTERDEPENDENT CONCEPT → Plan (P3: the trigger is +# scattered-single-concept, NOT genuinely-independent multi-file, which Layer 1 +# keeps Simple — resolves the HIGH-7 contradiction with Layer 1). +assert_grep "diagnose: ≥ 5 檔 file-count trigger" "≥ 5 檔" "$D" +assert_grep "sdd: ≥ 5 files file-count trigger" "≥ 5 files" "$S" +assert_grep "diagnose: ≥5 trigger qualified to one interdependent concept" "單一概念散佈" "$D" +assert_grep "sdd: ≥5 trigger qualified to one interdependent concept" "one interdependent concept" "$S" + +# (b) shared-abstraction predicate = referenced by ≥ 2 other files +assert_grep "diagnose: shared-abstraction predicate (≥ 2 個其他檔案)" "≥ 2 個其他檔案" "$D" +assert_grep "sdd: shared-abstraction predicate (≥ 2 other files)" "≥ 2 other files" "$S" + +# (c) escalate-only — does NOT invert the Simple default; non-firing falls through +assert_grep "diagnose: escalate-only, 不反轉 Simple 預設" "不反轉" "$D" +assert_grep "diagnose: non-firing gate 落回 Layer P" "落回 Layer P" "$D" +assert_grep "sdd: escalate-only — does not invert the Simple default" "does not invert" "$S" +assert_grep "sdd: non-firing gate falls through to Layer P" "falls through to Layer P" "$S" + +# N = 5 is the one tunable knob (design Open Question; ratified default) +assert_grep "diagnose: N = 5 knob documented" "N = 5" "$D" +assert_grep "sdd: N = 5 knob documented" "N = 5" "$S" + +# Simple-default preserved: the isolated single-file anchor must survive the gate +# insertion (spec scenario "Small isolated change preserves the Simple default"). +assert_grep "diagnose: 單檔案 → Simple anchor intact" "單檔案" "$D" +assert_grep "sdd: single-file → Simple anchor intact" "Single-file change" "$S" + +# ── Task 1.3 — hard-gate estimate disclosed in the audit trail ── +# diagnose emits a single audit line `Hard-gate: ` into the Diagnosis comment (alongside Layer V's audit trail). When +# signal is insufficient the gate does NOT fire (fail-open to Layer P) and the line +# reads `insufficient signal`. Three scenarios each assert their audit-line string. +assert_grep "diagnose: audit-line format template" "Hard-gate: " "$D" +assert_grep "diagnose: triggered audit line literal" "Hard-gate: triggered" "$D" +assert_grep "diagnose: not-triggered audit line literal" "Hard-gate: not triggered" "$D" +assert_grep "diagnose: insufficient-signal fail-open" "insufficient signal" "$D" + +# ── Task 1.4 — shared-abstraction trigger forces family-wide Plan scope ── +# When the gate fires on a shared abstraction, the resulting Plan must enumerate +# ALL known call sites / family members as in-scope, not just the file named in +# the issue title (spec: "Plan enumerates family members"; #44 lesson). The Plan +# body carries a named `Family-wide scope` section; diagnose cross-references it. +PLAN="$PLUGIN_ROOT/skills/idd-plan/SKILL.md" +assert_file_exists "idd-plan SKILL.md exists" "$PLAN" +PN="$(cat "$PLAN" 2>/dev/null || echo "")" +assert_grep "plan: Family-wide scope section in Plan body" "Family-wide scope" "$PN" +assert_grep "plan: enumerates all known call sites" "所有已知 call site" "$PN" +assert_grep "plan: family members are in-scope" "family member" "$PN" +assert_grep "diagnose: shared-abstraction → family-wide Plan" "Family-wide scope" "$D" + +# ── Task 3.1 — unified Step 3.5 routing order (resolves #129 × #57 coupling) ── +# Canonical MEETING-FIRST routing, faithful 7-step (P2 decision; HIGH-2 + round-3 +# HIGH fix — no lossy "5-stage" that drops Spectra): (1) type=meeting → (2) Layer 1 +# → (3) Layer V → (4) Spectra (Layer 2+3) → (5) #129 hard gate → (6) Layer P → +# (7) Simple default. meeting is checked FIRST (deterministic type field) so +# Layer 1's narrative disqualifier can't swallow a meeting's deliberation content. +# Round-2 HIGH-5 fix: the summary must FAITHFULLY enumerate every gate (no lossy +# "5-stage" label that silently drops Spectra/Layer 2+3). Summary now == the +# operational 7-step list, so a reader can't be left guessing which stage absorbs +# Spectra. +SEQ="(1) type=meeting → (2) Layer 1 → (3) Layer V → (4) Spectra(Layer 2+3)→ (5) #129 硬閘 → (6) Layer P → (7) Simple 預設" +assert_grep "diagnose: canonical routing sequence (meeting-first, faithful 7-step)" "$SEQ" "$D" +assert_grep "diagnose: meeting is an explicit early step in the order" "→ 走 meeting Strategy" "$D" +# Round-2 HIGH (codex): meeting-first is only real if Step 3.4 (Layer V) — which runs +# BEFORE Step 3.5 — short-circuits for type=meeting. Assert that short-circuit exists. +assert_grep "diagnose: Step 3.4 short-circuits Layer V for type=meeting" "跳過整個 Layer V" "$D" + +# ── P1/P2 systemic drift-guard (HIGH-1/HIGH-4/HIGH-6): the canonical rule file +# (sdd-integration.md) must not drift from the executor. The prior string-only +# guards were green while sdd-integration was internally stale — these assert the +# structural facts the DA proved were missing. ── +# sdd-integration must actually carry the meeting branch (it was entirely absent). +assert_grep "sdd: ordered list carries the type=meeting branch" "type=meeting" "$S" +# sdd stale '5-layer replaces 4-layer' prose must be gone (list is now 7 steps). +refute_grep "sdd: no stale '5-layer evaluation replaces' prose" "5-layer evaluation replaces" "$S" +# sdd truth table must have a Hard-gate column (was missing → wrong Simple verdict). +assert_grep "sdd: truth table has a Hard gate column" "Hard gate hit" "$S" +# Round-4 HIGH: the sdd ordered-list meeting bypass must name Spectra (Layer 2+3). +assert_grep "sdd: meeting bypass names Spectra (Layer 2+3)" "NOT scored by Layer 1 / Layer V / Spectra (Layer 2+3)" "$S" +# Round-4 HIGH: sdd '## Rules' item 7 must be meeting-first, not the stale +# 'Disqualifiers are evaluated first' (which contradicts the file's own order). +assert_grep "sdd: Rules item 7 is meeting-first" "is evaluated first, then Layer 1 disqualifiers" "$S" +refute_grep "sdd: Rules item 7 dropped stale 'Disqualifiers are evaluated first'" "**Disqualifiers are evaluated first**" "$S" + +# ── Round-2 systemic guard (HIGH-6/9/12): lock the NORMATIVE change artifacts, not +# just the executor prose. Round 1 fixed the SKILL/rule prose but left tasks.md + +# specs/*/spec.md encoding the DISPROVEN pre-fix rules (order + unqualified ≥5-file), +# and those spec.md files become canonical on archive. These artifacts live in the +# dev repo's openspec change dir (NOT distributed with the plugin), so assert only +# when present; skip gracefully for downstream consumers / post-archive. ── +CHANGE_DIR="$PLUGIN_ROOT/../../openspec/changes/reshape-plan-preimpl-tier" +if [ -d "$CHANGE_DIR" ]; then + HGS="$(cat "$CHANGE_DIR/specs/complexity-hard-gate/spec.md" 2>/dev/null || echo "")" + TKS="$(cat "$CHANGE_DIR/tasks.md" 2>/dev/null || echo "")" + DGN="$(cat "$CHANGE_DIR/design.md" 2>/dev/null || echo "")" + # spec Requirement must carry the interdependent-concept qualifier (P3), and the + # worked Example must document that independent multi-file stays Simple via Layer 1. + assert_grep "spec: hard-gate qualified to one interdependent concept" "one interdependent concept" "$HGS" + assert_grep "spec: Example documents independent-files → Simple (Layer 1)" "Simple (Layer 1 disqualifier)" "$HGS" + # tasks.md Task 3.1 order must be meeting-FIRST (the round-2 CRITICAL miss); the + # stale Layer-1-first order must be gone. + assert_grep "tasks.md: Task 3.1 routing order is meeting-first" "(1) \`type=meeting\` 分支" "$TKS" + refute_grep "tasks.md: Task 3.1 has no stale Layer-1-first order" "(1) Layer 1 disqualifier" "$TKS" + # Round-3 HIGH: design.md Decisions section (the guard previously never read + # design.md) must carry the faithful 7-step seq with Spectra at step 4, not the + # disproven 5-step that dropped Spectra. + assert_grep "design.md: Decisions routing seq includes Spectra at step 4" "(4) Spectra(Layer 2+3" "$DGN" + refute_grep "design.md: no stale 5-step tail (Layer P as step 5)" "(5) Layer P any-match + Simple 預設" "$DGN" +else + pass "change artifacts absent (downstream/post-archive) — spec/tasks guards skipped" +fi + +print_summary "complexity-hard-gate" diff --git a/plugins/issue-driven-dev/scripts/tests/meeting-issue-type/test.sh b/plugins/issue-driven-dev/scripts/tests/meeting-issue-type/test.sh new file mode 100755 index 0000000..5ae6d8a --- /dev/null +++ b/plugins/issue-driven-dev/scripts/tests/meeting-issue-type/test.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +# test.sh — drift-guard for the #57 first-class `meeting` issue type +# (change reshape-plan-preimpl-tier, spec meeting-issue-type). +# +# WHY A CONTENT DRIFT-GUARD: the meeting behaviors live in prose SKILL.md files +# (idd-issue taxonomy, idd-diagnose Strategy branch, idd-plan skip-chain, idd-close +# semantics) — AI prompts, not executable code. The falsifiable equivalent is +# asserting each SKILL's prose encodes the meeting contract. Assertions are on +# canonical tokens, non-line-bound. +# +# Usage: bash test.sh (exit 0 = all pass, 1 = any fail) + +set -u + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PLUGIN_ROOT="$HERE/../../.." +ISSUE="$PLUGIN_ROOT/skills/idd-issue/SKILL.md" +DIAGNOSE="$PLUGIN_ROOT/skills/idd-diagnose/SKILL.md" +PLAN="$PLUGIN_ROOT/skills/idd-plan/SKILL.md" +CLOSE="$PLUGIN_ROOT/skills/idd-close/SKILL.md" + +HELPERS="$HERE/../../lib/assert-helpers.sh" +[ -f "$HELPERS" ] || { echo "✗ missing $HELPERS — cannot run suite" >&2; exit 1; } +. "$HELPERS" + +assert_file_exists "idd-issue SKILL.md exists" "$ISSUE" +I="$(cat "$ISSUE" 2>/dev/null || echo "")" + +# ── Task 2.1 — meeting is a first-class issue type ── +# The taxonomy value set expands from {bug, feature, refactor, docs} to include +# `meeting`. idd-issue accepts meeting without falling back to feature / rejecting. +assert_grep "idd-issue: taxonomy lists meeting as a peer type" "bug / feature / refactor / docs / meeting" "$I" + +# ── Task 2.2 — diagnose emits a deliberation Strategy for meeting issues ── +# type=meeting → Phase A/B/C deliberation template (agenda / decision points / +# action items), NOT the code-centric Files & Changes Strategy. The meeting branch +# is evaluated BEFORE complexity scoring (so no hard-gate / Layer P verdict). +assert_file_exists "idd-diagnose SKILL.md exists" "$DIAGNOSE" +D="$(cat "$DIAGNOSE" 2>/dev/null || echo "")" +assert_grep "diagnose: has a type=meeting branch" "type=meeting" "$D" +assert_grep "diagnose: meeting Strategy Phase A (議程/agenda)" "Phase A(議程)" "$D" +assert_grep "diagnose: meeting Strategy Phase B (決策點/decisions)" "Phase B(決策點)" "$D" +assert_grep "diagnose: meeting Strategy Phase C (行動項/actions)" "Phase C(行動項)" "$D" +assert_grep "diagnose: meeting Strategy replaces code-centric Files & Changes" "而非 code-centric 的 Files & Changes" "$D" +assert_grep "diagnose: meeting branch splits before complexity scoring" "複雜度評估前分流" "$D" +# HIGH-5: Step 1 type RECOGNITION must list meeting (else meeting never reaches the branch). +assert_grep "diagnose: Step 1 type recognition includes meeting" "bug / feature / refactor / docs / meeting" "$D" +# MED-req: the verdict Next Step table must route meeting → /idd-plan (meeting-adapted). +assert_grep "diagnose: Next Step table has a meeting → /idd-plan row" "meeting-adapted plan" "$D" + +# ── Task 2.3 — plan for meeting issues skips the implement chain ── +# idd-plan for type=meeting uses a meeting-adapted Plan body schema and does NOT +# chain to /idd-implement (meeting is deliberation, not a TDD loop). +assert_file_exists "idd-plan SKILL.md exists" "$PLAN" +PN="$(cat "$PLAN" 2>/dev/null || echo "")" +assert_grep "plan: has a type=meeting branch" "type=meeting" "$PN" +assert_grep "plan: meeting-adapted Plan body schema" "meeting-adapted Plan body" "$PN" +assert_grep "plan: meeting skips chain to /idd-implement" "不 chain 到 /idd-implement" "$PN" + +# ── Task 2.4 — meeting closing maps decisions to actions without a TDD verify pass ── +# Closing a type=meeting issue uses a decision→action mapping as the closing summary +# and does NOT require an /idd-verify TDD pass as a precondition. +assert_file_exists "idd-close SKILL.md exists" "$CLOSE" +C="$(cat "$CLOSE" 2>/dev/null || echo "")" +assert_grep "close: has a type=meeting branch" "type=meeting" "$C" +assert_grep "close: decision→action mapping summary" "decision→action" "$C" +assert_grep "close: meeting close needs no /idd-verify TDD pass" "無 /idd-verify TDD pass" "$C" +# HIGH-3: the OPERATIVE path must branch, not just a declarative paragraph. The +# draft_closing_comment TaskCreate must itself branch on type=meeting (per the +# skill's own 'behavior not in TaskCreate = a bug' rule). +assert_grep "close: draft_closing_comment TaskCreate branches on meeting" "\`type=meeting\` 用 decision→action" "$C" +# Round-2 HIGH (codex): meeting Phase C action items are `- [ ]` boxes with no +# downstream step to check them off (plan skips implement), yet the checklist gate +# blocks close on any `- [ ]`. Deadlock. The close section must resolve each action +# item to a disposition marker so the gate is satisfiable. +assert_grep "close: meeting action items get [x]/[~]/[-] disposition markers (deadlock fix)" "\`- [~] — tracked in #NNN\`" "$C" +# Round-5 HIGH fixes: the meeting gate source resolution is mechanically defined +# (recency + heading-prefix, NOT an unimplemented 'approved' check), with a +# no-deliverable BLOCK (no vacuous pass), and dispositions decided BEFORE the gate. +assert_grep "close: meeting gate blocks when no deliverable exists (no vacuous pass)" "兩者皆無 → 擋 close" "$C" +assert_grep "close: meeting gate decides disposition before blocking check" "先決定 disposition 再跑 blocking check" "$C" +refute_grep "close: meeting source no longer relies on unimplemented 'approved' check" "approved \`## Meeting Plan\` 的 Phase C 行動項為 canonical" "$C" +# Round-4 CRITICAL fix: meeting is NO LONGER bolted onto the generic whitelist / +# authoritative_source machinery (that had no meeting branch → deadlock or silent +# bypass). It now has its OWN self-contained gate. Assert the mechanism, not a string. +assert_grep "close: type=meeting routes to a meeting-specific gate" "meeting-specific gate" "$C" +assert_grep "close: meeting gate is self-contained (no authoritative_source entanglement)" "self-contained" "$C" +refute_grep "close: reverted the round-3 whitelist bolt-on row" "\`Meeting Plan\` → \`Phase C\` | ✅" "$C" +# Round-3 MEDIUM: diagnose_by_type Step-0 TaskCreate must cover meeting (TaskCreate- +# completeness 鐵律 — every emitted step must be in the bootstrap list). +assert_grep "diagnose: diagnose_by_type TaskCreate covers meeting" "meeting→Phase A/B/C" "$D" +# Round-4 HIGH: the meeting BYPASS lists (what meeting skips) must also name Spectra +# — round-3 only fixed the routing *sequences*, missed the *bypass* variant. +assert_grep "diagnose: meeting bypass list (Step 3.5) names Spectra" "不進 Layer 1 / Layer V / Spectra(Layer 2+3)/ 硬閘 / Layer P" "$D" +# Round-5 HIGH: the 'type is a deterministic field' premise needs an actual +# resolution order (label vs body heading), else it's an unbacked claim. +assert_grep "diagnose: Step 1 type resolution order is defined (label > body > infer)" "Type 解析順序" "$D" +# Round-4 HIGH: CLAUDE.md whitelist copy must stay in sync — it now carries the +# meeting exception note (not a diverging whitelist row). +CLAUDE_MD="$PLUGIN_ROOT/CLAUDE.md" +assert_file_exists "plugin CLAUDE.md exists" "$CLAUDE_MD" +CM="$(cat "$CLAUDE_MD" 2>/dev/null || echo "")" +assert_grep "CLAUDE.md: checklist conventions carry the meeting exception" "meeting-specific gate" "$CM" +refute_grep "CLAUDE.md: reverted the diverging Meeting Plan whitelist row" "\`Meeting Plan\` → \`Phase C\` | ✅(#57" "$CM" + +# ── Round-2 systemic guard: the meeting spec Requirement must encode the FULL bypass +# (Layer 1 + Layer V), not just hard-gate + Layer P — the round-1 HIGH-2 mechanism +# was never written into the normative spec. Dev-only artifact → assert when present. +CHANGE_DIR="$PLUGIN_ROOT/../../openspec/changes/reshape-plan-preimpl-tier" +if [ -d "$CHANGE_DIR" ]; then + MTS="$(cat "$CHANGE_DIR/specs/meeting-issue-type/spec.md" 2>/dev/null || echo "")" + assert_grep "spec: meeting bypass names the Layer 1 disqualifier" "before the Layer 1 disqualifier" "$MTS" + assert_grep "spec: meeting bypass names Layer V" "Layer V" "$MTS" + # Round-3 HIGH: the bypass list must also name Spectra (Layer 2+3) — else the spec + # letter permits a meeting issue to get a Spectra verdict. + assert_grep "spec: meeting bypass names Spectra (Layer 2+3)" "before the Spectra (Layer 2+3) evaluation" "$MTS" + # Round-4: spec must encode the meeting-specific close gate (not just the bypass). + assert_grep "spec: meeting-specific close gate is a Requirement" "meeting-specific" "$MTS" +else + pass "change artifacts absent (downstream/post-archive) — meeting spec guard skipped" +fi + +print_summary "meeting-issue-type" diff --git a/plugins/issue-driven-dev/scripts/tests/superpowers-staging/test.sh b/plugins/issue-driven-dev/scripts/tests/superpowers-staging/test.sh new file mode 100755 index 0000000..f1dbf6a --- /dev/null +++ b/plugins/issue-driven-dev/scripts/tests/superpowers-staging/test.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# test.sh — drift-guard for the #111 pre-implementation staging hand-off to +# superpowers (change reshape-plan-preimpl-tier, spec superpowers-integration). +# +# WHY A CONTENT DRIFT-GUARD: the hand-off is prose (README stage-mapping table + +# idd-issue / idd-diagnose pointers) plus two mechanical filesystem invariants +# (no self-built staging skill; idd-plan stays superpowers-free). Assertions are +# on canonical tokens + filesystem presence, non-line-bound. +# +# Usage: bash test.sh (exit 0 = all pass, 1 = any fail) + +set -u + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PLUGIN_ROOT="$HERE/../../.." +README="$PLUGIN_ROOT/README.md" +DIAGNOSE="$PLUGIN_ROOT/skills/idd-diagnose/SKILL.md" +ISSUE="$PLUGIN_ROOT/skills/idd-issue/SKILL.md" +PLAN_DIR="$PLUGIN_ROOT/skills/idd-plan" + +HELPERS="$HERE/../../lib/assert-helpers.sh" +[ -f "$HELPERS" ] || { echo "✗ missing $HELPERS — cannot run suite" >&2; exit 1; } +. "$HELPERS" + +assert_file_exists "README.md exists" "$README" +assert_file_exists "idd-diagnose SKILL.md exists" "$DIAGNOSE" +assert_file_exists "idd-issue SKILL.md exists" "$ISSUE" +R="$(cat "$README" 2>/dev/null || echo "")" +D="$(cat "$DIAGNOSE" 2>/dev/null || echo "")" +I="$(cat "$ISSUE" 2>/dev/null || echo "")" + +IDD_UNIQUE="IDD 獨有 — 無 superpowers 對應" + +# ── Task 4.1 — pre-implementation staging hand-off to superpowers ── +# README carries an IDD↔superpowers stage-mapping table naming superpowers:brainstorming +# and marking the verify ensemble + close audit trail as IDD-unique (no counterpart). +assert_grep "README: stage-mapping table title (#111)" "IDD ↔ superpowers" "$R" +assert_grep "README: names superpowers:brainstorming as staging dest" "superpowers:brainstorming" "$R" +assert_grep "README: verify ensemble marked IDD-unique" "$IDD_UNIQUE" "$R" + +# idd-issue (summary step) and idd-diagnose (design-heavy) surface a non-binding +# hand-off pointer naming superpowers:brainstorming. +assert_grep "idd-diagnose: design-heavy hand-off pointer" "superpowers:brainstorming" "$D" +assert_grep "idd-issue: summary-step hand-off pointer" "superpowers:brainstorming" "$I" + +# No self-built staging skill is added (mechanical filesystem check). +assert_file_absent "no idd-brainstorm skill exists" "$PLUGIN_ROOT/skills/idd-brainstorm" +assert_file_absent "no idd-write-plan skill exists" "$PLUGIN_ROOT/skills/idd-write-plan" + +# ── Task 4.2 — kept disciplines are excluded from delegation ── +# The planning discipline (idd-plan / Spectra) must NOT delegate to superpowers. +# Mechanical check: grep 'superpowers:' anywhere under idd-plan → zero hits. +# Fail-loud if the dir is missing (a vanished target must not read as "pass" — +# fixes the silent-pass-on-missing-dir flagged in verify round 1). +if [ ! -d "$PLAN_DIR" ]; then + fail "idd-plan is superpowers-free (mechanical check)" "target dir missing: $PLAN_DIR (cannot verify — not a silent pass)" +elif grep -rqn "superpowers:" "$PLAN_DIR" 2>/dev/null; then + fail "idd-plan is superpowers-free (mechanical check)" "found a superpowers: reference under $PLAN_DIR" +else + pass "idd-plan is superpowers-free (mechanical check)" +fi +# Contract text explicitly distinguishes hand-off pointer from delegation. +assert_grep "README: contract states pointer ≠ delegation" "pointer ≠ delegation" "$R" + +print_summary "superpowers-staging" diff --git a/plugins/issue-driven-dev/skills/idd-close/SKILL.md b/plugins/issue-driven-dev/skills/idd-close/SKILL.md index 4fe9c65..8698394 100644 --- a/plugins/issue-driven-dev/skills/idd-close/SKILL.md +++ b/plugins/issue-driven-dev/skills/idd-close/SKILL.md @@ -32,6 +32,21 @@ allowed-tools: 設計理由:closing summary 是 IDD 紀律最神聖的部分(pretend N 個 issue 共一份 summary = 偷懶 hallucinate)。Cluster mode 只省「重複打 N 次 `/idd-close #N`」的肌肉動作,不省 audit content。 +## Meeting close(type=meeting,#57) + +`type=meeting` 的 issue closing 語意不同 —— closing summary 用 **decision→action mapping**(每個拍板決策 → 對應 follow-up action + owner),而非 code-centric 的 Problem / Root Cause / Solution / Verification / Changes 五段式。meeting 是使用者驅動的審議、不是 code change,其品質閘是 decision→action mapping 的完整性 + 人工 review,**無 /idd-verify TDD pass**(`/idd-verify` 的 6-AI code verify 對 meeting 是 dead weight,不作為 close 前置;PR gate / merge-completeness gate 同理不適用純 deliberation 的 meeting issue)。**Meeting gate(`type=meeting` 專屬 close gate;#57,round-4 verify CRITICAL fix — 取代 round-3 的 generic-whitelist bolt-on)**:meeting 不走 Step 0 的 generic checklist gate(見 Step 0 的 meeting 分支)。meeting close 自成一個 self-contained gate: + +- **Authoritative meeting deliverable(source resolution — 可機械判定;round-5 verify HIGH fix)**:依序解析(第一個命中者勝)—— + 1. issue comments 中 **heading 以 `## Meeting Plan` 開頭**的**最新一則**(by `createdAt`;`idd-plan` Step 2 寫回;**prefix 比對**,故實際 heading `## Meeting Plan: Issue #NNN` 也命中); + 2. 無 Meeting Plan → 退回 **heading 以 `### Strategy (meeting deliberation)` 開頭**的最新一則(`idd-diagnose` 寫回); + 3. **兩者皆無 → 擋 close**(不 vacuous pass),提示「先跑 `/idd-diagnose` 產生 meeting Strategy,或提供 Meeting Plan」。 + 掃描目標是該 deliverable 內的 **`### Phase C` 行動項 `- [ ]` 行**(只掃 `- [ ]` checkbox 行,不論 Phase C 是 heading 或粗體標記;Phase A 議程 / Phase B 決策點的非 checkbox 條列不計)。**用「最新一則 Meeting Plan comment」而非「approved」**:`idd-plan` 的 plan comment 在 Step 2(ExitPlanMode approve **之前**)就 post,故「comment 存在 ≠ 已核准」——以 recency 定 precedence 可機械判定,不需一個未實作的 approval 檢查。此 precedence 就地決定,**不**依賴 code-issue 的 `authoritative_source` / supersession 機制(那是為 `Strategy → Implementation Complete` 鏈設計、不含 meeting 標題)。 +- **執行順序(先決定 disposition 再跑 blocking check;round-5 verify HIGH fix)**:(1) 依上面解析 authoritative deliverable → (2) 對其每個 Phase C `- [ ]`,經 decision→action mapping 決定 disposition 並 **PATCH 該 deliverable comment** 成帶 marker 的行(不是只寫在 closing summary)→ (3) **才**跑 blocking check(掃剩餘 bare `- [ ]`)→ (4) 通過才 post closing summary + close。順序固定,避免「gate 先於 disposition 產生 → bare checkbox 直接擋」的假 deadlock。 +- **Disposition marker**:`- [x]`(會中已完成)/ `- [~] — tracked in #NNN`(延到已 file 的 follow-up issue,reason 即 follow-up ref)/ `- [-] — `(決定不做)。三態依 [Checklist Conventions](../../CLAUDE.md) 都不擋 close。 +- **Blocking**:PATCH 後仍是 bare `- [ ]` 且無 disposition(未給 owner / 未決)→ **擋 close**(未決 = 不算談完)。 + +四點同時成立:source 可機械解析(含 no-deliverable block)、順序固定解 deadlock、disposition 三態、契約不鬆。 + ## Retroactive remediation mode(`--retroactive`, v2.76.0+, #176) `idd-close --retroactive #N` 修補一個**已經被 auto-close、但沒有 `## Closing Summary`** 的 issue —— 也就是被 commit / PR-body 的 close keyword 繞過 `/idd-close` gate 關掉的受害者(`/idd-list --audit-closes` / `scripts/check-closed-without-summary.sh` 抓出來的那些)。它把「人工 reconstruct + 手貼 retroactive summary」這個**已文檔化的補救程序**(見 `CLAUDE.md` → Commit Conventions →「補救:commit 已 push 且 trailer 已觸發 auto-close」)自動化。 @@ -84,6 +99,8 @@ allowed-tools: 在動任何 closing comment 之前先 gate — 若有未完成的 todo,**refuse close** 並列出未勾項。 +> **`type=meeting` → meeting-specific gate(#57;round-4 verify CRITICAL fix)**:`type=meeting` issue **不走**下面的 generic checklist gate(含 whitelist 掃描表 + `authoritative_source` resolution)。原因:`authoritative_source` 的 supersession 機制是為 **code issue** 的 `Strategy → Implementation Plan → Implementation Complete` 鏈設計,meeting deliverable(Meeting Plan / Strategy deliberation)不在其枚舉內,硬把 meeting 標題塞進 whitelist 會落到「掃得到但沒有 supersession 邏輯 → 舊 Strategy Phase C 永久 deadlock」或「authoritative_source 回 None → meeting Phase C 完全不 gate」兩個壞結果(round-3 whitelist bolt-on 的教訓)。改跑 **self-contained meeting gate**(see 下方「Meeting close」段的 gate 定義 + source resolution):掃 authoritative meeting deliverable —— 最新一則 `## Meeting Plan` comment 的 Phase C 行動項(無則退回 diagnose `### Strategy (meeting deliberation)` 的 Phase C;**兩者皆無則擋 close,不 vacuous pass**)—— 先決定每項 disposition(`[x]`/`[~]`/`[-]`)再跑 blocking check,剩餘 bare `- [ ]` 擋 close。**以下 generic 掃描表與 authoritative_source resolution 只作用於 non-meeting(code)issue。** + **掃描範圍**: 掃 issue body + **所有 comments** 的 **結構化區段**: @@ -205,7 +222,7 @@ TaskCreate(name="check_attachments", description="確認 closing comment 即將 TaskCreate(name="check_open_prs", description="Step 1.5: gh pr list 找引用 #NNN 的 open PR;若有 unmerged PR → refuse close") TaskCreate(name="merge_completeness_gate", description="Step 1.55 (v2.84.0+, #184): resolve issue branch via merged-PR headRefOid (SHA — survives GitHub branch-delete-on-merge) → local idd/-* → VISIBLE skip note; bash scripts/check-merge-completeness.sh --branch --baseline origin/ (line-presence content-verify); rc=3 orphans → AskUserQuestion 3-option (close anyway / abort+land / mis-detection), warn-only; rc=4/no-branch print a note (never silent). Never hard-blocks.") TaskCreate(name="semantic_gate_check", description="Step 1.6: 對每個 - [x] bullet 做 keyword extraction → 驗證對應 artifact 真存在/有 commit。Warn-only。") -TaskCreate(name="draft_closing_comment", description="起草 Problem / Root Cause / Solution / Verification / Changes 五段式") +TaskCreate(name="draft_closing_comment", description="起草 closing summary:code issue(bug/feature/refactor/docs)用 Problem / Root Cause / Solution / Verification / Changes 五段式;`type=meeting` 用 decision→action mapping(每個決策 → follow-up action + owner),不用五段式、不跑 ### Verification、不要求 /idd-verify TDD pass(見上方「Meeting close」段 + Step 2 meeting 變體)") TaskCreate(name="review_with_user", description="顯示 closing comment 給使用者確認(若已明確 /idd-close 可省略此步)") TaskCreate(name="closing_followup_keyword_scan", description="Step 3.5: scan drafted closing summary for trigger phrases (follow-up / deferred / future / 之後 / 順便 etc); orphan mentions without #NNN cross-link → AskUserQuestion 3-option per canonical references/ic-r011-checkpoint.md; PATCH closing summary inline + add `### Closing Follow-ups Filed` audit trail (advisory, non-blocking, per IC_R011 #527)") TaskCreate(name="residue_acknowledgement", description="Step 3.6 (v2.66.0+, #105): read latest ## Diagnosis ### Residue section; if non-empty (not `(none)`), AskUserQuestion 3-option (still residue / file follow-up / skip); silent skip when residue is `(none)` or section missing. Audit trail PATCH to closing summary. Non-blocking, IC_R011 rollback respected. Closes the F3 write-only loop from #103.") @@ -440,6 +457,21 @@ for (bullet, reason) in WARNINGS: {相關 commit 列表} ``` +> **`type=meeting` closing summary 變體(#57,round-1 verify HIGH-3/HIGH-9 fix)**:meeting issue **不用**上面的五段式,改用 **decision→action mapping**: +> +> ```markdown +> ## Closing Summary (meeting) +> +> ### Decisions → Actions +> - **決策 1**:{拍板結論} → **action**:{follow-up + owner}(`#NNN` 若已開 follow-up issue) +> - **決策 2**:… → **action**:… +> +> ### Attendees / Context +> {與會者 / 脈絡(可選)} +> ``` +> +> meeting close **不跑 `### Verification`**(無 TDD verify)。Step 1.5 PR gate、Step 1.55 merge-completeness gate 對純 deliberation 的 meeting issue **不適用**(無 code branch / PR)—— 若 meeting 罕見地確實關聯 PR,照常跑。Step 1.6 semantic gate 對 meeting 的 checklist 語意改寫:Phase C 行動項對應到 **follow-up issue / artifact**(非 commit),warn-only 不硬擋。**行動項的 blocking gate 走上方 Step 0 的 meeting-specific gate(不是 generic checklist gate)** —— Phase C 未 disposition 的 bare `- [ ]` = 未決 = 不算談完、擋 close。 + ### Step 3: 確認 將 closing comment 顯示給使用者確認。 diff --git a/plugins/issue-driven-dev/skills/idd-diagnose/SKILL.md b/plugins/issue-driven-dev/skills/idd-diagnose/SKILL.md index 76b16dc..b1033dc 100644 --- a/plugins/issue-driven-dev/skills/idd-diagnose/SKILL.md +++ b/plugins/issue-driven-dev/skills/idd-diagnose/SKILL.md @@ -61,10 +61,10 @@ Aggregate report 在最後輸出(每個 issue 的 complexity 判定 + comment TaskCreate(name="read_issue", description="gh issue view #NNN 讀 title/body/labels/comments") TaskCreate(name="clarity_gate_check", description="Step 0.5 (v2.71.0+, #135): grep issue body for ### Clarity Surface unresolved rows; refuse if any per IC clarity axis hard-refuse rule (类比 PR Gate Check / idd-all-chain #119); backward compat: silent proceed if block absent (legacy pre-v2.71.0 issue)") TaskCreate(name="download_attachments", description="偵測 issue body/comments 的 attachment URL 全部下載到 .claude/.idd/attachments/issue-NNN/,寫 _manifest.json,parse(MCP-first: che-word-mcp / che-pdf-mcp / Read for images)。依 rules/process-attachments.md。忽略附件 = 忽略來源,違反鐵律。") -TaskCreate(name="diagnose_by_type", description="依 issue type 做診斷: bug→RCA / feature→需求分析 / refactor→現狀分析") +TaskCreate(name="diagnose_by_type", description="依 issue type 做診斷: bug→RCA / feature→需求分析 / refactor→現狀分析 / docs→敘述性審查 / meeting→Phase A/B/C 審議 Strategy(見 Step 3 meeting-adapted Diagnosis)") TaskCreate(name="post_diagnosis_report", description="產出 Diagnosis Report 並 comment 到 issue(非只在對話中顯示)") -TaskCreate(name="vagueness_precheck", description="Step 3.4 (v2.50+): Layer V Vagueness Pre-check — 用 .claude/rules/attribute-assessment.md 的 6-point Likert anchors 評 V1 + V4,trigger ≥ 4 跳 Hybrid 3-option (clarify/proceed/escalate),audit trail PATCH 到 Diagnosis comment。Unattended mode 自動 proceed + audit trail") -TaskCreate(name="complexity_assessment", description="Step 3.5: 5-layer 判定 Simple / Plan / Spectra 並寫入 report 的 Complexity 欄位(v2.36+ Spectra rename;v2.50+ Layer V 在 Layer 1 之後 Layer 2 之前)") +TaskCreate(name="vagueness_precheck", description="Step 3.4 (v2.50+): Layer V Vagueness Pre-check — 用 .claude/rules/attribute-assessment.md 的 6-point Likert anchors 評 V1 + V4,trigger ≥ 4 跳 Hybrid 3-option (clarify/proceed/escalate),audit trail PATCH 到 Diagnosis comment。Unattended mode 自動 proceed + audit trail。#57: type=meeting 直接短路跳過整個 Layer V,不評 V1/V4") +TaskCreate(name="complexity_assessment", description="Step 3.5: meeting-first 7-step routing 判定 Simple / Plan / Spectra(或 meeting 分支)並寫入 report 的 Complexity 欄位。序列: (1) type=meeting → (2) Layer 1 → (3) Layer V → (4) Spectra → (5) #129 硬閘 → (6) Layer P → (7) Simple 預設(v2.36+ Spectra rename;v2.50+ Layer V;#129 硬閘 + #57 meeting 分支)") TaskCreate(name="sister_concern_surfacing", description="Step 3.6: re-read posted Diagnosis content + scout session log for sister-concern markers (也有 / sister / 同樣的 / 另外 / etc); per IC_R011 file-by-default (v2.72.0+, see references/ic-r011-checkpoint.md §1.1); PATCH Diagnosis comment with `### Sister Concerns Filed` audit trail (per IC_R011 #528)") TaskCreate(name="confirm_and_route", description="與使用者確認診斷正確,依 complexity 顯示下一步命令") TaskCreate(name="auto_update_body", description="Step 5: 跑 /idd-update #NNN 同步 issue body Current Status phase → diagnosed(強制,常被漏;同 idd-close 2.18.1 模式)") @@ -192,7 +192,9 @@ fi gh issue view $NUMBER --repo $GITHUB_REPO --json title,body,labels,comments ``` -識別 issue type:bug / feature / refactor / docs。 +識別 issue type:bug / feature / refactor / docs / meeting。(`meeting` = 使用者驅動的審議 / 決策 issue —— 在 Step 3.5 routing 最優先分流走 meeting Strategy,不進 code 複雜度評估) + +**Type 解析順序(可機械判定;round-5 verify HIGH fix —— 支撐「type 是確定性欄位」的前提)**:`idd-issue` 建立時把 type 同時寫進 GitHub label(`--label `)與 body 的 `## Type` heading。讀取優先序:(1) **GitHub label** 中的 type 值為主(`gh issue view --json labels`);(2) label 無 type 時讀 body `## Type` heading;(3) 兩者衝突 → **label 勝**(label 是 idd-issue 的 canonical 寫入、且 filter/自動化以 label 為準);(4) 兩者皆無 type 訊號 → 依內容推斷,**預設非 meeting**(meeting 需 explicit 標記,避免把一般 issue 誤判成 meeting 而跳過複雜度評估)。 ### Step 1.5: 下載 Attachment(強制) @@ -276,7 +278,7 @@ Exit code: ## Diagnosis ### Type -{bug / feature / refactor} +{bug / feature / refactor / docs / meeting} ### Root Cause / Analysis {bug: root cause + evidence} @@ -313,6 +315,20 @@ Exit code: gh issue comment $NUMBER --repo $GITHUB_REPO --body "$DIAGNOSIS_REPORT" ``` +> **`type=meeting` 的 meeting-adapted Diagnosis(#57)**:當 issue type 是 `meeting` 時,`### Strategy` 段改用 **Phase A/B/C 審議模板**,**而非 code-centric 的 Files & Changes / Strategy checklist**(meeting 是使用者驅動的審議 / 決策工作,不是 TDD loop,emit code-centric 計畫沒有意義)。meeting Diagnosis 的 Strategy 段落格式: +> +> ```markdown +> ### Strategy (meeting deliberation) +> **Phase A(議程)** — 本次要談的議題清單 +> - {議題 1} / {議題 2} … +> **Phase B(決策點)** — 需要拍板的決策 + 候選選項(可列舉時用 AskUserQuestion render) +> - {決策點 1:候選 A / B / C} … +> **Phase C(行動項)** — 每個決策對應的 follow-up action + owner +> - [ ] {action item 1} … +> ``` +> +> meeting 分支在 Step 3.5 complexity scoring **之前分流**(**複雜度評估前分流**)—— meeting issue **不進 Layer 1 / Layer V / Spectra(Layer 2+3)/ 硬閘 / Layer P**,不產生 Simple / Plan / Spectra complexity verdict(見 Step 3.5「評估順序」的 meeting 分支)。closing 語意也不同(decision→action mapping,無 `/idd-verify` TDD pass;見 idd-close)。 + > **數學公式格式**:GitHub 支援 `$...$`(inline)和 `$$...$$`(display)math mode。 > 含底線的程式變數名(如 `mse_info`)**不放進 math mode** — KaTeX 無法可靠渲染底線跳脫。 > 改用混合寫法:數學部分用 `$R_I = J \cdot$`,變數名用 backtick code `` `mse_info` ``。 @@ -332,7 +348,11 @@ gh issue comment $NUMBER --repo $GITHUB_REPO --body "$DIAGNOSIS_REPORT" Diagnosis 完成、Step 3.5 Complexity Assessment 之前,評估 issue 的「需求清晰度」。如果模糊到無法可靠 routing,先讓 user 表態:澄清 / 照做 / 升級 Plan。 -**為何在 Step 3.5 之前**:Layer V 是 routing 決策的一階信號,放在 Step 3.5 之後等於 routing 已經做完才檢查 — 太晚。Layer 1 disqualifier 仍最優先(narrative / ad-hoc 強制 Simple,vagueness 不該推翻),所以 Step 3.4 在 Layer 1 之後、Layer 2/3/P 之前。 +> **`type=meeting` short-circuit(round-2 verify HIGH fix — MUST)**:若 issue `type=meeting`,**跳過整個 Layer V(Step 3.4)**,不評 V1/V4、不觸發 vagueness gate,直接進 Step 3.5 走 meeting 分支。理由:Step 3.4 在 Step 3.5 **之前**執行 —— 若不在此短路,meeting issue 會先撞上 Layer V 的 AskUserQuestion(或 unattended 下被設 `Plan via Layer V`),Step 3.5 的 meeting-first 排序就形同虛設。meeting 的模糊性由 Phase A/B/C 議程本身釐清(#57:type=meeting self-clarifying),故 Layer V 對它是 dead weight。 + +**為何在 Step 3.5 之前**:Layer V 是 routing 決策的一階信號,放在 Step 3.5 之後等於 routing 已經做完才檢查 — 太晚。Layer 1 disqualifier 仍最優先(narrative / ad-hoc 強制 Simple,vagueness 不該推翻),所以 Step 3.4 在 Layer 1 之後、Layer 2/3/P 之前(**但 `type=meeting` 更優先,見上方 short-circuit**)。 + +> **procedure vs verdict-precedence(round-4 verify HIGH 澄清)**:Step 3.4(Layer V)在 procedural 上先於 Step 3.5 執行(先 score、必要時 prompt),但 canonical 7-step 是 **verdict precedence** —— 其中 Layer 1(step 2)優先於 Layer V(step 3)。兩者不衝突:Layer V 在 3.4 只是**預先 score / 記 audit**,真正套用其結果是在 Step 3.5 step 3;而 Step 3.5 step 2 的 Layer 1 若命中 → `Simple` 並**停止**,覆蓋任何 Layer V escalation(narrative 勝 vagueness)。換言之 3.4 是 pre-check,最終裁決順序仍是 Layer 1 先於 Layer V。 #### A. 載入 attribute-assessment 規則(必要) @@ -464,22 +484,26 @@ gh api -X PATCH "/repos/$GITHUB_REPO/issues/comments/$COMMENT_ID" -f body="$NEW_ ### Step 3.5: Complexity Assessment (3-tier: Simple / Plan / Spectra) -Diagnosis 完成 + Step 3.4 Vagueness Pre-check 結束後,依 5 層 gate 判定 Complexity。**Default = Simple。** 完整邏輯見 [`rules/sdd-integration.md`](../../rules/sdd-integration.md)。 +Diagnosis 完成 + Step 3.4 Vagueness Pre-check 結束後(`type=meeting` 已在 Step 3.4 短路,直接落到本 step 的 meeting 分支),依 meeting-first 7-step routing 判定 Complexity。**Default = Simple。** 完整邏輯見 [`rules/sdd-integration.md`](../../rules/sdd-integration.md)。 > **v2.36.0+ rename**:原本是二元 `Simple` / `SDD-warranted`,現在是三層 `Simple` / `Plan` / `Spectra`。`SDD-warranted` 是 `Spectra` 的 backward-compat alias(既有 issue 不需重寫)。Plan 是新增的中間層,覆蓋「想先想清楚再動手,但沒到要寫 spec contract」的常見場景。 > > **v2.50.0+ Layer V**:Step 3.4 Vagueness Pre-check 在 Layer 1 之後、Layer 2 之前評估「需求清晰度」。若 user 在 Step 3.4 選 `escalate to Plan`,verdict 直接設 `Plan via Layer V`,本 step 跳過 Layer 2/3/P 評估。 -#### 評估順序(必須照此順序,5 層) +#### 評估順序(統一 routing,必須照此順序) + +**canonical routing 序列(#129 × #57 耦合收斂;meeting-first,忠實 7 步)**:**(1) type=meeting → (2) Layer 1 → (3) Layer V → (4) Spectra(Layer 2+3)→ (5) #129 硬閘 → (6) Layer P → (7) Simple 預設**(此序列與下方 operational list 一一對應,不省略任何 gate —— round-2 verify HIGH-5 fix:舊「5-stage」摘要漏列 Spectra 造成歧義)。**`type=meeting` 最優先分流**:type 是 issue 的確定性欄位,先於任何內容啟發式判定 —— 否則 meeting 的 Phase A/B/C 審議內容會被 Layer 1 的 narrative disqualifier 誤判成 Simple 而攔截(#57 裁決;round-1 verify HIGH-2 fix)。硬閘只作用於**非 meeting 的 code-centric issue**,兩者不對同一 issue 同時給出衝突 verdict。 -1. **Layer 1 disqualifiers** 任一命中 → `Simple`,停止 -2. **Layer V (Step 3.4)** Vagueness 已在 Step 3.4 處理: +1. **`type=meeting`** → 走 meeting Strategy(Phase A/B/C 審議模板,複雜度評估前分流)→ **本 step 結束**,**不進 Layer 1 / Layer V / Spectra(Layer 2+3)/ 硬閘 / Layer P**,不產生 Simple / Plan / Spectra complexity verdict(見 Step 3「meeting-adapted Diagnosis」)。meeting **刻意跳過 Layer V** vagueness pre-check —— 審議 issue 的模糊性由 Phase A/B/C 議程本身釐清(#57 裁決:type=meeting self-clarifying) +2. **Layer 1 disqualifiers** 任一命中 → `Simple`,停止 +3. **Layer V (Step 3.4)** Vagueness 已在 Step 3.4 處理: - User 選 `escalate to Plan` → verdict = `Plan via Layer V`,**本 step 結束** - User 選 `clarify now` → 已重跑 Layer V + 進到本 step - User 選 `proceed anyway` 或 V≤3 → 繼續以下評估 -3. **Layer 2 + Layer 3** 都命中 → `Spectra` -4. **Layer P** 任一命中 → `Plan` -5. 否則 → `Simple`(default) +4. **Layer 2 + Layer 3** 都命中 → `Spectra`(published API contract;優先於硬閘 / Layer P) +5. **#129 硬閘(Hard Gate,MUST-trigger)** 命中 → `Plan`(疊加於 Layer P 之上,只升級不反轉) +6. **Layer P** 任一命中 → `Plan` +7. 否則 → `Simple`(default) #### Layer 1: Simple-required disqualifiers(任一命中 → 強制 Simple) @@ -508,9 +532,22 @@ Diagnosis 完成 + Step 3.4 Vagueness Pre-check 結束後,依 5 層 gate 判 **Plan-Spectra 分界**:「published API/protocol 給 future callers」就是 line。內部 refactor 5 個檔案 → Plan;加新 MCP tool / plugin skill / public API → Spectra。 +#### Hard Gate(硬閘,MUST-trigger,疊加於 Layer P 之上) + +在 Layer P 之上先評一層 **MUST-trigger 硬閘**。`/idd-diagnose` 在 implementation 之前跑、**沒有實際 diff** 可 grep,故硬閘觸發是 AI 對「本 issue 預期改動範圍」的**估計**(依 `attribute-assessment` 紀律揭露理由 + 具體錨點,audit line 見下方 Step 3.5 尾),不是 diff-time 機械比對。 + +判準(OR,任一命中 → 強制 `Plan`): + +1. **單一概念散佈 ≥ 5 檔** — 門檻 **N = 5**(保守以保護 Simple 預設;3 = 激進、5 = 保守;N 是本設計唯一可調旋鈕)。**判準是「同一 conceptual 改動散佈到 ≥ 5 檔」,不是純檔數**:genuinely 各自獨立、無共享概念的多檔(parallel doc updates / 各自獨立的 script tweaks)由 Layer 1「Multi-file but each file independent」保持 Simple、**不**觸發硬閘(round-1 verify HIGH-7 fix —— 消解硬閘 vs Layer 1 的矛盾)。取 5 而非 3:impl + test + doc 這類合法小改常觸及 3 檔,門檻設 3 會過度觸發;5 檔才是「單一概念散佈多處」的可靠訊號(對齊 #44/#47 failure class —— CR/PTSR/PCQ 三量表共用一個 scoring helper 即是「散佈的單一概念」,非獨立多檔)。 +2. **動到 shared abstraction** — 被 **≥ 2 個其他檔案** 引用的 data structure / helper interface / constants set。以「issue 描述 + 對現有程式碼的引用查找」估計某待改符號的跨檔 caller 數;≥ 2 → 命中。**shared abstraction 命中時,產出的 Plan 必涵蓋 family-wide 影響** —— 列舉該抽象的所有已知 call site / family member 為 in-scope(填入 `/idd-plan` 的 `Family-wide scope` 小節),而非只覆蓋觸發當下那個檔案(#44 教訓:miss 不在沒開 Plan,而在 Plan 只覆蓋一個量表、漏了同 family 的 sibling)。 + +硬閘**只升級、不反轉** Simple 預設 —— 命中 → 強制 `Plan`;硬閘未命中 → **落回 Layer P** + Simple 預設(既有行為不變)。硬閘是「加法」不是「換底」:把大型多檔 / 共用抽象改動從 Simple 拉升到 Plan,但不把小改也拖進 plan-mode approval gate(**替代方案「反轉為 Default-Plan」已被使用者否決** —— over-trigger 成本高於 under-plan 殘餘風險)。硬閘只作用於**非 meeting 的 code-centric issue**(Layer 1 已把 narrative / 各自獨立的 multi-file 改動強制 Simple、不會進到這裡)。 + +**Audit line(揭露估計,與 Layer V 同等 audit trail)**:硬閘評估後於 Diagnosis comment 印**一行** `Hard-gate: `,與 Step 3.4 的 Layer V audit line 並列。reason 必引**具體錨點**(估計的檔名 / 符號名),不是 style words。命中 → `Hard-gate: triggered — <列出估計觸及的模組 + shared helper>`;未命中 → `Hard-gate: not triggered — `。**訊號不足**(issue 描述太稀、無法估計檔數或 caller 數)→ 硬閘**不觸發**(fail-open 回 Layer P + Simple 預設),該行寫 `Hard-gate: not triggered — insufficient signal`。理由:硬閘是「加保護」,訊號不足時不應誤升級;漏升級由既有 Layer P 兜底。 + #### Plan(Layer P,至少一個命中) -如果 Layer 1 沒命中、Layer 2 沒滿足 Spectra,評估 Plan signals: +如果 Layer 1 沒命中、Layer 2 沒滿足 Spectra、硬閘也沒命中,評估 Plan signals: - **2+ 檔案有順序依賴** — 檔案 A 的改動影響檔案 B 必須怎麼改,無法 parallel edit - **Strategy 有 5+ ordered steps** — sequential 複雜度,受惠於 explicit checkpoint @@ -551,6 +588,9 @@ Diagnosis 完成 + Step 3.4 Vagueness Pre-check 結束後,依 5 層 gate 判 | `Plan` | `/idd-plan #NNN` | diagnose → plan (EnterPlanMode 審查 Implementation Plan → 使用者 approve via ExitPlanMode) → implement → verify → close | | `Spectra` (default) | `/spectra-discuss` | diagnose → discuss → propose → apply → verify → close + archive | | `Spectra` (opt-out) | `/spectra-propose` | diagnose → propose → apply → verify → close + archive(僅當 ALL opt-out conditions 成立) | +| `meeting`(**type 分流,非 complexity verdict** —— 在 Step 3.5 最優先分支、不經複雜度評分) | `/idd-plan #NNN`(meeting-adapted plan) | diagnose(Phase A/B/C Strategy)→ plan(meeting Plan body:議程 → 決策點 → 行動項;**不** chain to `/idd-implement`)→ close(decision→action mapping + meeting-specific gate,無 `/idd-verify` TDD pass) | + +> **Pre-implementation staging hand-off(#111,非綁定)**:verdict 為 `Plan` 或 `Spectra`(design-heavy)時,diagnose 在 report 印一行非綁定 pointer —— `→ 建議 pre-implementation staging: superpowers:brainstorming`(先 brainstorm 對齊方向再進 plan / propose)。這是**非綁定建議**:IDD 自身**不** invoke `superpowers:brainstorming`,使用者自行決定是否跟進(見 README「IDD ↔ superpowers stage mapping」)。 > **為什麼 discuss 是 Spectra default?** AI 常常高估 diagnosis 的完整度。一份看起來詳盡的 diagnosis 可能仍留下關鍵的未決項:命名、範圍邊界、多個合理方案中該選哪個、新產物要放哪裡。直接跳到 `spectra-propose` 會產生建立在未確認假設之上的 proposal。`spectra-discuss` 是對齊的 safety net — 強制把假設列出、讓使用者修正。跳過它應該是例外,不是預設。 > diff --git a/plugins/issue-driven-dev/skills/idd-issue/SKILL.md b/plugins/issue-driven-dev/skills/idd-issue/SKILL.md index 959e0da..578eb46 100644 --- a/plugins/issue-driven-dev/skills/idd-issue/SKILL.md +++ b/plugins/issue-driven-dev/skills/idd-issue/SKILL.md @@ -524,9 +524,9 @@ echo " 3) 全部存好後告訴我「ok」,skill 會接手 upload + 嵌入 is 缺少的話詢問使用者: 1. **Title** — 一句話描述問題 -2. **Type** — bug / feature / refactor / docs +2. **Type** — bug / feature / refactor / docs / meeting(`meeting` = 使用者驅動的審議 / 決策工作,不是 code change — 走專屬的 diagnose Strategy / plan skip-chain / decision→action closing,見 [`rules/sdd-integration.md`](../../rules/sdd-integration.md) 與 idd-diagnose Step 3.5) 3. **Priority** — P0(立即)/ P1(本週)/ P2(排程)/ P3(有空再做) -4. **Description** — 問題描述(bug: 重現步驟 + expected + actual;feature: 需求 + 目的) +4. **Description** — 問題描述(bug: 重現步驟 + expected + actual;feature: 需求 + 目的;meeting: 議題 + 待決策點) 5. **Stakeholders(v2.32.0+,可選)** — 若需要在 issue body 中 tag 人,使用 `--mention [,...]` flag 或自然語言("tag X")。**任何 @xxx 必走 [`rules/tagging-collaborators.md`](../../rules/tagging-collaborators.md) 5 步協定**(gh api → fuzzy match → AskUserQuestion fallback → @login 不用 display name → post 前 verify)。違反 = 通知錯人,不可逆。派送時把 resolved logins 帶進 `gh-egress.sh --mention-attested `(#117 unconditional mention net);非 mention 的附帶 `@xxx` token 一律 backtick-escape。 實作:resolution 完成後設 `MENTION_ATTESTED="login1,login2"`(無 mention 時留空 — 模板的 `${MENTION_ATTESTED:+...}` 條件式自動省略 flag)。 @@ -631,7 +631,7 @@ bash "$CLAUDE_PLUGIN_ROOT/scripts/gh-egress.sh" create \ {Plain language interpretation} ## Type -{bug / feature / refactor / docs} +{bug / feature / refactor / docs / meeting} ## Expected ... @@ -1075,6 +1075,8 @@ options: 提示下一步:`/issue-driven-dev:idd-diagnose #NNN` +> **Pre-implementation staging hand-off(#111,非綁定)**:若這是 design-heavy issue(預期會走 Plan / Spectra、方向未定),在 Step 5 摘要**額外印一行非綁定 pointer** —— `→ 若要先 brainstorm 對齊方向: superpowers:brainstorming`。這是**非綁定建議**:idd-issue **不** invoke `superpowers:brainstorming`,由使用者自行決定是否跟進(見 README「IDD ↔ superpowers stage mapping」)。 + > **CRITICAL: 建立 issue 後必須停止。不要自動開始 diagnose 或 implement。** > Issue 建立是人的決定點 — 人決定優先級、分配、時機。 > AI 不應該擅自開始解決問題。等使用者明確說「開始做」或呼叫 `idd-diagnose` 才繼續。 diff --git a/plugins/issue-driven-dev/skills/idd-plan/SKILL.md b/plugins/issue-driven-dev/skills/idd-plan/SKILL.md index c29c7ac..201cae5 100644 --- a/plugins/issue-driven-dev/skills/idd-plan/SKILL.md +++ b/plugins/issue-driven-dev/skills/idd-plan/SKILL.md @@ -75,6 +75,9 @@ gh issue view $NUMBER --repo $GITHUB_REPO --json title,body,labels,comments - [ ] `path/to/file2.ext` — {改什麼 + 與 file1 的依賴關係} - [ ] `tests/path/to/test_file.ext` — {測什麼 invariant,RED→GREEN expectation} +### Family-wide scope (shared-abstraction hard-gate trigger only) +{僅當 #129 硬閘因 **shared abstraction** 命中時填:列舉該抽象的**所有已知 call site / family member** 為 in-scope,而非只覆蓋 issue 標題點名的觸發檔。例:scoring helper 被 CR + PTSR + PCQ 三個 sibling 量表共用 → 三個 sibling 全列入 Files & Changes。這是硬閘的產出契約(#44 教訓:Plan 只覆蓋一個量表、漏了同 family 的 sibling,兩次 close 才補齊)。非 shared-abstraction 觸發時填 `n/a`。} + ### Sequencing & Dependencies {file A 的改動先 land,因為 file B 的測試會 import file A 的新 helper / file B 改完才能測 end-to-end / 等等} @@ -102,6 +105,20 @@ gh issue comment $NUMBER --repo $GITHUB_REPO --body "$IMPLEMENTATION_PLAN" > **為什麼比 idd-implement 的 plan 詳盡?** Plan tier 的 user 審查是事前 deliberation 的 core moment — plan 越具體,user 越容易抓出 missing case / wrong assumption / better alternative。idd-implement 的 plan 是「執行清單」,本 plan 是「decision artifact」。 +> **`type=meeting` 用 meeting-adapted Plan body schema(#57)**:上面的 code-centric 模板(Files & Changes / Sequencing / Test Plan)**不適用** meeting。`type=meeting` 改用審議 Plan body: +> +> ```markdown +> ## Meeting Plan: Issue #NNN +> ### Phase A — 議程(本次要談的議題) +> - {議題 1} … +> ### Phase B — 決策點(需拍板 + 候選選項) +> - {決策點 1:候選 A / B / C} … +> ### Phase C — 行動項(decision → follow-up action + owner) +> - [ ] {action} … +> ``` +> +> meeting plan 過 user approve 後 **不 chain 到 /idd-implement**(見 Step 6 skip-chain)。 + ### Step 2.5: Tangential Observations Sweep **Per IC_R011 follow-up filing checkpoint** (see [`references/ic-r011-checkpoint.md`](../../references/ic-r011-checkpoint.md))。 @@ -158,6 +175,8 @@ gh issue comment $NUMBER --repo $GITHUB_REPO --body "$IMPLEMENTATION_PLAN" ### Step 6: Chain to /idd-implement +> **`type=meeting` → 跳過本步(skip-chain,#57)**:meeting 是 user-driven deliberation,不是 TDD loop。`type=meeting` 的 plan 用 **meeting-adapted Plan body** schema(Phase A/B/C 審議計畫:議程 → 決策點 → 行動項,非 code-centric 的 Files & Changes),且 **不 chain 到 /idd-implement**(輸出不含對 `/idd-implement` 的邀請 / 呼叫)。plan 過 user approve 後即結束於 deliberation artifact;closing 走 decision→action mapping、無 `/idd-verify` TDD pass(見 idd-close)。以下 chain 僅適用於 code-centric(bug / feature / refactor)plan。 + User approved → invoke idd-implement skill 繼續 TDD loop: ```