Crowi Spec Review (敵対的・実コード裏取りの spec 検証)
核心原則
spec は、それを書いた本人(= あなた)が鵜呑みにすると診断を外す。 独立した複数観点で 実コードに当てて検証し、結論で spec を是正する。コメントを返すだけでは終わらない。
実績: editor-preview-reliability spec は「desync したクライアント Y.Doc が空 save で本文消失」を 中核に据えていたが、3観点レビューが実コード(Hocuspocus 内部 + yjs 実測)で中核診断の誤り (save はサーバ doc を読む / save 前に必ず seed 済み / CRDT 上空クライアントは消せない)を捕捉し、 真の経路(楽観ロック欠如 + yjsState 空上書き)へ是正できた。鵜呑みレビューなら通過していた。
いつ使う
- 実装(
/crowi-feature)前に、correctness critical な spec を検証したい(データ消失 / 並行 / 認証 / セキュリティ / トランザクション境界 / 移行)。 - ユーザーが「この spec で大丈夫? ちゃんとチェックして」と言った。
- spec の根本原因 / 修正の十分性に自信が持てない。
- 使わない: trivial/small で機械的な spec、すでに実装が始まっている(その場合は
/code-review)。
非交渉の3ルール(これを外すと検証にならない)
- 実コード裏取り必須 — spec の各主張を「成立 / 過大 / 誤り」で判定し、file:line を引く。
spec の言い分・記憶・推測で確定しない。必要なら依存ライブラリの実装 (
node_modules) や実測まで。 - 独立レンズ — レビューは並列・互いにブラインドの異なるレンズで走らせる(同じ観点を
複数回ではなく、根本原因 / 修正の red-team / 網羅+アーキ / implementation-ready)。
redundancy では拾えない失敗を拾う。
レンズの定義・実行は
review-document.workflow.jsが正本(下記)— prose に複製しない。 - 結論で spec を是正 — 出力はコメント集ではない。是正済み spec(改訂注記を残さず、最初から そう書かれていたかのようにクリーンに書き直す。誤り→是正の二重記載は実装者を混乱させる)か、 問題なければ「検証済み」と明示。是正内容の説明は spec ではなく会話側で返す。 ユーザーには verdict(OK / 要是正 + 何を)を一言で返す。
手順(薄い入口 — レビュー本体は crowi-design Workflow B)
この skill は入口で、レビューの実行系は crowi-design の reviewOnly Workflow に集約 されている(spec レンズは Codex ×4 + critical 固定の Claude ×1。 Codex 不可時は各レンズが Claude に fail-open)。
- spec(
.feature-state/specs/<id>.md)を読み、scope と criticality(消失/並行/認証 が 絡むか)を掴む。これは main がやる。 - reviewOnly Workflow を起動。spec-review は本質的に correctness-critical 用途なので
critical: true固定(= Codex 4 レンズ + Claude red-team レンズ 1 本):
返り値 =Workflow({ scriptPath: '.claude/skills/crowi-design/review-document.workflow.js', args: { reviewOnly: true, docPath: '.feature-state/specs/<id>.md', outputType: 'spec', slug: '<id>', critical: true, round: <毎回変える値> } }){ status: 'OK'|'ISSUES'|'DEGRADED', blocking[], preexisting[], findings[], reviewStats, reviewSummary, codexFallbacks }。findings[]は{lens, category: 'mustFix'|'carryForward'|'preexisting', text}の dedup 済み構造化指摘 (blocking[] は互換のため残る)。status: 'DEGRADED'のとき、この round の verdict を採用してはならない — 独立した codex 判定を経なかった lens (Claude fallback + 死亡) が閾値以上で、OK でも ISSUES でもその判定は縮退している。codex 復旧後に再実行するか、縮退を承知で使う場合のみacceptFallback: trueを付けて再起動する (spec を approved に上げる根拠には使わない)。reviewStats(lensesPlanned / viaFallback / deadLenses) で縮退の内訳が見える。再実行するときはargs.roundを必ず変える — Workflow は同一{scriptPath, args}をセッション全体でキャッシュするので、同じ引数のまま呼び直すと codex が復旧していても DEGRADED がそのまま返る(crowi-design のキャッシュ規則と同じ)。 - 統合(レビューのレビュー): blocking を main が判断する。レビュアーは過大主張も するので、怪しい指摘は自分で実コードに当てて再確認してから採用する。
- 是正: 採用した blocking を反映して spec をクリーンに書き直す(改訂注記・
before/after は spec に残さない。「何を・なぜ」是正したかは会話側の報告で返す)。
v2 spec を編集するときは先に
status: draft/implementation_ready: falseへ戻す。 是正後、provisional に approved/true へ変更して.claude/skills/_shared/validate-implementation-spec.shを実行する。green なら確定し、 red なら draft/false へ戻す。問題なければ現状 marker を維持する。ユーザーへ verdict を報告し、codexFallbacksが非空なら 「レンズ X は Claude fallback で実行」も明記する。
観点(定義の正本は review-document.workflow.js の spec 用 lenses)
| レンズ | 担当 | 仕事 |
|---|---|---|
| root-cause | Codex | spec の各根本原因主張を実コードで confirm/refute。誤診断を暴く。 |
| red-team | Codex | 提案 fix をすり抜けてバグ/消失が残る経路を、並行・stale・race・認証境界の具体イベント列で探す。 |
| coverage | Codex | 抜けた failure mode 列挙 + アーキ妥当性 + 過剰スコープ指摘。 |
| implementability | Codex | .claude/skills/_shared/spec-contract.md に対し path/symbol・契約・AC→test mapping を実コードで検証。 |
| claude-red-team | Claude | critical=true の追加レンズ。Codex の盲点を単一障害点にしないための保険。 |
よくある失敗
- rubber-stamp(「読んだ感じ良さそう」で通す)→ 誤診断を見逃す。実コードに当てるまで OK と言わない。
- 観点が独立していない(同じ問いを3回)→ redundancy では拾えない。レンズを変える。
- file:line を引かない→ 主張が検証されていない。根拠を必須に。
- コードでなく prose をレビュー→ spec の文章だけ読んで満足。実装・依存・実測まで。
- コメントで終える→ 是正された spec を残さない。結論は「直した spec」か明示の verdict。
- レビュアーを鵜呑み→ レビュアーも過大主張する。怪しい指摘は自分で再確認(レビューのレビュー)。
- fallback を黙る→ どのレンズが Claude fallback で走ったかを報告に書かないと、 cross-model 検証が効いていたかをユーザーが判断できない。
crowi-feature との関係
correctness critical な spec は、crowi-spec-review で是正 → /crowi-feature で実装の順。
spec が正しくなければ planner/implementer は正しい間違いを丁寧に作る。レビューは実装前に効く。