Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
schema: spec-driven
created: 2026-07-02
created_by: che cheng <kiki830621@gmail.com>
43 changes: 43 additions & 0 deletions openspec/changes/idd-verify-depend-on-pai-engine/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## Context

#207(使用者依賴裁決)。pai 2.18.0 契約:args `profile|file|diffFile|contextBlock|customLenses|daFocus|codexEnabled|codexCallPath|agentModel|maxAgents…`;return `{findings[{lens,severity,title,file,body}], verdict, stats.dispatchModel}`——與 IDD 現引擎同構(血緣 fork)。

## Goals / Non-Goals

Goals:canonical 依賴為主路徑、版本閘門防契約前引擎、三層 graceful degrade、fork 凍結。Non-goals 見 proposal。

## Decisions

### D1 — 三層解析鏈 + 版本閘門

```
PAI_ENGINE=$(ls -d ~/.claude/plugins/cache/parallel-ai-agents/parallel-ai-agents/*/ 2>/dev/null | sort -V | tail -1)
PAI_VER=$(basename "$PAI_ENGINE") # cache 目錄名即版本
MIN_PAI=2.18.0 # agentModel + STABLE 契約起點
若 PAI_ENGINE 存在且 sort -V 判 PAI_VER ≥ MIN_PAI 且 workflows/ensemble-workflow.js 存在
→ backend = pai-ensemble(canonical)
否則若 dynamic-workflow primitive 可用 → backend = vendored fallback(凍結 fork)
否則 → manual fan-out
```

每層印 notice:`→ verify backend: pai-ensemble 2.18.0 (canonical)` / `vendored fallback (pai absent or < 2.18.0)` / `manual fan-out`。**閘門理由**:2.17.0 引擎會靜默忽略 `agentModel`(無此參數)→ 派發回退繼承 session model(#205 根因復發且審計行造假)——寧可用自家已修的 fork 也不用契約前的 canonical。

### D2 — args 映射(IDD lens 語意以 custom profile 表達)

`profile:'custom'`;`customLenses` = requirements / logic / security / regression 四鍵(focus 文本自 vendored 引擎 LENSES port,字面不變);`daFocus` = 現 daPrompt 之反駁指令精髓;`contextBlock` = `DATA_GUARD 前言 + ISSUE #N: <title>\n<body>(各 issue)+ Source-of-truth attachments: <清單>`(pai 端 `dataBlock()` 對整個 contextBlock 再包 PAI_ENSEMBLE sentinel + 偽造 marker 剝除——雙層防injection);`diffFile` 直傳;`codexCallPath` = IDD 自己 vendored 的 codex-call 絕對路徑(不依賴 pai 的 bin 佈局);`agentModel` = 既有 Step 2 前 `IDD_AGENT_MODEL` 解析值。

### D3 — 揭露與消費

pai return 與 IDD 同構 → Step 3 normalization 原樣消費;Engine 行:`pai-ensemble <ver> — 6/6 (model: <stats.dispatchModel>)`。lens 鍵沿用 IDD 命名(customLenses 自帶鍵,harness 強制 attribution),master report 的 Source 欄零改動。

### D4 — fork 凍結

vendored `ensemble-workflow.js` header 加 FROZEN banner:fallback-only、新功能/修復一律上游 pai(canonical single source),本檔僅接受「與 pai 契約同步的必要對齊」。

## Implementation Contract

- SKILL.md 有三層解析鏈 + `MIN_PAI` 常數 + 三種 notice line;`agentModel` 傳遞至 pai args
- customLenses 四鍵 focus 與 vendored LENSES 字面一致(grep 可驗)
- vendored 引擎首屏可見 FROZEN banner
- `spectra validate` 綠;雙軌掃尾:解析鏈變更未觸碰 manual fan-out 與 dispatch-model 規則(#205 不回歸)
- **Tier-1 契約 live smoke(closed,2026-07-02 run `wf_27d7d3dd-c35`)**:pai 2.18.0 branch 引擎 × 一字不差的 Tier-1 args 映射 × 種了雙 bug 的 15 行 diff——(1) lens attribution 回 IDD 鍵名(requirements/logic/security/regression/devils-advocate);(2) contextBlock 送達(requirements lens 逐字引用 issue #999 acceptance examples 並 trace);(3) `stats.dispatchModel='opus'`(巢狀位置實證 → 雙路徑抽取規則正確);(4) 5/5 agent transcript 實跑 `claude-opus-4-8`(session 為 Fable 級);(5) 兩個 planted bug 被四 lens 獨立抓到、DA 有效對抗、integrity 0
18 changes: 18 additions & 0 deletions openspec/changes/idd-verify-depend-on-pai-engine/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Why

idd-verify vendor 一份 305 行窄化 ensemble fork,與 parallel-ai-agents(pai)的 513 行 canonical 引擎重複維護同構機件;#205/pai#20 證實同一 bug 要修兩次。使用者裁決(pai#20 decision comment 逐字在案):「idd不是應該要依賴 parallel-ai-agents嗎…需要官方就直接依賴」。pai 2.18.0 已官方化 EXTERNAL-CONSUMER CONTRACT(args surface + return shape 為 STABLE API),依賴接口就緒。

## What Changes

1. `skills/idd-verify/SKILL.md`:backend 解析鏈改三層——(1) 已安裝 pai canonical 引擎(plugin cache `sort -V` 最高版,版本閘門 ≥ 2.18.0)→ (2) vendored fallback(凍結)→ (3) manual fan-out;args 映射(profile:'custom' + customLenses ×4 + daFocus + DATA_GUARD contextBlock + diffFile + codexCallPath + agentModel);Engine 行揭露實際 backend + 版本
2. `skills/idd-verify/ensemble-workflow.js`:凍結 banner(fallback-only;新功能一律上游 pai)
3. spec delta:idd-verify MODIFIED(backend resolution 條款 + version-gate degrade scenario)
4. CHANGELOG + plugin.json 2.88.0 → 2.89.0

**時序解耦**:現裝 pai 2.17.0 < 閘門 → 解析鏈自然落 vendored fallback;pai 2.18.0 shipped 後 canonical 路徑零改動點亮。本 change 可先於 pai#21 merge 安全出貨。

## Impact

- Affected specs: idd-verify (MODIFIED)
- Affected code: plugins/issue-driven-dev/skills/idd-verify/SKILL.md, plugins/issue-driven-dev/skills/idd-verify/ensemble-workflow.js, plugins/issue-driven-dev/CHANGELOG.md, plugins/issue-driven-dev/.claude-plugin/plugin.json, .claude-plugin/marketplace.json(close 時 dist-sync)
- Non-goals:pai 端任何改動(契約已在 pai#20 凍結);manual fan-out 路徑不動;vendored copy 的物理刪除(等 canonical 跑過數輪真 verify 後另議,見 issue Residue)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## MODIFIED Requirements

### Requirement: Independent-agent cross-verification ensemble

The `/idd-verify` capability SHALL verify an implementation through an ensemble of independent agents: distinct-lens reviewers (requirements, logic, security, regression), an adversarial devil's-advocate that attempts to refute the other lenses' pass judgments, and a cross-model blind verifier. The reported result SHALL be the merged, deduplicated union of all sources, with each finding's severity taken as the highest reported. Ensemble agents (both workflow-backend and manual fan-out) SHALL be dispatched on an explicitly configured Claude model — defaulting to `opus` and overridable via the `IDD_AGENT_MODEL` environment variable — rather than inheriting the session's main-loop model; an invalid override value SHALL fail loudly at dispatch time. The cross-model verifier's non-Claude engine is exempt (it runs on a different model family by design), but the agent that drives it is dispatched like any other ensemble agent. The master report SHALL disclose the dispatch model. The workflow backend SHALL be resolved through a three-tier chain: (1) the installed parallel-ai-agents canonical ensemble engine when its version meets the minimum contract version (2.18.0, the start of the `agentModel` + stable external-consumer contract), configured via that contract's custom-profile surface so the four IDD lenses, devil's-advocate focus, untrusted-content guard, and dispatch model are preserved; (2) the frozen vendored fallback engine when the canonical engine is absent or predates the contract; (3) manual fan-out when no workflow primitive is available. The resolved backend and, for the canonical tier, its version SHALL be disclosed in a notice line and in the master report's engine line.

#### Scenario: ensemble composition and merge

- **WHEN** `/idd-verify` runs on a change
- **THEN** findings are produced from each distinct lens, the devil's-advocate has attempted to refute the other lenses' pass judgments, and the cross-model verifier has run independently
- **AND** the reported findings are the merged + deduplicated union, severity taken highest

#### Scenario: dispatch model defaults to opus

- **GIVEN** `IDD_AGENT_MODEL` is unset
- **WHEN** the ensemble dispatches its agents
- **THEN** every reviewer, the devil's-advocate, and the cross-model runner agent carry an explicit `opus` model designation
- **AND** the master report's engine line discloses the dispatch model

#### Scenario: explicit override is honored and validated

- **GIVEN** `IDD_AGENT_MODEL=sonnet`
- **WHEN** the ensemble dispatches
- **THEN** agents run on sonnet
- **AND** an invalid value (e.g. `gpt-4`) aborts dispatch with a usage error naming the accepted values

#### Scenario: canonical engine preferred when contract version is met

- **GIVEN** the parallel-ai-agents plugin is installed at version 2.18.0 or newer
- **WHEN** `/idd-verify` resolves its workflow backend
- **THEN** the installed canonical engine runs the ensemble via the custom-profile contract (four IDD lenses, DA focus, guarded untrusted context, `agentModel` threaded)
- **AND** the notice and engine lines disclose `pai-ensemble <version>`

#### Scenario: graceful degrade below the contract version

- **GIVEN** the installed parallel-ai-agents version predates 2.18.0, or the plugin is absent
- **WHEN** `/idd-verify` resolves its workflow backend
- **THEN** the frozen vendored fallback engine runs instead (never the pre-contract canonical engine, which would silently drop `agentModel`)
- **AND** the degrade reason is disclosed in the notice line
21 changes: 21 additions & 0 deletions openspec/changes/idd-verify-depend-on-pai-engine/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## 1. SKILL.md — 三層 backend 解析鏈

- [x] 1.1 「Capability detection + fallback」段改三層:pai canonical(cache `sort -V` 最高版 + `MIN_PAI=2.18.0` 閘門)→ vendored fallback → manual fan-out;三種 notice line
- [x] 1.2 pai 路徑的 args 映射:profile:'custom'、customLenses ×4(focus 字面 port 自 vendored LENSES)、daFocus、contextBlock(DATA_GUARD + issues + attachments)、diffFile、codexCallPath(IDD 自有)、agentModel
- [x] 1.3 Engine 行揭露格式:canonical 帶 `pai-ensemble <ver>` + `stats.dispatchModel`(首輪僅 prose、模板未接線——verify 2×HIGH 抓出;4.1 完成真接線)

## 4. Verify fixes(wf_00d8cb60-2b3)

- [x] 4.1 兩個 `### Engine` 模板改 `${BACKEND_DESC}, model: ${DISPATCH_MODEL}`;三 tier 各設 BACKEND_DESC;normalization 抽取規則雙路徑(top-level || stats.dispatchModel || request-echo 標注)
- [x] 4.2 `$CONTEXT_BLOCK` 顯式組裝步驟(DATA_GUARD literal + issues + attachments;Tier 1 專用註記)
- [x] 4.3 semver 目錄過濾 + fallback notice 精確 reason;D3 prose 標注 codexCall/codexCallPath 雙 arg 名;標題/status prose 三層化;Tier 3 前置冗餘註記
- [x] 4.4 Tier-1 契約 live smoke(pai 2.18.0 branch 引擎 × 完整 args 映射)——證明 customLenses attribution / contextBlock 落地 / stats.dispatchModel

## 2. vendored 引擎凍結

- [x] 2.1 ensemble-workflow.js header 首屏 FROZEN banner(fallback-only;新功能一律上游 pai)

## 3. 收尾

- [x] 3.1 plugin.json 2.88.0 → 2.89.0 + CHANGELOG 條目
- [x] 3.2 `spectra validate` 綠;雙軌掃尾(manual fan-out 與 #205 dispatch-model 規則零回歸;customLenses focus 與 LENSES 字面一致 grep 驗證)
2 changes: 1 addition & 1 deletion plugins/issue-driven-dev/.claude-plugin/plugin.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions plugins/issue-driven-dev/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- **idd-verify now depends on parallel-ai-agents' canonical ensemble engine (#207)** — per the owner's direct-dependency ruling (recorded verbatim on pai#20), the workflow backend resolves through a three-tier chain: (1) the **installed pai engine** (plugin-cache discovery, `sort -V` highest, version gate `>= 2.18.0` — the start of the `agentModel` + STABLE external-consumer contract; a pre-contract engine would silently drop `agentModel` and reintroduce #205, so it is never used), configured via `profile:'custom'` with the four IDD lenses (focus text identical to the vendored `LENSES`), the DA refutation focus, a DATA_GUARD-prefixed `contextBlock` (double-wrapped by pai's own sentinel machinery), `diffFile`, IDD's own vendored `codexCallPath`, and the resolved `IDD_AGENT_MODEL` as `agentModel`; (2) the now-**FROZEN vendored fork** as fallback (banner added — new features go upstream to pai); (3) manual fan-out. Notice + Engine lines disclose the resolved backend and, for canonical, the pai version and `stats.dispatchModel`. Ships safely before pai 2.18.0 is installed — the chain simply keeps using the fallback until the canonical engine lights up. Spectra change `idd-verify-depend-on-pai-engine`; interface defined in pai#20's officialized contract.

### Added

- **Explicit dispatch model for all verify fan-outs — default `opus` (#205)** — every ensemble agent dispatch now carries an explicit Claude model instead of inheriting the session's main-loop model (which, on high-tier sessions, burned 563k–1,092k subagent tokens per verify round and killed a lens agent at a session limit mid-run). `ensemble-workflow.js` resolves `AGENT_MODEL` from the new `args.agentModel` (whitelist `sonnet|opus|haiku|fable`, absent/invalid → `opus` as a legacy-caller backstop) and passes `model: AGENT_MODEL` at all 3 `agent()` sites (4 lens reviewers, the codex-runner Bash-agent, devil's-advocate); the return value now includes `dispatchModel`. `idd-verify` SKILL.md gains a pre-engine resolution step: `IDD_AGENT_MODEL` env var overrides, unset → `opus`, invalid → **abort with a usage error** (fail-loud; a typo'd override must not silently dispatch on a different tier). All 5 manual fan-out `Agent()` templates, the Step 2.5b retry spawn, and the `team` engine carry the same explicit model; master-report Engine lines disclose it (`model: ${AGENT_MODEL}`). The rule applies uniformly across the plugin's other fan-outs (verify round caught the first literal-grep inventory as structurally blind to prose-described dispatch): `idd-diagnose`'s #182 parallel fan-out and `references/parallel-orchestration.md` now require the same explicit model, and the vendored `spectra-archive` / `spectra-audit` / `spectra-apply` reference copies get doc-only alignment (that tree is a third-party reference, not in this plugin's execution cycle — the canonical rule lives in idd-verify). Both layers fail loudly on an explicitly invalid value (skill: `exit 64`; workflow: `throw` before any dispatch); only an absent `agentModel` falls back to `opus`. **Model routing confirmed live** (run `wf_6c1d8ee6-5f3`): a claude-fable-5 session dispatching with `agentModel:'opus'` produced six agent transcripts all recording `claude-opus-4-8` — a genuine tier downgrade, and the returned `dispatchModel` (now preferred by the Engine disclosure line) matches what actually ran. Directionality caveat documented: the default only lowers burn when the session tier is above opus; sub-opus sessions should set `IDD_AGENT_MODEL=sonnet|haiku` explicitly. Codex's gpt-5.5 side is exempt by design (cross-model lens) — only the driving agent is pinned. Spectra change `agent-dispatch-model-default`; tracking sibling: parallel-ai-agents#20.
Expand Down
Loading