# コーディングポリシー

速さより丁寧さ、実装の楽さよりコードの正確さを優先する。

## 原則

| 原則 | 基準 |
|------|------|
| Simple > Easy | 書きやすさより読みやすさを優先 |
| DRY | 本質的な重複は排除する |
| コメント | Why のみ。What/How は書かない |
| 関数・ファイルサイズ | 行数ではなく、責務と変更理由で判断する |
| ボーイスカウト | 今回の変更が依存・影響拡大・新規露出する問題だけを改善する |
| Fail Fast | エラーは早期に検出。握りつぶさない |
| プロジェクトスクリプト優先 | ツール実行はプロジェクト定義のスクリプトを使う。直接実行は最後の手段 |
| 状態の正規化 | 同じ事実を複数の状態として保持しない |

最小とは行数の少なさではなく、要件と実在する安全条件を満たす直接的な差分を指す。将来の柔軟性や品質指標だけを理由に構造を増やさない一方、変更した信頼境界の検証、認可、後片付け、エラー処理は省略しない。

## フォールバック・デフォルト引数の禁止

値の流れを不明瞭にするコードは書かない。ロジックを追わないと値が分からないのは悪いコード。

### 禁止パターン

| パターン | 例 | 問題 |
|---------|-----|------|
| 必須データへのフォールバック | `user?.id ?? 'unknown'` | エラーになるべき状態で処理が進む |
| デフォルト引数の濫用 | `function f(x = 'default')` で全呼び出し元が省略 | 値がどこから来るか分からない |
| null合体で渡す口がない | `options?.cwd ?? process.cwd()` で上位から渡す経路なし | 常にフォールバックになる（意味がない） |
| try-catch で空値返却 | `catch { return ''; }` | エラーを握りつぶす |
| 不整合な値のサイレントスキップ | `if (a !== expected) return undefined` | 設定ミスが実行時に黙って無視される |

### 正しい実装

```typescript
// ❌ 禁止 - 必須データへのフォールバック
const userId = user?.id ?? 'unknown'
processUser(userId)  // 'unknown' で処理が進んでしまう

// ✅ 正しい - Fail Fast
if (!user?.id) {
  throw new Error('User ID is required')
}
processUser(user.id)

// ❌ 禁止 - デフォルト引数で全呼び出し元が省略
function loadConfig(path = './config.json') { ... }
// 全呼び出し元: loadConfig()  ← path を渡していない

// ✅ 正しい - 必須引数にして明示的に渡す
function loadConfig(path: string) { ... }
// 呼び出し元: loadConfig('./config.json')  ← 明示的

// ❌ 禁止 - null合体で渡す口がない
class Engine {
  constructor(config, options?) {
    this.cwd = options?.cwd ?? process.cwd()
    // 問題: options に cwd を渡す経路がない場合、常に process.cwd() になる
  }
}

// ✅ 正しい - 上位から渡せるようにする
function createEngine(config, cwd: string) {
  return new Engine(config, { cwd })
}
```

### 許容されるケース

- 外部入力（ユーザー入力、API応答）のバリデーション時のデフォルト値
- 設定ファイルのオプショナル値（明示的に省略可能と設計されている）
- 一部の呼び出し元のみがデフォルト引数を使用（全員が省略している場合は禁止）

### 判断基準

1. **必須データか？** → フォールバックせず、エラーにする
2. **全呼び出し元が省略しているか？** → デフォルト引数を削除し、必須にする
3. **上位から値を渡す経路があるか？** → なければ引数・フィールドを追加
4. **関連する値に不変条件があるか？** → ロード・セットアップ時にクロスバリデーションする

## 解決責務の一元化

設定、Option、provider、パス、権限のような「早い段階で決められる値」は、境界で一度だけ解決する。同じ値を複数の層で再解決しない。

| パターン | 判定 | 理由 |
|---------|------|------|
| 入口で解決した値を下位層へ明示的に渡す | OK | 値の出所が追える |
| 解決専用のメソッド/オブジェクトに委譲する | OK | SSOTが保たれる |
| 上位と下位で同じ設定を別々に解決する | REJECT | 優先順位のズレを生む |
| ログ表示用と実行用で別々に解決する | REJECT | 表示と挙動が乖離する |
| メイン処理内で `if` を重ねて設定解決する | REJECT | オーケストレーションに詳細が漏れる |

```typescript
// REJECT - 各層がそれぞれ設定を解決
function executeTask(options) {
  const provider = options.provider ?? loadGlobalConfig().provider;
  return runAgent({
    provider,
    stepProvider: resolveProviderForStep(options.step),
  });
}

function runAgent(options) {
  const provider = options.provider ?? resolveProviderFromConfig();
  return getProvider(provider).call();
}

// OK - 境界で解決し、以降は解決済みの値だけを使う
function executeTask(options) {
  const resolved = resolveExecutionContext(options);
  return runAgent({
    resolvedProvider: resolved.provider,
    resolvedModel: resolved.model,
  });
}

function runAgent(options) {
  return getProvider(options.resolvedProvider).call();
}
```

判断基準:
1. この値は実行前に確定できるか？ → できるなら境界で解決する
2. 同じ優先順位ロジックが2箇所以上にあるか？ → 専用メソッド/オブジェクトに集約する
3. 下位層が設定ソースそのものを知っているか？ → 解決済みの値だけを渡す
4. 表示・実行・保存で別々に解決しているか？ → 同じ解決結果を共有する

## フェーズ分離

入力の収集、解釈・正規化、実行、出力・副作用は段階で分ける。ループやメイン処理の途中で未解決の入力を受け取り直して、その場で解釈しない。

| パターン | 判定 | 理由 |
|---------|------|------|
| `RawOptions -> ResolvedOptions -> ExecutionContext` の順で段階を分ける | OK | 各段階の責務が明確 |
| ループ前に入力をまとめて正規化する | OK | 各反復が同じ前提で動く |
| ループ内で毎回 `options ?? config ?? env` を解決する | REJECT | 各反復の前提が揺れる |
| 反復ごとに入力解釈と実行ロジックが混在する | REJECT | 処理の意図が読めない |
| 1件ずつ「入力→解釈→実行→出力」を繰り返すしかない場合でも、解釈処理を専用メソッドに隔離する | OK | 最低限の責務分離を保てる |

```typescript
// REJECT - ループ内で毎回入力を解釈
for (const step of steps) {
  const provider = options.provider
    ?? step.provider
    ?? projectConfig.provider
    ?? globalConfig.provider;
  const result = await executeStep(step, { provider });
  printResult(result);
}

// OK - 先に解決し、ループ内は実行だけ
const context = resolveExecutionContext(rawOptions, steps);

for (const step of context.steps) {
  const result = await executeStep(step, {
    resolvedProvider: step.resolvedProvider,
  });
  printResult(result);
}
```

判断基準:
1. ループ内の分岐は「業務判断」か「入力解釈」か？ → 入力解釈ならループ外へ出す
2. 同じ入力解釈が各反復で繰り返されているか？ → 先にまとめて正規化する
3. 実行関数が raw input を直接受け取っているか？ → `Resolved*` 型へ変換してから渡す
4. 最適化で逐次処理が必要か？ → 解釈だけでも先に関数へ抽出する

## 抽象化

### 条件分岐を追加する前に考える

- 同じ意味・契約・変更理由を持つ条件が他にもあるか → 共通所有者または抽象化の候補
- 今後も分岐が増えそうか → 将来予測だけでは抽象化せず、実在する変更軸を確認する
- 型ごとに独立した名前付き責務があり、同じ差し替え契約を持つか → ポリモーフィズムを検討する

```typescript
// ❌ 条件分岐を増やす
if (type === 'A') { ... }
else if (type === 'B') { ... }
else if (type === 'C') { ... }  // また増えた

// ✅ 実在する差し替え契約を業務概念として表現
const paymentMethods = { card: cardPaymentMethod, bankTransfer: bankTransferPaymentMethod };
paymentMethods[type]?.pay(order);
```

### 抽象化しすぎない

抽象化は重複や変更軸を減らすだけでなく、概念に名前を与えて理解しやすくするためにも使う。ただし、数件の具体処理を「設定オブジェクト + 関数オブジェクト + ループ」に変換して、業務上の違いが読みづらくなるだけなら抽象化ではない。

| 基準 | 判定 |
|------|------|
| 少数の分岐がイベント種別・状態・業務概念ごとに異なる | `when` / `switch` で明示する |
| 設定配列・関数オブジェクトが意味・契約・変更境界を隠し、設定と実行処理を往復しないと振る舞いが分からない | REJECT。概念を命名するか明示分岐にする |
| 設定オブジェクトを読まないと副作用や削除対象が分からない | REJECT |
| Strategy が業務概念に名前を与え、複数実装の差し替え点を明確にしている | OK |
| 分岐名がドメイン概念として読める | OK |

```typescript
// ❌ 過剰抽象化 - 何が起きるかを設定配列とループの両方から読む必要がある
const operations = [
  { kind: 'create', normalize: ['owner'], remove: [] },
  { kind: 'revise', normalize: ['owner'], remove: ['legacyOwner'] },
]
for (const operation of operations) {
  applyOperation(record, operation)
}

// ✅ 分岐ごとの意味が重要なら明示する
switch (record.kind) {
  case 'create':
    normalizeOwner(record)
    break
  case 'revise':
    removeLegacyOwner(record)
    normalizeOwner(record)
    break
}
```

### 抽象度を揃える

1つの関数内では同じ粒度の処理を並べる。詳細な処理は別関数に切り出す。「何をするか」と「どうやるか」を混ぜない。

```typescript
// ❌ 抽象度が混在
function processOrder(order) {
  validateOrder(order);           // 高レベル
  const conn = pool.getConnection(); // 低レベル詳細
  conn.query('INSERT...');        // 低レベル詳細
}

// ✅ 抽象度を揃える
function processOrder(order) {
  validateOrder(order);
  saveOrder(order);  // 詳細は隠蔽
}
```

オーケストレーション関数（Step 1 → Step 2 → Step 3 と処理を並べる関数）では特に注意する。あるStepの内部に条件分岐が膨らんでいたら、そのStepを関数に抽出する。判定基準は分岐の数ではなく、**その分岐がその関数の抽象レベルに合っているか**。

```typescript
// ❌ オーケストレーション関数に詳細な分岐が露出
async function executePipeline(options) {
  const task = resolveTask(options);      // Step 1: 高レベル ✅

  // Step 2: 低レベル詳細が露出 ❌
  let execCwd = cwd;
  if (options.createWorktree) {
    const result = await confirmAndCreateWorktree(cwd, task, true);
    execCwd = result.execCwd;
    branch = result.branch;
  } else if (!options.skipGit) {
    baseBranch = getCurrentBranch(cwd);
    branch = generateBranchName(config, options.issueNumber);
    createBranch(cwd, branch);
  }

  await executeTask({ cwd: execCwd, ... }); // Step 3: 高レベル ✅
}

// ✅ 詳細を関数に抽出し、抽象度を揃える
async function executePipeline(options) {
  const task = resolveTask(options);
  const ctx = await resolveExecutionContext(options);
  await executeTask({ cwd: ctx.execCwd, ... });
}
```

### 言語・フレームワークの作法に従う

- Pythonなら Pythonic に、KotlinならKotlinらしく
- フレームワークの推奨パターンを使う
- 独自の書き方より標準的な書き方を選ぶ
- 不明なときはリサーチする。推測で実装しない

### インターフェース設計

インターフェースは利用側の都合で設計する。実装側の内部構造を露出しない。

| 原則 | 基準 |
|------|------|
| 利用者視点 | 呼び出し側が必要としないものを押し付けない |
| 構成と実行の分離 | 「何を使うか」はセットアップ時に決定し、実行APIはシンプルに保つ |
| メソッド増殖の禁止 | 同じことをする複数メソッドは構成の違いで吸収する |

```typescript
// ❌ メソッド増殖 — 構成の違いを呼び出し側に押し付けている
interface NotificationService {
  sendEmail(to, subject, body)
  sendSMS(to, message)
  sendPush(to, title, body)
  sendSlack(channel, message)
}

// ✅ 構成と実行の分離
interface NotificationService {
  setup(config: ChannelConfig): Channel
}
interface Channel {
  send(message: Message): Promise<Result>
}
```

### 依存の明示

依存は役割と型が読める形で渡す。関数型引数を一律に禁止せず、安定した業務上の役割や外部依存を匿名のコールバックとして隠していないかで判定する。

| パターン | 判定 |
|---------|------|
| 業務規則や外部照会が匿名のコールバックとして複数層を中継される | REJECT。役割に名前を付け、ポート・validator・サービス等の境界へ昇格する |
| 関数型が業務上の役割を表す名前付きの型やポートとして定義されている | OK。依存の意味と差し替え境界が読める |
| 層境界で値を局所的に補完・変換する関数を渡す | OK。責務が境界内に閉じ、別の層へ中継されない |
| ロック・トランザクション・リソースのスコープを制御するブロックを渡す | OK。依存の密輸ではなく制御構造 |

### 抽象化の漏れ

特定実装が汎用層に現れたら抽象化が漏れている。汎用層はインターフェースだけを知り、分岐は実装側で吸収する。

```typescript
// ❌ 汎用層に特定実装のインポートと分岐
import { uploadToS3 } from '../aws/s3.js'
if (config.storage === 's3') {
  return uploadToS3(config.bucket, file, options)
}

// ✅ 汎用層はインターフェースのみ。非対応は生成時にエラー
const storage = createStorage(config)
return storage.upload(file, options)
```

## 命名

名前は実装機構ではなく、実際の役割・効果を表す。読み手が名前から挙動、責務、副作用を誤読するコードは悪いコード。

| パターン | 例 | 判定 |
|---------|-----|------|
| 名前が実際の効果と矛盾 | 毎回副作用を起こすように読めるが、実体はキャッシュ済み値の取得 | REJECT |
| 副作用や実行頻度が読めない | 初期化、取得、更新のどれが起きるか名前から判断できない | REJECT |
| 近接する API と区別できない | ラップ元や委譲先と同じ名前で、どちらの責務か読めない | REJECT |
| 役割・効果で命名 | 実際に提供する値、状態変化、責務が名前から読める | OK |
| 経路・由来サフィックスに対応する別経路が実在しない | 唯一の経路なのに FromRequest / ViaApi が付く | REJECT。サフィックスを外す。対の経路が消えたら命名も追随する |
| 同種操作の並びで一部だけ命名規則が異なる | createXxxFromRequest / updateXxxFromRequest / deleteXxx | REJECT。揃える |

```typescript
// REJECT - 名前は毎回副作用を起こすように読めるが、実体はメモ化アクセサ
let resourcePromise: Promise<Resource> | null = null
function openResource(): Promise<Resource> {
  if (!resourcePromise) {
    resourcePromise = createResource()
  }
  return resourcePromise
}

// OK - 実際の役割である「利用可能なリソースの取得」を表す
function getResource(): Promise<Resource> {
  if (!resourcePromise) {
    resourcePromise = createResource()
  }
  return resourcePromise
}
```

判断基準:
1. 名前は実際の役割・効果を表しているか
2. 名前から想像される副作用、実行頻度、責務と実装が一致しているか
3. ラップ元、委譲先、近接する API と紛らわしい名前になっていないか
4. 既存コードの命名慣習と矛盾していないか

## 構造

### 分割の基準

- 独立した変更理由・責務・再利用単位を持つ定義 → 分離。小さな補助型の同居可否は、言語の慣習とファイルの凝集度で判断する

### 機能追加時の到達経路

新しい機能や画面を追加したら、実装と同じ変更セットで利用者が到達する経路も更新する。フレームワーク固有の配線方法は各ドメイン知識に従う。

| 基準 | 判定 |
|------|------|
| 新機能の実装だけ追加し、呼び出し側・導線・到達経路の更新を忘れる | REJECT |
| 利用者がどこから到達するか未定義のまま公開機能を追加する | REJECT |
| 実装追加と同じ変更セットで導線と到達経路を更新する | OK |
| 一時導線を追加した場合、その用途と除去条件を記録する | OK |

### 依存の方向

- 上位層 → 下位層（逆方向禁止）
- データを取得・更新し、失敗を処理する画面や領域が、表示側へ必要な値と操作を渡す
- 子は親の内部構造を直接変更せず、親が渡したcallback、dispatch、store、bindingなどで操作を知らせる

### 実行条件と依存条件の一致

依存やトリガーは、実際にその処理を再実行したい条件と一致させる。静的ルールや実装都合のためだけに依存を増やし、意図しない再実行を起こさない。

| 基準 | 判定 |
|------|------|
| lint や実装都合だけで依存やトリガーを増やし、再実行ループを生む | REJECT |
| 無関係な state 変化や callback 再生成で初期処理が再実行される | REJECT |
| 再実行条件が URL・フィルタ・明示的更新操作などの仕様に対応している | OK |
| 初期化と再取得のトリガーを分けて設計している | OK |

## 契約変更の整合性

型、インターフェース、API、設定スキーマ、永続化形式、イベント、ファイル形式など、他のコードや利用者が依存する契約を変更する場合は、定義側・生成側・利用側・検証側を同じ変更で整合させる。

| 基準 | 判定 |
|------|------|
| 契約定義だけを変更し、呼び出し元・生成元・読み取り側を更新していない | REJECT |
| 新しい引数・フィールド・設定値を追加したが、利用側へ値を渡す経路がない | REJECT |
| 文書化されたスキーマや設定形式に存在しないフィールド・値を使っている | REJECT |
| モック、fixture、テストデータが実際の契約と異なる形を返している | REJECT |
| 契約変更と呼び出し元・生成元・テスト更新が同じ変更で行われている | OK |

## 状態管理

- 状態は使う場所に閉じ込める
- 呼び出し元から受け取った値や共有状態・外部公開値を直接変更せず、値を持つ側が用意した更新方法を使う
- 関数やテストが内部で新規作成し、外部へ公開しない局所的な蓄積用コレクションは、その所有範囲内で変更してよい
- 子は親や別の部分木のstateを直接変更せず、公開callback、dispatch、store、bindingなどで操作を知らせる
- stateを持つ側から表示までの値と操作の流れを読めるようにする
- 正規状態から計算できる派生値を、独立した状態として保持しない
- 複数フィールド間に常時同期が必要なら、状態モデルを見直す

| 基準 | 判定 |
|------|------|
| ある状態から常に計算できる値を別の状態として保持している | REJECT |
| 複数の状態間に「常に一致すべき」不変条件がある | REJECT |
| 保存・送信・差分判定が派生値に依存している | REJECT |
| 正規状態だけを保持し、派生値は利用箇所や境界で生成している | OK |

## 入力集合と生成物の分離

処理が探索する入力と、その処理が書き出す生成物を暗黙に同じ集合へ混在させない。生成物を後続処理の入力にする場合は、反復境界、終了条件、重複排除を明示する。

| 基準 | 判定 |
|------|------|
| ディレクトリへ書き込んだ後、同じ範囲を無条件に走査して生成物も入力として処理する | REJECT |
| 一時ファイルや中間生成物が広すぎる glob・列挙に入り、同じ変換や検証を再適用される | REJECT |
| 生成物が同じ処理へ再注入されるが、反復境界、終了条件、重複排除が定義されていない | REJECT |
| 副作用の前に入力集合を確定する、または入力と出力の場所・種別を分離する | OK |
| 生成物を意図的に次の反復へ渡し、終了条件と冪等性を振る舞いとして検証している | OK |

## 未完成コード

TODO/FIXME、空実装、スタブ、コメントアウトされた旧実装を、完成した実装の代わりに残さない。今必要な処理は今実装し、不要な処理は削除する。

| 基準 | 判定 |
|------|------|
| 認可、バリデーション、永続化、エラー処理を TODO で先送りしている | REJECT |
| 空実装、`return null`、`pass`、コメントアウトされた旧実装が残っている | REJECT |
| 外部制約により今は実装できず、その制約と TODO/FIXME を削除できる条件が明記されている | 許容 |
| 将来拡張のためだけの TODO | REJECT |

## 機密情報の扱い

パスワード、トークン、APIキー、セッションID、認証ヘッダ、個人情報などの機密情報をコード、ログ、エラーレスポンス、テスト出力に露出させない。

| 基準 | 判定 |
|------|------|
| 機密情報をソースコードや設定ファイルにハードコードしている | REJECT |
| ログ、例外、エラーレスポンス、テストスナップショットに機密情報が含まれる | REJECT |
| リクエストやDTO全体をログ出力し、機密フィールドが混入しうる | REJECT |
| 機密フィールドを明示的に除外またはマスクしている | OK |
| デバッグログに個人情報が含まれるが本番では無効化される想定 | 警告。設定ミスで露出しないか確認 |

## エラーハンドリング

同じ外部契約へのエラー変換は、その契約を所有する境界へ集約する。異なる操作やプロトコルのエラー契約まで単一のglobal handlerへ集約しない。

```typescript
// ❌ 同じHTTPエラー変換をendpointごとに重複
async function createUser(data) {
  try {
    const user = await userService.create(data)
    return user
  } catch (e) {
    console.error(e)
    throw new Error('ユーザー作成に失敗しました')
  }
}

// ✅ 同じHTTP契約を所有するadapter境界で変換
async function createUser(data) {
  return await userService.create(data)  // 例外はそのまま上に投げる
}
```

### エラー処理の配置

| 層 | 責務 |
|----|------|
| ドメイン/サービス層 | ビジネスルール違反時に例外をスロー |
| Application層 | 例外を握りつぶさず、必要な補償や再試行だけを明示的に扱う |
| Adapter境界 | 例外をプロトコル固有のレスポンスや表示に変換 |
| グローバルハンドラ | 認証、入力検証、共通エラー形状など横断的な例外だけを処理 |

### HTTP 例外変換

HTTP adapter / controller / handler は、endpoint ごとに例外を HTTP 表現へ変換しない。例外から HTTP ステータス、レスポンス本文、ヘッダへの変換は HTTP adapter 境界の例外変換レイヤへ集約する。

| 基準 | 判定 |
|------|------|
| 各 endpoint が同じ try-catch や wrapper で例外を HTTP 表現に変換している | REJECT。HTTP adapter 境界の例外変換レイヤに分離 |
| 特定 API 固有の例外変換を全 API 共通の global handler に追加する | REJECT。対象 API の境界に閉じる |
| 認証、入力検証、共通エラー形状など真に横断的な変換だけを global handler で扱う | OK |
| 例外型から HTTP 表現への変換が application/domain 層にある | REJECT。HTTP adapter 境界で扱う |

## 変換処理の配置

変換メソッドはDTO側に持たせる。

```typescript
// ✅ Request/Response DTOに変換メソッド
interface CreateUserRequest {
  name: string
  email: string
}

function toUseCaseInput(req: CreateUserRequest): CreateUserInput {
  return { name: req.name, email: req.email }
}

// Controller
const input = toUseCaseInput(request)
const output = await useCase.execute(input)
return UserResponse.from(output)
```

変換の方向:
```
Request → toInput() → UseCase/Service → Output → Response.from()
```

## 共通化の判断

同じ意味・契約・変更理由を持つ2個目の実装を確認した時点で、共通所有者への集約を判断する。同じ正本・不変条件・変更理由を共有することを実コードで確認できれば、直接の参照・呼び出し関係は必須ではない。一方だけの変更で契約が乖離するため、両方が今回の変更契約の影響経路に参加する。

同じ汎用APIを使う、見た目や引数構造が似るという理由だけでは同一契約にしない。外部I/Oとドメイン、PolicyとMechanism、公開契約と内部実装のような境界が現在の変更に実在する場合は、1個目でも境界を所有する抽象化を検討できる。将来のバリアント予測だけでは抽象化しない。

### 共通化すべきもの

- 同じ正本から導かれ、同じ変更理由を持つロジック
- 同じ外部契約を実装するバリデーションや変換
- 片方だけの変更で契約不整合になるUIパターン

### 共通化すべきでないもの

- ドメインが異なる重複（例: 顧客用バリデーションと管理者用バリデーションは別物）
- 表面的に似ているが変更理由が異なるコード
- 共通ロジックが既に共通化（注入可能な依存等）されている場合の、呼び出し側の配管コード（例: データ取得 → 共通バリデータに渡す、の呼び出しコードが複数箇所で同じでも、バリデータ自体が共通化されていれば呼び出し側は重複ではない）
- 「将来使うかも」という予測に基づくもの

```typescript
// ❌ 過度な汎用化
function formatValue(value, type, options) {
  if (type === 'currency') { ... }
  else if (type === 'date') { ... }
  else if (type === 'percentage') { ... }
}

// ✅ 用途別に関数を分ける
function formatCurrency(amount: number): string { ... }
function formatDate(date: Date): string { ... }
function formatPercentage(value: number): string { ... }
```

## 同一実装の別名関数（DRY 違反）

AIは同じ処理を異なる関数名で複数定義しがちである。

| パターン | 例 | 判定 |
|---------|-----|------|
| 同一実装の別名関数 | `copyFacets()` と `placeFacetFiles()` が同じ処理 | REJECT |
| 引数シグネチャが同一で本体も同一 | 2つの関数が同じパラメータを受け取り同じ処理を行う | REJECT |
| public メソッドが同一シグネチャの private メソッドへ1:1委譲し、固有の公開契約・登録・デコレーター・認可・計測・副作用を持たない | 内部別名が実装へそのまま委譲する | REJECT。委譲先を昇格して統合 |
| 1:1委譲する public メソッドが、安定 API またはフレームワーク登録・デコレーター・認可・計測の入口である | 外部契約を維持する公開境界が実装へ委譲する | OK。境界を維持し、役割を明示する |

```typescript
// REJECT - 同じ実装が別名で存在
function copyFiles(src: string, dest: string): void {
  for (const f of readdirSync(src)) {
    copyFileSync(join(src, f), join(dest, f));
  }
}
function placeFiles(src: string, dest: string): void {
  for (const f of readdirSync(src)) {
    copyFileSync(join(src, f), join(dest, f));
  }
}

// OK - 1つの関数にまとめる
function copyFiles(src: string, dest: string): void {
  for (const f of readdirSync(src)) {
    copyFileSync(join(src, f), join(dest, f));
  }
}
```

検証アプローチ:
1. 新規追加された関数の本体が、既存関数と同一または酷似していないか確認
2. 同じファイル内の関数同士、および同じモジュール内の関数同士を比較
3. 重複があれば1つにまとめ、呼び出し元を統一

## Stateful Regex の危険なパターン

`/g` フラグ付き正規表現はステートフル（`lastIndex` を保持する）。モジュールスコープに定義して `test()` と `replace()` を混用すると予期しない結果になる。

| パターン | 例 | 判定 |
|---------|-----|------|
| モジュールスコープの `/g` 正規表現を `test()` で使用 | `const RE = /x/g; if (RE.test(s)) ...` | REJECT |
| `/g` 正規表現を `test()` と `replace()` で使い回し | `RE.test(s)` の後に `s.replace(RE, ...)` | REJECT |

```typescript
// REJECT - モジュールスコープの /g 正規表現を test() で使用
const PATTERN = /\{\{facet:(\w+)\}\}/g;
function hasFacetRef(text: string): boolean {
  return PATTERN.test(text);  // lastIndex が進み、次回の呼び出しで結果が変わる
}

// OK - test() には /g を付けない、または関数内で new RegExp
const PATTERN_CHECK = /\{\{facet:(\w+)\}\}/;  // /g なし
const PATTERN_REPLACE = /\{\{facet:(\w+)\}\}/g;  // replace 用は /g
function hasFacetRef(text: string): boolean {
  return PATTERN_CHECK.test(text);
}
function replaceFacetRefs(text: string): string {
  return text.replace(PATTERN_REPLACE, ...);
}
```

検証アプローチ:
1. モジュールスコープの正規表現に `/g` フラグがあるか確認
2. `/g` 付き正規表現が `test()` で使われていないか確認
3. 同一の正規表現が `test()` と `replace()` の両方で使われていないか確認

## 禁止事項

- **フォールバックは原則禁止** - `?? 'unknown'`、`|| 'default'`、`try-catch` で握りつぶすフォールバックを書かない。エラーは上位に伝播させる。どうしても必要な場合はコメントで理由を明記する
- **説明コメント** - コードで意図を表現する。What/How のコメントは書かない
- **未使用コード** - 「念のため」のコードは書かない
- **未完成コード** - 必要な処理を TODO/FIXME で先送りせず、空実装やコメントアウト旧実装を残さない
- **any型** - 型安全を破壊しない
- **共有値の直接変更** - 呼び出し元所有・共有・外部公開される値を直接書き換えず、新しく作るか、値を持つ側の更新方法を使う
- **console.log** - 本番コードに残さない
- **機密情報の露出** - ハードコード、ログ、エラーレスポンス、テスト出力に機密情報を含めない
- **契約文字列のハードコード散在** - ファイル名・設定キー名は定数で1箇所管理。リテラルの散在は禁止
- **各所でのtry-catch** - 同じ外部契約のエラー変換は、その境界の所有者へ集約する。異なる操作のエラー契約を1つのglobal handlerへ混ぜない
- **内部実装のパブリック API エクスポート** - 公開するのはドメイン操作の関数・型のみ。インフラ層の関数や内部クラスをエクスポートしない
- **リファクタリング後の旧コード残存** - 置き換えたコード・エクスポートは削除する。明示的に残すよう指示されない限り残さない
- **安全機構を迂回するワークアラウンド** - 根本修正が正しいなら追加の迂回は不要
- **プロジェクトスクリプトを迂回するツール直接実行** - `npx tool` 等の直接実行は lockfile を迂回しバージョン不一致を起こす。プロジェクトが定義したスクリプト（npm scripts, Makefile 等）を探して使う。見つからない場合のみ直接実行を検討する
- **配線忘れ** - 新しいパラメータやフィールドの producer、伝播、consumer が同じ契約を共有しない状態は禁止。呼び出し元が値を渡さず `options.xxx ?? fallback` が常用される状態も配線済みとみなさない
- **冗長な条件分岐** - if/else で同一関数を呼び出し引数の差異のみの場合、三項演算子やスプレッド構文で統一する
