adversarial-swift について
adversarial-swiftは、一定の合否判定を必要とするチームやエージェント向けのSwiftコードレビュー用スキルです。単一のブラインドレビュアーがコード上の証拠に基づいて判定し、修正は行いません。
主な機能
- 01単一レビュアーによるブラインド判定
- 02並行処理とタスク構造のチェック
- 03プロパティとエラー処理のチェック
- 04列挙型、API、コレクションのチェック
- 05対象を固定するレビュー手順
活用シーン
- 01マージ前のSwift PR判定
- 02エージェント作成コードの監査
- 03旧式Swiftの現代化レビュー
- 04判定と修正作業の分離
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ pproenca/ dot-skills --skill adversarial-swiftインストール後、Claude Code で/adversarial-swiftを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
gotchas.mdmetadata.jsonassets/templates/verdict.mdreferences/_sections.mdapi-autoclosure-conditional-params.mdapi-final-or-private-classes.mdapi-memberwise-init-via-extension.mdapi-never-for-nonreturning-paths.mdapi-opaque-return-over-concrete-nesting.mdapi-optionset-over-boolean-rows.mdapi-unavailable-on-fatalerror-stubs.mdcoll-count-where-over-filter-count.mdcoll-dictionary-default-subscript.mdcoll-mapvalues-value-only-transforms.mdcoll-optional-chaining-in-place-mutation.mdcoll-reduce-into-accumulators.mdconc-async-let-for-independent-awaits.mdconc-check-cancellation-in-loops.mdconc-concurrent-offload-under-mainactor-default.mdconc-resume-continuation-every-path.mdconc-taskgroup-for-dynamic-fanout.mdenum-caseiterable-over-hand-lists.mdenum-caseless-namespaces.mdenum-derived-comparable-declaration-order.mdenum-unknown-default-external-enums.mderr-callsite-location-default-args.mderr-preserve-underlying-error.mderr-result-get-over-manual-switch.mderr-rethrows-for-closure-only-throws.mderr-warning-directive-for-pending-work.md詳細
Adversarial Swift Gate
Swift 言語レビューゲート — 合否判定:単独のブラインドレビュアーサブエージェントが、敵対的な立場からこのゲートのルールに照らして成果物を判定し、すべてのルールが PASS または N/A の場合にのみ合格となります。このスキルは判定を下すものであり、成果物を修正することはありません。
ルールは、レビュアーがコード上の証拠だけで判断できるチェック項目に絞り込まれています。このゲートでは、エージェントや、熟練していても専門家ではない開発者が実際に起こしがちな失敗を判定します。たとえば、停止する継続処理、キャンセルを無視するループ、直列化された独立の await、手作業で同期された派生状態、破棄される元のエラー、陳腐化する手作業で管理されたケース一覧、ブール値パラメーターの行、O(n²) のコレクション蓄積、スライスで壊れるインデックス演算などです。
適用する場合
- Swift の差分、機能、または PR をマージする前に、助言的なフィードバックではなく、客観的な PASS/FAIL が必要な場合 — 対象は問いません。アプリのロジック、サーバーサイド Swift、CLI ツール、パッケージなどが該当します。
- エージェント(Claude、Codex)がコードを作成し、典型的な並行処理やエラー処理の失敗パターン(再開されない継続処理の分岐、キャンセル確認を装う
try? await Task.sleep、ペイロードを持たないドメインケースをスローするcatchブロック)を再現していないことや、コンパイラーが合成する機能(CaseIterable、Comparable、メンバーごとのイニシャライザー、確定初期化チェック)を手作業で実装していないことを、独立して確認したい場合。 - 並行処理導入前、または Objective-C 時代の Swift をモダナイズしており、移植した範囲を現在の言語機能(
@unknown default、rethrows、canImport、reduce(into:)、count(where:)、String(validating:))に照らして監査する必要がある場合。
Swift 以外のコードベースには適用しないでください(レビュアープロンプトの前提条件チェックにより「GATE NOT APPLICABLE」で中断されます)。また、ユーザーが判定ではなく説明やリファクタリングを求めている場合も適用しないでください。SwiftUI 固有のレビュー(状態の所有権、ビューのアイデンティティ、更新コスト、タスクのライフサイクル、リスト、アクセシビリティ)は、すべて兄弟ゲートの adversarial-swift-ui が担当します。このゲートのルールはフレームワークに依存せず、そちらと並行して適用されます。対処にプロジェクトより新しいツールチェーンが必要なルールは FAIL ではなく N/A です。レビュアープロンプトにはバージョンゲートの表が含まれています。
レビュープロトコル
以下の手順を正確に守ってください — すべてのレビューを同じ方法で実行することに、このゲートの価値があります。
ステップ 1 の前に、2 つの前提条件があります。どちらも、これに違反するとゲート群で記録された現場での失敗モードにつながるため設けられています(2026 年 7 月:変化し続ける対象に対するクリーンアップ作業としてゲートを実行した結果、差分が 33 ファイルに膨らむ間、判定が一度も出ませんでした)。
- 対象の凍結。 固定された参照 — コミット SHA、stash、または保存した差分 — のみを対象に実行し、それを対象マニフェストに記録してください。レビュー対象のコードがまだ変化している場合(作業ツリーに編集が追加され続けている、または他のエージェントが作業中である場合)は、実行しないでください。レビュー中に対象が変更された場合、その実行は無効になります。判定の代わりに
GATE VOID — target changedを報告し、新たに凍結した状態に対して再実行してください。実行したゲートは必ず、判定結果、「GATE NOT APPLICABLE」、または記録された無効判定のいずれかで終了させてください。何も報告しない状態では、レビュー済みかどうかが区別できません。 - クリーンアップではなく判定。 このゲートは、完成した作業に対する最終チェックです。「ゲートを実行して、すべて積極的に修正する」では契約が逆転し、スコープの肥大化につながることが記録されています。まず実装し、凍結してからゲートを実行してください。FAIL の場合、呼び出し側は元の対象範囲内でのみ修正し、再ゲートでは同じ対象マニフェストに対して新たなブラインドレビュアーを実行します。ラウンド間で対象範囲を広げてはいけません。新しいコードには、独自のマニフェストを持つ新しいゲート実行が必要です。
レビュー中に他のエージェントがワークスペースを変更する可能性がある場合、レビュアーはライブのチェックアウトではなく、不変のスナップショット(例:git archive <ref> <skill-dir> | tar -x -C "$TMPDIR")からルールを読み込みます。また、スキルディレクトリは読み取り専用のインフラストラクチャであり、クリーンアップや修正の対象範囲から常に除外してください。
- 対象を特定します。 レビュー対象(差分、ファイル一式、PR)を正確に特定し、参照先とパスを記録して、曖昧さのない固定された対象に対してレビューを実施します。レビュアー向けプロンプトで必要なスタック情報を記録します。Swift ツールチェーンのバージョン(
Package.swiftまたはプロジェクト設定から確認)、対象のデフォルトのアクター分離設定(デフォルトが MainActor かどうか。conc-concurrent-offload-under-mainactor-defaultの判定に使用)、および警告をエラーとして扱う設定や TODO リンターの慣例(err-warning-directive-for-pending-workの例外)を記録します。対象の説明にはリポジトリのルートを含めてください。enum-unknown-default-external-enums、prop-private-set-internal-mutation、prop-computed-over-stored-derived、enum-caseless-namespaces、api-final-or-private-classes、api-autoclosure-conditional-paramsの判定には、宣言モジュール、書き込み箇所、インスタンス化、サブクラス、呼び出し箇所を差分の範囲外まで検索する必要があります。 - ルールを読み込みます。 references/_sections.md と、
references/内のすべてのルールファイル(conc-*.md、prop-*.md、err-*.md、enum-*.md、api-*.md、coll-*.md、flow-*.mdの全ファイル)を読みます。 - レビュアー向けプロンプトを作成します。 ルール、対象、スタック情報を references/reviewer-prompt.md に記入します。作成するプロンプトは完全に自己完結している必要があります。レビュアーには会話履歴が渡されないため、プロンプト外の文脈を参照してはいけません。
- ブラインドレビュアーを1人起動します。 入力全体が作成したプロンプトだけとなる単一の Task サブエージェントを起動し、会話の文脈やコメントを添えてはいけません。
- フェイルクローズで判定します。 レビュアーの構造化出力を判定結果とし、統合ステップはありません。すべてのルールが PASS または N/A の場合に限り、総合判定を PASS とします。1つでも FAIL があればゲートは失敗です。重大度を平均したり、重み付けしたり、ルールの適用を免除したりしてはいけません。「軽微」な FAIL も FAIL です。レビュアーが「GATE NOT APPLICABLE」(Swift の対象ではない場合)を返したら、判定を出さずにそこで終了し、その旨を報告します。
- 判定結果を出力します。 assets/templates/verdict.md に記入します。FAIL の場合、レビュアーの「PASS に必要な変更」案を修正リストに集約し、それぞれの箇所を示して、カテゴリの重要度順に並べます。最終結果が FAIL のルールはすべて修正リストに含め、記載したとおりに適用できる具体的な変更を示す必要があります。レビュアーの提案が違反内容を言い換えただけの場合は、出力前にルールの Correct 例をもとに修正方法を導き出してください。修正リストは検証資料です。各 FAIL が判定可能で、修正によって解消できることを証明するものであり、作業キューではありません。各修正には、宣言された対象内で該当ルールを PASS に変える最小限の変更を記載してください。ルールを満たすために安全でない回避策(
@unchecked Sendable、try!、強制アンラップ)を用いても、そのルールは PASS になりません。対象マニフェストの範囲外でレビュアーが見つけた違反は、判定結果の範囲外の所見に記載します。将来のゲート実行に向けて報告するものであり、今回修正してはならず、判定にも含めません。
変更のない対象を再レビューした際に同じルールの判定が変わる場合、または人間が根拠を確認して判定結果を覆す場合、それはルールの判定可能性に関するバグです。gotchas.md に記録してルールを明確化し、ゲートの判定を覆してはいけません。
判定形式
レビュアーはルールごとに、PASS | FAIL | N/A、根拠(file:line または引用。PASS と FAIL の両方で必須)を返します。また、FAIL ごとに、適用後にそのルールを PASS に変える修正(違反の言い換えではなく、具体的な変更とその箇所)を示します。最終レポートは assets/templates/verdict.md に従います。
ルールカテゴリ
| # | カテゴリ | プレフィックス | 対象 |
|---|---|---|---|
| 1 | 並行処理とタスク構造 | conc- | すべての経路で継続処理を再開すること、長いループでキャンセルを確認すること(try? でラップしたスリープは対象外)、独立した await には async let を使うこと、要素ごとの非構造化スレッド生成より TaskGroup を使うこと、MainActor のデフォルト分離のもとで CPU 処理に @concurrent を使うこと |
| 2 | プロパティとリソースの不変条件 | prop- | 保存値から導出される値には計算プロパティを使うこと、内部で変更する変数には private(set) を使うこと、オブザーバーを発火させる初期化代入には defer を使うこと、後片付けを消費する discard self が deinit と重複する場合 |
| 3 | エラー処理と診断 | err- | エラーをラップする際に元のエラーを添付すること、クロージャー内でのみスローする場合は rethrows を使うこと、手動の switch より try result.get() を使うこと、デフォルト引数として #file/#line を使うこと、リリース済みコードの TODO コメントより #warning を使うこと |
| 4 | 列挙型の進化と網羅性 | enum- | 外部の列挙型には @unknown default を使うこと、手書きのリストより CaseIterable を使うこと、手書きの比較条件より自動合成された Comparable を使うこと、ケースを持たない列挙型を名前空間として使うこと |
| 5 | API と型の表面 | api- | メンバー単位の初期化子を拡張の初期化子で保持すること、ブール値の配列より OptionSet を使うこと、ネストされた具象型の戻り値より some P を使うこと、@available(*, unavailable) のスタブ、トラップのみの経路には -> Never を使うこと、条件付きパラメーターには @autoclosure を使うこと、静的ディスパッチには final/private クラスを使うこと |
| 6 | コレクションと辞書 | coll- | 辞書の default: サブスクリプト、オプショナルチェーンによるインプレース変更、mapValues()、reduce(into:)、count(where:) |
| 7 | 制御フロー、文字列、条件付きコンパイル | flow- | プレースホルダーの var より分岐内で代入する let を使うこと、enumerated() による添字アクセスより zip(indices,) を使うこと、エスケープが多いリテラルには生文字列を使うこと、信頼できないバイト列には String(validating:) を使うこと、#if os の連鎖より canImport を使うこと、1 回だけ消費する場合は Optional.take() を使うこと |
注意事項
レビュアーに依頼する前に gotchas.md を読んでください。ここには、ソースの忠実性を守るためのガード(型付き throws より型指定のない throws を推奨するなど、コミュニティの通説では否定されるものの、元の資料が推奨するパターン)と、作成時に判定困難なリスクがあると事前にフラグ付けされたルールが記録されています。これにより、レビュアーが外部のルールを持ち込まず、判定の反転が繰り返された場合にもすばやく認識できます。
関連スキル
adversarial-swift-ui— すべての SwiftUI アーキテクチャレビュー(状態、アイデンティティ、更新コスト、タスクのライフサイクル、リスト、アクセシビリティ)を担当する関連ゲートです。SwiftUI の機能では両方を実行してください。ios-taste(厳選)— このゲートでは意図的に除外している、判断を要する iOS デザインのガイダンスです。判定ではなくデザインの良し悪しを目的とする場合に使用してください。search-ios26-docs/search-macos26-docs— バージョンに関する質問がルールの判断を左右する場合に、最新 SDK での API の利用可否を確認します。adversarial-ts-patterns/adversarial-zod/adversarial-tanstack— TypeScript スタック向けの関連ゲートです。プロトコルは同じですが、ルールは異なります。
参照ファイル
| ファイル | 説明 |
|---|---|
| references/reviewer-prompt.md | ブラインドレビュアー向けの自己完結型プロンプトテンプレート |
| assets/templates/verdict.md | 判定レポートのテンプレート |
| references/_sections.md | カテゴリの定義と順序 |
| metadata.json | バージョンとソースの参照情報 |