diff --git a/.gitignore b/.gitignore index d2f547e..7c3d065 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ node_modules/ settings.local.json .claude_review_state.json .claude_nit_history.json +.claude_workflows/ .claude/ # Local-only skills (not published) diff --git a/CLAUDE.md b/CLAUDE.md index 1a243ce..3404bd4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,6 +51,8 @@ Coverage: happy path + error handling + edge cases (null, empty, extremes) | `/feasibility-study` | Feasibility analysis | Requirements | | `/tech-spec` | Generate tech spec | Design | | `/review-spec` | Review tech spec | Design | +| `/plan-review` | Pre-ExitPlanMode adversarial plan review loop | Planning | +| `/orchestrate` | Agent-driven workflow planning + read-only fanout (report-only v1) | Planning | | `/deep-analyze` | Deep analysis + roadmap | Design | | `/architecture` | Architecture design + 3-architecture.md | Design | | `/project-brief` | PM/CTO executive summary | Design | @@ -139,7 +141,7 @@ Coverage: happy path + error handling + edge cases (null, empty, extremes) ## Development Rules 1. **Reference existing code** -- find similar files first, keep style consistent -2. **Test command** -- `node --test test/**/*.test.js` +2. **Test command** -- `npm test`(`node --test $(find test -name '*.test.js')` — npm scripts 走 `/bin/sh`,`**` glob 不展開巢狀目錄,勿用 `test/**/*.test.js`) 3. **Author attribution** -- use developer's GitHub username, never AI names (exception: `/smart-commit --ai-co-author`). Forbidden patterns in commit messages **and PR title/body** (canonical source: `scripts/commit-msg-guard.sh`): Co-Authored-By AI, Generated-by tags, emoji robot tags. Commits: install `commit-msg-guard.sh` via `/install-scripts`. PRs: `/create-pr` Step 4b enforces sanitization automatically. 4. **No auto-commit** -- Claude must not run `git add`, `git commit`, `git push` (exception: `/push-ci` may execute `git push` after user approval; `/smart-commit --execute` may execute `git add` + `git commit` after user approval) diff --git a/CLAUDE.template.md b/CLAUDE.template.md index ca48490..f7d2b65 100644 --- a/CLAUDE.template.md +++ b/CLAUDE.template.md @@ -99,6 +99,8 @@ Coverage: happy path + error handling + edge cases (null, empty, extremes) | `/feasibility-study` | Feasibility analysis | Requirements | | `/tech-spec` | Generate tech spec | Design | | `/review-spec` | Review tech spec | Design | +| `/plan-review` | Pre-ExitPlanMode adversarial plan review loop | Planning | +| `/orchestrate` | Agent-driven workflow planning + read-only fanout (report-only v1) | Planning | | `/deep-analyze` | Deep analysis + roadmap | Design | | `/architecture` | Architecture design + 3-architecture.md | Design | | `/project-brief` | PM/CTO executive summary | Design | diff --git a/README.es.md b/README.es.md index a43105d..a992954 100644 --- a/README.es.md +++ b/README.es.md @@ -55,7 +55,7 @@ La mayoría de proyectos de harness cubren 2–4 de estos subproblemas. sd0x-dev /project-setup ``` -Un solo comando autodetecta framework, package manager, base de datos, entry points y scripts. Instala un subconjunto de rules y hooks; el plugin completo incluye 14 rules + 9 hooks. +Un solo comando autodetecta framework, package manager, base de datos, entry points y scripts. Instala un subconjunto de rules y hooks; el plugin completo incluye 14 rules + 8 hooks. Usa `--lite` para solo configurar CLAUDE.md (sin rules/hooks). @@ -249,9 +249,9 @@ Escenarios reales que muestran qué habilidades combinar y en qué orden. |-----------|----------|----------| | Skills | 96 public (96 bundled) | `/project-setup`, `/codex-review-fast`, `/verify`, `/smart-commit`, `/deep-research` | | Agents | 15 | strict-reviewer, verify-app, coverage-analyst, architecture-designer | -| Hooks | 9 | pre-edit-guard, auto-format, review state tracking, stop guard, namespace hint, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | +| Hooks | 8 | pre-edit-guard, auto-format, review state tracking, stop guard, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | | Rules | 14 | auto-loop, auto-loop-project, codex-invocation, security, testing, git-workflow, self-improvement, context-management | -| Scripts | 13 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, utils (shared lib), emit-review-gate, build-codex-artifacts, resolve-feature (CLI + shell), feature-resolver, readme-catalog | +| Scripts | 17 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, emit-review-gate, emit-plan-gate, build-codex-artifacts, resolve-feature (CLI + shell), classify-docs, detect-scope, migration-audit, security-redact, readme-catalog | ### Mínimo consumo de context @@ -419,7 +419,7 @@ Los skills se cargan bajo demanda. Los skills inactivos no consumen tokens. ## Reglas & Hooks -14 reglas (convenciones siempre cargadas) + 9 hooks (guardrails automatizados). +14 reglas (convenciones siempre cargadas) + 8 hooks (guardrails automatizados). > **Personalización**: Edita `auto-loop-project.md` para sobrescribir el comportamiento de auto-loop por proyecto. Las actualizaciones del plugin no conflictuarán — ver [Rule Override Pattern](docs/features/rule-override-pattern/2-tech-spec.md). diff --git a/README.ja.md b/README.ja.md index 3bd127b..f25631d 100644 --- a/README.ja.md +++ b/README.ja.md @@ -55,7 +55,7 @@ sd0x-dev-flow は reference implementation です。以下の各行は、harness /project-setup ``` -1つのコマンドでフレームワーク、パッケージマネージャー、データベース、エントリポイント、スクリプトを自動検出します。ルールとフックのサブセットをインストールします。完全なプラグインには14ルール + 9フックが含まれます。 +1つのコマンドでフレームワーク、パッケージマネージャー、データベース、エントリポイント、スクリプトを自動検出します。ルールとフックのサブセットをインストールします。完全なプラグインには14ルール + 8フックが含まれます。 `--lite` で CLAUDE.md のみ設定(ルール/フックをスキップ)。 @@ -249,9 +249,9 @@ flowchart TD |----------|-----|-----| | スキル | 96 public (96 bundled) | `/project-setup`, `/codex-review-fast`, `/verify`, `/smart-commit`, `/deep-research` | | エージェント | 15 | strict-reviewer, verify-app, coverage-analyst, architecture-designer | -| フック | 9 | pre-edit-guard, auto-format, review state tracking, stop guard, namespace hint, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | +| フック | 8 | pre-edit-guard, auto-format, review state tracking, stop guard, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | | ルール | 14 | auto-loop, auto-loop-project, codex-invocation, security, testing, git-workflow, self-improvement, context-management | -| スクリプト | 13 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, utils (shared lib), emit-review-gate, build-codex-artifacts, resolve-feature (CLI + shell), feature-resolver, readme-catalog | +| スクリプト | 17 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, emit-review-gate, emit-plan-gate, build-codex-artifacts, resolve-feature (CLI + shell), classify-docs, detect-scope, migration-audit, security-redact, readme-catalog | ### 極小の Context 使用量 @@ -419,7 +419,7 @@ Claude の 200k context window のわずか ~4% — 96% はコードに使えま ## ルール & フック -14 ルール(常時読み込みの規約)+ 9 フック(自動ガードレール)。 +14 ルール(常時読み込みの規約)+ 8 フック(自動ガードレール)。 > **カスタマイズ**:`auto-loop-project.md` を編集してプロジェクトの auto-loop 動作をオーバーライドできます。プラグイン更新と競合しません — [Rule Override Pattern](docs/features/rule-override-pattern/2-tech-spec.md) 参照。 diff --git a/README.ko.md b/README.ko.md index bac336e..3149084 100644 --- a/README.ko.md +++ b/README.ko.md @@ -55,7 +55,7 @@ sd0x-dev-flow는 그 reference implementation입니다. 아래 각 행은 harnes /project-setup ``` -하나의 명령어로 프레임워크, 패키지 매니저, 데이터베이스, 엔트리포인트, 스크립트를 자동 감지합니다. Rules와 Hooks의 서브셋을 설치합니다. 전체 플러그인에는 14개 Rules + 9개 Hooks가 포함됩니다. +하나의 명령어로 프레임워크, 패키지 매니저, 데이터베이스, 엔트리포인트, 스크립트를 자동 감지합니다. Rules와 Hooks의 서브셋을 설치합니다. 전체 플러그인에는 14개 Rules + 8개 Hooks가 포함됩니다. `--lite`로 CLAUDE.md만 설정 (Rules/Hooks 스킵). @@ -249,9 +249,9 @@ flowchart TD |----------|------|------| | Skills | 96 public (96 bundled) | `/project-setup`, `/codex-review-fast`, `/verify`, `/smart-commit`, `/deep-research` | | Agents | 15 | strict-reviewer, verify-app, coverage-analyst, architecture-designer | -| Hooks | 9 | pre-edit-guard, auto-format, review state tracking, stop guard, namespace hint, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | +| Hooks | 8 | pre-edit-guard, auto-format, review state tracking, stop guard, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | | Rules | 14 | auto-loop, auto-loop-project, codex-invocation, security, testing, git-workflow, self-improvement, context-management | -| Scripts | 13 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, utils (shared lib), emit-review-gate, build-codex-artifacts, resolve-feature (CLI + shell), feature-resolver, readme-catalog | +| Scripts | 17 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, emit-review-gate, emit-plan-gate, build-codex-artifacts, resolve-feature (CLI + shell), classify-docs, detect-scope, migration-audit, security-redact, readme-catalog | ### 최소한의 Context 사용량 @@ -419,7 +419,7 @@ Skills는 온디맨드로 로드됩니다. 미사용 Skills는 토큰을 소비 ## 규칙 & Hook -14개 규칙 (상시 로드 컨벤션) + 9개 Hook (자동 가드레일). +14개 규칙 (상시 로드 컨벤션) + 8개 Hook (자동 가드레일). > **커스터마이징**: `auto-loop-project.md`를 편집하여 프로젝트별 auto-loop 동작을 오버라이드할 수 있습니다. 플러그인 업데이트와 충돌하지 않습니다 — [Rule Override Pattern](docs/features/rule-override-pattern/2-tech-spec.md) 참조. diff --git a/README.md b/README.md index 8eedaab..0673e9a 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ **Quality gates that AI can't skip.** A reference implementation of AI Agent Harness Engineering for [Claude Code](https://claude.com/claude-code) — hook-enforced dual review, state-machine gates that survive context compaction, and fail-closed safety where it counts. -96 bundled · 96 public skills · 15 agents — ~4% of Claude's context window +98 bundled · 98 public skills · 15 agents — ~4% of Claude's context window [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![npm](https://img.shields.io/badge/npx-skills%20add-blue)](https://www.npmjs.com/package/skills) @@ -26,7 +26,7 @@ sd0x-dev-flow is a reference implementation. Each row below maps a canonical har | 2 | **Sentinel-driven state machine** | `✅ Ready` / `⛔ Blocked` / `✅ All Pass` gate markers parsed into durable state | [`scripts/emit-review-gate.sh`](scripts/emit-review-gate.sh) (producer) + [`hooks/post-tool-review-state.sh`](hooks/post-tool-review-state.sh) (parser) | | 3 | **Context recovery across compaction** | `[AUTO_LOOP_RESUME]` stdout injection after SessionStart(compact) | [`hooks/post-compact-auto-loop.sh`](hooks/post-compact-auto-loop.sh) | | 4 | **Lifecycle interceptors** | 5 hook event types dispatched to 8 scripts: PreToolUse / PostToolUse / Stop / SessionStart / UserPromptSubmit | [`hooks/`](hooks/) (8 scripts) + [`.claude/settings.json`](.claude/settings.json) | -| 5 | **Capability-based tool gating** | Skill frontmatter `allowed-tools` — e.g., `/ask` has no Edit/Write | 86 of 95 public skills declare `allowed-tools` | +| 5 | **Capability-based tool gating** | Skill frontmatter `allowed-tools` — e.g., `/ask` has no Edit/Write | 89 of 98 public skills declare `allowed-tools` | | 6 | **Defense-in-depth safety** | 5 layers: pre-edit-guard → commit-msg-guard → pre-push-gate → stop-guard → sidecar fail-closed marker | [`scripts/pre-push-gate.sh`](scripts/pre-push-gate.sh) + [`scripts/commit-msg-guard.sh`](scripts/commit-msg-guard.sh) + [`hooks/stop-guard.sh`](hooks/stop-guard.sh) | | 7 | **Generator-evaluator split** | Dual review: Codex (primary) + Claude (secondary) dispatched in parallel on every review cycle | [`rules/codex-invocation.md`](rules/codex-invocation.md) + [`rules/auto-loop.md`](rules/auto-loop.md) (Dual Review Mode) | | 8 | **Incremental progress tracking** | `iteration_history.current_round` + `max_rounds` + convergence plateau detection | [`rules/auto-loop.md`](rules/auto-loop.md) (exit conditions + strategic reset) | @@ -55,7 +55,7 @@ Most harness projects cover 2–4 of these. sd0x-dev-flow covers all 10 — whic /project-setup ``` -One command auto-detects framework, package manager, database, entrypoints, and scripts. Installs a subset of rules and hooks; the full plugin bundles 14 rules + 9 hooks. +One command auto-detects framework, package manager, database, entrypoints, and scripts. Installs a subset of rules and hooks; the full plugin bundles 14 rules + 8 hooks. Use `--lite` to only configure CLAUDE.md (skip rules/hooks). @@ -162,8 +162,8 @@ npx skills add sd0xdev/sd0x-dev-flow | Method | Tools | Coverage | |--------|-------|----------| -| Plugin install | Claude Code | Full (96 bundled skills, hooks, rules, auto-loop) | -| `npx skills add` | Codex CLI, Cursor, Windsurf, Aider | Skills only (96 public skills) | +| Plugin install | Claude Code | Full (98 bundled skills, hooks, rules, auto-loop) | +| `npx skills add` | Codex CLI, Cursor, Windsurf, Aider | Skills only (98 public skills) | | `/codex-setup init` | Codex CLI | AGENTS.md kernel + git hooks | @@ -247,11 +247,11 @@ Real-world scenarios showing which skills to combine and in what order. | Category | Count | Examples | |----------|-------|---------| -| Skills | 96 public (96 bundled) | `/project-setup`, `/codex-review-fast`, `/verify`, `/smart-commit`, `/deep-research` | +| Skills | 98 public (98 bundled) | `/project-setup`, `/codex-review-fast`, `/verify`, `/smart-commit`, `/deep-research` | | Agents | 15 | strict-reviewer, verify-app, coverage-analyst, architecture-designer | -| Hooks | 9 | pre-edit-guard, auto-format, review state tracking, stop guard, namespace hint, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | +| Hooks | 8 | pre-edit-guard, auto-format, review state tracking, stop guard, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | | Rules | 14 | auto-loop, auto-loop-project, codex-invocation, security, testing, git-workflow, self-improvement, context-management | -| Scripts | 13 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, utils (shared lib), emit-review-gate, build-codex-artifacts, resolve-feature (CLI + shell), feature-resolver, readme-catalog | +| Scripts | 17 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, emit-review-gate, emit-plan-gate, build-codex-artifacts, resolve-feature (CLI + shell), classify-docs, detect-scope, migration-audit, security-redact, readme-catalog | ### Minimal Context Footprint @@ -291,7 +291,7 @@ Skills load on-demand. Idle skills cost zero tokens.
-All 96 public skills +All 98 public skills ### Development (33) @@ -331,7 +331,7 @@ Skills load on-demand. Idle skills cost zero tokens. | `/smart-rebase` | Smart partial rebase for squash-merge repositories. | | `/watch-ci` | Monitor GitHub Actions CI runs until completion. | -### Review (Codex MCP) (14) +### Review (Codex MCP) (15) | Skill | Description | Loop Support | |-------|-------------|--------------| @@ -346,6 +346,7 @@ Skills load on-demand. Idle skills cost zero tokens. | `/codex-test-gen` | Generate unit tests for specified functions using Codex MCP | - | | `/codex-test-review` | Review test case sufficiency using Codex MCP, suggest additional edge cases. | `--continue ` | | `/doc-review` | Document review via Codex MCP. | - | +| `/plan-review` | Pre-ExitPlanMode adversarial plan review loop via Codex MCP. | - | | `/security-review` | Security review via Codex MCP. | - | | `/seek-verdict` | Independent second-opinion verification for any finding. | - | | `/test-review` | Test coverage review via Codex MCP. | - | @@ -368,7 +369,7 @@ Skills load on-demand. Idle skills cost zero tokens. | `/test-health` | Holistic test coverage measurement. | | `/verify` | Verification loop — lint -> typecheck -> unit -> integration -> e2e | -### Planning (16) +### Planning (17) | Skill | Description | |-------|-------------| @@ -378,6 +379,7 @@ Skills load on-demand. Idle skills cost zero tokens. | `/deep-research` | Universal multi-source research orchestration. | | `/feasibility-study` | Feasibility analysis from first principles. | | `/fp-brief` | First-principles briefing from technical documents. | +| `/orchestrate` | Agent-driven workflow orchestration (v1 report-only). | | `/post-dev-recap` | Post-development recap wrapper. | | `/project-brief` | Convert a technical spec into a PM/CTO-readable executive summary. | | `/recap-ask` | Interactive Q&A over an existing recap document. | @@ -419,7 +421,7 @@ Skills load on-demand. Idle skills cost zero tokens. ## Rules & Hooks -14 rules (always-loaded conventions) + 9 hooks (automated guardrails). +14 rules (always-loaded conventions) + 8 hooks (automated guardrails). > **Customization**: Edit `auto-loop-project.md` to override auto-loop behavior per project. Plugin updates won't conflict — see [Rule Override Pattern](docs/features/rule-override-pattern/2-tech-spec.md). diff --git a/README.zh-CN.md b/README.zh-CN.md index fd8ef90..3550d31 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -55,7 +55,7 @@ sd0x-dev-flow 是一个 reference implementation。下表的每一行都把一 /project-setup ``` -一个命令自动检测框架、包管理器、数据库、入口文件和脚本命令。安装部分 rules 和 hooks;完整插件包含 14 条 rules + 9 个 hooks。 +一个命令自动检测框架、包管理器、数据库、入口文件和脚本命令。安装部分 rules 和 hooks;完整插件包含 14 条 rules + 8 个 hooks。 使用 `--lite` 仅配置 CLAUDE.md(跳过 rules/hooks)。 @@ -249,9 +249,9 @@ flowchart TD |------|------|------| | Skills | 96 public (96 bundled) | `/project-setup`, `/codex-review-fast`, `/verify`, `/smart-commit`, `/deep-research` | | 代理 | 15 | strict-reviewer, verify-app, coverage-analyst, architecture-designer | -| 钩子 | 9 | pre-edit-guard, auto-format, review state tracking, stop guard, namespace hint, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | +| 钩子 | 8 | pre-edit-guard, auto-format, review state tracking, stop guard, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | | 规则 | 14 | auto-loop, auto-loop-project, codex-invocation, security, testing, git-workflow, self-improvement, context-management | -| 脚本 | 13 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, utils (shared lib), emit-review-gate, build-codex-artifacts, resolve-feature (CLI + shell), feature-resolver, readme-catalog | +| 脚本 | 17 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, emit-review-gate, emit-plan-gate, build-codex-artifacts, resolve-feature (CLI + shell), classify-docs, detect-scope, migration-audit, security-redact, readme-catalog | ### 极小的 Context 占用 @@ -419,7 +419,7 @@ Skills 按需加载。闲置 Skill 不占用任何 Token。 ## 规则与钩子 -14 条规则(常驻加载的规范)+ 9 个钩子(自动化防护栏)。 +14 条规则(常驻加载的规范)+ 8 个钩子(自动化防护栏)。 > **定制化**:编辑 `auto-loop-project.md` 可覆写项目的 auto-loop 行为。插件更新不会冲突 — 详见 [Rule Override Pattern](docs/features/rule-override-pattern/2-tech-spec.md)。 diff --git a/README.zh-TW.md b/README.zh-TW.md index 4276017..6c5897d 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -55,7 +55,7 @@ sd0x-dev-flow 是一個 reference implementation。下表每一列都將一個 /project-setup ``` -一個指令自動偵測 framework、package manager、資料庫、entry point 和 script 指令。安裝部分 rules 與 hooks;完整 plugin 包含 14 條 rules + 9 個 hooks。 +一個指令自動偵測 framework、package manager、資料庫、entry point 和 script 指令。安裝部分 rules 與 hooks;完整 plugin 包含 14 條 rules + 8 個 hooks。 使用 `--lite` 僅設定 CLAUDE.md(跳過 rules/hooks)。 @@ -249,9 +249,9 @@ flowchart TD |------|------|------| | Skills | 96 public (96 bundled) | `/project-setup`, `/codex-review-fast`, `/verify`, `/smart-commit`, `/deep-research` | | Agents | 15 | strict-reviewer, verify-app, coverage-analyst, architecture-designer | -| Hooks | 9 | pre-edit-guard, auto-format, review state tracking, stop guard, namespace hint, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | +| Hooks | 8 | pre-edit-guard, auto-format, review state tracking, stop guard, post-compact-auto-loop, post-skill-auto-loop, user-prompt-review-guard, session-init | | Rules | 14 | auto-loop, auto-loop-project, codex-invocation, security, testing, git-workflow, self-improvement, context-management | -| Scripts | 13 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, utils (shared lib), emit-review-gate, build-codex-artifacts, resolve-feature (CLI + shell), feature-resolver, readme-catalog | +| Scripts | 17 | precommit runner, verify runner, dep audit, namespace hint, skill runner, commit-msg guard, pre-push gate, emit-review-gate, emit-plan-gate, build-codex-artifacts, resolve-feature (CLI + shell), classify-docs, detect-scope, migration-audit, security-redact, readme-catalog | ### 極小的 Context 佔用 @@ -419,7 +419,7 @@ Skills 按需載入。閒置 Skill 不佔用任何 Token。 ## Rules & Hooks -14 條 rules(常駐載入的慣例)+ 9 個 hooks(自動化護欄)。 +14 條 rules(常駐載入的慣例)+ 8 個 hooks(自動化護欄)。 > **客製化**:編輯 `auto-loop-project.md` 可覆寫專案的 auto-loop 行為。Plugin 更新不會衝突 — 詳見 [Rule Override Pattern](docs/features/rule-override-pattern/2-tech-spec.md)。 diff --git a/docs/features/create-pr-ai-sanitization/2-tech-spec.md b/docs/features/create-pr-ai-sanitization/2-tech-spec.md index b550d1e..0d13d88 100644 --- a/docs/features/create-pr-ai-sanitization/2-tech-spec.md +++ b/docs/features/create-pr-ai-sanitization/2-tech-spec.md @@ -13,20 +13,20 @@ | Module | 可復用部分 | | ------ | ---------- | -| `scripts/commit-msg-guard.sh:19-23` | Canonical forbidden patterns(3 組 POSIX ERE) | -| `skills/smart-commit/SKILL.md:290-305` | AI trailer sanitization flow、`--ai-co-author` narrow whitelist | +| `scripts/commit-msg-guard.sh` | Canonical forbidden patterns(3 組 ERE + `\b` 字界) | +| `skills/smart-commit/SKILL.md`(AI Attribution Sanitization 節) | AI trailer sanitization flow、`--ai-co-author` narrow whitelist | | `skills/smart-commit/references/execute-mode.md` | `validate_msg()` 實作、post-commit detection | | `skills/create-pr/SKILL.md` | 現有 PR 建立/更新 workflow(Step 1-7) | ### Canonical Forbidden Patterns -來源:`scripts/commit-msg-guard.sh:19-23`(POSIX ERE, case-insensitive) +來源:`scripts/commit-msg-guard.sh`(ERE, case-insensitive — 僅 `AI` 加 `\b` 字界,避免在 `-i` 下誤中 "maintainer"、"domain" 等一般字詞;`GPT`/`OpenAI` 刻意不加字界,以匹配 `ChatGPT`/`GPT-4`) | Pattern Category | Regex | |-----------------|-------| | Co-Authored-By AI | `Co-Authored-By:.*(Claude\|Anthropic\|GPT\|OpenAI\|Copilot\|noreply@anthropic)` | -| Generated-by tag | `Generated (by\|with).*(Claude\|Claude Code\|AI\|GPT\|Copilot)` | -| Emoji robot tag | `🤖.*(Claude\|AI\|GPT)` | +| Generated-by tag | `Generated (by\|with).*(Claude\|\bAI\b\|GPT\|OpenAI\|Copilot)` | +| Emoji robot tag | `🤖.*(Claude\|\bAI\b\|GPT\|OpenAI)` | ### Files Requiring Changes @@ -94,7 +94,7 @@ sequenceDiagram # 1. Fetch actual published content gh pr view --json title,body --template '{{.title}}{{"\n"}}{{.body}}' -# 2. Scan for forbidden patterns (same 3 POSIX ERE from commit-msg-guard.sh) +# 2. Scan for forbidden patterns (same 3 ERE + \b patterns from commit-msg-guard.sh) # 3. If leak detected — auto-remediate (single attempt): # Title (safe escaping via printf): @@ -151,7 +151,7 @@ gh pr view --json title,body --template '{{.title}}{{"\n"}}{{.body}}' | Dependency | Status | |-----------|--------| -| `scripts/commit-msg-guard.sh` 的 3 組 POSIX ERE pattern | 已存在,穩定 | +| `scripts/commit-msg-guard.sh` 的 3 組 ERE + `\b` pattern | 已存在,穩定 | | `gh` CLI 安裝 | `/create-pr` 已假設存在 | | SKILL.md 現有 Step 1-7 workflow | 穩定,僅插入新步驟 | diff --git a/docs/features/harness-engineering-adoption/2-tech-spec.md b/docs/features/harness-engineering-adoption/2-tech-spec.md index 7898ba9..9c992df 100644 --- a/docs/features/harness-engineering-adoption/2-tech-spec.md +++ b/docs/features/harness-engineering-adoption/2-tech-spec.md @@ -170,7 +170,7 @@ END { print p0+0, p1+0, p2+0, nit+0 } | 問題 | 位置 | Fix | |---|---|---| -| 每次 edit 同步呼叫 `npx prettier` cold-start 200-500ms | `npx prettier` 實際執行點為 `hooks/post-edit-format.sh` 單一 `npx prettier` 呼叫行(實作 PR 以 `grep -n 'npx prettier' hooks/post-edit-format.sh` 取得最新行號) | (a) TMPDIR 快取 prettier 檢測結果 TTL 1h:`$TMPDIR/.claude_prettier_$(pwd_hash)`;(b) prettier 以 `&` 背景執行(state write 不依賴它) | +| 每次 edit 同步做 prettier 偵測(config 探測 + binary 解析)並同步執行 prettier;npx cold-start 已於先前變更移除(`post-edit-format.sh` 現要求已安裝 binary:`node_modules/.bin/prettier` 或 PATH,config-only repo 不再 fallback 到 `npx prettier`) | `hooks/post-edit-format.sh` 的 prettier 偵測/執行區塊(`prettier_bin` 解析 + 呼叫;以 `grep -n 'prettier_bin' hooks/post-edit-format.sh` 定位) | (a) TMPDIR 快取 prettier 偵測結果 TTL 1h:`$TMPDIR/.claude_prettier_$(pwd_hash)`;(b) prettier 以 `&` 背景執行(state write 不依賴它) | **Target**: 平均 hook 執行時間 <50ms(預留 50% margin 到 100ms 官方目標)。 diff --git a/docs/features/plan-review-loop/0-feasibility-study.md b/docs/features/plan-review-loop/0-feasibility-study.md new file mode 100644 index 0000000..02fc046 --- /dev/null +++ b/docs/features/plan-review-loop/0-feasibility-study.md @@ -0,0 +1,234 @@ +# Feasibility Study: Plan-Review-Loop — Pre-ExitPlanMode Codex Review Gate + +> **Doc class**: Lifecycle — Phase 0 feasibility study (per [`rules/docs-numbering.md`](../../../rules/docs-numbering.md)). +> **Created**: 2026-05-15 +> **Canonical requirements**: [`./1-requirements.md`](./1-requirements.md) +> **Codex debate threadId**: `019e298f-3645-7801-b6ff-b60b8d1235e6` + +## 1. Requirement Decomposition + +Consumed from canonical [`1-requirements.md`](./1-requirements.md) §1 + §5; this study does **not** redecompose problem space. Three driver requirements anchor the feasibility evaluation: + +| Anchor | Source FR/NFR | Implication for feasibility | +|--------|---------------|------------------------------| +| Plan must reach user only after review converges | FR-4 | Triggering mechanism must guarantee ordering between review and plan delivery | +| Plan-review state must not pollute existing review state | FR-6 / NFR-7 | State carrier and sentinel naming are first-class design axes | +| Reviewer failure must degrade gracefully | NFR-3 | Architecture must support a deterministic fall-through path that still delivers plan | + +The 11 Open Questions in §9 of the requirements doc cluster around three strongly coupled architectural axes (A/B/C below); the remaining items (default mode, budget config, trail noise, dual-review trigger, `/codex-review-doc` boundary, plateau detection) are policy- or implementation-level and resolved derivatively. A 1:1 disposition mapping is given in §8. + +## 2. Constraint Inventory + +| Type | Constraint | Flexibility | Source | +|------|------------|-------------|--------| +| Hard | `ExitPlanMode` is harness-provided; not in plugin scope | None | `grep -rn ExitPlanMode` → only this feature's lifecycle docs | +| Hard | Existing `PreToolUse` matcher covers only `Edit\|Write` | Extensible, but harness behavior on `ExitPlanMode` matcher is unverified | [`hooks/hooks.json:32-41`](../../../hooks/hooks.json) | +| Hard | `rules/codex-invocation.md` mandates independent research / no feeding conclusions | None | [`rules/codex-invocation.md`](../../../rules/codex-invocation.md) | +| Assumption | Plan mode is read-only w.r.t. `Edit\|Write`; MCP and Skill calls are believed to remain available | Soft — needs smoke test before §7 recommendation is fully de-risked; tracked as OQ-Sx-2 in §8 | Inferred from harness UX; not yet confirmed by executable contract | +| Soft | `.claude_review_state.json` schema currently has `code_review`, `doc_review`, `precommit`, `aggregate_gate`, root `iteration_history` | Schema-extensible with migration | [`hooks/post-tool-review-state.sh:133`](../../../hooks/post-tool-review-state.sh) | +| Soft | MCP sentinel routing already discriminates via `## Document Review` header before `✅ Mergeable` to avoid sentinel collision | Pattern extensible | [`hooks/post-tool-review-state.sh:684`](../../../hooks/post-tool-review-state.sh) | +| Soft | `auto-loop-project.md` exposes only `Max Rounds`, `Git Memory`, `Think Harder` config points | New config point possible but non-standard | [`rules/auto-loop-project.md`](../../../rules/auto-loop-project.md) | + +## 3. Code Research + +Verified primitives that any implementation **must** reuse or coexist with: + +| Primitive | Reuse posture | Reference | +|-----------|---------------|-----------| +| `.claude_review_state.json` (lock-protected, schema-versioned, compact-resume aware) | Extend with namespaced field | [`hooks/post-tool-review-state.sh`](../../../hooks/post-tool-review-state.sh) | +| MCP sentinel routing pattern (`##
+ ✅/⛔ `) | Mirror for plan-specific header | [`hooks/post-tool-review-state.sh:684-690`](../../../hooks/post-tool-review-state.sh) | +| `emit-review-gate.sh` PENDING/READY/BLOCKED contract | Extend or mirror for plan tier | [`scripts/emit-review-gate.sh`](../../../scripts/emit-review-gate.sh) | +| `skills/doc-review/SKILL.md` Codex loop + `threadId` continuation | Adopt loop topology | [`skills/doc-review/SKILL.md:48`](../../../skills/doc-review/SKILL.md) | +| `skills/codex-brainstorm/SKILL.md` Nash equilibrium engine (independent research, attack/defense, termination) | Delegate for deep tier | [`skills/codex-brainstorm/SKILL.md:19`](../../../skills/codex-brainstorm/SKILL.md) | +| `rules/auto-loop.md` convergence decision table (max_rounds, plateau, strategic reset) | Reuse rule-level model; plateau requires fingerprint storage not yet implemented in hook | [`rules/auto-loop.md`](../../../rules/auto-loop.md) | +| `stop-guard.sh` aggregate-gate awareness | Extend to recognize plan gate | [`hooks/stop-guard.sh`](../../../hooks/stop-guard.sh) | + +**Confirmed negatives** (search returned nothing — clean namespace): + +- `grep -rn "plan_review\|REVIEW_PLAN_GATE\|Plan Ready"` in `hooks/` `scripts/` `skills/` → no hits +- `ExitPlanMode` not referenced anywhere outside this feature's own lifecycle docs (`0-feasibility-study.md` + `1-requirements.md`) + +## 4. Solution Exploration + +Three axes; each is a real fork in the architecture. Options derived from §9 of [`1-requirements.md`](./1-requirements.md). + +### Axis A — Triggering mechanism + +| Option | Description | Pros | Cons | +|--------|-------------|------|------| +| A1 | Skill-driven: `/plan-review` self-invoked by Claude in plan mode before `ExitPlanMode` | No `ExitPlanMode` PreToolUse dependency; full orchestration control; degrades cleanly when harness shifts | Trigger relies on rule + skill enforcement, not contract | +| A2 | PreToolUse hook intercepts `ExitPlanMode` | Hard gate at tool boundary | Harness PreToolUse semantics on `ExitPlanMode` unverified; hook cannot orchestrate model-mediated review; depends on harness retry behavior | +| A3 | Hybrid: A1 primary + hook tripwire as audit | Catches Claude self-invocation drift | Tripwire produces telemetry, not enforcement — see §5 debate | + +### Axis B — Review state carrier + +| Option | Description | Pros | Cons | +|--------|-------------|------|------| +| B1 | Extend `.claude_review_state.json` with `plan_review` field + own `iteration_history` sub-tree | Reuses the state-file integration surface (lock / migration / compact-resume); Stop Hook support is a v1 work item, not a free-lunch property | Schema migration cost (additive) | +| B2 | Separate `.claude_plan_state.json` file | Full isolation | Duplicates lock, migration, compact-resume, stop-guard, user-prompt reminder logic | +| B3 | Reuse `doc_review` field + sentinel discriminator | No schema change | Violates NFR-7 isolation; false-positive risk (prior `/codex-review-doc` can satisfy plan gate by accident) | + +### Axis C — Depth tier & relationship with `/codex-brainstorm` + +| Option | Description | Pros | Cons | +|--------|-------------|------|------| +| C1 | Inline 3-tier (quick / standard / deep); deep implements own adversarial debate | All logic in one skill | Duplicates `/codex-brainstorm`; prompt / termination drift | +| C2 | Quick / standard internal; deep delegates to `/codex-brainstorm` | Reuses Nash equilibrium engine; same precedent as `necessity-audit` deep tier | Composition complexity; tier-detection heuristic must be specified | +| C3 | Single fixed tier | Simplest | No escalation path; over-reviews simple plans, under-reviews complex ones | + +## 5. Codex Discussion Record (Nash Equilibrium) + +**threadId**: `019e298f-3645-7801-b6ff-b60b8d1235e6` + +### Round 0 — Independent positions + +| Side | Position | Core argument | +|------|----------|---------------| +| Claude | **A1 + B1 + C2** | PreToolUse on `ExitPlanMode` unverified; B3 collides with `doc_review`; `/codex-brainstorm` already ships Nash engine | +| Codex | **A3 + B1 + C2** | Skill primary, hook as tripwire for audit trail; B1/C2 identical to Claude | + +### Round 1 — Claude attacks A3 + +| # | Attack | Target | +|---|--------|--------| +| 1 | Tripwire produces telemetry only; FR-4 demands review-before-plan, telemetry-after-violation does not satisfy that | Hook value claim | +| 2 | Hook surface expansion (`Edit\|Write` → `Edit\|Write\|ExitPlanMode`) introduces self-suppression race between skill state-write and hook fire | Hook hygiene | +| 3 | "Claude forgot self-invoke" failure mode is symmetric: a Claude that forgot the skill also disregards a non-blocking warning sentinel | Tripwire effectiveness | + +### Codex response — concedes A1 for v1 + +Codex updated position: **A1 for v1**, with A3 promoted only if a future harness smoke test proves all five conditions: + +1. PreToolUse can match `ExitPlanMode` +2. Hook receives sufficient `tool_input` to identify outgoing plan +3. Non-zero exit reliably prevents plan delivery +4. Claude receives the denial in a form that triggers `/plan-review` + retry +5. State write ordering is deterministic before subsequent `ExitPlanMode` call + +Until any one is unprovable from inside the plugin, A3 ships as dead-or-noisy code. + +### Equilibrium + +**A1 + B1 + C2** stands. Neither side can attack further; remaining divergence is a v2 follow-up gated by an empirical harness probe, not a v1 design conflict. + +## 6. Quantitative Comparison + +Scoring against [`@rules/feasibility-study/references/analysis-phases.md`](../../../skills/feasibility-study/references/analysis-phases.md) dimensions (Green / Yellow / Red). + +### Axis A — Triggering mechanism + +| Dimension | A1 (skill) | A2 (hook) | A3 (hybrid) | +|-----------|------------|-----------|--------------| +| Technical feasibility | 🟡 reuses doc-review loop pattern, **but** plan-mode Skill/MCP availability is unverified (OQ-Sx-2 smoke test is a v1 hard precondition; failure → ⛔ architecture revisit) | 🔴 harness contract unverified | 🟡 inherits A2 unverifiability | +| Effort | 🟢 1-2 person-days | 🟡 3-5 person-days (matcher + block semantics) | 🔴 4-6 person-days (both paths + reconciliation) | +| Risk | 🟡 depends on Claude self-invocation + plan-mode Skill/MCP availability (unverified contract) | 🔴 silent failure if harness rejects | 🟡 partial if probe inconclusive | +| Extensibility | 🟢 trivial to upgrade to A3 later | 🟡 hook-only locks out skill-driven UX | 🟢 superset of A1 | +| Maintenance cost | 🟢 single source of orchestration | 🟡 dual paths to keep in sync | 🟡 dual paths | + +### Axis B — State carrier + +| Dimension | B1 (extend) | B2 (separate file) | B3 (reuse doc_review) | +|-----------|-------------|---------------------|------------------------| +| Technical feasibility | 🟢 schema migration pattern exists | 🟢 trivially possible | 🔴 violates FR-6 / NFR-7 | +| Effort | 🟢 0.5 person-day | 🟡 2 person-days (duplicate infra) | 🟢 0.5 person-day | +| Risk | 🟢 additive migration | 🟡 stop-guard / compact-resume must learn new file | 🔴 false passes from prior doc reviews | +| Extensibility | 🟢 same patterns as code/doc | 🟢 isolated | 🔴 collapses on first locale collision | +| Maintenance cost | 🟢 single state file | 🟡 two carriers | 🔴 ambiguous ownership | + +### Axis C — Depth tier + +| Dimension | C1 (inline) | C2 (delegate deep) | C3 (fixed) | +|-----------|-------------|---------------------|-------------| +| Technical feasibility | 🟡 reimplement Nash engine | 🟢 reuses `/codex-brainstorm` | 🟢 no tier logic | +| Effort | 🔴 5+ person-days | 🟢 1-2 person-days | 🟢 1 person-day | +| Risk | 🔴 prompt/termination drift vs brainstorm | 🟢 single source of truth | 🟡 deep plans under-reviewed | +| Extensibility | 🟡 own escalation path | 🟢 inherits brainstorm upgrades | 🔴 no upgrade path | +| Maintenance cost | 🔴 two adversarial engines | 🟢 shared engine | 🟢 minimal | + +## 7. Recommendation + +**Architecture for v1: A1 + B1 + C2**. + +### Rationale (one paragraph) + +FR-4 requires that the user does not see the plan before review converges. A1 is the **best-effort enforceable** option without depending on an unverified harness contract: Claude orchestrates the loop via a `/plan-review` skill before calling `ExitPlanMode`, with `auto-loop.md`-style rules + Stop Hook reinforcement raising self-invocation compliance toward — but not provably equal to — 100 %. **FR-4 honesty note**: under A1, FR-4 is satisfied at the *review-conclusion* layer (plan with unresolved P0/P1 is never delivered, because Claude only calls `ExitPlanMode` after `✅ Plan Ready`) but not at the *tool-boundary* layer (a Claude that forgets the skill could bypass review). The plugin's `auto-loop` + Stop Hook stack is the practical mitigation; the OQ-Sx-1 harness probe (deferred to v2) is the only way to upgrade to tool-boundary enforcement. Hard enforcement (A2 / A3) is therefore explicitly deferred to v2 pending that probe. Extending the existing review state file (B1) reuses lock, migration, and compact-resume infrastructure with a namespaced `plan_review.*` field that cannot collide with `code_review` / `doc_review` / `aggregate_gate`; `stop-guard.sh` does **not** recognize plan sentinels today and must be extended (tracked as a v1 work item, not a free-lunch property). Delegating the deep tier to `/codex-brainstorm` (C2) avoids duplicating an adversarial debate engine that the plugin already ships and trusts. + +### V1 hard preconditions + +Before any v1 implementation begins, the following must clear: + +| Precondition | Outcome required | Source | +|--------------|-------------------|--------| +| OQ-Sx-2 plan-mode MCP/Skill smoke test | Codex MCP + Skill invocations confirmed available inside plan mode | Required for A1 to be implementable at all | +| Stop Hook extension design | `stop-guard.sh` recognizes plan-review sentinels and aggregate state | Required for FR-6 / NFR-7 isolation guarantees | + +OQ-Sx-1 (PreToolUse on ExitPlanMode) remains v2-only; it is not a v1 precondition. + +### Backup option + +If the harness probe (see §8) shows PreToolUse can block `ExitPlanMode`, promote architecture to **A3 + B1 + C2** in v2. State carrier and tier choices are unchanged — only the trigger surface gains a hook tripwire. + +### Concrete v1 design contract + +| Element | Decision | +|---------|----------| +| Trigger | `/plan-review` skill, self-invoked by Claude in plan mode | +| State field | `.claude_review_state.json.plan_review` (namespaced, with own `iteration_history`) | +| Sentinels (plan-only namespace) | `## Plan Review`, `✅ Plan Ready`, `⛔ Plan Blocked`, `⚠️ Plan Needs Human`, `[PLAN_REVIEW_DEGRADED]` | +| Gate emission | New `scripts/emit-plan-gate.sh` (or extend `emit-review-gate.sh` with namespace flag) | +| Tier ladder | quick (1-pass) → standard (loop) → deep (`/codex-brainstorm` delegate) | +| Convergence | Reuse rule-level convergence decision table from `rules/auto-loop.md`, but plan-review owns its own `iteration_history` and does **not** consume code/doc `total_rounds_session` | +| Bypass | Skill flag `--skip-review` + user explicit "skip review" detection | +| Degrade | Reviewer unavailable → mark `plan_review.degraded=true`, emit `[PLAN_REVIEW_DEGRADED]`, proceed to ExitPlanMode | +| Forbidden | Plan-review must never emit bare `✅ Ready` / `✅ Mergeable` / `## Gate: ✅` (collides with code/doc/aggregate routing) | + +## 8. Remaining Open Questions — 1:1 Disposition + +All 11 Open Questions from [`1-requirements.md` §9](./1-requirements.md#9-open-questions) are addressed below. Disposition values: + +- **Resolved** — answered by §7 recommendation +- **Tech-spec** — must be resolved before implementation (gates v1) +- **V2** — explicitly deferred; not blocking v1 +- **Post-merge** — documentation / UX polish iterable after v1 ships + +| # | Requirements OQ (source) | Disposition | How addressed | +|---|--------------------------|-------------|---------------| +| OQ-1 | 觸發機制(skill / hook / hybrid) | **Resolved** | §7 → A1 (skill-driven); A3 v2-gated on OQ-Sx-1 | +| OQ-2 | Plan artifact 可見性 | **Resolved** | §7 → skill mediates plan text (Claude has plan in context); Codex prompt framing detail in OQ-Sx-5 | +| OQ-3 | Default 啟用 vs opt-in | **Tech-spec** | Default proposal: opt-in initially; promote to opt-out after 2-week pilot | +| OQ-4 | Review trail 訊噪比 (UC-3 vs NFR-4) | **Tech-spec** | Default proposal: summary block (rounds / findings count / modified-sections); `--verbose` = round-by-round | +| OQ-5 | Auto-loop 預算共享 / 隔離 | **Resolved** | §7 → independent `plan_review.iteration_history`; does not consume `total_rounds_session` | +| OQ-6 | State scope: per-session vs per-plan | **Tech-spec** | Default proposal: per-plan reset; `plan_review.history[]` keeps last-5 trails | +| OQ-7 | Dual-review trigger (FR-8 always vs deep tier) | **Tech-spec** | Default proposal: deep tier only (dual-review's marginal benefit is low on short plans); revisit if pilot shows false-negative rate elevated | +| OQ-8 | 與 `/codex-brainstorm` 的關係 / 深度光譜 | **Resolved** | §7 → C2 delegated; quick / standard inline, deep delegates | +| OQ-9 | Plateau / fingerprint 偵測可行性 | **V2** | Requires hook-level fingerprint storage (not yet implemented); v1 honors only `max_rounds` + plateau row 3 of rule-level decision table is unreachable until storage lands | +| OQ-10 | Plan-review 預算配置點 | **Tech-spec** | Default proposal: new `## Plan Review Max Rounds` block in `auto-loop-project.md`, default 5 | +| OQ-11 | 與 `/codex-review-doc` 的邊界 | **Resolved** | Boundary axiom: `/plan-review` reviews in-context plan drafts produced inside plan mode; `/codex-review-doc` reviews `.md` files on disk. Different trigger (pre-ExitPlanMode vs ad-hoc), different artifact (in-context text vs filesystem path), different repair model (Claude auto-revise vs human-revise). No reuse of `doc_review` state field | + +**Additional spike items (not in requirements §9, surfaced by feasibility):** + +| # | Question | Disposition | Notes | +|---|----------|-------------|-------| +| OQ-Sx-1 | Harness `PreToolUse` smoke test on `ExitPlanMode` | **V2** | Required to promote A1 → A3; spike ticket; not blocking v1 | +| OQ-Sx-2 | Plan-mode availability of MCP / Skill invocations (Codex MCP, `/plan-review`, `/codex-brainstorm`) | **Tech-spec — hard precondition** | If unavailable, A1 is not implementable; escalate to ⛔ architecture revisit | +| OQ-Sx-3 | `stop-guard.sh` extension to recognize plan-review sentinels and aggregate state | **Tech-spec — hard precondition** | Required for FR-6 / NFR-7 isolation guarantees | +| OQ-Sx-4 | Tier auto-detection heuristic | **Tech-spec** | Default proposal: `standard` always; explicit upgrade for deep | +| OQ-Sx-5 | Codex prompt framing for plan artifact handover | **Tech-spec** | Plan text passed as "candidate artifact to attack" per `rules/codex-invocation.md`; never "Claude's conclusion to confirm" | + +## 9. Verification + +- [x] 5-Why decomposition consumed from canonical `1-requirements.md` +- [x] Constraints inventoried with flexibility ratings +- [x] Existing code researched (grep / Read confirmed primitives + clean namespace) +- [x] Three solution options explored per axis with quantitative scoring +- [x] Codex discussion executed with independent research and adversarial rounds; equilibrium reached at R1 via convergence +- [x] Comparison table + recommendation + backup + open questions + +## 10. References + +- Canonical requirements: [`./1-requirements.md`](./1-requirements.md) +- Sibling lifecycle docs: [`docs/features/dual-reviewer/2-tech-spec.md`](../dual-reviewer/2-tech-spec.md), [`docs/features/codex-review-spec/1-requirements.md`](../codex-review-spec/1-requirements.md) +- Reused skills: [`skills/codex-brainstorm/SKILL.md`](../../../skills/codex-brainstorm/SKILL.md), [`skills/doc-review/SKILL.md`](../../../skills/doc-review/SKILL.md), [`skills/codex-code-review/SKILL.md`](../../../skills/codex-code-review/SKILL.md) +- Loop primitives: [`hooks/post-tool-review-state.sh`](../../../hooks/post-tool-review-state.sh), [`hooks/stop-guard.sh`](../../../hooks/stop-guard.sh), [`scripts/emit-review-gate.sh`](../../../scripts/emit-review-gate.sh) +- Rules: [`rules/auto-loop.md`](../../../rules/auto-loop.md), [`rules/codex-invocation.md`](../../../rules/codex-invocation.md), [`rules/auto-loop-project.md`](../../../rules/auto-loop-project.md), [`rules/docs-numbering.md`](../../../rules/docs-numbering.md) +- Codex debate threadId: `019e298f-3645-7801-b6ff-b60b8d1235e6` diff --git a/docs/features/plan-review-loop/1-requirements.md b/docs/features/plan-review-loop/1-requirements.md new file mode 100644 index 0000000..502ff73 --- /dev/null +++ b/docs/features/plan-review-loop/1-requirements.md @@ -0,0 +1,155 @@ +# Requirements: Plan-Review-Loop — Pre-ExitPlanMode Codex Review Gate + +> **Doc class**: Lifecycle — Phase 1 requirements (per `@rules/docs-numbering.md`). Feature-level problem-space analysis. **Not** a task tracking ticket; for per-task progress tracking see `requests/*.md` (created via `/create-request`). +> **Created**: 2026-05-14 +> **Updated**: 2026-05-14 +> **Tier**: standard + +## 1. Problem Statement + +Claude Code 的 plan mode 由 `ExitPlanMode` 工具終結:Claude 草擬完計畫後直接把 plan 文字交給使用者裁決。整個流程**只有一個視角**——草擬者就是定稿者,沒有獨立挑戰者;使用者既要當決策者又要當品管。當 plan 立基於錯誤假設、過度設計、或漏掉關鍵考量時,缺陷的偵測責任被推給使用者,造成「批准 → 開工 → 才發現方向錯」的反覆。 + +使用者希望在 ExitPlanMode 把 plan 還給使用者**之前**先讓 Codex(或任何具備獨立研究能力的 reviewer)對 plan 做對抗性審查,跑類似 `/codex-review-doc` 的多輪 review loop,討論完、收斂到 ✅ Plan Ready 後才把最終 plan(含精煉/修正後內容)呈現給使用者。本質是把「使用者人工 review plan」這道流程左移成「自動化 review + 收斂」,降低使用者的 cognitive load 並提升 plan 品質。 + +### 5-Why Trace + +1. **表層**:使用者要在 plan mode 流程中插入一個 Codex review loop,討論完才返回 plan +2. **Why**:目前 Claude → ExitPlanMode → User 是單一視角流;plan 任何缺陷只能靠使用者人工發現 +3. **Why**:缺乏獨立挑戰者,plan 的假設、推理、邊界、替代方案皆未經對抗檢驗 +4. **Why**:使用者批准 plan 後若才發現缺陷,已耗費實作成本,回頭成本高 +5. **根因**:plan 階段缺乏「fail-fast adversarial gate」——讓 plan 在進入「使用者裁決」與「實作」前先過獨立 FP 審查,把缺陷壓在最低成本的窗口 + +## 2. Goals / Non-Goals + +| Goals | Non-Goals | +|-------|-----------| +| 在使用者看到 plan 之前,plan 先經過獨立 reviewer 對抗性審查 | 修改 ExitPlanMode 工具本身(須在 harness 工具契約內運作) | +| 多輪 fix → re-review → 直到審查收斂才把 plan 呈現給使用者 | 取代使用者最終裁決——review 完仍由使用者批准 | +| 與既有 review 基礎建設(hooks/skills/rules)相容,不破壞或污染既有狀態 | 自動執行 plan(review 通過 ≠ 開工) | +| 與既有 code/doc/spec review 路徑保持 MECE,依各自職責處理對應審查對象 | review 非 plan-mode 場景的審查對象(lifecycle spec 等屬於既有/未來 spec-review 範疇) | +| 提供使用者逃生口(override / bypass / disable)避免 review 劫持控制權 | 強制所有 plan 都進 review(啟用光譜需可調:opt-in / opt-out / always)| +| 透明化 review 過程——使用者能知道 plan 是否被審、被挑戰了什麼 | 把 review 對話原文夾雜進 plan(須有訊噪比設計) | + +## 3. Stakeholders + +| Stakeholder | Role | Key Concern | +|-------------|------|-------------| +| 使用者(Plan Receiver) | User | 拿到品質更高、已過獨立挑戰的 plan,而不被 review 流程拖慢或淹沒 | +| Claude(Plan Author) | Operator | 在不破壞 ExitPlanMode 契約的前提下,能 orchestrate review loop | +| Codex MCP | Dependent | 收到符合 `@rules/codex-invocation.md` 的 prompt——獨立研究、不被餵養結論 | +| Secondary reviewer(Task agent) | Dependent | 對 plan 提供第二視角(可選 dual-review parity) | +| Auto-loop / Stop Hook | Operator | 須能辨識 plan-review gate sentinel,與 code/doc review 不衝突 | +| Plan-review state carrier(review 狀態的持久化載體)| Dependent | 新增的狀態紀錄不破壞既有 `code_review` / `doc_review` / `aggregate_gate`;具體 schema / 欄位名 / 載體(是否沿用 `.claude_review_state.json`)由 feasibility 決定 | +| 既有 review skills / features / infrastructure(`/codex-review-doc` 與 `/review-spec` 是現有 skill;`dual-reviewer` 與 `codex-review-spec` 目前僅有 feature docs,尚未 ship 為 skill) | Dependent | 不重複職責、不爭奪 sentinel/state namespace、Auto-loop 觸發條件不衝突 | +| Harness 開發者(Claude Code)| External Dependent | 提供 ExitPlanMode 工具契約、PreToolUse hook 能否攔截為未知,影響可行性 | + +## 4. Use Cases + +| # | Actor | Action | Expected Outcome | +|---|-------|--------|-----------------| +| UC-1 | Claude in plan mode | 準備 ExitPlanMode 前自動觸發 plan-review-loop | Codex 對 plan 跑 ≥1 輪 FP 審查;若有 P0/P1 finding,Claude 自動修 plan,再 review,直到 ✅ Plan Ready 才呼叫 ExitPlanMode | +| UC-2 | 使用者 | 想直接看 raw plan(跳過 review) | 透過 disable flag / 環境變數 / explicit 指示,可一次性 bypass 該輪 review loop | +| UC-3 | 使用者 | 想看 review 過程 | 取得 review trail 摘要:每輪 findings 數、最終解決狀態、被修改的 plan 段落 diff | +| UC-4 | Auto-loop | plan review 與既有 code/doc review 並存時 | 兩者 state field 隔離,stop-guard 不誤判;plan review 不消耗 code review max_rounds 預算 | +| UC-5 | Plan author (Claude) | review loop 達 max_rounds 仍未收斂 | 觸發 ⚠️ Need Human:把目前 plan + 殘餘 findings 列表交給使用者裁決,不強制進 ExitPlanMode | +| UC-6 | Codex MCP 不可用 | 連線/授權失敗 | Graceful degradation:跳過 review、附 warning 標籤 ExitPlanMode(plan 仍可送達使用者),不阻塞 plan mode | + +## 5. Functional Requirements + +> **Note**: FRs are stated as **observable capabilities / outcomes**, not implementation mechanisms. Specific mechanisms(hook attachment point、sentinel naming、state schema key、prompt 重用方式)皆推延至 `/feasibility-study` 評估,列入 §9 Open Questions。 + +| ID | Requirement | Priority | Rationale | +|----|-------------|----------|-----------| +| FR-1 | 系統必須能在 plan 被呈現給使用者之前介入並啟動 review;具體攔截點(harness-level hook、skill-level pre-step、或其他)由可行性研究決定 | Must | 無觸發點即無 review;機制屬於 solution-space | +| FR-2 | 系統必須將 plan 內容送獨立 reviewer(具備獨立研究能力,符合 `rules/codex-invocation.md`)做對抗性審查 | Must | 核心功能;reviewer 為什麼引擎與 prompt 設計屬於 solution-space | +| FR-3 | 系統必須支援多輪 fix → re-review → 收斂;有最大輪數上限(達上限後升 ⚠️ Need Human) | Must | 單輪不保證收斂;plateau / fingerprint 等進階偵測屬 Should,視可行性 | +| FR-4 | 系統必須在 review 收斂(無 P0/P1)後才把最終 plan 呈現給使用者。**「Blocked」** 在此 FR 指 reviewer 仍標示 P0/P1(review 結論為 `⛔`);reviewer 不可達 / 失效不視為 blocked,走 NFR-3 graceful degradation 例外路徑(plan 仍可送達,但 output 須附明確 degradation 標記) | Must | 「review 通過才回 plan」核心承諾;本款只規範 review 結論層級,不規範 reviewer infrastructure 可用性 | +| FR-5 | 系統必須提供使用者逃生口:明示要直接看 plan / disable review / dry-run 時,當輪立即跳出 loop 並呈現原 plan | Must | 控制權保留——review 不可劫持流程 | +| FR-6 | 系統必須確保 plan-review 狀態不污染既有 code/doc/aggregate review 狀態(任一邊狀態變化不互相覆蓋) | Must | research findings 指出 sentinel / state collision 為已知風險;隔離方式(獨立 sentinel namespace 或獨立 state field)屬 solution-space | +| FR-7 | 系統必須在跨 reply / 跨 round 場景保留 review 進度,使中斷後能恢復 | Must | 跨 reply 持久化需求;具體欄位/檔案/schema 為 solution-space | +| FR-8 | 系統應支援多 reviewer 並行視角(不僅單一 Codex),以降低單點與 false-negative | Should | 多視角顯著提升審查命中率;具體 reviewer 組合 / 並行模式參考既有 dual-reviewer 設計,但實現方式為 solution-space | +| FR-9 | 系統應在最終 plan output 附 review trail summary(至少輪數、findings 數、主要被修正項),讓使用者可審計 | Should | 透明度——避免「黑箱潤色」破壞信任 | +| FR-10 | Plan-review 的迭代 / 成本預算應與 code/doc review 預算邏輯隔離,避免互耗 | Should | UC-4 隔離需求;具體 max_rounds、token cap 透過配置或新配置點實現屬 solution-space | +| FR-11 | 系統可支援不同審查深度(淺/中/深)以匹配 plan 複雜度;深度模式可升級為 `/codex-brainstorm` 級對抗式辯論 | Could | 簡單 plan 不必跑完整辯論;`/codex-brainstorm` 提供成熟 pattern 可借鑑或鏈接 | +| FR-12 | 系統可依 plan domain(architecture / refactor / bug-fix...)路由到專長 reviewer | Could | 提升命中率,但會增加 prompt 維護負擔,需評估 ROI | +| FR-13 | 修改 ExitPlanMode 工具內部行為 | Won't | Harness 工具契約屬於 Claude Code 上游,本 plugin 只能在外圍 orchestrate | +| FR-14 | review 通過後自動執行 plan(auto-implement) | Won't | 使用者最終裁決權保留;review 通過 ≠ 開工 | +| FR-15 | 對 lifecycle spec(`1-requirements.md`、`2-tech-spec.md` 等)執行 review | Won't | 由既有 `/review-spec` 或未來 `/codex-review-spec` 負責;本範圍只覆蓋 plan-mode 輸出 | + +## 6. Non-Functional Requirements + +| ID | Category | Requirement | Metric | +|----|----------|-------------|--------| +| NFR-1 | Performance | review loop 應在合理輪數內收斂 | 典型 plan p50 ≤3 輪、p95 ≤5 輪收斂(具體 max_rounds 數值在 feasibility 階段決定) | +| NFR-2 | Cost | 系統須有 plan-review 預算上限機制,避免 plan-mode 變成 token sink | 達 max_rounds 或預算上限時不靜默通過,必須升 ⚠️ Need Human;預算配置點(複用既有 `auto-loop-project.md` 還是新增)由 feasibility 決定 | +| NFR-3 | Reliability | Reviewer 失效時須 graceful degradation,不阻塞 plan mode | Reviewer 不可達(連線錯誤、auth 失敗)情境下,plan 仍能在當輪送達使用者,且 plan output 含可被 grep 偵測的明確 degradation 標記(namespaced sentinel `[PLAN_REVIEW_DEGRADED]`,與既有 code/doc review routing 不衝突)| +| NFR-4 | Usability | 預設行為對使用者透明:是否進 review、進幾輪、最後改了什麼 | Plan output 含可辨識的 review summary 區塊(至少輪數、findings count、修正摘要 3 欄);verbose 模式可看 round-by-round | +| NFR-5 | Safety | 使用者可隨時 escape(明示「skip review」、reply override、其他逃生指令) | 從使用者發送 escape 訊號到下一個 plan output 之間最多經過 1 輪 review;不存在「卡死於 loop 無法跳出」的狀態 | +| NFR-6 | Maintainability | 與既有 review 基礎建設共用核心模式(loop convergence、sentinel emission、state persistence),盡量擴充而非複製 | 對既有介面的修改幅度最小化;可重用模式 vs 必要修改的取捨在 feasibility 階段量化 | +| NFR-7 | Boundary | plan-review state 與 code/doc/aggregate review state 不互相覆寫 | 自動化測試證明:plan-review 觸發後,既有 code_review / doc_review / aggregate_gate 欄位值不變;反之亦然 | +| NFR-8 | Security | review 過程不外流 secrets / tokens / API keys 到 reviewer 上下文 | plan 內容含 **regex-valid** dummy secret(須真正命中 [`scripts/security-redact.js`](../../../scripts/security-redact.js) 的高敏 pattern:`sk-` + ≥20 字元如 `sk-abcdefghijklmnopqrstUVWX`、`ghp_` + 恰 36 字元如 `ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`、PEM header)時,送 reviewer 前的 payload grep 結果不含任何高敏 pattern;遵循 [`rules/security.md`](../../../rules/security.md) 的「Logging private keys/passwords/tokens」禁令,redact 實作可重用 `security-redact.js` 或同等 primitive | + +## 7. Constraints & Assumptions + +| Type | Description | Source | +|------|-------------|--------| +| Constraint | ExitPlanMode 是 harness-provided tool,本 plugin 無法修改其行為 | 本 repo grep 找不到 ExitPlanMode 程式碼;屬 Claude Code harness 範疇 | +| Constraint | 本 repo `hooks/hooks.json:32-41` PreToolUse matcher 目前僅覆蓋 `Edit\|Write`;要攔截其他 tool 需擴充,且 harness 是否支援 PreToolUse 對 ExitPlanMode 為未知 | [`hooks/hooks.json:32-41`](../../../hooks/hooks.json) + harness 文件缺口 | +| Constraint | review 必須遵守 `rules/codex-invocation.md` 全文——獨立研究、不餵養結論、prompt 來自 reference template | [`rules/codex-invocation.md:1`](../../../rules/codex-invocation.md)(全文)| +| Constraint | sentinel / state field 不可污染既有 review state;既有可辨識 sentinel 與 state 欄位列於 `rules/auto-loop.md` Standard Gate Sentinels 與 [`hooks/post-tool-review-state.sh`](../../../hooks/post-tool-review-state.sh) | [`rules/auto-loop.md`](../../../rules/auto-loop.md) Standard Gate Sentinels 章節 | +| Constraint | Plan review 必須非 destructive:不刪除 plan 段落或改變語意,只能 surface findings 讓 Claude 重寫 | 衍生自 NFR-4 透明度 + UC-3 review trail | +| Assumption | Claude 在 plan mode 能取得自己即將傳給 ExitPlanMode 的 plan 文字 | 推論:Claude 是 plan author;plan 內容本來就在其 working context | +| Assumption | 獨立 reviewer(Codex MCP 為主要候選)在 plan mode 仍可被呼叫,不被 plan-mode 的 read-only constraint 排除 | 推論:Codex 屬 MCP 諮詢工具,plan-mode 限制針對 Edit/Write | +| Assumption | 使用者多數情境希望 plan 經過 review;少數情境(探索、demo、教學)需要 raw plan | 來自 user 原始陳述「希望...透過 codex review loop」——預設啟用為主要訴求 | +| Assumption | Plan review 平均 1-3 輪內收斂(plan 為高層敘述,issues 比 code review 少) | 經驗推論;確切數值待 feasibility / pilot 驗證 | +| Assumption | 使用者願意接受 plan 被 review 修改後再呈現,但要求透明度(FR-9) | 「討論完後才返回使用者 plan」隱含接受修改後版本 | + +## 8. Acceptance Signals + +Acceptance signals 列述使用者可觀察的外部行為,刻意避免綁定特定 state schema、sentinel 字串、或 hook 實作方式(那些屬 feasibility / design 階段決定)。 + +- **Signal 1 (FR-1, FR-4)**:在 plan mode 工作階段中,使用者實際看到的 plan output 之前,系統 log / output 中可觀察到 review 已執行過至少一次的證據(具體呈現方式由 feasibility 決定) +- **Signal 2 (FR-3, FR-4)**:給定一個含已知缺陷的 plan,系統觀察到 reviewer 標示 P0/P1,Claude 修改 plan 後再 review,直到 reviewer 不再標示 P0/P1,才把 plan 呈現給使用者;若 review 持續未收斂達上限,系統升 `⚠️ Need Human` 並把殘餘 findings 一併列出(不靜默通過) +- **Signal 3 (FR-5, NFR-5)**:使用者在 review loop 中明示「skip review」/「直接 show plan」/ 同義指令,在不超過 1 輪 review 後系統跳出 loop 並呈現 plan(review 已啟動者可顯示部分 trail,但不繼續迭代) +- **Signal 4 (FR-6, FR-7, NFR-7)**:對同一 session 並行觸發既有 code-review 與 plan-review 的測試情境下,兩者狀態互不覆蓋(自動化測試可驗證) +- **Signal 5 (FR-9, NFR-4)**:使用者最終看到的 plan output 包含可辨識的 review summary 區塊,至少含輪數、findings 數、被修正項摘要 3 欄 +- **Signal 6 (NFR-3)**:模擬 reviewer 不可用情境(offline / 401 / timeout),plan-review-loop 不卡死;plan 仍能在當輪交付使用者,且 output 含可被 grep 偵測的明確 degradation 標記 +- **Signal 7 (NFR-1, NFR-2)**:review 達 max_rounds 後系統明確輸出 `⚠️ Need Human` + 殘餘 findings 列表,並把目前狀態的 plan 交給使用者裁決 +- **Signal 8 (NFR-8)**:plan 內容含 **regex-valid** dummy secret(須真正命中 `security-redact.js` 高敏 pattern,如 `sk-abcdefghijklmnopqrstUVWX`、`ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`、PEM header;**不可**用 `sk-test-xxx`/`ghp_xxx` 這類長度不足、不會命中 regex 的假樣本,否則測試會假性通過而未實際驗證 redaction)時,送 reviewer 前的 payload grep 結果不含高敏 pattern;reviewer log(若可取)亦不含原始 secret + +## 9. Open Questions + +- [ ] **Solution concern — 觸發機制**:plan-review-loop 應該是 (a) skill-driven(Claude 在 plan mode 自覺呼叫 plan-review-loop skill)、(b) PreToolUse hook 攔截 ExitPlanMode、還是 (c) 兩者並存(hook 兜底 + skill 為主)?harness PreToolUse 對 ExitPlanMode 是否可用為未知 — 建議執行 `/feasibility-study` +- [ ] **Solution concern — Plan artifact 可見性**:Claude 在準備呼叫 ExitPlanMode 時,plan 內容存在哪?(in-context message draft?ExitPlanMode 的 `plan` 參數?)如果 plan 只在工具呼叫瞬間才具象化,review 須在 Claude 端 orchestrate 而非 hook 端攔截 — 建議 `/feasibility-study` +- [ ] **Solution concern — 預設啟用 vs opt-in**:plan-review-loop 預設 always-on、opt-out、還是 opt-in?影響 NFR-2 cost 與 UC-2 user override 設計 — 建議 stakeholder 討論 +- [ ] **Trade-off — review trail 訊噪比**:UC-3 要看 review 過程 vs NFR-4 透明度但不淹沒 plan,平衡點在哪?默認 summary、verbose 可選?需 UX 設計 +- [ ] **Boundary — auto-loop 預算共享**:plan_review 是否共用 `total_rounds_session` 還是獨立計?FR-10 傾向獨立,但若使用者一個 session 內進多次 plan mode,總成本上限如何控制? +- [ ] **State scope — per-session vs per-plan**:`plan_review` 欄位是覆蓋還是累積?每次新 plan mode 重置,還是保留歷史 plan 的 review trace? +- [ ] **Dual-review trigger**:FR-8 應在所有 tier 預設啟用 dual,還是只 deep tier?dual-review 對短 plan 文字的邊際效益可能較小 +- [ ] **與 `/codex-brainstorm` 的關係 / 深度光譜**:plan-review-loop 的 tier 譜系該如何切?quick = 單輪 Codex 文件審查、standard = 多輪 fix→re-review、deep = `/codex-brainstorm` 對抗式辯論?兩者皆有 Codex 多輪 loop,但 `/codex-brainstorm` 強調 Nash equilibrium 收斂條件、attack/defense 對稱、threadId 追溯 — plan-review 是否該完全內嵌或僅作為 escalation 路徑?需 `/feasibility-study` 評估深度與成本比 +- [ ] **Solution concern — Plateau / fingerprint 偵測可行性**:`rules/auto-loop.md` 定義 plateau detection(fingerprint overlap ≥50% 連 3 輪),但 `hooks/post-tool-review-state.sh` 目前只記錄 finding counts,未儲存 fingerprints。plan-review-loop 是否要在收斂偵測上同樣支援 plateau?若是,須先擴充 state schema — 屬 solution-space,建議列入 `/feasibility-study` +- [ ] **Solution concern — Plan-review 預算配置點**:NFR-2 要求 plan-review 須有預算上限,但目前 `rules/auto-loop-project.md` 僅支援 `Max Rounds`、`Git Memory`、`Think Harder` 三個配置點,無 token / cost cap 配置介面。是否新增獨立的 `Plan Review Budget` 配置欄位,還是重用 `Max Rounds` 但獨立 namespace?需 feasibility 評估 +- [ ] **與 `/codex-review-doc` 的邊界**:Goals 區塊主張「與既有 review 路徑保持 MECE」,但本 Open Question 列出的「是否為 `/codex-review-doc` 變體」尚未拍板——兩者皆審查文字內容,差別在於 review 對象(plan 文字 vs lifecycle .md 檔)、觸發時機(pre-ExitPlanMode vs ad-hoc)、修正模型(Claude 自動 revise vs 人工 revise)。需在 `/feasibility-study` 階段給出明確 boundary 公理 + +## 10. References + +- Related lifecycle docs (problem-space sibling features): + - [`docs/features/dual-reviewer/2-tech-spec.md`](../dual-reviewer/2-tech-spec.md) — 並行 Codex + Task 雙視角審查架構(feature spec,尚未 ship 為獨立 skill;可借鑑模式) + - [`docs/features/codex-review-spec/1-requirements.md`](../codex-review-spec/1-requirements.md) — Codex FP spec 審查(feature requirements,尚未 ship 為 skill;boundary 對照) +- Request-level implementation history: + - [`docs/features/review-state-tracking/requests/`](../review-state-tracking/requests/) — `.claude_review_state.json` schema 演進的 request 紀錄(非 lifecycle,僅供溯源) +- Related skills (currently shipped — reusable patterns): + - [`skills/codex-brainstorm/SKILL.md`](../../../skills/codex-brainstorm/SKILL.md) — 對抗式 Nash equilibrium 辯論(Phase 1-5 workflow、termination conditions、attack/defense templates);可作為 deep-tier 升級路徑或 prompt-pattern 來源 + - [`skills/codex-code-review/SKILL.md`](../../../skills/codex-code-review/SKILL.md) — review loop convergence + `--continue` threadId 延續 + - [`skills/doc-review/references/review-loop-doc.md`](../../../skills/doc-review/references/review-loop-doc.md) — 多輪文件審查 loop template + - [`skills/review-spec/SKILL.md`](../../../skills/review-spec/SKILL.md) — 現有 spec 審查 skill(FR-15 排除範圍的對應 owner) +- Hook / loop primitives: + - `hooks/post-tool-review-state.sh` — sentinel parser + iteration_history schema + - `hooks/stop-guard.sh` — gate enforcement + dual mode + - `scripts/emit-review-gate.sh` — gate emission contract +- Rules: + - [`rules/auto-loop.md`](../../../rules/auto-loop.md) — rule-level convergence model(decision table、max_rounds、plateau detection 與 strategic reset 的規格描述;plateau 之 fingerprint 偵測尚未在 hook 端實作,須 feasibility 評估補上) + - `rules/codex-invocation.md` — Codex prompt 規範 + - `rules/fix-all-issues.md` — analysis-only mode(plan-review 內在屬性) +- Research: + - Phase 2 Explore findings(2026-05-14): 確認 ExitPlanMode 不在本 repo(屬 harness)、`hooks/hooks.json` PreToolUse 僅 Edit\|Write、sentinel/state collision 風險、`auto-loop-project.md` 已支援 max_rounds 配置 diff --git a/docs/features/plan-review-loop/2-tech-spec.md b/docs/features/plan-review-loop/2-tech-spec.md new file mode 100644 index 0000000..42a7f7f --- /dev/null +++ b/docs/features/plan-review-loop/2-tech-spec.md @@ -0,0 +1,490 @@ +# Technical Spec: Plan-Review-Loop — Pre-ExitPlanMode Codex Review Gate + +> **Doc class**: Lifecycle — Phase 2 technical spec (per [`rules/docs-numbering.md`](../../../rules/docs-numbering.md)). +> **Created**: 2026-05-18 +> **Canonical inputs**: [`./1-requirements.md`](./1-requirements.md) (Phase 1), [`./0-feasibility-study.md`](./0-feasibility-study.md) (Phase 0) +> **Architecture decision**: v1 = **A1 + B1 + C2** (feasibility Nash equilibrium, threadId `019e298f-3645-7801-b6ff-b60b8d1235e6`) + +## 1. Requirement Summary + +- **Problem**: Claude Code 的 plan mode 由 `ExitPlanMode` 終結,草擬者即定稿者,無獨立挑戰者;plan 缺陷的偵測責任全推給使用者,造成「批准 → 開工 → 才發現方向錯」的高成本反覆([`1-requirements.md` §1](./1-requirements.md))。 +- **Goals**: 在 plan 呈現給使用者**之前**插入一個 Codex 對抗式 review loop,多輪 fix → re-review 收斂後才呼叫 `ExitPlanMode`;與既有 code/doc/aggregate review 狀態與 sentinel **完全隔離**;reviewer 失效時 graceful degrade 不阻塞 plan mode;保留使用者逃生口。 +- **Scope**: + +| In Scope (v1) | Out of Scope | +|---------------|--------------| +| 新增 `/plan-review` skill(A1 skill-driven trigger) | 修改 `ExitPlanMode` 工具本身(harness 上游,FR-13 Won't) | +| `.claude_review_state.json` 加 namespaced `plan_review` 欄位(B1,schema v2→v3 additive migration) | PreToolUse hook 攔截 `ExitPlanMode`(A3,v2-gated on OQ-Sx-1 harness probe) | +| plan-only sentinel namespace + `scripts/emit-plan-gate.sh` | 對 lifecycle spec 執行 review(FR-15 → `/review-spec` owns) | +| 3-tier ladder:quick / standard / deep(deep 委派 `/codex-brainstorm`,C2) | review 通過後自動執行 plan(FR-14 Won't) | +| `stop-guard.sh` 擴充辨識 plan sentinel 並維持隔離(OQ-Sx-3 hard precondition) | plateau / fingerprint 偵測(OQ-9 → V2,需 hook 端 fingerprint 儲存) | +| Bypass(`--skip-review` + 使用者明示偵測)、graceful degradation、review trail summary | | + +## 2. Existing Code Analysis + +### 2.1 Related modules (verified) + +| Module | Role for plan-review | Reference | +|--------|---------------------|-----------| +| `hooks/post-tool-review-state.sh` | State carrier + MCP sentinel router;pre-v1 既有 state 為 `schema_version: 2`(as-built:`init_state_file()` 直接產出 v3 含 `plan_review`;既有 v2 檔由 migration 升級) | [`init_state_file()`](../../../hooks/post-tool-review-state.sh)(state init)、[MCP routing Priority 1.5 plan branch](../../../hooks/post-tool-review-state.sh)(`## Plan Review` discriminator;行號隨版本漂移,以符號名為準) | +| `hooks/stop-guard.sh` | Stop gate enforcement;`grep -E '✅ Mergeable\|✅ Ready'` 視為 REVIEW_PASSED | transcript-fallback 模式的 `REVIEW_PASSED` / `REVIEW_BLOCKED` / `LAST_REVIEW` 變數([`hooks/stop-guard.sh`](../../../hooks/stop-guard.sh);引用穩定符號名而非行號以免漂移) | +| `scripts/emit-review-gate.sh` | gate emission contract(`PENDING\|READY\|BLOCKED` → `REVIEW_GATE=$GATE`) | [`scripts/emit-review-gate.sh`](../../../scripts/emit-review-gate.sh) | +| `skills/doc-review/SKILL.md` | Codex loop topology:first `mcp__codex__codex`(存 threadId)→ `mcp__codex__codex-reply` loop;`sandbox: read-only`, `approval-policy: never` | [`skills/doc-review/SKILL.md:48-58`](../../../skills/doc-review/SKILL.md) | +| `skills/codex-brainstorm/SKILL.md` | Nash equilibrium engine(deep tier 委派目標) | [`skills/codex-brainstorm/SKILL.md`](../../../skills/codex-brainstorm/SKILL.md) | +| `rules/auto-loop.md` | Convergence decision table(max_rounds / plateau / strategic reset),rule-level model 可重用 | [`rules/auto-loop.md`](../../../rules/auto-loop.md) Exit Conditions | +| `hooks/hooks.json` | PreToolUse 僅 `Edit\|Write`;A1 **不需**改 hooks.json | [`hooks/hooks.json:32-41`](../../../hooks/hooks.json) | +| `scripts/security-redact.js` | secret redaction primitive(NFR-8 送 reviewer 前 sanitize) | [`scripts/security-redact.js`](../../../scripts/security-redact.js) | + +### 2.2 Reusable components + +| Component | Reuse posture | +|-----------|---------------| +| `.claude_review_state.json` lock / migration / compact-resume infra | **Extend**:加 `plan_review` 子樹,沿用既有 lock + atomic write | +| MCP sentinel routing `##
+ ✅/⛔ ` pattern | **Mirror**:新增 `## Plan Review` discriminator branch | +| doc-review `mcp__codex__codex` → `codex-reply` loop | **Adopt topology**:plan-review standard tier 同構 | +| `rules/auto-loop.md` convergence decision table | **Reuse rule-level model**:plan-review 擁有獨立 `iteration_history`,不消耗 code/doc `total_rounds_session` | +| `/codex-brainstorm` Nash engine | **Delegate**:deep tier 直接呼叫,不複製對抗引擎 | + +### 2.3 Files requiring changes + +| File | Change type | Detail | +|------|-------------|--------| +| `skills/plan-review/SKILL.md` | **New** | 核心 orchestration skill(A1) | +| `skills/plan-review/references/codex-prompt-plan.md` | **New** | Codex prompt template(OQ-Sx-5:plan 作為 "candidate artifact to attack") | +| `skills/plan-review/references/review-loop-plan.md` | **New** | re-review 續輪 template | +| `.claude/skills/plan-review/...`(經 `.claude/skills -> ../skills` dir symlink 自動可見)+ `docs/skill-catalog.yml` + 3 份 CLAUDE quick-ref row | **New/Modify** | 使用者可呼叫入口(v3 起無 `commands/` thin entry,skill 直接註冊) | +| `scripts/emit-plan-gate.sh` | **New** | plan gate emission contract | +| `hooks/post-tool-review-state.sh` | **Modify** | (a) `init_state_file()` 加 `plan_review`、`schema_version` 2→3;(b) schema migration 分支;(c) MCP routing 加 Priority 1.5 plan branch | +| `hooks/stop-guard.sh` | **Modify** | plan sentinel 隔離(`✅ Plan Ready` 不得滿足 code/doc gate;plan pending 獨立追蹤)— OQ-Sx-3 | +| `rules/auto-loop-project.md` | **Modify** | 新增 `## Plan Review Max Rounds` 配置區塊(OQ-10,default 5) | +| `rules/auto-loop.md` | **Modify** | Standard Gate Sentinels 表加 plan namespace 列 | +| `test/skills/plan-review.test.js` | **New** | skill 結構/契約測試(靜態斷言;行為驗證見 §6) | +| `test/scripts/emit-plan-gate.test.js` | **New** | gate emission 測試 | +| `test/hooks/post-tool-review-state.test.js` | **Modify** | 加 plan sentinel routing + schema migration fixtures | +| `test/hooks/stop-guard.test.js` | **Modify** | 加 plan isolation fixtures | + +## 3. Technical Solution + +### 3.1 Architecture Design + +```mermaid +sequenceDiagram + participant U as User + participant C as Claude (plan mode) + participant PR as /plan-review skill + participant RD as security-redact + participant CX as Codex MCP + participant SA as Secondary (Task agent) + participant BR as /codex-brainstorm + participant ST as .claude_review_state.json (plan_review.*) + participant EX as ExitPlanMode (harness) + + C->>C: 草擬 plan(in-context) + C->>PR: opt-in 啟用 → 呼叫 /plan-review(前置於 ExitPlanMode) + PR->>PR: Step1 tier 判定 (quick/standard/deep) + PR->>RD: Step2 scanHighConfidence(plan) + alt high-confidence secret 命中(fail-closed,終態) + RD-->>PR: {name,fingerprint} + PR->>ST: degraded=true; status_reason=secret-detected + PR->>C: [PLAN_REVIEW_DEGRADED](plan 不外送 reviewer) + C->>EX: ExitPlanMode(plan + degradation 標記) + EX->>U: 呈現 plan(未經 review,degradation 標記) + else 無 high → maskMediumConfidence(唯一進入 reviewer 的路徑) + RD-->>PR: masked plan + alt tier = quick + PR->>CX: 單輪 review(plan = candidate artifact) + else tier = standard + par dual dispatch + PR->>CX: Codex review loop(存 threadId) + and + PR->>SA: Secondary 視角(並行) + end + else tier = deep + PR->>BR: 委派 Nash equilibrium 辯論 + end + CX-->>PR: findings + ## Plan Review sentinel + PR->>ST: 寫 plan_review.iteration_history(獨立預算) + alt 有 P0/P1 (⛔ Plan Blocked) + PR->>C: surface findings(不改寫 plan) + C->>C: revise plan + C->>PR: re-review (codex-reply --continue) + Note over PR: loop 直到 ✅ Plan Ready 或 max_rounds + else 收斂 (✅ Plan Ready) + PR->>C: 附 review trail summary + C->>EX: 呼叫 ExitPlanMode(精煉後 plan) + EX->>U: 呈現最終 plan + else max_rounds 未收斂 + PR->>C: ⚠️ Plan Needs Human + 殘餘 findings + C->>U: 交付當前 plan + findings(不靜默通過) + else reviewer 不可達 + PR->>ST: plan_review.degraded=true; status_reason=reviewer-unavailable + PR->>C: [PLAN_REVIEW_DEGRADED] + C->>EX: ExitPlanMode(plan + degradation 標記) + end + end + Note over U,PR: 任一時點使用者明示「skip review」/ --skip-review → ≤1 輪內跳出 +``` + +### 3.2 Data Model + +`.claude_review_state.json` schema v2 → **v3**(additive)。新增 `plan_review` 頂層欄位,與 `code_review` / `doc_review` / `aggregate_gate` 同層但**互不覆寫**(NFR-7)。 + +> **以下 JSON 為部分節錄(partial excerpt),僅示 `plan_review` 新增子樹**。As-built:[`init_state_file()`](../../../hooks/post-tool-review-state.sh) 直接產出 **v3**(含 `plan_review`);**pre-v1 既有 state 檔為 v2**,由 migration 升級。v2/v3 頂層欄位(migration 必須完整保留**值**者):`session_id`、`updated_at`、`review_mode`、`has_code_change`、`has_doc_change`、`code_review`、`doc_review`、**`precommit`**、`aggregate_gate`、root `iteration_history`——不只 code/doc/aggregate/root iteration;`schema_version` 為唯一刻意改值的欄位(2→3,見 migration 一節)。 + +```jsonc +// partial excerpt — only the additive plan_review subtree shown +{ + "schema_version": 3, // bumped from 2 + // ...all existing v2 top-level fields preserved verbatim + // (session_id, updated_at, review_mode, has_code_change, + // has_doc_change, code_review, doc_review, precommit, + // aggregate_gate, iteration_history) ... + "plan_review": { + "executed": false, + "passed": false, + "degraded": false, + "skipped": false, + "status_reason": null, + "tier": null, + "last_run": "", + "iteration_history": { + "current_round": 0, + "max_rounds": 5, + "findings_by_round": [], + "total_rounds_session": 0 + }, + "history": [] + } +} +``` + +| Field | Semantics | OQ resolved | +|-------|-----------|-------------| +| `plan_review.iteration_history` | **獨立** loop 預算;不讀寫 root `iteration_history` / `total_rounds_session` | OQ-5 / FR-10 | +| `plan_review.iteration_history.max_rounds` | default `5`;可由 `auto-loop-project.md ## Plan Review Max Rounds` 覆寫 | OQ-10 / NFR-1 | +| `plan_review.history[]` | per-plan reset;保留最近 **5** 筆 trail(schema 見下),超出 FIFO 汰除 | OQ-6 | +| `plan_review.degraded` | reviewer 不可達 **或** 偵測到 high-confidence secret 時 `true`;output 伴隨 `[PLAN_REVIEW_DEGRADED]` | NFR-3 / NFR-8 | +| `plan_review.skipped` | 使用者明示 bypass 時 `true`(**與 `degraded` 區分**:使用者意圖 ≠ reliability 失效) | FR-5 / NFR-5 | +| `plan_review.status_reason` | `null \| "user-skip" \| "reviewer-unavailable" \| "secret-detected" \| "needs-human"`(最後者由 `update_plan_state()` 於 `NEEDS_HUMAN` 寫入) | NFR-3/5/8 | +| `plan_review.tier` | `"quick"\|"standard"\|"deep"` | OQ-Sx-4 | +| 無 `strategic_reset_fired` | plan-review v1 不啟用 strategic reset(plateau 屬 V2) | OQ-9 → V2 | + +`plan_review.history[]` 元素 schema(範例;v1 實作僅寫入以下 5 欄——`hooks/post-tool-review-state.sh update_plan_state()`): + +```json +{ "ts": "2026-05-18T10:00:00Z", "tier": "standard", "rounds": 3, + "findings_total": 5, "outcome": "ready" } +``` + +**Migration**(`post-tool-review-state.sh`,`init_state_file()` 之後新增分支;jq 以 `. +` 合併保留未知欄位): + +``` +讀 STATE_FILE.schema_version + == 3 → no-op + == 2 (或缺) → jq '. + {plan_review: $default} | .schema_version = 3'(atomic write,鎖保護) + 其他 → 保守不動,stderr 結構化告警 +``` + +Migration 為**純加法**:`. +` 合併確保**所有**既有頂層欄位(含 `session_id`/`updated_at`/`review_mode`/`has_*`/`precommit`)保留。**唯一刻意變更為 `schema_version` 2→3**;回歸測試斷言 migration 前後**除 `schema_version` 外**全部 v2 頂層欄位語意等價(`schema_version` 單獨斷言由 2 變 3)。 + +### 3.3 API Design + +#### T1 — Plan-only sentinel namespace(forbidden collision 表) + +| Sentinel | 意義 | Parsed by | +|----------|------|-----------| +| `## Plan Review` | section discriminator(**必出現**,路由前綴) | hook routing | +| `✅ Plan Ready` | 無 P0/P1,收斂 | hook + behavior | +| `⛔ Plan Blocked` | 有 P0/P1,續 loop | hook + behavior | +| `⚠️ Plan Needs Human` | max_rounds 未收斂 / hard precondition 未過 | behavior-only | +| `[PLAN_REVIEW_DEGRADED]` | reviewer 不可達 **或** high-confidence secret 偵測 → fail-closed,不送 reviewer(reason 區分) | hook + behavior | +| `[PLAN_REVIEW_SKIPPED]` | 使用者明示 bypass(≠ degrade;使用者意圖非 reliability 失效) | hook + behavior | + +> **Forbidden(硬約束)**:plan-review 路徑**永不**輸出裸 `✅ Ready` / `✅ Mergeable` / `## Gate: ✅` / 裸 `⛔ Block*`(會被 code/doc/aggregate routing 誤收)。Collision 分析(**已實測**:`printf '✅ Plan Ready' | grep -qE '✅ Ready'` → **SAFE**):`✅ Plan Ready` 不含子字串 `✅ Ready`(`✅` 與 `Ready` 間為 `" Plan "`),故 `✅` 方向安全。**真正風險在 `⛔` 方向**:`stop-guard.sh` 的 `REVIEW_BLOCKED` / `LAST_REVIEW` grep(`⛔.*Block`)會匹配 `⛔ Plan Blocked`——故 `## Plan Review` discriminator + routing 順序(T2)+ stop-guard 過濾(T4)三層防護缺一不可。 + +#### T2 — MCP sentinel routing 擴充(`post-tool-review-state.sh` MCP routing Priority 1.5 分支) + +於既有 doc(Priority 1) 與 code(Priority 2) 之間插入 **Priority 1.5 plan branch**: + +``` +if '## Document Review' && '✅ Mergeable' → doc_review pass # P1(不動) +elif '## Document Review' && '⛔ Needs revision' → doc_review fail # P1(不動) +elif '## Plan Review' && grep -F '[PLAN_REVIEW_DEGRADED]' → plan_review degraded # P1.5(token 先判) +elif '## Plan Review' && grep -F '[PLAN_REVIEW_SKIPPED]' → plan_review skipped # P1.5(token 先判) +elif '## Plan Review' && '⛔ Plan Blocked' → plan_review fail # P1.5(BLOCKED 先於 READY) +elif '## Plan Review' && '✅ Plan Ready' → plan_review pass # P1.5 +elif '✅ Ready' → code_review pass # P2(不動) +elif '⛔ Blocked' → code_review fail # P2(不動) +``` + +> **⚠️ Literal-match 硬約束**:`[PLAN_REVIEW_DEGRADED]` / `[PLAN_REVIEW_SKIPPED]` 含 `[` `]`,在 `grep -E`(ERE)中 `[...]` 是 **character class**(會匹配 `P/L/A/N/_/...` 任一字元),**絕不可**用 `grep -qE '[PLAN_REVIEW_DEGRADED]'`。**必須** `grep -qF '[PLAN_REVIEW_DEGRADED]'`(fixed string)或 escaped ERE `\[PLAN_REVIEW_DEGRADED\]`。Routing regression 必含:`## Plan Review` + `⚠️ Plan Needs Human`(無 degraded/skipped token)**不得**被標記為 degraded。 +> +> **分支優先序(as-built,fail-closed)**:machine token(DEGRADED/SKIPPED)**先於** verdict 文字——degraded/skipped 輸出若在 prose 中引述 verdict marker,不得丟失 flag/status_reason;再 `⛔ Plan Blocked` **先於** `✅ Plan Ready`——同時含兩個 verdict marker 的 ambiguous 輸出一律路由為 blocked。 + +**寫入路徑(as-built,history 單一擁有者)**:terminal `history[]` 由 emit-plan-gate Bash 路徑獨佔。MCP verdict 分支走 `_update_plan_iteration`(先記 round/finding counts,state file 缺失時 `init_state_file`)→ `update_plan_verdict(passed)`(僅 verdict,無 history append);MCP token 分支走 `update_plan_state(gate, "", "", "no-history")`。如此後續 `emit-plan-gate.sh` 的 history snapshot 取得 fresh counts 且不重複 append。MCP degraded 不帶 reason(恆 `reviewer-unavailable`):secret-detected 永不經 MCP 路由——skill 在外送 reviewer 前即 fail-closed,由 Bash 路徑記錄 reason。 + +#### T3 — `scripts/emit-plan-gate.sh` + **hook parse branch**(鏡射 `emit-review-gate.sh` 全鏈) + +`emit-review-gate.sh` 只是 emitter;**狀態真正被更新是因為 `post-tool-review-state.sh` 的 `emit-review-gate` parse 分支**(`Bash` PostToolUse)解析 `REVIEW_GATE=`。plan gate 必須補齊**兩端**: + +**(a) Emitter** `scripts/emit-plan-gate.sh`: + +``` +Usage: bash scripts/emit-plan-gate.sh PENDING [quick|standard|deep] # tier(僅 PENDING 接受) + bash scripts/emit-plan-gate.sh DEGRADED [reviewer-unavailable|secret-detected] # reason(僅 DEGRADED 接受) + bash scripts/emit-plan-gate.sh READY|BLOCKED|NEEDS_HUMAN|SKIPPED # 其餘 gate 拒絕額外參數 +→ echo "PLAN_REVIEW_GATE=$GATE" # namespace 前綴避免與 REVIEW_GATE 衝突 +→ 另輸出 PLAN_REVIEW_TIER= / PLAN_REVIEW_REASON=(有對應參數時) +非法值 / 空參數 / 非法 tier/reason → exit 1(set -euo pipefail) +``` + +**(b) Hook parse branch**(`post-tool-review-state.sh`,鏡射 `emit-review-gate` 分支,新增獨立分支): + +```bash +# === emit-plan-gate parse branch (as-built) === +if [[ "$TOOL_NAME" == "Bash" ]] && echo "$COMMAND" | grep -qF 'emit-plan-gate'; then + PLAN_GATE=$(echo "$TOOL_OUTPUT" | grep -oE '^PLAN_REVIEW_GATE=(PENDING|READY|BLOCKED|DEGRADED|NEEDS_HUMAN|SKIPPED)' | tail -1 | cut -d= -f2) || PLAN_GATE="" + # REASON 集合鏡射 emitter 實際輸出(僅 DEGRADED;SKIPPED 不發 REASON,user-skip 由 update_plan_state 內部硬編碼) + PLAN_REASON=$(... '^PLAN_REVIEW_REASON=(reviewer-unavailable|secret-detected)' ...) || PLAN_REASON="" + PLAN_TIER=$(... '^PLAN_REVIEW_TIER=(quick|standard|deep)' ...) || PLAN_TIER="" + update_plan_state "$PLAN_GATE" "$PLAN_REASON" "$PLAN_TIER" # 第 4 參數 history_mode 預設 append +fi +``` + +**全 6 值 → `update_plan_state()` 語意(無未定義值)**: + +| Gate | `executed` | `passed` | 其他 flag | stop-guard 視角 | +|------|-----------|----------|-----------|------------------| +| `PENDING` | `true` | `false` | reset per-plan cycle(round 0、findings 清空、degraded/skipped/status_reason 歸零;接受 tier) | loop 進行中:warn-only 提示,不阻塞 | +| `READY` | `true` | `true` | terminal → history append | 收斂;不滿足 code/doc gate(隔離) | +| `BLOCKED` | `true` | `false` | — | 續 loop;不阻塞 code/doc Stop(T4 過濾) | +| `DEGRADED` | `true` | `false` | `degraded=true`、`status_reason`(reason 參數,預設 reviewer-unavailable);terminal → history append | 非阻塞,warn-only | +| `SKIPPED` | `true` | `false` | `skipped=true`、`status_reason=user-skip`;terminal → history append | 非阻塞,warn-only | +| `NEEDS_HUMAN` | `true` | `false` | `status_reason=needs-human`(stop-guard 以此視為終態,不發 pending warn);terminal → history append | 終態 `⚠️ Plan Needs Human`;behavior-layer 升級,warn-only(非 hook hard-block) | + +> **as-built 補充**:terminal history(FIFO last-5,欄位 ts/tier/rounds/findings_total/outcome)僅由本 Bash 路徑 append(`history_mode=append` 預設);MCP 路由一律 no-history(見 T2)。Schema migration fail-closed:`schema_version` 非數字或 >3 → `_migrate_state_plan_review` 回傳 1,所有 plan writers(update_plan_state /_update_plan_iteration / update_plan_verdict)整段 skip 並 stderr 註記,state 完全不動。 +> +> hook 端測試**必須涵蓋全 6 值**(非僅 READY/BLOCKED/DEGRADED/SKIPPED)。 +> +> 測試必須涵蓋 **hook 端**(Bash 命令含 `emit-plan-gate` → `plan_review.*` 正確更新),不僅 script stdout。 + +#### T4 — `stop-guard.sh` 隔離擴充(OQ-Sx-3 hard precondition) + +| 問題 | 實際風險(已驗證) | 修正 | +|------|------|------| +| `REVIEW_PASSED` 的 `✅ Ready` 誤收 `✅ Plan Ready` | **低**:實測 `✅ Plan Ready` 不含 `✅ Ready`(SAFE) | 加防護但非主風險 | +| **`REVIEW_BLOCKED` + `LAST_REVIEW` 的 `⛔.*Block` 匹配 `⛔ Plan Blocked`** | **高(主風險)**:plan ⛔ 被誤判為 code/doc FAIL,阻塞無關 Stop | **as-built:`_strip_plan_sentinels()` substring strip**(sed 移除四個 plan sentinel token),套用於 `REVIEW_PASSED`/`REVIEW_BLOCKED`/`LAST_REVIEW` 三處掃描。**不採整行 `grep -v`**:transcript 為 JSONL(一行打包整則訊息),整行過濾會把同行的真 code/doc gate verdict 一併丟棄(false allow);substring strip 使 plan sentinel **既不滿足也不阻塞** code/doc gate,且保留同行其餘內容 | +| plan-review pending 未被 stop-guard 感知 | — | 讀 `plan_review.executed && !passed && !degraded && !skipped && status_reason != "needs-human"` → **warn-only** 提示「plan-review 進行中」,**不**併入 code/doc aggregate 決策(隔離)。`needs-human` 為終態(使用者仲裁中),排除於 pending 之外 | + +> stop-guard 對 plan-review 採 **warn-only**(不 strict-block):plan-review 是 analysis-only、skill-driven、ExitPlanMode 前置流程,非 precommit-style 強制 gate。 + +#### T5 — `/plan-review` skill 介面 + +| Arg | 行為 | +|-----|------| +| (無) | tier=standard(OQ-Sx-4 default);dual-dispatch(使用者決策:standard+deep 啟用 dual) | +| `--quick` | 單輪 Codex,無 loop,**不** dual | +| `--deep` | 委派 `/codex-brainstorm`(C2),dual(Nash engine 內含對抗雙視角) | +| `--skip-review` | 立即跳出,輸出 raw plan + `[PLAN_REVIEW_SKIPPED]`、`plan_review.skipped=true`、`status_reason=user-skip`(≤0 輪;**與 degrade 區分**) | +| `--verbose` | review trail round-by-round(預設僅 summary,OQ-4) | + +### 3.4 Core Logic + +#### 啟用光譜(OQ-3,使用者決策:opt-in → pilot → opt-out) + +| 階段 | 行為 | +|------|------| +| **v1(ship)** | **opt-in**:預設**不**啟用。使用者明示 `/plan-review`、或 `auto-loop-project.md` 設 `## Plan Review: enabled` 表達意圖。未 opt-in → plan mode 原行為(Claude → ExitPlanMode 直送) | +| **2 週 pilot 後** | 評估 false-negative / 使用者摩擦 → 升級 **opt-out**(預設開、`--skip-review` 可關)。升級為文件 + 預設值變更,無 schema 變動 | + +> **⚠️ v1 Acceptance Scope(A1 enforcement boundary)**:v1 的 review gate **僅在 `/plan-review` 實際被呼叫時生效**(review-gated only when invoked)。`## Plan Review: enabled` 在 v1 是 **advisory opt-in**——它表達「希望 Claude 在 ExitPlanMode 前 self-invoke `/plan-review`」的意圖,但 **v1 不提供「已啟用卻從未呼叫」的偵測或強制**。原因(已驗證):(a) stop-guard 的 plan-pending 檢查只在 `plan_review.executed` 已存在後才有意義,無法偵測「該執行卻從未執行」;(b) ExitPlanMode 為 harness 上游工具、v1 不攔截(A3 → v2,gated on OQ-Sx-1 harness probe),故已送入 ExitPlanMode 的 plan 無法事後 gate。因此 **v1 驗收明確界定為**:「`/plan-review` 被呼叫 → 跑收斂 loop → `✅ Plan Ready` 才呈現 plan」;**enabled-but-unexecuted 偵測 + pre-ExitPlanMode / tool-boundary 強制(FR-4 完整版)列為 v2**(見 R3、§7 OQ-Sx-1 / A3)。 + +#### Tier ladder + dual-review(OQ-7,使用者決策:standard + deep 啟用 dual) + +| Tier | Reviewer | Dual? | Loop | 委派 | +|------|----------|-------|------|------| +| quick | 單 Codex MCP | ❌ | 1-pass | — | +| **standard**(default) | Codex MCP + Secondary(Task agent,Explore) **並行** | ✅ | fix→re-review loop(`codex-reply --continue`) | — | +| deep | `/codex-brainstorm` | ✅(Nash 內含 attack/defense 雙視角) | brainstorm termination | `/codex-brainstorm` | + +> **決策來源(Decision Record DR-1)**:feasibility OQ-7 disposition 的 default proposal 為 **deep-only**;本 spec 採 **standard + deep** 係 **使用者於 `/tech-spec` 互動決策覆寫 feasibility default**(AskUserQuestion,2026-05-18)。此 spec 區塊**即為該決策的 durable record**(無獨立 request artifact;本 DR-1 註記讓未來審查者能區分「使用者決策」與「作者假設」)。Trade-off:標準 plan 命中率↑,但 standard tier 成本/延遲約翻倍(見 §4 R5)。**可逆性**:屬預設值層級、無 schema 變動;pilot 量測若不符 ROI,回退 feasibility deep-only default 僅需改本表預設,不影響已 ship 介面。 +> +> standard tier 的 dual 鏡射 `auto-loop.md` Dual Review Mode:Codex 為阻塞主審,Secondary 背景並行;late P0/P1 重開 loop。Secondary 用 Task agent(subagent_type: `Explore` 或 `strict-reviewer`),prompt 同樣遵守 `codex-invocation.md` 獨立研究原則。 + +#### Plan handover 與 Codex prompt framing(OQ-2 / OQ-Sx-5) + +- Claude 為 plan author,plan 文字本就在 working context(`1-requirements.md` Assumption)。 +- `/plan-review` 把 plan 文字作為 **"candidate artifact to attack"** 傳給 Codex,**絕不**寫成 "Claude 的結論,請確認"(`codex-invocation.md` Prohibited Pattern)。 +- **Secret redaction contract(NFR-8,依 [`scripts/security-redact.js`](../../../scripts/security-redact.js) **實測 API**)**。實測行為(勿信 source docstring,已驗證): + - `scanHighConfidence(text)` → 命中回傳 **`{name, fingerprint}`**、無命中回傳 **`null`**;**不 throw**(docstring 寫 throw 為誤導)。 + - `maskMediumConfidence(text)` → 僅遮罩 medium pattern,**不**遮罩 high-confidence(實測 `sk-…` 原樣穿透)。 + - `redact(text)` 預設 `abortOnHigh=true` → high 命中時 throw `AbortError`;`redact(text,{abortOnHigh:false})` 僅回傳遮罩字串、無 metadata、**無法分辨 high/medium**。 + - 送 reviewer 前的契約(採 truthy-return,主路徑,無例外控制流): + + ``` + const high = scanHighConfidence(planText); // {name,fingerprint} | null + if (high) { + // fail-closed:plan 不外送 reviewer + plan_review.degraded=true; status_reason=secret-detected; emit [PLAN_REVIEW_DEGRADED] + // plan 仍交付使用者(這是使用者自己的 plan),僅拒絕外送 reviewer + } else { + send(maskMediumConfidence(planText)) // medium → [REDACTED] 後才送 + } + ``` + + 等價替代:`try { send(redact(planText)) } catch (AbortError) { failClosed(...) }`(靠 `redact` 預設 throw)。 + - 高敏 pattern 範圍:PEM、`AKIA…`、`sk-[A-Za-z0-9_-]{20,}`、`ghp_[A-Za-z0-9]{36}`、`xox[aboprs]-…`、`AIza…`。 + - 反例(禁用):以 `redact(...,{abortOnHigh:false})` 回傳值判 high(high 已遮罩成 `[REDACTED]`、與 medium 不可區分)。 +- prompt template 強制含 §「You must independently research the project」+ 具體 git/grep 指令;plan 文字標註為待攻擊產物。 + +#### Convergence(reuse rule-level decision table) + +採 [`rules/auto-loop.md`](../../../rules/auto-loop.md) Exit Conditions 決策表,但作用於 `plan_review.iteration_history`: + +| # | Condition | Action | +|---|-----------|--------| +| 1 | `current_round >= max_rounds`(default 5) | `⚠️ Plan Needs Human` + 殘餘 findings(不靜默通過,Signal 7) | +| 2 | `findings_by_round[n].total == 0` | `✅ Plan Ready` → 附 trail summary → ExitPlanMode | +| 3 | plateau(fingerprint overlap ≥50% 連 3 輪) | **V1 不可達**(OQ-9 → V2:需 hook fingerprint 儲存);v1 僅靠 row 1 hard cap | +| 5 | `total < prev_total` | Continue loop | + +#### Bypass / Escape(FR-5 / NFR-5 / UC-2) + +``` +使用者明示「skip review」/「直接 show plan」/ --skip-review + → 偵測點:skill 入口 + 每輪 re-review 前 + → ≤1 輪 review 內跳出(NFR-5) + → 已啟動者輸出部分 trail + → plan_review.skipped=true; status_reason=user-skip; emit [PLAN_REVIEW_SKIPPED] + (使用者意圖 — 非 reliability 失效,與 degrade 分離) + → raw / 當前 plan → ExitPlanMode +``` + +#### Graceful degradation(NFR-3 / NFR-8 / Signal 6) + +兩種 degrade 來源,皆 `plan_review.degraded=true` + emit `[PLAN_REVIEW_DEGRADED]`,但 `status_reason` 區分: + +``` +(a) reviewer 不可達:Codex MCP 連線錯誤 / 401 / timeout + → 不 retry-storm(最多 1 retry) + → status_reason=reviewer-unavailable +(b) plan 含 high-confidence secret(redact contract fail-closed) + → 不外送 reviewer + → status_reason=secret-detected +共同:plan 當輪交付使用者 + output 含可 grep 的 [PLAN_REVIEW_DEGRADED] 標記;不阻塞 plan mode +``` + +## 4. Risks and Dependencies + +| # | Risk | Likelihood | Impact | Mitigation | +|---|------|-----------|--------|------------| +| R1 | **OQ-Sx-2**:plan mode 內 MCP / Skill 呼叫不可用 → A1 根本不可實作 | Medium | **Critical** | **Hard precondition**:實作前先跑 smoke test(見 §7);若不可用 → ⛔ 架構回頭(A1 不成立,需重評 A2/A3 或 harness 協作) | +| R2 | **OQ-Sx-3**:stop-guard 未隔離 → `⛔ Plan Blocked` 觸發 `⛔.*Block`(stop-guard `REVIEW_BLOCKED`/`LAST_REVIEW` grep)誤判 code/doc FAIL,阻塞無關 Stop(NFR-7 破功) | Medium | High | **Hard precondition**:T4 隔離擴充(as-built:`_strip_plan_sentinels()` **substring strip**——transcript 為 JSONL 一行打包整則訊息,整行 `grep -v` 會把同行真 code/doc verdict 一併丟棄造成 false allow)+ 回歸測試斷言互不覆寫 | +| R3 | A1 為 best-effort:即使使用者已 `## Plan Review: enabled`,Claude 忘記 self-invoke `/plan-review` → 繞過 review(**enabled-but-unexecuted gap**)。v1 無偵測路徑:stop-guard 的 plan-pending 檢查需 `plan_review.executed` 已存在才有意義、ExitPlanMode 不被攔截(FR-4 tool-boundary 層 v1 未保證) | Medium | Medium | **v1 明確界定為「review-gated only when /plan-review invoked」**(見 §3.4 v1 Acceptance Scope);`auto-loop` + Stop Hook 提示 raise compliance(advisory);enabled-but-unexecuted 偵測 + tool-boundary 強制留待 v2 OQ-Sx-1 harness probe(A3) | +| R4 | schema migration 破壞既有 state | Low | High | 純加法 jq 注入;atomic write + lock;回歸測試斷言除 `schema_version` 外語意等價 | +| R5 | dual-review 在 standard tier 使短 plan 成本/延遲翻倍 | Medium | Low | Secondary 背景並行不阻塞主 gate;pilot 量測;不符 ROI 可回退 deep-only(feasibility default) | +| R6 | Codex prompt 違反 `codex-invocation.md`(餵養結論) | Low | Medium | 強制使用 `references/codex-prompt-plan.md` template;plan 標註為待攻擊產物;review checklist 把關 | +| R7 | secret 洩漏到 reviewer context(NFR-8) | Low | High | redact contract(§3.4):medium→mask、high→fail-closed 不外送;測試用**regex-valid** dummy(`sk-` + ≥20 字元如 `sk-abcdefghijklmnopqrstUVWX`、`ghp_` + 恰 36 字元、PEM header),斷言 high-confidence 走 `[PLAN_REVIEW_DEGRADED]`、`status_reason=secret-detected` 且 payload 不外送 | +| R8 | plateau 偵測 v1 缺位 → 同類 finding 反覆但不升 Need Human | Low | Medium | v1 靠 max_rounds=5 hard cap 兜底;OQ-9 明列 V2;trail summary 讓使用者可觀測重複 | + +**Dependencies**: + +| Dependency | Type | Status | +|------------|------|--------| +| Codex MCP 在 plan mode 可呼叫 | External (harness) | **未驗證 — OQ-Sx-2 hard precondition** | +| Skill 在 plan mode 可呼叫 | External (harness) | **未驗證 — OQ-Sx-2 hard precondition** | +| `scripts/security-redact.js` 存在且涵蓋高敏 pattern | Internal | 需確認介面(W1 預檢) | +| `/codex-brainstorm` skill 穩定 | Internal | 已 ship(deep tier 委派) | + +## 5. Work Breakdown + +> **Gate**:W0 hard preconditions **必須全綠**才進 W1+。任一不過 → `⚠️ Plan Needs Human`,停工回報(不繞過)。 + +| ID | Task | Depends | Size | Test mapping | +|----|------|---------|------|--------------| +| **W0** | **Hard precondition spikes** | — | S | — | +| W0.1 | OQ-Sx-2 smoke test:plan mode 內呼叫 `mcp__codex__codex` + Skill 是否回傳;記錄結論 | — | S | spike report(非自動化測試) | +| W0.2 | OQ-Sx-3 stop-guard 隔離設計定稿(regex 過濾 + warn-only 策略確認) | — | S | 設計 note | +| **W1** | **State 基建** | W0 | M | | +| W1.1 | `post-tool-review-state.sh`:`init_state_file()` 加 `plan_review`、`schema_version` 2→3 | W0 | S | `test/hooks/post-tool-review-state.test.js`(新 fixtures) | +| W1.2 | schema v2→v3 additive migration 分支 + atomic/lock | W1.1 | M | 同上(migration:除 `schema_version` 外語意等價斷言) | +| W1.3 | MCP routing Priority 1.5 plan branch(`grep -F` literal for `[PLAN_REVIEW_*]`)+ `update_plan_state()` | W1.1 | M | 同上(plan routing + literal-match + collision 斷言) | +| **W2** | **Gate emission + 隔離** | W1 | M | | +| W2.1 | `scripts/emit-plan-gate.sh`(6 值含 SKIPPED + namespace 前綴)**+ `post-tool-review-state.sh` `emit-plan-gate` parse 分支**(鏡射 `emit-review-gate` parse 分支) | W1.3 | M | `test/scripts/emit-plan-gate.test.js`(emitter)+ `test/hooks/post-tool-review-state.test.js`(hook parse 分支) | +| W2.2 | `stop-guard.sh` 隔離擴充(T4) | W0.2,W1 | M | `test/hooks/stop-guard.test.js`(plan isolation fixtures) | +| **W3** | **`/plan-review` skill** | W1,W2 | L | | +| W3.1 | `skills/plan-review/SKILL.md`(tier ladder / loop / bypass / degrade) | W1,W2 | L | `test/skills/plan-review.test.js`(new) | +| W3.2 | `references/codex-prompt-plan.md` + `review-loop-plan.md`(OQ-Sx-5 framing) | W3.1 | M | skill test 引用斷言 | +| W3.3 | secret redaction 串接(NFR-8,呼叫 `security-redact.js`) | W3.1 | S | skill test(**as-built:靜態斷言** SKILL.md 含 redaction contract + fail-closed 流程;end-to-end dummy-payload 行為驗證留 pilot 手動) | +| W3.4 | standard tier dual-dispatch(Codex + Task secondary 並行) | W3.1 | M | skill test(**as-built:靜態斷言** dual-dispatch 段落存在;skill 為 model-driven markdown,行為驗證留 pilot 手動) | +| W3.5 | deep tier 委派 `/codex-brainstorm` | W3.1 | S | skill test(**as-built:靜態斷言** deep tier 委派段落存在;行為驗證留 pilot 手動) | +| **W4** | **Config + rules + 文件** | W3 | M | | +| W4.1 | `auto-loop-project.md` 加 `## Plan Review Max Rounds`(default 5)+ `## Plan Review: enabled` opt-in 開關 | W1 | S | Max Rounds:hook 解析測試(`_read_project_plan_max_rounds`,含 range/邊界);**`## Plan Review: enabled` 為 model-read advisory(v1 無 hook 解析,無自動化測試)** | +| W4.2 | `rules/auto-loop.md` Standard Gate Sentinels 加 plan namespace 列 | W3 | S | doc review | +| W4.3 | `/plan-review` skill 登錄(`.claude/skills -> ../skills` symlink 自動可見 + `docs/skill-catalog.yml`)+ `CLAUDE.md` Command Quick Reference 加列(v3 起無 thin command entry) | W3 | S | skills-schema 測試 + symlink parity 斷言 | +| W4.4 | request ticket(`/create-request`)追蹤 AC 進度 | W3 | S | — | + +預估:W0 ~1 day(gating);W1-W4 ~6-8 person-days(feasibility §6 A1+B1+C2 估值範圍內)。 + +## 6. Testing Strategy + +| Layer | Scope | Cases (key) | +|-------|-------|-------------| +| **Unit** | `emit-plan-gate.sh`(emitter) | 6 合法值(含 SKIPPED)→ 正確 `PLAN_REVIEW_GATE=`;非法值 exit 1;空參數 exit 1 | +| **Unit** | **emit-plan-gate hook parse 分支** | Bash 命令含 `emit-plan-gate` + stdout `PLAN_REVIEW_GATE=` **全 6 值**(`PENDING`/`READY`/`BLOCKED`/`DEGRADED`/`SKIPPED`/`NEEDS_HUMAN`)→ `update_plan_state()` 各依 §3.3 T3 語意表更新 `plan_review.*`(**hook 端**,非僅 script stdout) | +| **Unit** | schema migration | v2→v3 `. +` 合併注入 `plan_review`;v3 no-op;migration 後**全部 v2 頂層欄位**(`session_id`/`updated_at`/`review_mode`/`has_code_change`/`has_doc_change`/`code_review`/`doc_review`/**`precommit`**/`aggregate_gate`/root `iteration_history`)語意等價,**`schema_version` 單獨斷言 2→3**(NFR-7 Signal 4) | +| **Unit** | MCP routing | `## Plan Review`+`✅ Plan Ready` → pass;`+⛔ Plan Blocked` → fail;`+[PLAN_REVIEW_DEGRADED]`(**`grep -F` literal**)→ degraded;`+[PLAN_REVIEW_SKIPPED]` → skipped;**`## Plan Review`+`⚠️ Plan Needs Human`(無 token)不得標 degraded**(literal-match regression);實測 `printf '✅ Plan Ready' \| grep -qE '✅ Ready'` = SAFE 斷言;doc/code branch 不回歸 | +| **Unit** | stop-guard 隔離 | **主**:`⛔ Plan Blocked` 不觸發 `REVIEW_BLOCKED`(`⛔.*Block` regex)→ 不誤判 code/doc FAIL;`✅ Plan Ready` 不滿足 `REVIEW_PASSED`;plan pending → warn-only 不併入 aggregate | +| **Unit** | config 解析 | `## Plan Review Max Rounds` 覆寫 default 5(含 range 3-50 inclusive 邊界 + 超界 fallback + migration path 覆寫);缺區塊 → fallback 5;**`## Plan Review: enabled` 為 model-read advisory,v1 無 hook 解析 → 無自動化測試(doc review 覆蓋)** | +| **Integration**(v1 deferred → pilot 手動) | skill loop(mock Codex) | P0/P1 → revise → re-review → `✅ Plan Ready` 收斂;max_rounds=5 未收斂 → `⚠️ Plan Needs Human`+殘餘 findings(Signal 2/7)。**As-built:skill 為 model-driven markdown,無法以 node:test 驅動 loop;v1 以 `test/skills/plan-review.test.js` 靜態結構斷言 + pilot 手動驗證取代** | +| **Integration**(v1 部分自動化) | bypass vs degrade(分離斷言) | `--skip-review` ≤1 輪跳出 → `[PLAN_REVIEW_SKIPPED]`+`skipped=true`(Signal 3);mock reviewer offline/401/timeout → `[PLAN_REVIEW_DEGRADED]`+`status_reason=reviewer-unavailable` 不卡死(Signal 6);兩者 sentinel/flag 不混用。**As-built:sentinel/state 語意(含不混用)已由 emit-plan-gate + hook routing unit tests 覆蓋;end-to-end skill 行為留 pilot** | +| **Integration**(v1 deferred → pilot 手動) | secret redaction | medium dummy(`password=hunter2dummy`)→ `maskMediumConfidence` `[REDACTED]` 後照送;high dummy(**regex-valid**:`sk-` + ≥20 字元、`ghp_` + 恰 36 字元、PEM header)→ `scanHighConfidence` truthy → fail-closed:plan **不外送** reviewer + `[PLAN_REVIEW_DEGRADED]`、`status_reason=secret-detected`,payload grep 無高敏 pattern(Signal 8/NFR-8)。**As-built:redaction contract 由 skill 結構測試靜態斷言;`security-redact.js` 自身既有測試;end-to-end fail-closed 行為留 pilot** | +| **Integration**(v1 已於 unit 層覆蓋) | 並行隔離 | 同 session 觸發 code-review + plan-review → 兩者 state 互不覆寫(Signal 4/NFR-7)。**As-built:雙向隔離由 `post-tool-review-state.test.js` unit fixtures 自動化覆蓋** | + +Conventions 遵 [`rules/testing.md`](../../../rules/testing.md):AAA、`assert/strict`、≤7 assertions/case、realistic data。Evidence 對應(Acceptance Signals 定義於 [1-requirements.md §8](./1-requirements.md)):state / sentinel / gate / 隔離層 Signal 由 unit + 靜態結構自動化證據覆蓋(Evidence Model priority 1);上表標記「v1 deferred → pilot 手動」的 end-to-end skill 行為面向,v1 以結構斷言 + pilot 手動驗證為證據(priority 2/3,pilot 期間補齊)。 + +**Doc link-check**:本 lifecycle doc 位於 depth 3(`docs/features/plan-review-loop/`),跨 repo-root 引用用 `../../../`。CI doc-link 檢查涵蓋本檔;已 spot-check `../../../rules/auto-loop.md`、`../../../hooks/post-tool-review-state.sh`、`../dual-reviewer/2-tech-spec.md` 均可解析。 + +## 7. Open Questions + +### 7.1 Hard preconditions(gating W1+,必須先解) + +| OQ | Question | Resolution path | +|----|----------|-----------------| +| OQ-Sx-2 | plan mode 內 MCP / Skill 是否可呼叫? | **W0.1 smoke test**。不可用 → ⛔ A1 不成立,停工升 `⚠️ Plan Needs Human` | +| OQ-Sx-3 | `stop-guard.sh` 如何隔離 plan sentinel? | **W0.2 設計定稿** → T4 實作 + 回歸斷言 | + +### 7.2 已於本 spec 拍板(feasibility tech-spec disposition + 使用者決策) + +| OQ | 決策 | 來源 | +|----|------|------| +| OQ-3 啟用光譜 | opt-in v1 → 2 週 pilot → opt-out(= feasibility default,使用者確認) | **使用者決策**(`/tech-spec` AskUserQuestion,2026-05-18) | +| OQ-7 dual-review | standard + deep 啟用 dual;quick 單 Codex(**覆寫** feasibility deep-only default) | **使用者決策**(`/tech-spec` AskUserQuestion,2026-05-18) | +| OQ-4 trail 訊噪比 | 預設 summary(rounds/findings/modified-sections);`--verbose` round-by-round | feasibility default | +| OQ-6 state scope | per-plan reset;`history[]` 保留最近 5 筆 | feasibility default | +| OQ-10 預算配置點 | `auto-loop-project.md` 新增 `## Plan Review Max Rounds`,default 5 | feasibility default | +| OQ-Sx-4 tier 自動偵測 | default `standard`;`--quick`/`--deep` 顯式升降 | feasibility default | +| OQ-Sx-5 Codex framing | plan 作為 "candidate artifact to attack",遵 `codex-invocation.md` | feasibility default | + +### 7.3 Deferred to V2(不阻塞 v1) + +| OQ | Question | 條件 | +|----|----------|------| +| OQ-9 | plateau / fingerprint 偵測 | 需 hook 端 fingerprint 儲存;v1 僅 max_rounds hard cap | +| OQ-Sx-1 | PreToolUse 攔截 `ExitPlanMode`(A1→A3 升級) | harness probe;成立則 v2 升 A3+B1+C2(state/tier 不變,僅加 hook tripwire) | + +### 7.4 Pilot-revisit(v1 ship 後量測再定) + +| 項目 | 量測訊號 | +|------|---------| +| OQ-3 opt-in → opt-out 升級時機 | 2 週 false-negative rate + 使用者摩擦回饋 | +| OQ-7 standard dual ROI | dual vs single 在短 plan 的邊際命中率;不符 ROI → 回退 deep-only | + +## 8. References + +- Canonical: [`./1-requirements.md`](./1-requirements.md), [`./0-feasibility-study.md`](./0-feasibility-study.md) +- Sibling lifecycle: [`docs/features/dual-reviewer/2-tech-spec.md`](../dual-reviewer/2-tech-spec.md), [`docs/features/codex-review-spec/1-requirements.md`](../codex-review-spec/1-requirements.md) +- Reused skills: [`skills/codex-brainstorm/SKILL.md`](../../../skills/codex-brainstorm/SKILL.md), [`skills/doc-review/SKILL.md`](../../../skills/doc-review/SKILL.md), [`skills/codex-code-review/SKILL.md`](../../../skills/codex-code-review/SKILL.md) +- Loop primitives: [`hooks/post-tool-review-state.sh`](../../../hooks/post-tool-review-state.sh), [`hooks/stop-guard.sh`](../../../hooks/stop-guard.sh), [`scripts/emit-review-gate.sh`](../../../scripts/emit-review-gate.sh) +- Rules: [`rules/auto-loop.md`](../../../rules/auto-loop.md), [`rules/codex-invocation.md`](../../../rules/codex-invocation.md), [`rules/auto-loop-project.md`](../../../rules/auto-loop-project.md), [`rules/docs-numbering.md`](../../../rules/docs-numbering.md), [`rules/testing.md`](../../../rules/testing.md), [`rules/security.md`](../../../rules/security.md) +- Codex feasibility debate threadId: `019e298f-3645-7801-b6ff-b60b8d1235e6` diff --git a/docs/features/plan-review-loop/requests/2026-06-12-plan-review-v1.md b/docs/features/plan-review-loop/requests/2026-06-12-plan-review-v1.md new file mode 100644 index 0000000..ee57dd3 --- /dev/null +++ b/docs/features/plan-review-loop/requests/2026-06-12-plan-review-v1.md @@ -0,0 +1,73 @@ +# Plan Review Loop — V1 A1+B1+C2 全量實作 + +> **Doc class**: Request ticket (date-prefixed non-lifecycle — per `@rules/docs-numbering.md`). Per-task work breakdown unit for progress tracking. **Not** a feature-level requirements doc — for that see `../1-requirements.md`. +> **Created**: 2026-06-12 +> **Status**: Done +> **Priority**: P1 +> **Tech Spec**: [2-tech-spec.md](../2-tech-spec.md) +> **Requirements**: [1-requirements.md](../1-requirements.md) + +## Background + +實作 plan-review-loop v1(A1+B1+C2):skill 驅動的 `/plan-review` 對抗式計畫審查迴圈,在 plan mode 中於 `ExitPlanMode` 前讓 Codex 攻擊 plan 草稿並迭代收斂。State 以 namespaced `plan_review.*` subtree 存於 `.claude_review_state.json`(schema v2→v3 additive migration),與 code/doc/aggregate 平面完全隔離(NFR-7);deep tier 委派 `/codex-brainstorm`。工作分解依 tech-spec §5 W0–W4。 + +## Requirements + +- W1 state 基建 — `plan_review` 欄位 init + schema v2→v3 migration + `_read_project_plan_max_rounds`(`## Plan Review Max Rounds`,default 5) +- W2 gate 通道 — `scripts/emit-plan-gate.sh`(6 gates + tier/reason 參數)+ hook parse 分支 + MCP Priority 1.5 routing(`## Plan Review` discriminator)+ stop-guard plan sentinel 隔離(transcript grep filter + warn-only advisory) +- W3 skill — `skills/plan-review/SKILL.md` + `references/codex-prompt-plan.md`(candidate-artifact framing + 獨立研究指令)+ `references/review-loop-plan.md`(codex-reply VERIFY-not-CONFIRM) +- W4 設定與文件 — `rules/auto-loop.md` plan sentinel rows、`rules/auto-loop-project.md` 兩個 opt-in 區段、3 份 CLAUDE quick-ref row、`docs/skill-catalog.yml` 登錄 + +## Scope + +| Scope | Description | +|-------|-------------| +| In | `plan_review` state subtree(init/migration/update/iteration);`emit-plan-gate.sh` + hook parse;MCP plan routing;stop-guard 隔離(warn-only);`/plan-review` skill + 2 references;rules/CLAUDE/catalog 登錄;對應 unit tests | +| Out | Hook 強制 enabled-but-unexecuted 偵測(v2);plateau/fingerprint 收斂偵測(OQ-9, v2);ExitPlanMode hook 攔截(A2,已否決);aggregate_gate 整合 plan 平面 | + +## Related Files + +| File | Action | Description | +|------|--------|-------------| +| `scripts/emit-plan-gate.sh` | New | PLAN_REVIEW_GATE sentinel emitter(PENDING tier / DEGRADED reason 驗證) | +| `hooks/post-tool-review-state.sh` | Modify | plan_review init + v2→v3 migration + `update_plan_state` + `_update_plan_iteration` + emit-plan-gate parse + MCP Priority 1.5 routing | +| `hooks/stop-guard.sh` | Modify | transcript grep plan sentinel 過濾(×3 處)+ plan pending warn-only advisory | +| `skills/plan-review/SKILL.md` | New | Skill 主文件(tier ladder / redaction contract / convergence / degradation) | +| `skills/plan-review/references/codex-prompt-plan.md` | New | Codex 首輪 prompt 模板 | +| `skills/plan-review/references/review-loop-plan.md` | New | codex-reply 複審模板 | +| `.claude/skills/plan-review/**` | New | Install-visible path(經 `.claude/skills -> ../skills` symlink 可見,非獨立複本) | +| `rules/auto-loop.md` | Modify | Standard Gate Sentinels 表 + plan namespace isolation note | +| `rules/auto-loop-project.md` | Modify | `## Plan Review` + `## Plan Review Max Rounds` opt-in 區段 | +| `CLAUDE.template.md` / `CLAUDE.md` / `.claude/CLAUDE.md` | Modify | `/plan-review` quick-ref row | +| `docs/skill-catalog.yml` | Modify | `/plan-review` review category 登錄 | +| `test/scripts/emit-plan-gate.test.js` | New | 6 gates + tier/reason 驗證 + 拒絕非法參數 | +| `test/hooks/post-tool-review-state.test.js` | Modify | migration v2→v3 / update_plan_state 各 gate / plan iteration / MCP plan routing / 隔離雙向 | +| `test/hooks/stop-guard.test.js` | Modify | plan sentinel 不觸發 code 評估 + plan pending warn-only | +| `test/skills/plan-review.test.js` | New | SKILL.md 結構 + sentinel 約束 + references 存在 | + +## Acceptance Criteria + +- [x] `emit-plan-gate.sh` 對 6 個 gate 輸出 `PLAN_REVIEW_GATE=`;PENDING 接受 tier、DEGRADED 接受 reason、其餘拒絕額外參數;非法值 exit 1(FR-6/T3) +- [x] State schema v2→v3 additive migration:v2 檔案升級後保留既有 code/doc 欄位且新增完整 `plan_review` default subtree;v3 重跑 no-op;ver>3 / 非數字 warn skip(B1/T3) +- [x] `update_plan_state` 六種 gate 語意符合 T3(PENDING reset cycle、terminal gates 寫 history FIFO last-5、DEGRADED/SKIPPED 帶 status_reason),且不觸碰 `code_review`/`doc_review`/`aggregate_gate`/root `iteration_history`(NFR-7 方向一) +- [x] MCP Priority 1.5 routing:`## Plan Review` + `✅ Plan Ready`/`⛔ Plan Blocked`/`[PLAN_REVIEW_DEGRADED]`/`[PLAN_REVIEW_SKIPPED]` 正確更新 plan 平面;`⚠️ Plan Needs Human`(無 token)不誤觸任何分支;`✅ Plan Ready` 不誤觸 code review `✅ Ready` 分支(collision regression) +- [x] stop-guard:transcript 含 `⛔ Plan Blocked` 不產生 code/doc BLOCKED 誤判;plan pending(executed=true, passed/degraded/skipped 皆 false)僅 stderr warn、不加入 MISSING/blocking(NFR-7 方向二 + T4) +- [x] `## Plan Review Max Rounds` 設定可覆寫 plan max_rounds(default 5, range 3-50),且與 `## Max Rounds`(code/doc, default 10)互不干擾 +- [x] `/plan-review` skill 結構通過 skills-schema 驗證;references 存在;prompt 模板含獨立研究指令 + plan sentinel 約束 + 禁用 bare `✅ Ready`/`✅ Mergeable`/`## Gate:`(rules/codex-invocation.md 合規) +- [x] Pass /codex-review-fast + /precommit-fast + +## Progress + +| Phase | Status | Note | +|-------|--------|------| +| Analysis | Done | Tech spec §3–§6 定案;W0.1 spike(plan mode 工具可用性)via claude-code-guide agent 確認 A1 可行 | +| Development | Done | W1/W2/W3/W4 完成。Review 迭代追加:token-first + BLOCKED-first 路由、`update_plan_verdict`(MCP no-history,history 由 emit-plan-gate Bash 路徑獨佔)、`update_plan_state` history_mode 參數、migration fail-closed(非數字/>3 全 writer skip)、`status_reason=needs-human` 終態、`_update_plan_iteration` init-on-missing、stop-guard `_strip_plan_sentinels` substring strip(取代整行 grep -v) | +| Testing | Done | 4 個測試檔(emit-plan-gate 11、hook plan 區段、stop-guard plan T4/pending、skill 結構 17+);AC trace gap closure(migration subtree 形狀、max rounds 邊界 3/50、override 流經 migration path);stub/real divergence guard。全套 1495 pass / 0 fail | +| Acceptance | Done | Codex dual review ✅(多輪收斂)+ Secondary ×3 READY;/codex-test-review --ac-trace:✅ Adequate(gaps 清空);/precommit-fast ✅ All Pass ×2 | + +## References + +- Tech Spec: [../2-tech-spec.md](../2-tech-spec.md) §3.3 T1–T4, §5 W0–W4, §6 測試映射 +- Requirements: [../1-requirements.md](../1-requirements.md) FR-6/FR-9/FR-14, NFR-3/NFR-4/NFR-5/NFR-7/NFR-8 +- Feasibility: [../0-feasibility-study.md](../0-feasibility-study.md) A1+B1+C2 決策 +- Test evidence: [`test/scripts/emit-plan-gate.test.js`](../../../../test/scripts/emit-plan-gate.test.js)、[`test/hooks/post-tool-review-state.test.js`](../../../../test/hooks/post-tool-review-state.test.js)(plan 區段)、[`test/hooks/stop-guard.test.js`](../../../../test/hooks/stop-guard.test.js)(plan T4/pending)、[`test/skills/plan-review.test.js`](../../../../test/skills/plan-review.test.js) diff --git a/docs/features/smart-commit-hardening/2-tech-spec.md b/docs/features/smart-commit-hardening/2-tech-spec.md index a77425e..5c88a30 100644 --- a/docs/features/smart-commit-hardening/2-tech-spec.md +++ b/docs/features/smart-commit-hardening/2-tech-spec.md @@ -25,7 +25,7 @@ | ---- | ------ | ----------- | | `skills/smart-commit/SKILL.md` | Modify | 新增 Step 1c/1d/1e + runtime validation | | `commands/smart-commit.md` | Modify | Context block 加入 identity/signing 資訊 | -| `scripts/commit-msg-guard.sh` | Modify | Regex 正規化為 POSIX ERE | +| `scripts/commit-msg-guard.sh` | Modify | Regex 正規化為 ERE + `\b` 字界 | | `test/scripts/smart-commit.test.js` | New | Identity/AI guard/signing pre-flight 測試 | ## 3. Technical Solution @@ -223,11 +223,12 @@ cat <<'EOF' > "$TMPFILE" EOF -# 3. Runtime validation(POSIX ERE, all use grep -Ei) +# 3. Runtime validation(ERE + \b 字界, all use grep -Ei) AI_CO_AUTHOR="${AI_CO_AUTHOR:-0}" # set to 1 when --ai-co-author passed validate_msg() { local tmpfile="$1" + # 僅 AI 加 \b 字界,避免 -i 下誤中一般字詞(maintainer、domain);GPT/OpenAI 刻意不加界以匹配 ChatGPT/GPT-4 # Pattern 1: Co-Authored-By AI(若 --ai-co-author 啟用,僅允許精確格式) if [ "$AI_CO_AUTHOR" = "1" ]; then # 移除精確允許行後再檢查殘留 AI patterns @@ -237,9 +238,9 @@ validate_msg() { grep -Ei 'Co-Authored-By:.*(Claude|Anthropic|GPT|OpenAI|Copilot|noreply@anthropic)' "$tmpfile" && return 1 fi # Pattern 2: Generated-by tag(always blocked) - grep -Ei 'Generated (by|with).*(Claude|Claude Code|AI|GPT|Copilot)' "$tmpfile" && return 1 + grep -Ei 'Generated (by|with).*(Claude|\bAI\b|GPT|OpenAI|Copilot)' "$tmpfile" && return 1 # Pattern 3: Emoji robot tag(always blocked) - grep -Ei '🤖.*(Claude|AI|GPT)' "$tmpfile" && return 1 + grep -Ei '🤖.*(Claude|\bAI\b|GPT|OpenAI)' "$tmpfile" && return 1 return 0 } @@ -278,15 +279,15 @@ MSG=$(git log -1 --format='%B') **現況問題**: `SKILL.md` 用 PCRE-style(`(?:...)`),`commit-msg-guard.sh` 用 BRE-style(`\(...\)`),產生方言不一致。 -**統一為 POSIX ERE**(`grep -E`): +**統一為 ERE + `\b` 字界**(`grep -E`): -| Pattern | 舊(混合) | 新(POSIX ERE, `grep -Ei`) | +| Pattern | 舊(混合) | 新(ERE + `\b` 字界, `grep -Ei`) | |---------|-----------|----------------| | Co-Authored-By AI | `Co-Authored-By:.*(?:Claude\|Anthropic\|...)` (PCRE) | `Co-Authored-By:.*(Claude\|Anthropic\|GPT\|OpenAI\|Copilot\|noreply@anthropic)` | -| Generated-by tag | `Generated (?:by\|with).*(?:Claude\|...)` (PCRE) | `Generated (by\|with).*(Claude\|Claude Code\|AI\|GPT\|Copilot)` | -| Emoji robot tag | `🤖.*\(Claude\|AI\|GPT\)` (BRE) | `🤖.*(Claude\|AI\|GPT)` | +| Generated-by tag | `Generated (?:by\|with).*(?:Claude\|...)` (PCRE) | `Generated (by\|with).*(Claude\|\bAI\b\|GPT\|OpenAI\|Copilot)` | +| Emoji robot tag | `🤖.*\(Claude\|AI\|GPT\)` (BRE) | `🤖.*(Claude\|\bAI\b\|GPT\|OpenAI)` | -**注意**:POSIX ERE 中 `|` 和 `()` 不需要反斜線跳脫。上表「新」欄位中的 `\|` 為 Markdown 表格跳脫,實際 regex 為 `|`。所有 pattern 使用 `grep -Ei`(ERE + case-insensitive)。 +**注意**:ERE 中 `|` 和 `()` 不需要反斜線跳脫。上表「新」欄位中的 `\|` 為 Markdown 表格跳脫,實際 regex 為 `|`。所有 pattern 使用 `grep -Ei`(ERE + case-insensitive)。裸 `AI` 在 `-i` 下會誤中 "maintainer"、"domain" 等一般字詞,故僅對 `AI` 加 `\b` 字界(BSD 與 GNU grep 皆支援;POSIX `[[:<:]]` 不可攜);`GPT`/`OpenAI` 刻意不加字界,以匹配 `ChatGPT`/`GPT-4`(無英文字含 "gpt")。 **Canonical source**: `scripts/commit-msg-guard.sh` 為正規化後的唯一真實來源,SKILL.md 引用之。 @@ -329,7 +330,7 @@ MSG=$(git log -1 --format='%B') | W5 | 修改 SKILL.md:Step 5b `--ai-co-author` 窄白名單 | S | W4 | | W6 | 修改 SKILL.md:Post-commit 洩漏 hard stop | S | W4 | | W7 | 修改 SKILL.md:Commit plan 摘要增強 | S | W1, W2, W3 | -| W8 | 正規化 `commit-msg-guard.sh` regex 為 POSIX ERE | S | — | +| W8 | 正規化 `commit-msg-guard.sh` regex 為 ERE + `\b` 字界 | S | — | | W9 | 修改 `commands/smart-commit.md` context block | S | W1, W2 | | W10 | 新增 `--sign` / `--no-sign` flags | S | W2 | | W11 | 新增 `test/scripts/smart-commit.test.js` | M | W1–W10 | @@ -355,7 +356,7 @@ MSG=$(git log -1 --format='%B') | Signing: enabled + key present | 顯示 enabled 狀態 | | Signing: enabled + key missing | 顯示 warning | | Signing: not configured | 顯示 inherit 狀態 | -| Regex: POSIX ERE 跨平台一致性 | GNU grep 和 BSD grep 相同結果 | +| Regex: ERE + `\b` 字界跨平台一致性 | GNU grep 和 BSD grep 相同結果 | | Hook detection: `core.hooksPath` awareness | 非標準 hook 路徑正確偵測 | ### 6.2 Integration Tests diff --git a/docs/features/workflow-orchestration/0-feasibility-study.md b/docs/features/workflow-orchestration/0-feasibility-study.md new file mode 100644 index 0000000..627c3a6 --- /dev/null +++ b/docs/features/workflow-orchestration/0-feasibility-study.md @@ -0,0 +1,269 @@ +# Workflow Orchestration(代理式編排器)可行性研究報告 + +> **Doc class**: Lifecycle — Phase 0 feasibility(依 `@rules/docs-numbering.md`)。 +> **Created**: 2026-05-29 +> **Requirements**: [1-requirements.md](./1-requirements.md) +> **方法**: 5-Why + 約束盤點 + code research + 4 方案 + Codex 雙輪對話 + feasibility-analyst 獨立查證 + +## 1. 問題本質 + +### 1.1 Surface Requirement + +設計一版通用 workflow,把「98 個 skill 如何串成 workflow」的編排決策交給 agent,而非由人依 `CLAUDE.md:13-17` 的固定流程表手動編排(k8s 解決容器編排的類比)。 + +### 1.2 Underlying Problem(5-Why) + +| 層 | 結論 | +|----|------| +| Surface | 想要 agent 自動編排 skill | +| Why | 編排決策目前 100% 人工,靠人腦 + 記憶流程表 | +| Why | 編排知識鎖在人腦/文件;98 skill 組合爆炸;固定表無法因應動態情境 | +| Root | 需「宣告意圖 → 自動規劃並執行 → 持續比對現況 vs 期望直到達成」的能力——**但本專案的核心價值是 hook 強制的 fail-closed 審查 gate,編排自動化不可繞過它** | + +核心張力:**自動化編排(FR-1/2)⟷ 安全 gate 不可繞過(FR-4/NFR-1/NFR-4)**。可行性的成敗完全取決於能否在不破壞安全平面的前提下引入編排自動化。 + +### 1.3 Success Criteria(量化驗收) + +| # | 條件 | 來源 | +|---|------|------| +| SC-1 | 給定意圖能輸出「隨 repo 狀態變動」的 workflow 計畫(非固定模板) | 需求 Signal 1 | +| SC-2 | 計畫/執行含該 change-type 所需 gate,且 0 次未授權 git 變更 | 需求 Signal 2 | +| SC-3 | v1 通用 workflow 端到端跑通至少一個真實情境 | 需求 Signal 3 | +| SC-4 | 既有 auto-loop / hook 測試 0 回歸 | 需求 Signal 4 | +| SC-5 | 新增 skill 可被自動納入候選,無需改編排核心 | 需求 Signal 5 | + +## 2. 約束盤點 + +| 類型 | 約束 | 來源 | 彈性 | +|------|------|------|------| +| Technical | 安全保證錨定**單一信號** `has_code_change`,由 `PostToolUse(Edit\|Write)` 設定——**主 session 與同 cwd DW subagent 的 `Edit/Write` 皆會觸發**(Spike 1 已驗證,見 §8);lock 失敗 fallback 與 doc 對應 `has_doc_change` 同函式 | `hooks/post-edit-format.sh`(`update_change_flag "has_code_change"`;引用穩定符號名而非行號以免漂移) | **None** | +| Technical | `hooks.json` 對 `Task`/`Agent`/`SubagentStop` **零綁定**(已驗證);但 subagent 自帶一份 project hooks,其 `Edit\|Write` **會觸發** `post-edit-format.sh`(Spike 1 已驗證,見 §8)——`hooks.json` 無 `SubagentStop` 並非判據 | `hooks/hooks.json:43`(grep 無結果) | None | +| Technical | `stop-guard` 的 git 對帳是**單向 `true→false`**,永不從 git status 補回 dirty | `hooks/stop-guard.sh`「Stale-state git check」section | None | +| Technical | Dynamic Workflows 腳本本身**不能讀寫檔/跑 shell**,只能透過 subagent | Workflow 工具契約 | None | +| Technical | DW `resume` 僅同一 CC session 內有效 | Workflow 工具契約 | Low | +| Compat | 既有 stop-guard 預設 **warn 模式**(非全面 fail-closed) | `.claude/settings.json:3`、`stop-guard.sh`(`_resolve_guard_mode` 預設 `warn`) | Med(使用者偏好 warn) | +| Compat | `allowed-tools` **不可信任**為 read-only 判據(見 §3.3) | 多處 SKILL.md | None | +| Resource | DW 為付費 **research preview**,API 可能變動 | Workflow 工具契約 | Low | +| Business | 不可繞過 no-auto-commit 與既有例外 | `rules/git-workflow.md:6-9` | None | +| Business | Codex 呼叫須獨立研究 | `rules/codex-invocation.md` | None | + +### 2.1 已驗證的關鍵證據(vs 待 Spike 驗證) + +| 主張 | 狀態 | 證據 | +|------|------|------| +| stop-guard 預設 warn 模式 | ✅ 已驗證 | `.claude/settings.json:3` | +| git 對帳單向 `true→false` | ✅ 已驗證 | `hooks/stop-guard.sh`「Stale-state git check」section | +| 旗標 false 時 stop-guard 為 no-op | ✅ 已驗證 | `hooks/stop-guard.sh`「Stale-state git check」(`HAS_CODE_CHANGE="false"` 單向覆寫) | +| 僅 strict 模式 `exit 2` 封鎖 | ✅ 已驗證 | `hooks/stop-guard.sh`(state-file 模式 strict 分支 `exit 2`) | +| `post-skill-auto-loop` 只印 directive 不執行 | ✅ 已驗證 | `hooks/post-skill-auto-loop.sh:108-115` | +| `hooks.json` 無 Task/Agent/SubagentStop 綁定 | ✅ 已驗證 | `grep -niE '(task\|agent\|subagent)' hooks/hooks.json` → exit 1(檔中無此事件鍵) | +| subagent `Edit\|Write`(同 cwd、hooks 已安裝)觸發 `post-edit-format.sh` 設 `has_code_change` | ✅ 已驗證(2026-06-02 Spike 1,見 §8) | 探針:state 旗標 false→true + touched-files 收錄(`post-edit-format.sh` 指紋) | + +> 註:外部 runtime 主張(DW 16 並行/1000 總量、resume 限制、acceptEdits)來自 Claude Code「Workflow 工具契約」,非本 repo 可驗證;`hooks.json` 零綁定的實證來自 `grep -niE "(task|agent|subagent)" hooks/hooks.json`(exit 1)。 + +## 3. 既有能力盤點 + +### 3.1 既有編排機制(三種,皆非通用引擎) + +| 機制 | 性質 | 決策方式 | 證據 | +|------|------|---------|------| +| Wave-based 平行(`deep-explore`/`deep-research`) | agent 派發 + 分數 gate | `deep-explore`:每波 2-3 agent、最多 2-3 wave;`deep-research`:2-3 並行 researcher(結構不同,非 wave);subagent 預設 `Explore`,但 `deep-research` 有 `general-purpose` fallback(`:148,:180`)→ read-only 須靠 admission 強制,非天生保證 | `deep-explore/SKILL.md:56,193`、`deep-research/SKILL.md:50,250` | +| Heuristic next-step(`analyze.js`) | 16 條規則(註釋稱 16,實際 17 個 `findings.push`,第 17 個在 `:609`) | 計算 phase + 信心排序指令,**閉集合** | `skills/next-step/scripts/analyze.js:326-619` | +| 反應式狀態機(hooks + `.claude_review_state.json`) | FSM;**只提示/封鎖,不執行 skill** | stop-guard 的「下一步必跑」**寫死 3 個指令**(`MISSING` 組裝 `/codex-review-fast`、`/precommit`、`/codex-review-doc`) | `stop-guard.sh`(`MISSING` logic)、`post-skill-auto-loop.sh`(只印 `[AUTO_LOOP]` directive,不執行) | + +### 3.2 可重用基礎設施 + +| 資產 | 用途 | 證據 | +|------|------|------| +| `mkdir` lockdir + TTL | 狀態檔併發鎖 | `post-edit-format.sh:45`、`post-tool-review-state.sh:35` | +| `.blocked` sidecar(fail-closed) | 強制 strict + dirty | `stop-guard.sh`「Sidecar fail-closed marker」section | +| Context Packet(傳事實不傳結論) | 防 context 污染(行為層,無強制碼) | `deep-explore/SKILL.md:87-94` | +| `analyze.js` phase + findings | planner 的**輸入信號** | `analyze.js:215-279` | +| 15 custom agents(`performance-optimizer` 僅 `Read,Grep,Glob` 為純讀;`feasibility-analyst` 無 Edit/Write 但有 `Bash(git/codex/bash:*)` → 非嚴格 read-only,須全量盤點 mutation 能力) | 編排 worker 候選 | `agents/performance-optimizer.md:4`、`agents/feasibility-analyst.md:4` | + +### 3.3 Tech Debt / 阻礙(需繞過) + +| 問題 | 影響 | +|------|------| +| **既有 skill 已派發會 mutate 的 subagent**:`/doc-refactor` 派 `doc-refactor` agent(`agents/doc-refactor.md:4` 含 `Edit`)、`/simplify` 派 `code-simplifier`(Edit)+ `refactor-reviewer`;另 `codex-implementer` 含 `Edit,Write`(agent 存在,但目前無 skill 以 `subagent_type` 派發它) | **Spike 1(2026-06-02,§8)已證實:同 cwd subagent 的 `Edit/Write` 會觸發 `post-edit-format.sh`**——故 `/doc-refactor`、`/simplify` 在 Edit/Write 偵測路徑上**應同樣不繞 gate**(推論自共享的 subagent project-hook 語意;本探針實測為 DW `Workflow agent()`,Agent-tool 子代理建議另跑 smoke test 確認(`-uno` 降級 bug 已於 2026-06-03 修復,見 §8);殘餘風險限 subagent 內 Bash/process 改檔與 worktree isolation。DW 的 16 並行/1000 總量只是把規模放大(~111×),非新風險類別 | +| `allowed-tools` 無 Edit/Write ≠ read-only:`/smart-commit:370`(--execute 跑 git add/commit)、`/jira:102`(--execute 跑 checkout -b)、`/update-readme:52`(委派 `generate-readme-catalog.js:365` 寫 README)、`/op-session:19`、`/statusline-config:79`(無 allowed-tools 卻寫 `~/.claude/`)、`/bump-version:43`(用 Edit) | 98 skill 中 89 宣告 allowed-tools、僅 **40** 在 `allowed-tools` 含 Edit/Write(另如 `/bump-version` 無 allowed-tools 卻於 body 用 Edit)→ 天真分類器需信任其餘 **58** 個(= 98−40,含 9 個無 allowed-tools 者)| +| 安全狀態無 monotonic `safety_epoch`:review 結果未與 edit epoch 關聯 | 晚到的 review 可能覆寫已被 edit 失效的 gate(`post-tool-review-state.sh:225`) | +| 個別 review-state 寫入 lock 失敗時 **fail-open** | 與 edit/aggregate 的 sidecar fail-closed 不一致(`post-tool-review-state.sh:235`) | + +## 4. 可能方案 + +### Option A:全面採用 Dynamic Workflows(含 mutation 階段) + +**Core idea**:把通用 workflow 寫成 `.claude/workflows/*.js`,由 DW runtime 規劃並執行**全部**步驟(含改 code)。 + +**Implementation path**:1) 啟用 preview;2) 撰寫 planner workflow;3) mutation 走 DW subagent。 + +| 維度 | 評級 | 說明 | +|------|:----:|------| +| Technical Feasibility | 🟡 | 工具存在;mutation × hook 觸發在 `Edit/Write` 同 cwd 路徑**已驗證會觸發**(§8),但 Bash/process 改檔、worktree isolation 仍斷裂(`-uno` 降級已修,2026-06-03) | +| Effort | 🟡 | 建置中等,但「做到安全」極高 | +| Risk | 🔴 | linchpin(Edit/Write 偵測)已解,但 A「全面含 mutation」仍含 Bash/process + worktree + async race 多重 bypass(`-uno` 降級已修);preview API 變動;無護欄直接違反 FR-4 | +| Extensibility | 🟢 | DW 原語強大(pipeline/budget/16 並行) | +| Maintenance | 🔴 | preview churn + 兩套狀態模型 | + +**Cost**:A 全面含 mutation 仍須面對多個殘餘安全向量(Bash/process、worktree、async race;`-uno` 降級已修),且無護欄即違反 FR-4。 + +--- + +### Option B:自製 meta-orchestrator skill(僅用既有原語) + +**Core idea**:新 `/orchestrate` skill——planner agent 產出計畫,主 Claude 用 `Skill()`/`Agent()` 逐步執行。 + +**Implementation path**:1) 意圖輸入;2) planner agent 讀 `skill-catalog.yml` + SKILL.md 產計畫;3) 主 agent 逐步派發;4) hook gate 生效於 **mutation 由 `Edit/Write` 觸發時**——主 session 或同 cwd DW subagent 的 `Edit/Write` 皆會設 `has_code_change`(`post-edit-format.sh` 的 `update_change_flag "has_code_change"` 呼叫,Spike 1 已驗證,見 §8)。**注意**:`Bash` 改檔/commit/切 branch **不設旗標**(`Bash` 綁 `post-tool-review-state.sh`,只解析 review/precommit 輸出,`hooks.json:54`),不論主 session 或 subagent 皆須靠 pre/post HEAD/branch/worktree/external 檢查補強。 + +| 維度 | 評級 | 說明 | +|------|:----:|------| +| Technical Feasibility | 🟢 | 全用既有 Agent/Skill + deep-explore 模式 | +| Effort | 🟡 | 3-10 人日(planner + 計畫格式 + executor) | +| Risk | 🟡 | 安全保留**有條件**(主 session + 同 cwd subagent 的 `Edit/Write` 確定**設 change flag、失效 review state**;完整 enforcement 仍須 strict(`-uno` fix 已完成);Bash/process 例外);編排漂移仍在(行為層執行) | +| Extensibility | 🟡 | 受限 3 並行;非 runtime scheduler | +| Maintenance | 🟢 | 無 preview 依賴,模式熟悉 | + +**Cost**:「安全但不夠 k8s」——`next-step --go` 本質是 single-step dispatcher(信心 + 無 P0 才自動派發一個 top action),非 reconciler(`next-step/SKILL.md:61`)。**注意**:B/C 的「mutation 走主 agent Skill」並非自動安全——若該 Skill 內部派發會 mutate 的 subagent(如 `/doc-refactor`/`/simplify`),其 `Edit/Write` 雖會觸發 hook(Spike 1 已驗證,§8),但 subagent 內的 Bash/process 改檔仍不設旗標。故 mutation 安全須靠**明確 metadata/allowlist + pre/post 檢查**,而非「只要走 Skill」。 + +--- + +### Option C:混合兩平面(control plane / safety plane 分離)★ + +**Core idea**:宣告式「意圖編譯器」——read-only/高扇出階段路由給 DW,mutation/安全關鍵階段走既有 **hook-enforced 主 session 執行路徑**(`Edit/Write` 是會由 hook 設 change flag 的路徑:code→`has_code_change`、doc→`has_doc_change`;主 session 與同 cwd DW subagent 的 `Edit/Write` 皆觸發,Spike 1 已驗證,§8);**編排 run-state 與安全 state 分離**。注意:`Bash` 改檔/git 操作不觸發 change flag,須另以 pre/post HEAD/branch/worktree/external 檢查補強。 + +**Implementation path**: +1. **Control plane**:`/orchestrate` 把意圖編譯成宣告式 run plan,狀態存 `.claude_workflows/.json`(擁有 desired steps / deps / budget / evidence / retry / convergence)。 +2. **Safety plane**:`.claude_review_state.json` 維持 hook 獨佔;orchestrator **只讀不寫**(不得偽造 `has_code_change`/`*.passed`)。 +3. **Execution policy**:v1 DW 只跑 read-only fanout worker;mutation 由**主 agent 自身的 `Edit/Write`** 執行。Spike 1(§8)已證明同 cwd DW subagent 的 `Edit/Write` 亦會觸發 hook,故 v2 可在護欄就緒後(strict + `-uno` 已修 + 等背景結束 + 同 cwd + Edit/Write-only)開放 mutation subagent。**`Bash` 例外**:`Bash` 改檔/commit/切 branch **不設 change flag**(綁 `post-tool-review-state.sh`,只解析 review/precommit 輸出),須限縮在已知 verification/review 指令,或搭配獨立 mutation detector + pre/post HEAD/branch/worktree/external 檢查。 +4. **Admission controller**:依**明確 mutation metadata**(非 `allowed-tools`)決定哪些工作可進 DW。 + +| 維度 | 評級 | 說明 | +|------|:----:|------| +| Technical Feasibility | 🟢 (v1 read-only) / 🟡 (later mutation) | v1 用 deep-explore 既有模式 + pre/post dirty check | +| Effort | 🟡 | v1 ~3-5 人日;完整版另需 metadata 2-3 人日 + spikes + epoch | +| Risk | 🟢 (v1) / 🟡 (overall) | v1 worker fanout 無 mutation,唯一寫入為主 session 報告(受 doc hook/review 管控);preview 風險隔離在非安全半邊 | +| Extensibility | 🟢 | DW backend 證實後可擴至 16/1000;backend 可插拔 | +| Maintenance | 🟡 | 兩平面但職責清晰;共用 lock helper | + +**Cost**:兩個編排機制需維護;分類邊界需 admission controller。 + +--- + +### Option D:把 hook FSM 擴成宣告式 reconciler + +**Core idea**:泛化 `.claude_review_state.json` + stop-guard 成「desired-state 控制迴圈」(最 k8s-faithful,無新 runtime)。 + +| 維度 | 評級 | 說明 | +|------|:----:|------| +| Technical Feasibility | 🟡 | bash 限制;無平行;**hook 不執行 skill**(`post-skill-auto-loop.sh:108` 只印字) | +| Effort | 🔴 | 需把 stop-guard 寫死的 3-指令 ladder 改寫成宣告式依賴圖 | +| Risk | 🟡 | 把窄而專的安全 FSM 污染成 scheduler | +| Extensibility | 🔴 | bash、僅 tool 邊界反應、無 fanout | +| Maintenance | 🔴 | 安全 + 編排耦合的複雜 bash FSM | + +**Cost**:把反應式安全 hook 變調度器——方向性錯誤。 + +## 5. Codex 深入討論記錄 + +### 5.1 討論過程 + +| 輪 | 主題 | Codex 關鍵觀點 | +|----|------|---------------| +| 1 | 方案枚舉 + pivotal risk | 不要讓 mutation 走 DW;安全模型錨在單一 `has_code_change` 信號;repo 其實是 warn-mode 非全面 fail-closed;提出**兩平面**綜合方案 + 最小風險 v1 + 3 spikes | +| 2 | admission 信號 + 兩平面分歧風險 | `allowed-tools` 不足為 read-only 判據(6 個誤判實例);需明確 `mutation:` metadata(2-3 人日);列出 stale-read / late-overwrite / invisible-mutation / compaction split-brain 四種分歧;可重用 lockdir/sidecar 模式 | + +### 5.2 Codex 建議方向 + +- **兩平面分離**:control-plane run-state 獨立於 hook-owned safety-plane,orchestrator 只讀安全平面。 +- **最小風險 v1**:report-only `/orchestrate "audit/research topic" --dry-run --execute`——planner 讀 catalog → 計畫預覽 → read-only fanout(DW 可用則用、否則退回既有 Agent)→ pre/post 驗證 HEAD/branch/worktree/外部副作用無變更(變更則 fail-closed;非僅 porcelain)→ 報告由主 agent 寫 → 正常 `/codex-review-doc`。 +- **明確 metadata**:`mutation: none|workspace|git|external|delegated` + `requires-human-gate` + `dynamic-workflow-admissible`。 + +### 5.3 Codex 指出的風險 + +- **High bypass risk**(與 feasibility-analyst 獨立一致):DW subagent 改 code 若不觸發主 session hook,gate 靜默失效。 +- 無 `safety_epoch`:晚到 review 覆寫失效 gate。 +- compaction split-brain:`post-compact-auto-loop.sh`("Derive next required command" 的 `NEXT` 推導邏輯)不知 workflow 狀態。 +- review-state lock 失敗 fail-open 與 edit/aggregate fail-closed 不一致。 + +### 5.4 與 Claude 分析的差異 + +| 觀點 | Claude 初判 | Codex | 採納 | +|------|------------|-------|------| +| fail-closed 現況 | 假定全面 fail-closed | **實為 warn-mode**(settings.json:3) | Codex(修正假設) | +| 最 k8s 的方案 | 傾向 Option D(hook reconciler) | D 是反模式(hook 不執行 skill) | Codex(棄 D) | +| 狀態該放哪 | 想擴充既有 state 檔 | **兩平面分離**,安全平面 hook 獨佔 | Codex(更安全) | +| read-only 判據 | 想用 `allowed-tools` | 不可信,需明確 metadata | Codex(加 metadata) | +| v1 能否全 agent-driven | 想直接 agent 規劃 | **mutation 流程須先用受限模板**,agent 只參數化;read-only 子集可全 agent-driven | Codex(分階段) | + +### 5.5 整合結論 + +兩個獨立來源(Codex 2 輪 + feasibility-analyst)對 **pivotal risk 一致**:安全模型錨在單一信號、`hooks.json` 對 subagent 零綁定、git 對帳單向(皆已驗證)。**但 bypass 本身尚未實證——它是「unverified, high-risk」而非「已證實」**:`hooks.json` 無 subagent 綁定不等於證明 runtime 不傳播 `PostToolUse`(CC 文件區分 subagent frontmatter hook 與 project-level lifecycle hook),故須 Spike 1。結論(撰寫當時):**mutation 編排在 Spike 1 驗證前不可交給 DW**(→ §8:Spike 1 已於 2026-06-02 實證——DW subagent `Edit/Write` 會觸發 hook,此限制就 Edit/Write 路徑解除,須配護欄)。最務實路徑=**Option C 分階段**:v1 先做 report-only 編排器(read-only,可全 agent-driven),用 pre/post dirty check 證明零變更;mutation 編排延後到 metadata + spike + safety-epoch 就緒。這既滿足使用者「至少一版通用 workflow + 把編排交給 agent」的核心訴求(v1 的 planning 確實由 agent 動態決策),又不賭上安全模型。 + +## 6. 方案比較 + +| 維度 | A 全面 DW | B 自製 orchestrator | **C 混合兩平面 ★** | D hook reconciler | +|------|:--------:|:------------------:|:------------------:|:-----------------:| +| Technical Feasibility | 🟡 | 🟢 | 🟢 (v1) | 🟡 | +| Effort | 🟡 | 🟡 3-10d | 🟡 v1 ~3-5d | 🔴 >10d | +| Risk | 🔴 | 🟡 | 🟢 (v1) | 🟡 | +| Extensibility | 🟢 | 🟡 | 🟢 | 🔴 | +| Maintenance | 🔴 | 🟢 | 🟡 | 🔴 | +| 滿足 FR-4(不繞 gate) | ❌ | ✅* | ✅* | ✅ | +| 滿足 k8s 願景(規模/宣告式) | ✅ | ⚠️ | ✅(漸進) | ⚠️ | + +> \* B/C **有條件**滿足 FR-4:已知安全的 mutation 偵測路徑為主 session `Edit/Write` 與同 cwd DW subagent `Edit/Write`(hooks 已安裝,Spike 1 已驗證,見 §8),或經 admission 限定為 read-only 時成立。**主 session `Bash` 改檔/commit/切 branch 不設 change flag**(`Bash` 綁 `post-tool-review-state.sh`,只解析 review/precommit 輸出),須限縮在已知 verification 指令或搭配 pre/post HEAD/branch/worktree/external 檢查;經未驗證的 mutating subagent 改檔亦不保證。 + +## 7. 建議 + +**推薦:Option C(混合兩平面),分階段導入。** + +**v1 範圍(最小風險,report-only `/orchestrate`)**: +- 接受意圖 + 約束 + budget + 完成定義 → planner agent 讀 `docs/skill-catalog.yml` + SKILL.md 產**隨狀態變動**的計畫(SC-1)。 +- 計畫預覽(FR-3):選用 skill/agent、平行 shard、驗證點、停止條件。 +- read-only fanout:DW 可用則用、否則退回既有 background `Agent`(沿用 `deep-explore` fanout + 完整性 gate)。 +- **read-only admission(deny-by-default)適用於所有 fanout backend**:DW、退回的 background `Agent`、以及任何 skill 委派——只有明確標記為 read-only 的 skill/agent 才可被 fanout;未知者在所有後端一律拒絕(避免 DW 不可用時退回 Agent 仍派出 mutating agent)。 +- **無變更驗證須超越 `git status --porcelain`**:porcelain 抓不到 commit(worktree 仍乾淨)、`git checkout -b`(branch 變更)、Jira/外部副作用、寫 repo 外(如 `~/.claude/`)。v1 須檢查 `HEAD`、branch、worktree、以及宣告的外部副作用;任一變動即 fail-closed(SC-2)。 +- worker fanout 為 read-only;**最終報告由主 agent 自身 `Write` 寫入(這是主 session 的 doc mutation,會觸發 hook)→ 正常 `/codex-review-doc`**。 + +**Rationale**: +- 滿足約束:v1 的 worker fanout 不含 mutation;唯一變更是主 session 寫報告(受 hook 監看 + doc review),安全平面風險極低(SC-2/SC-4)。 +- **Risk hedge(Spike 1 已解,2026-06-02 更新,見 §8)**:Spike 1 已證明 DW subagent 的 `Edit/Write`(同 repo cwd、hooks 已安裝)會觸發宿主 hook 並設 `has_code_change`,故 mutation 編排走 DW 在 `Edit/Write` 路徑**不繞 mutation detection / change-flag 傳播**(完整 enforcement 仍須下列護欄)——mutation 平面不再被迫永久限縮於主 session。**但 mutation 編排解禁前須一組護欄**:(1) `STOP_GUARD_MODE=strict`;(2) ✅ 已修 `stop-guard.sh` 的 `-uno` 降級 bug(已改 `-uall`,2026-06-03);(3) Stop 前須等待背景 workflow/subagent 結束,否則 review/precommit 後仍可能有遲到的背景寫入(async mutation race);(4) mutation agent 限同 repo cwd(worktree isolation 待 Spike 1b);(5) mutation 限 `Edit/Write`(`MultiEdit` 須加入 matcher),**`Bash`/process 改檔仍不觸發 change flag,須搭配 pre/post HEAD/branch/worktree/external 檢查**;(6) **hook preflight**:執行前確認 `.claude/settings.json` 含已安裝的 `Edit|Write` hook、腳本可執行、`CLAUDE_PROJECT_DIR` 正確;(7) **tamper protection**:`pre-edit-guard.sh` 須防 agent `Edit/Write` 竄改 `.claude_review_state.json`、`.claude/hooks`、`.claude/settings*.json`。在護欄就緒前,v1 維持 report-only 為零前置成本的安全起點;即使退回 Option B 亦同此護欄。 +- 平衡點:核心訴求(agent 動態規劃)在 v1 即達成;高風險的 mutation 編排延後到證據就緒。 +- Codex 觀點:兩來源獨立一致——report-only 是「不賭安全模型」的唯一安全起點。 + +**Backup:Option B(C 去除 DW backend)。** +**適用情境**:若 DW preview 不可用/不穩、或團隊要求零 preview 依賴——則 v1 的 fanout 純用既有 3-並行 `Agent`,其餘設計不變(C 與 B 的 v1 執行後端本就可互換)。 + +**明確不推薦**:A(賭安全模型)、D(hook 不執行 skill,方向錯)。 + +## 8. Open Questions + +- [x] **Spike 1(linchpin,二元)— 2026-06-02 已實證解除**:用本環境 `Workflow` 工具(即 DW)在本 repo(`.claude/settings.json` hooks 已安裝)派 subagent 以 `Write` 建立 `.spike1-probe.tmp.js`。**結果:`has_code_change` false → true、`changed_files_since_review` + `session_commit_scope.touched_files` 收錄該檔、`review_phase=pending_review`、`code_review.passed=false`(invalidation 路徑相符)——即 `post-edit-format.sh:341-355`(`update_change_flag` + `_track_changed_file` + review invalidation)的指紋。** 結論:**DW subagent 的 `Edit/Write`(同 repo cwd、hooks 已安裝)會觸發宿主 PostToolUse hook,change flag 經共享 `.claude_review_state.json` 傳到主 session Stop——即 mutation 偵測 / change-flag 傳播路徑就 `Edit/Write` 成立。** ⚠️ 注意:這證明的是「偵測 + 旗標傳播」,**非端到端 fail-closed enforcement**——因 `stop-guard.sh` 當時(修復前)用 `git status --porcelain -uno`,strict Stop 對本探針的 untracked 檔仍可能回 `{"ok":true}`;完整 gate 須先修 `-uno`(✅ 2026-06-03 已修,見下方殘餘缺口)並啟用 strict。 靜態分析(`hooks.json` 無 `Task/Agent/SubagentStop` 綁定)不足以判定,因 subagent 自帶一份 project hooks,其內部 `Write` 命中 `Edit|Write` matcher;故本題必須實證。subagent 自身 transcript 看不到 hook 輸出(`post-edit-format.sh` 走 stderr、prettier `2>/dev/null`、`[AUTO_LOOP]` 僅 `Skill` 後觸發),但 state 檔確實被寫入。 + - **殘餘缺口(與 Spike 1 正交,mutation 編排前須處理)**: + - ✅ **`stop-guard.sh` 的 `git status --porcelain -uno` bug(2026-06-03 本 session 已修)**(雙方獨立實證:`-uno` 看不到新 untracked 檔,`-u` 才看得到):stop-guard 單向 true→false 對帳會把已正確設好的 flag **降級回 false** → 回 `{"ok":true}`。此 bug 對主 agent 與 subagent 一視同仁(影響所有新建 untracked 檔),是既有 fail-closed 漏洞,須改用 `-u`(更穩健可用 `--untracked-files=all`/`-uall`,涵蓋新建未追蹤目錄內的檔;`user-prompt-review-guard.sh` 已刻意避開 `-uno`)。**另 `post-skill-auto-loop.sh`(修復前)也用 `-uno`**——雖非 fail-closed Stop 的一環,但會對新建 untracked 檔抑制 auto-loop directive,已一併以同樣對帳修正(現為 `:71`/`:73` 的 `-uall`)。**修復摘要(2026-06-03)**:4 hook 改 `-uall`(`stop-guard.sh`/`post-skill-auto-loop.sh`/`post-compact-auto-loop.sh`;`user-prompt-review-guard.sh` 改 `--porcelain -uall`)+ flag-aware git stub 與回歸測試。連帶修正 reconciliation 的兩個次生 fail-open:(a) `echo | grep -q` 在 pipefail 下的 SIGPIPE 誤降級 → 改 here-string;(b) 無界 `-uall` walk → `timeout 5/3` 包覆,無 `timeout`/`gtimeout` helper 時 fail-closed skip(設 `__GIT_UNAVAILABLE__`、保留旗標)。dual-review ✅✅、precommit-fast ✅、tests 669/669。 + - ✅ **`stop-guard.sh` transcript-missing 繞過 state gate 的 P0(2026-06-03 本 session 由 Codex 獨立揪出並修)**(與 `-uno` 同屬 **fail-open** 類別):當 `transcript_path` 缺失/不可讀時,hook 在**諮詢 state 檔之前**就以 `{"ok":true,"reason":"no transcript"}` 早退;但 state 檔才是**主要 enforcement 來源(不需 transcript)**,故缺 transcript 會靜默清掉一個 pending 的 strict/dual gate → fail-OPEN。根因:此 transcript 早退邏輯早於「state-file primary」設計,改版時未同步更新。**修復**:改為三分支 fail-closed——(a) 無 state 檔且無 `.blocked` sidecar → 允許(視為無待辦;無可執行的 review state/sidecar);(b) 無 state 檔但有 `.blocked` sidecar → 一律 fail-closed 阻擋(exit 2,不分 warn/strict;與 jq-available 主路徑對 sidecar force-strict 一致);(c) state 檔存在 → 設 `TRANSCRIPT=""` 落到 review-state enforcement(`USE_STATE_FILE=true` 會跳過 legacy transcript 掃描,安全)。**測試**:`test/hooks/stop-guard.test.js` 新增 3 個 transcript-missing 回歸案——`strict+pending→block`、`strict+sidecar-only→block`(此 2 案 pin 舊 `{"ok":true}` fail-open,revert 即 FAIL)、`warn+pending→allow`(保留 warn 不過度阻擋的 over-block guard,非 mutation pin);分支 (a) 由既有 no-state allow 案覆蓋(`jq unavailable` recursion-guard 案屬另一 Nit#1,不計入本 P0)。本 session 另手動跑 dual-review ✅✅(未納入 repo artifact)。對 mutation 編排意義同 `-uno`:缺 transcript 不再能繞過 strict gate。 + - ✅ **sidecar fail-open 兩個延伸 corner(2026-06-10 本 session 由 Codex dual-review 揪出並修,secondary 該輪回 ✅ 漏掉)**:(P0-2) 上述 sidecar-only fail-closed 原僅在 transcript 缺失分支內——若 `.blocked` 在、主 state 檔不在、但 **transcript 可讀**,line 147 條件為 false → 跳過該分支 → `USE_STATE_FILE=false` → 落到 legacy transcript parsing → 可能放行;改為把 sidecar-only 檢查**上提到 transcript 處理之前**,一律阻擋。(P0-1) jq 遺失時,jq-missing 分支對 sidecar / `review_mode=dual` 原本只在 strict 才擋、warn 放行,與 jq-available 主路徑(force-strict)不一致;改為 **sidecar 一律擋 + jq-free grep 偵測 `"review_mode":"dual"` 一律擋**(single-mode warn 維持放行,與主路徑一致,不破壞既有 `jq unavailable + warn → allow` 契約)。3 個 mutation-pinned 回歸案(`jq-available sidecar-only + readable transcript`、`jq-missing sidecar`、`jq-missing dual`;revert 各自 → EXIT 0 放行 → FAIL,已實證)。 + - 安裝設定為 `STOP_GUARD_MODE=warn`;mutation 編排要真 fail-closed 須 strict(惟 sidecar 與 dual-mode gate 即使 warn 也一律 fail-closed,見上兩條)。 + - **Bash/process mutation**(subagent 內 `echo >`、`sed -i`、`git checkout`、workflow JS `fs.writeFileSync`)仍不觸發 change flag(沿用 R4 caveat),須 pre/post HEAD/branch/worktree/external 檢查。 +- [x] **Spike 1b(承 Spike 1)— 2026-06-03 以 code-reading + Codex 獨立驗證(threadId `019e8c7d`)解除,不需 live spike**: + - **問題**:`isolation:'worktree'` 的 DW agent 在獨立 worktree 改檔時,hook 會寫 worktree 自身還是主 repo 的 `.claude_review_state.json`?主 session Stop 是否看得到? + - **判定(雙方獨立一致)**:7 個 state-touching hook(見下方前置 1 完整清單)全用**相對路徑** `STATE_FILE=".claude_review_state.json"`、**不 `cd`**、**不以 `CLAUDE_PROJECT_DIR` 定位 state**(`post-edit-format.sh:43`、`stop-guard.sh:110`;`post-edit-format.sh:309` 的 `--show-toplevel` 僅正規化被編輯檔路徑)。故 worktree agent 的 `Edit/Write` 把 state 寫進 `/.claude_review_state.json`,主 session Stop 以主 repo cwd 讀 `/.claude_review_state.json` → **不同檔 → split-brain → fail-OPEN**。Codex 實測 git 語義佐證:`--show-toplevel`=worktree top、`--git-common-dir`=主 `.git`。 + - **決策**:**v1 維持「mutation agent 限同 repo cwd(禁 worktree isolation)」為硬約束**(即護欄 (4));worktree-isolated mutation 延後至前置就緒。 + - **解禁前置(雙重,路徑收斂為必要非充分)**: + 1. **Canonical state resolver**:以 `git rev-parse --path-format=absolute --git-common-dir`(fallback `CLAUDE_PROJECT_DIR` → `PWD`)解析出 `/.claude_review_state.json` 為唯一 canonical 路徑(須一次性從舊的 repo-root `.claude_review_state.json` 遷移、並更新測試/文件預期),統一 7 個 state-touching hook(`post-edit-format.sh`、`post-tool-review-state.sh`、`stop-guard.sh`、`post-skill-auto-loop.sh`、`post-compact-auto-loop.sh`、`session-init.sh`、`user-prompt-review-guard.sh`)。 + 2. **Reconciliation 須 worktree-aware 或停用**(Codex 補的耦合點):本 session 修好的 `-uall` 降級對帳本質是 **cwd-scoped**——即使統一 state 路徑,主 repo `git status` 仍看不到 linked worktree 內的 dirty 檔,會再次誤降旗 → fail-open 復活。須改為對每個登錄 worktree 跑 `git -C status --porcelain -uall`(全乾淨才降)或直接停用 true→false 降級(更 fail-closed 但跨 worktree 正確)。 + - **與 Spike 2 耦合**:canonical 共享 state 使 `mkdir` lock 與 `.blocked` sidecar 變**全域**,高並行下 lock 競爭/fail-closed 阻塞上升——故 Spike 2(16 並行 lock 競爭)成為 Spike 1b 前置的**硬依賴**,非正交。 +- [ ] **Spike 2**:isolation on/off + 16 並行 edit,確認皆命中同一 `.claude_review_state.json`、lock 競爭產生 sidecar、stop-guard 看得到。 +- [ ] **Spike 3**:把 98 skill + 15 agent 分類成 read-only / workspace / git / external / delegated / human-gate(admission metadata 盤點,~2-3 人日)。 +- [ ] 安全平面是否需加 monotonic `safety_epoch` + CAS,關聯 review 與 edit epoch? +- [ ] `mutation:` metadata schema 與 lint 強制(→ `/tech-spec`)。 +- [ ] 意圖宣告 schema 設計(→ `/tech-spec`)。 +- [ ] control plane 的 compaction resume(需 workflow resume hook,補 `post-compact-auto-loop.sh` 的 split-brain)。 + +## 9. Next Steps + +- `/tech-spec workflow-orchestration` — 針對 Option C v1(report-only 編排器)詳細設計,含兩平面狀態、admission metadata schema、計畫格式。 +- **Spike 1 + 1b 已完成、`-uno` bug 已修(2026-06-02/06-03,§8)**:mutation 編排前的順序更新為——(1) ✅ 修 `-uno` 降級 bug(已改 `-uall` + 次生 fail-open 一併修);(2) 啟用 `STOP_GUARD_MODE=strict` + hook preflight;(3) **同 cwd mutation**(無 worktree)即可在護欄就緒後解禁;(4) **worktree-isolated mutation 另需**:canonical state resolver(`--git-common-dir` 統一 7 hook)+ worktree-aware/停用 reconciliation 降級 + Spike 2(16 並行 lock 競爭,已升為硬依賴),三者就緒才設計 mutation 平面。 +- `/necessity-audit` — 對 tech-spec 做過度設計檢查(兩平面/metadata 是否必要)。 +- 參考:[1-requirements.md](./1-requirements.md)、`docs/features/multi-agent-enhancement/2-tech-spec.md`(Phase C 排除)。 diff --git a/docs/features/workflow-orchestration/1-requirements.md b/docs/features/workflow-orchestration/1-requirements.md new file mode 100644 index 0000000..5955938 --- /dev/null +++ b/docs/features/workflow-orchestration/1-requirements.md @@ -0,0 +1,138 @@ +# Requirements: Workflow Orchestration(代理式編排器) + +> **Doc class**: Lifecycle — Phase 1 requirements(依 `@rules/docs-numbering.md`)。Feature 層級的問題空間分析。**非**任務追蹤 ticket;逐任務進度追蹤見 `requests/*.md`(由 `/create-request` 建立)。 +> **Created**: 2026-05-29 +> **Updated**: 2026-05-29 +> **Tier**: standard + +## 1. Problem Statement + +目前要把專案的 98 個 skill 串成一條可用的 workflow,**完全靠人工編排**:開發者必須自己決定「先 `/req-analyze` → 再 `/tech-spec` → 再 `/codex-review-fast` → …」,並憑記憶遵循 `CLAUDE.md:13-17` 的固定流程表。這個「編排決策」是問題的核心——它鎖在人腦與文件中,無法因應動態情境,也無法隨 skill 數量成長而擴展。 + +我們要的能力:**人只聲明「意圖 + 約束 + 完成定義」,由 agent 自動推導出該跑哪些 skill、用什麼順序/並行、何時驗證、何時收斂,並持續維持「期望狀態」直到達成**——一如 k8s 把容器編排從「人工逐步部署」轉為「宣告期望狀態、由控制迴圈自動調度」。 + +### 5-Why Trace + +1. **Surface**:想要一版通用 workflow,把「skills 如何串成 workflow」交給 agent 決定,而非人手動編排。 +2. **Why(為何需要)**:每個任務都要人決定步驟順序,靠人腦 + 記憶 `CLAUDE.md` 流程表;編排是純人工活動。 +3. **Why(為何是問題)**:(a) 編排知識鎖在人腦/文件,新情境難正確編排;(b) 98 skills 組合爆炸,人記不住最佳路徑;(c) 固定流程表無法因應動態情境(這個 task 該不該跳過某步?該不該並行?);(d) 編排成果不可重用、不可隨 skill 成長擴展。 +4. **Root(成功樣貌)**:給定「意圖 + 約束」,系統能自動規劃並執行 workflow,持續比對「現況 vs 期望」決定下一步,直到完成定義被滿足——編排能力本身成為一項可被 agent 承擔的服務,而非人工負擔。 + +## 2. Goals / Non-Goals + +| Goals | Non-Goals | +|-------|-----------| +| 以「宣告式意圖」取代「命令式步驟序列」作為 workflow 的輸入 | 設計具體的編排引擎/控制器架構(屬 `/tech-spec`、`/architecture`) | +| 由 agent 動態推導 skill 組合與順序/並行(而非寫死於 skill 作者的 if/then 或文件流程表) | 取代或繞過既有 auto-loop / hook safety gate | +| 提供一版 v1「通用 workflow」作為規劃基線,涵蓋最常見任務形狀 | 為全部 98 skill 一次性補齊完整 metadata(範圍待 feasibility 評估) | +| 執行前可預覽 agent 推導出的計畫(plan preview / dry-run) | 全自動無人監督地大規模改檔(高風險,刻意排除) | +| 編排層與 skill 邏輯解耦,新增 skill 可被自動納入候選 | 決定採用 Dynamic Workflows preview 或自製(屬 `/feasibility-study`) | +| 與既有 98 skill、15 agent、hook 狀態機、Codex 規則共存 | 多人協作/跨 session 的團隊式編排(後續迭代) | + +> **與 `multi-agent-enhancement` 的關係**:該 feature(`docs/features/multi-agent-enhancement/2-tech-spec.md:10`)明確將「full agent platform (C)」排除於範圍外。本 feature 正是那個被排除的**編排平台層**,與其互補而非重疊。 + +### Adjacent Scope(與 `multi-agent-enhancement` 對照) + +| 面向 | `multi-agent-enhancement` | 本 feature(workflow-orchestration) | +|------|---------------------------|--------------------------------------| +| 核心目標 | 把既有 agent 接線到 skill(該 spec 當時 14 個;目前 repo 為 15);平行化 2 個高 ROI skill | 由 agent 動態**規劃**整條 workflow(選 skill + 編排) | +| 抽象層級 | 單一 skill 內的 agent 派發 | 跨 skill 的編排決策層 | +| 編排者 | skill 作者預先寫死 | agent 依意圖執行期推導 | +| 範圍歸屬 | Phase B0/B1 | 被該 spec 排除的 Phase C「full agent platform」 | + +## 3. Stakeholders + +| Stakeholder | Role | Key Concern | +|-------------|------|-------------| +| Plugin 使用者(開發者) | User | 少記 workflow,下「意圖」即可;計畫可預覽、可信任 | +| Plugin 維護者(本 repo 作者) | Developer | 編排核心可維護;不破壞既有 safety gate(現況預設 `STOP_GUARD_MODE=warn` 為 advisory,strict 為 opt-in fail-closed——見 §7 Constraints) | +| 既有 98 個 skill | Dependent | 被編排的對象——編排器需理解其用途/前後置/I-O 契約(`docs/skill-catalog.yml` 已編目 96 筆,其中部分有 `use_when`) | +| auto-loop / hook 狀態機 | Operator / Dependent | 既有反應式編排器(`hooks/stop-guard.sh`、`post-tool-review-state.sh`、`.claude_review_state.json` `review_phase`);新編排器須相容,避免雙頭衝突 | +| Claude 主 agent | Operator | 規劃與執行的承載者;編排狀態不應污染主上下文 | +| Codex(MCP 驗證者) | Dependent | 驗證步驟須遵守獨立研究規則(`rules/codex-invocation.md`) | + +## 4. Use Cases + +| # | Actor | Action | Expected Outcome | +|---|-------|--------|-----------------| +| UC-1 | 開發者 | 下達「完成這個 feature 並確保品質」 | 編排器自動規劃 req → spec → dev → test → review → precommit 並執行,全程過既有 gate | +| UC-2 | 開發者 | 下達「audit 整個 repo 的某主題」 | 編排器規劃 fan-out 審計 + 交叉驗證 + 匯總(report-only,不改檔) | +| UC-3 | 開發者 | 執行前想先看計畫 | 系統輸出可讀的 workflow 計畫(skill + 順序 + 平行點 + 驗證點 + 收斂條件),確認後才執行 | +| UC-4 | 維護者 | 新增一個 skill | 下次編排自動將其納入候選,無需修改編排核心 | +| UC-5 | 開發者 | 編排中途某步失敗或偏離 | 編排器重新規劃或安全停在 human gate,而非整體失敗或繞過 gate | +| UC-6 | 開發者 | 編排執行中主動中止 | 系統安全停止、不留下半完成的危險狀態(如未驗證的部分變更),並可報告已完成/未完成步驟 | + +## 5. Functional Requirements + +| ID | Requirement | Priority | Rationale | +|----|-------------|----------|-----------| +| FR-1 | 接受**宣告式意圖**輸入(目標 + 約束 + 完成定義),而非命令式步驟序列 | Must | 問題根因——把「怎麼做」從人轉移給系統 | +| FR-2 | 由 **agent 動態推導**候選 skill 集合與相依順序/並行;決策不寫死於文件流程表或 skill 作者的 if/then 分支 | Must | 現況條件呼叫皆為作者寫死(`req-analyze` SKILL.md:199、`deep-research` SKILL.md:221-238 的條件→派發、`remind` SKILL.md:76-83 偵測+:154-165 執行、`next-step` SKILL.md:60-72),非執行期適應 | +| FR-3 | 輸出可讀的 **workflow 計畫**(選用 skill + 順序 + 平行點 + 驗證點 + 收斂條件),支援執行前預覽(plan preview / dry-run) | Must | Safety——人需在執行前審視 agent 推導出的計畫 | +| FR-4 | 編排執行**必須尊重既有 safety gate**:auto-loop review/precommit、no-auto-commit、human gate——不可繞過。對會**改檔/mutating** 的編排,須在執行前確保 stop-guard 處於 fail-closed(`STOP_GUARD_MODE=strict`);否則維持 report-only(見 §7 strict-preflight constraint) | Must | 編排器**期望**達到 fail-closed 強制;但現況 stop-guard 預設 `STOP_GUARD_MODE=warn`(advisory),strict 為 opt-in,故 mutating 編排須做 strict preflight 而非假設既有預設已 fail-closed;`rules/git-workflow.md`、`rules/auto-loop.md` | +| FR-5 | 支援三種編排形狀:**循序**、**平行**(多步同時進行後彙整)、**重複直到收斂**。v1 至少涵蓋此三者(具體原語/語法屬 `/tech-spec`) | Should | 對應既有 wave-based(`deep-explore`)與 auto-loop 收斂迴圈兩種已存在形狀 | +| FR-6 | 每個被編排步驟可宣告**前置條件與完成判準**;編排器依此判斷某步是否該執行、是否已達成(如何持續比對屬 `/tech-spec`) | Should | 對應既有 `review_phase` FSM 的轉移概念;使用者 k8s 類比的核心 | +| FR-7 | 編排**中間結果與狀態獨立持有**,不污染主對話上下文 | Should | 既有痛點——`deep-explore` 已用 background agent fan-out(`SKILL.md:56-67`)+ context packet 過濾(`SKILL.md:87-94`)緩解 | +| FR-8 | 提供 v1「**通用 workflow**」起點:一份涵蓋最常見任務形狀(feature 開發、bug 修復、審計/研究)的通用編排基線 | Must | 使用者明確要求「至少先設計一版通用 workflow」 | +| FR-9 | 步驟失敗/偏離時可**重新規劃**(re-plan),而非整體失敗 | Could | v1 可選;提升韌性 | +| FR-10 | 編排成果可**保存/重用**,同類任務可重跑 | Could | v1 可選;對應 Dynamic Workflows 的「saved workflow command」概念 | +| FR-11 | 新增 skill 時,編排器能在**不修改編排核心**的前提下將其納入候選 | Should | k8s「新資源自動可被調度」;維護性關鍵 | + +Priority: Must / Should / Could / Won't (MoSCoW) + +## 6. Non-Functional Requirements + +| ID | Category | Requirement | Metric | +|----|----------|-------------|--------| +| NFR-1 | Security | 預設 plan-first / report-only;寫檔、刪除等高風險動作須經 human gate;不得執行 Claude 禁止的 git 變更操作(`add`/`commit`/`push`/`stash`/`reset --hard`/`rebase`),既有例外(`/push-ci`、`/smart-commit --execute`、`/epic-merge`)仍須經各自的使用者核可 | 0 次未授權 git 變更;高風險步驟 100% 經 gate | +| NFR-2 | Observability | 編排過程可見:哪個 skill 在跑、為何被選、目前處於哪個 phase | 每個編排決策附「選用理由」且可追溯 | +| NFR-3 | Cost | 編排規劃本身 token 成本可控、可預估;規劃階段須有可配置 token 上限,超出即 fail-closed(不靜默截斷)。分層方式(例如 S/M/L budget tier)屬 `/tech-spec` | 規劃有 token 上限;超預算時規劃明確失敗而非無限展開 | +| NFR-4 | Compatibility | 與既有 98 skill、15 agent、auto-loop hook FSM、Codex 規則共存 | 既有 auto-loop / hook 測試 0 回歸 | +| NFR-5 | Maintainability | 編排邏輯與 skill 邏輯解耦;skill 作者不需在各 skill 寫死 if/then 編排分支 | 新增情境不需改既有 skill 內文 | +| NFR-6 | Reliability | 編排可重入;中斷後狀態可恢復或安全重跑 | 中斷後不產生重複副作用,可從狀態恢復 | + +Categories: Performance, Security, Usability, Maintainability, Reliability, Scalability + +## 7. Constraints & Assumptions + +| Type | Description | Source | +|------|-------------|--------| +| Constraint | 不可繞過 git 變更禁令(完整集合與例外見 NFR-1 與 `rules/git-workflow.md:6-9`) | `rules/git-workflow.md` | +| Constraint | **現況 safety gate 預設為 advisory,非 fail-closed**:`.claude/settings.json` 設 `STOP_GUARD_MODE=warn`,且 `hooks/stop-guard.sh` 預設亦為 `warn`——此模式僅警告缺步驟但仍放行 stop;唯有 `STOP_GUARD_MODE=strict` 才硬阻擋(exit 2)。編排器**不可假設既有預設已 fail-closed**。 | `.claude/settings.json:3`、`hooks/stop-guard.sh`(`_resolve_guard_mode` 預設 `warn`、strict 才 exit 2) | +| Constraint | **Strict-preflight(mutating 編排)**:任何會改檔/mutating 的編排在執行前須確保 stop-guard 為 `STOP_GUARD_MODE=strict`(fail-closed);無法確保 strict 時,該編排須降級為 report-only(v1 預設行為,見 NFR-1),不得在 warn 模式下執行 mutating 步驟而誤以為 gate 會硬阻擋 | 衍生自 FR-4 + 現況 warn 預設 | +| Constraint | 既有 auto-loop 由 hook FSM 強制(`hooks/stop-guard.sh`、`post-tool-review-state.sh`);新編排器須相容,不可形成兩套互相衝突的編排 | 程式碼觀察 | +| Constraint | 編排中所有 Codex 驗證須遵守獨立研究規則 | `rules/codex-invocation.md` | +| Constraint | 目前無宣告式 workflow 引擎;`CLAUDE.md:13-17` 流程為 documentation-as-policy,僅供 Claude 遵循 | 程式碼觀察 | +| Assumption | 編排層可用 Claude Code 既有原語(`Skill()`、`Agent()`)組裝(16 個 SKILL.md 已引用 `Agent(`,其中 7 個用 `run_in_background` 背景派發) | 程式碼觀察 | +| Constraint | 各 skill 的**用途**可部分由 SKILL.md `description` / `docs/skill-catalog.yml`(96 筆)的 `use_when` 推導;但**前置/後置/I-O 契約 metadata 尚未系統化**,需 feasibility 階段盤點補齊(見 Open Questions) | 程式碼觀察 | +| Assumption | 使用者願意以「宣告意圖」取代「逐步下指令」 | 使用者陳述 | +| Assumption | k8s 類比(宣告期望狀態 + 控制迴圈調度)適用於 skill 編排領域 | 使用者陳述(待 feasibility 驗證) | + +## 8. Acceptance Signals + +- **Signal 1(FR-1/2/3)**:給定一段自然語言意圖,系統輸出一份「自動推導的 workflow 計畫」(含 skill + 順序 + 平行點 + 驗證點 + 收斂條件)。「非預先人工編排」的判準:相同意圖在不同 repo 狀態下,計畫會隨現況改變(例如已有 tech-spec 時跳過 `/tech-spec`),而非套用固定模板。 +- **Signal 2(FR-4 / NFR-1)**:計畫與執行包含**該 change type 所需的既有 gate**——code 變更含 `/codex-review-fast` + `/precommit`、`.md` 變更含 `/codex-review-doc`、report-only 流程可無 precommit;**mutating 編排須附 strict-preflight 證據(確認 `STOP_GUARD_MODE=strict`),否則降級為 report-only**(見 §7 strict-preflight constraint);全程無未授權 git 變更。 +- **Signal 3(FR-8)**:v1 通用 workflow 能端到端跑通至少一個真實情境(如 UC-1 或 UC-2)。 +- **Signal 4(NFR-4)**:既有 auto-loop / hook 相關測試全綠(0 回歸)。 +- **Signal 5(FR-11 / NFR-5)**:新增一個 dummy skill 後,編排候選自動納入該 skill,無需修改編排核心。 +- **Signal 6(NFR-2)**:每個編排步驟的「為何被選」可被追溯(observability)。 + +## 9. Open Questions + +- [ ] **Solution**:採用 Claude Code **Dynamic Workflows**(research preview)還是自製編排層?兩者在 safety gate 整合、resume、`acceptEdits` 上差異重大 — 建議 `/feasibility-study` +- [ ] **Solution**:宣告式 intent 的 schema / 介面如何設計? — 建議 `/tech-spec` +- [ ] 如何讓 agent 取得各 skill 的前置/後置條件與 I/O 契約?是否需為 98 個 skill 補充 metadata(範圍/成本)? — 建議 `/feasibility-study` +- [ ] 新編排器與既有 hook FSM(`stop-guard` / `review_phase`)如何整合,避免兩套編排互相衝突? +- [ ] Dynamic Workflows 的 `acceptEdits`、無中途人工輸入、session-bound resume 與本專案 human-gate 哲學(及 strict-mode opt-in fail-closed,見 §7 strict-preflight constraint)的張力如何調和? +- [ ] v1「通用 workflow」的範圍邊界:明確涵蓋哪幾種任務形狀(feature / bugfix / audit / research)? +- [ ] 保存的編排成果(FR-10)是否需要版本化?意圖 schema 演進時,舊的保存計畫如何相容? +- [ ] 使用者若不接受「宣告意圖取代逐步下指令」模型(見 Assumptions),是否需提供「逐步確認」的漸進式採用路徑? + +## 10. References + +- 既有編排器型 skill:`skills/deep-explore/SKILL.md`(wave-based agent 決策,完整性 gate :106-127;fan-out :56-67)、`skills/deep-research/SKILL.md`(3-phase + 條件 Phase 3 :221-227)、`skills/next-step/SKILL.md`(17 條 heuristic + `skills/next-step/scripts/analyze.js`,`--go` 自動派發 :60-72) +- 反應式狀態機(既有編排):`.claude_review_state.json`(`review_phase` FSM)、`hooks/stop-guard.sh`("Stale-state git check" 對帳區)、`hooks/post-tool-review-state.sh`(`update_aggregate_gate()`)、`hooks/hooks.json` +- 條件式 skill 派發(作者寫死):`skills/remind/SKILL.md:76-83`(偵測對應)+ :154-165(執行契約) +- 固定流程(documentation-as-policy):`CLAUDE.md:13-17`、`rules/auto-loop.md` +- 相鄰 feature:`docs/features/multi-agent-enhancement/2-tech-spec.md:10`(Phase C 排除)、`docs/features/proactive-suggestion/`(規劃中)、`docs/features/scenario-cookbook/`(手動查找) +- Skill 編目:`docs/skill-catalog.yml`(96 筆 catalog entries) diff --git a/docs/features/workflow-orchestration/2-tech-spec.md b/docs/features/workflow-orchestration/2-tech-spec.md new file mode 100644 index 0000000..d5f0567 --- /dev/null +++ b/docs/features/workflow-orchestration/2-tech-spec.md @@ -0,0 +1,436 @@ +# Tech Spec: Workflow Orchestration v1 — Report-only `/orchestrate`(Option C 兩平面) + +> **Doc class**: Lifecycle — Phase 2 tech spec(依 `@rules/docs-numbering.md`)。 +> **Created**: 2026-06-12 +> **Requirements**: [1-requirements.md](./1-requirements.md) +> **Feasibility**: [0-feasibility-study.md](./0-feasibility-study.md)(Option C two-plane 決策,v1 report-only) + +## 1. Requirement Summary + +### 1.1 Problem + +近百個 skill(執行期以 `docs/skill-catalog.yml` 為準,as-built 98 筆 command entries,含 `/orchestrate` 自身)的編排決策 100% 人工(人腦 + `CLAUDE.md` 流程表)。需要「宣告意圖 → agent 自動推導計畫 → 預覽 → 受控執行」的能力,**且不可繞過 hook 強制的安全 gate**(feasibility §1 核心張力)。 + +### 1.2 Goals(v1) + +| # | Goal | 來源 | +|---|------|------| +| G1 | `/orchestrate` skill:意圖 + 約束 + budget + 完成定義 → planner agent 產出**隨 repo 狀態變動**的 workflow 計畫 | FR-1/FR-2、SC-1 | +| G2 | 計畫可預覽(plan preview);執行前經人核可(human gate) | FR-3、NFR-1 | +| G3 | **Report-only 執行**:fanout worker 一律 read-only(deny-by-default admission);唯一 **user-facing repo 內容 mutation** = 主 session `Write` 報告(走既有 doc hook + `/codex-review-doc`)。control-plane run-state 寫入為 gitignored bookkeeping、對 safety plane 惰性(§3.2) | FR-4、NFR-1、feasibility §7 | +| G4 | 兩平面分離:control-plane run-state(`.claude_workflows/.json`)獨立於 hook 獨佔的 safety plane(`.claude_review_state.json`,orchestrator 只讀不寫) | feasibility Option C | +| G5 | Pre/post 無變更驗證(HEAD/branch/worktree/porcelain+content hash),任一變動 → fail-closed | SC-2 | +| G6 | 新 skill 進 `docs/skill-catalog.yml` 即自動成為規劃候選,不改編排核心 | FR-11、SC-5 | +| G7 | 三種編排形狀:循序 / 平行 / 重複直到收斂(wave + 完整性 gate) | FR-5 | + +### 1.3 Non-Goals(v1 明確排除) + +| 排除 | 理由 / 去處 | +|------|------------| +| Mutation 編排(worker 改檔) | 護欄未齊(strict preflight、Bash mutation detector、tamper protection、Spike 2/3)——見 feasibility §7 護欄 (1)-(7)、§7 OQ | +| 為全部 catalog skills + agents 補 `mutation:` metadata | Spike 3(~2-3 人日),v2 前置 | +| Hook 端強制(orchestrate 專屬 hook / sentinel 解析) | v1 純行為層 + scripted lint;不動任何 hook(SC-4 零回歸的最強保證) | +| 跨 session 編排 / 多人協作 | requirements Non-Goals | +| `safety_epoch` + CAS | feasibility §8 OQ,v2 | + +## 2. Existing Code Analysis + +### 2.1 Related Modules + +| Module | 角色 | 證據 | +|--------|------|------| +| `docs/skill-catalog.yml` | 規劃候選的單一來源(as-built 98 筆 command entries;欄位 `command`/`category`/`featured`/`public`,**`use_when` 為選填**——目前僅 19 筆有)。候選描述不足時以 SKILL.md frontmatter `description` 補(同 `scripts/generate-readme-catalog.js` 的讀取模式);**數字以執行期讀取為準,本表僅 snapshot** | 檔案本身;`/update-readme` 由它產 README catalog | +| `agents/*.md`(15 個) | fanout worker 候選;frontmatter `tools:` 為 admission 訊號之一(**不可單獨信任**,見 feasibility §3.3) | `agents/performance-optimizer.md:4`(純 `Read,Grep,Glob`)等 | +| `skills/deep-explore/SKILL.md` | 可重用 fanout 模式:wave(2-3 agent × ≤2-3 wave)、80/20 contract、context packet、完整性 gate | `SKILL.md` Wave 1/Inter-Wave 區段 | +| `skills/next-step/scripts/analyze.js` | repo 狀態信號(phase + findings)——planner 輸入的現成來源 | `analyze.js`(17 條 findings 規則) | +| `hooks/post-edit-format.sh` | Safety plane 寫入者。**關鍵事實**:change-flag 分類 regex——code 副檔名集(ts/tsx/js/…/sh/bash/zsh)與 doc 副檔名集(md/mdx)——**`.json`/`.yml` 皆不在內**,故 run-state 檔經 `Write` 寫入不觸發任何 flag | `post-edit-format.sh`(code/doc 分類 regex;引用符號語意非行號) | +| `hooks/stop-guard.sh` | 單向 true→false reconciliation(`-uall`):**untracked 且未 gitignore 的檔會讓 worktree 永不乾淨** → run-state 目錄必須 gitignore | `stop-guard.sh`「Stale-state git check」 | +| `scripts/run-skill.sh` + `test/scripts/next-step-analyze.test.js` | skill script 執行與測試慣例(`skills//scripts/*.js` → `test/scripts/-