> ## Documentation Index
> Fetch the complete documentation index at: https://adcp-docs-ja.pier1.co.jp/llms.txt
> Use this file to discover all available pages before exploring further.

# Specification Guidelines

# AdCP 仕様ガイドライン

このドキュメントは AdCP 仕様を維持するための設計原則とルールを示します。複数のプログラミング言語で一貫性・明確さ・実装容易性を確保することが目的です。

## 型命名の原則

### 型名の再利用禁止

**ルール**: コンセプトが異なるのに同じ enum 名やフィールド名を使わないでください（文脈が違っても不可）。

**理由**: TypeScript/Python/Go などの型ジェネレータは、同名で値や意味が異なると衝突し、エイリアスや深い import といった回避策を強要します。

**問題の例**:

```json theme={null}
// ❌ BAD: 意味が異なる "Type" enum が複数
// asset-type.json
{ "type": "string", "enum": ["image", "video", "html"] }

// format.json
{ "type": "string", "enum": ["audio", "video", "display"] }

// 結果: Python では Type/Type1/Type2 生成、あるいはアルファベット順の先勝ち
```

**解決策**: ドメインに即した意味的な名前を使います。

```json theme={null}
// ✅ GOOD: コンセプトごとに異なる enum 名
// asset-content-type.json
{ "type": "string", "enum": ["image", "video", "html"] }

// format-category.json
{ "type": "string", "enum": ["audio", "video", "display"] }

// 結果: Python では AssetContentType と FormatCategory を生成
```

### セマンティックなフィールド名

フィールド名は「何を表すか」を示します。汎用的なカテゴリ名は避けてください。

**例:**

* ✅ `format_category` - どのチャネル/タイプのフォーマットかが明確
* ❌ `type` - 何のタイプか不明
* ✅ `asset_content_type` - アセットが含むコンテンツの種類を示します
* ❌ `asset_type` - まだマシだが他の type フィールドと衝突しうる

### Enum の統合

同じ概念が複数箇所に異なるサブセットで現れる場合:

1. **単一の正準 enum** を作り、取りうる値をすべて含めます
2. すべてのスキーマで `$ref` を用いて参照します
3. サブセットの期待値は必要に応じてフィールド説明に記載します

**例:**

```json theme={null}
// enums/asset-content-type.json - 単一の真実のソース
{
  "$id": "/schemas/v2/enums/asset-content-type.json",
  "type": "string",
  "enum": ["image", "video", "audio", "text", "html", "javascript", ...]
}

// brand-manifest.json - フル enum を参照
{
  "asset_type": {
    "$ref": "/schemas/v2/enums/asset-content-type.json",
    "description": "Type of asset. Note: Brand manifests typically contain basic media assets (image, video, audio, text)."
  }
}

// list-creative-formats-request.json - フル enum を参照
{
  "asset_types": {
    "type": "array",
    "items": {
      "$ref": "/schemas/v2/enums/asset-content-type.json"
    }
  }
}
```

**メリット:**

* 型ジェネレータが単一で一貫した型を生成します
* API は任意の値でのフィルタや指定を許容します
* 新しい値の追加は非破壊的です
* 典型的な使い方をドキュメントで明示しつつ能力を制限しません

## Specialist Module Naming

### Core Principle

スペシャリストモジュール名は、教えられている**技術的能力** — 実践者が何を検証、解決、または運用するか — を反映しなければならず、ビジネスやマーケティングのカテゴリではありません。

「Brand」というタイトルのモジュールは曖昧です: ブランドセーフティポリシー、ブランドアイデンティティスキーマ検証、それともブランドキャンペーン戦略を教えるのか？「Brand Identity & Verification」というタイトルのモジュールは、開発者に何をできるようになるかを正確に伝えます。

### Naming Consistency

モジュール名は、それが現れる 4 つのすべてのサーフェスで一貫していなければなりません。

1. **ページタイトル** — モジュールの `.mdx` ファイルの `title:` フロントマター
2. **バッジ** — `adcp_specialist_*` 資格情報サフィックス（例: `adcp_specialist_signals`）
3. **サイドバーナビゲーション** — `sidebarTitle:` フロントマター
4. **スペシャリスト概要表** — 認定概要ページの行

これらのいずれかが乖離すると、1 つのサーフェスを見る実装者は、別のものを読む人とは異なるメンタルモデルを形成します。4 つすべてを同期に保ちます。

### Good vs. Bad Names

| Avoid | Prefer                        | Why                                                 |
| ----- | ----------------------------- | --------------------------------------------------- |
| Brand | Brand Identity & Verification | 「Brand」はマーケティングと読める。モジュールはスキーマ検証とアイデンティティ解決を教える     |
| Ads   | Creative Asset Management     | 「Ads」は広すぎる。モジュールはクリエイティブフォーマット、アセットパイプライン、承認フローをカバー |
| Data  | Signals & Audience Activation | 「Data」は汎用的。モジュールはシグナルディスカバリー、プライバシー制御、有効化ループを教える    |

### Naming Checklist

新しいスペシャリストモジュールを提案する前に:

* [ ] 名前はビジネスドメインではなく技術的ワークフローを記述しているか？
* [ ] AdCP に不慣れな開発者が、名前だけからモジュールが何を教えるか理解できるか？
* [ ] 名前はページタイトル、バッジ、サイドバー、概要表で一貫しているか？
* [ ] バッジサフィックス（`adcp_specialist_*`）は資格情報のコンテキストで自然に読めるか？

## Enum 設計

### Enum ファイル構成

すべての enum は `/schemas/v2/enums/` に置き、意味がわかる名前にします。

```
/schemas/v2/enums/
  asset-content-type.json      # このアセットは何か？
  format-category.json         # この広告はどこに表示されるか？
  pricing-model.json           # どのように課金されるか？
  media-buy-status.json        # バイの状態は？
```

### Enum の命名規則

* 分類対象を説明する **名詞句** を使います
* ファイル名は **kebab-case**
* 生成される型名は **PascalCase**（AssetContentType, FormatCategory）
* 修飾子のない "type" "kind" "status" のような汎用語は避けてください

### 新しい Enum を作るべきとき

以下に該当する場合は専用の enum ファイルを作成します:

* 値が複数スキーマで再利用されます
* 値が閉じた選択肢です
* プロトコルにとって基本的な概念です
* 型安全性が実装者の利便につながる

### Enum membership — when to add a value

*既存の* enum に値を追加するのはキュレーションの決定であり、デフォルトではありません。enum は、実在する共有セマンティクスの厳選された名簿であり — すべてのベンダーや統合のレジストリではありません。値は、**すべて**が成り立つときにメンバーシップを獲得します。

* **公開されている** — バイヤーごとや統合ごとの形状ではなく、安定した定義を持つ外部文書化された概念を名付けている。
* **ネイティブにサポートされている** — 少なくとも 1 つの実在する実装者が、値ごとのビスポークマッピングなしに直接処理する（`feed_format` については、セラーが `feed_field_mappings` なしにネイティブにパースする）。
* **共有された需要** — 複数のプロデューサー**かつ**複数のコンシューマーにわたって関連する（単一の双方向統合のためのブランディングではなく、共有された方言）。

既存の値の実質的な**方言**は、その差異が親の値のコンシューマーに誤処理させる場合にのみ、独自の値を獲得します — 名前が変更された主キー、複合エンコードされたフィールド、または親が任意として扱うが方言が要求するフィールド。表面的または追加的-任意の差異はそうではありません。親の値を使います。概念がこれらのテストに失敗する場合、enum 値を作成するのではなく、スキーマの既存の拡張パス（`custom` + マッピング、または `ext`）を通じてモデル化します。

これは [Platform Agnosticism](#platform-agnosticism) とは異なります: `feed_format` 値はベンダーの*公開された仕様*を正当に名付けます（値が仕様**そのもの**）が、プラットフォーム非依存性は一般的概念の*ベンダー固有バージョン*を禁止します。

**ワークド例 — `feed_format`（[#3456](https://github.com/adcontextprotocol/adcp/issues/3456)）。** `tiktok_shop`、`pinterest_catalog`、`openai_product_feed` は適格です: 公開され、Google Merchant Center 由来のフィード方言で、実在するセラーがネイティブにパースし、それぞれ厳格な GMC パーサーが誤処理するデルタを持ちます。公開されネイティブにパースされる仕様のないフィードは `custom` + `feed_field_mappings` を使います。

## フィールド設計

### 判別共用体（Discriminated Unions）

オブジェクトに複数の形があり得るときは、明示的な判別フィールドを使います。

```json theme={null}
{
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "delivery_type": { "type": "string", "const": "url" },
        "url": { "type": "string" }
      },
      "required": ["delivery_type", "url"]
    },
    {
      "type": "object",
      "properties": {
        "delivery_type": { "type": "string", "const": "inline" },
        "content": { "type": "string" }
      },
      "required": ["delivery_type", "content"]
    }
  ]
}
```

これにより TypeScript の型絞り込みや他言語でのパターンマッチが正しく機能します。

### 過度なサブセット制限を避ける

技術的理由がない限り、リクエストスキーマで enum 値を不自然に絞り込まないでください。

* ❌ `asset_types` フィルタを「よく使う 7 値」に限定します
* ✅ すべての asset content type を許容し、利用者が自由にフィルタできるようにします

特定値が稀なら説明で触れればよいです。使用を阻害してはいけません。

## スキーマ参照

### `$ref` を使うとき

`$ref` を使うべきもの:

* enum 値（常に）
* 複数箇所で使うコアデータモデル
* 繰り返し使う複雑なネストオブジェクト

`$ref` を避けるもの:

* 一度きりのシンプルなインラインオブジェクト
* リクエスト固有のパラメータ
* 強い文脈依存の構造

### 参照パス

すべての `$ref` パスはスキーマルートからの絶対パスにします。

```json theme={null}
// ✅ GOOD: 絶対パス
"$ref": "/schemas/v2/enums/asset-content-type.json"

// ❌ BAD: 相対パス
"$ref": "../../enums/asset-content-type.json"
```

## Platform Agnosticism

**RULE**: 規範的スキーマの**フィールド名**は、一般的概念の特定ベンダーバージョンを表してはなりません（MUST NOT）。プラットフォーム固有のフィールドは `ext.{vendor}` の下に属します。

**Why**: AdCP はプロトコルであり、プラットフォームではありません。スキーマのトップレベルの `google_campaign_id` や `ttd_line_id` という名前のフィールドは、1 つのベンダーのデータモデルを仕様に焼き付け、ロックインを生みます。プロトコルがオープン標準として信頼できるのは、その規範的フィールドサーフェスがベンダー中立である限りにおいてです。

**How**: ベンダー固有のフィールドは `ext.{vendor}` 名前空間（スキーマ: `/schemas/core/ext.json`、ソース: `static/schemas/source/core/ext.json`）に属します。`ext` は `additionalProperties: true` です — 名前空間化は JSON スキーマではなくレビューによって強制される慣例です。

```json theme={null}
// ❌ BAD: vendor name in a normative field (a general concept dressed up as a vendor)
{
  "google_campaign_id": "abc123"
}

// ✅ GOOD: vendor-specific under ext
{
  "ext": {
    "gam": { "campaign_id": "abc123" }
  }
}
```

### External system identifiers

**正準の外部識別子空間**を参照する名前は、フィールド名と enum 値の両方で正当です。区別は「ベンダートークンを含むか」ではなく「*プロトコルがすでに一般的概念を持つもののそのベンダーバージョン*を表すか」です。

* `google_campaign_id`（bad） — プロトコルがすでにモデル化する概念（`media_buy_id`）のベンダー固有 ID。`ext.gam` に移動。
* `apple_podcast_id`（正当） — 特定の Apple Podcasts アイテムの正準識別子。マップする一般的概念がない。Apple Podcasts 名前空間が*その*名前空間。
* `nielsen_dma`（正当） — 業界標準の地理区分。「Nielsen 版の地理」ではない。

正当なパターンの既存の例:

* 配信プラットフォーム識別子タイプ: `distribution-identifier-type.json` の `amazon_music_id`、`roku_channel_id`（enum 値）
* フィードフォーマット: `brand.json` の `google_merchant_center`、`facebook_catalog`（enum 値） — 多くのサードパーティが実装する広く採用されたオープン交換フォーマット
* 測定/データ識別子: `get-adcp-capabilities-response` の `nielsen_dma`（フィールド名）
* プラットフォーム ID: `apple_podcast_id`、`apple_id`（フィールド名）

適用するルール: 名前が「AdCP がモデル化するもののどのベンダー相当バージョンか？」を尋ねるなら（bad — `ext` を使う）、拒否。名前が「どの外部定義のシステム/フォーマット/識別子空間か？」を尋ねるなら（正当）、許可。フィールド名を許可するとき、`tests/check-platform-agnostic.cjs` の `FIELD_ALLOWLIST` に 1 行の正当化とともに追加します。enum 値を許可するとき、`ENUM_VALUE_ALLOWLIST` にパス修飾されたエントリと 1 行の正当化とともに追加します。

### Reviewer checklist

* 名前が `{vendor}_{general_concept}`（例: `google_campaign_id`、`ttd_line_id`）である新しいトップレベルまたはリクエスト/レスポンスフィールドを拒否。
* 外部定義のシステム、フォーマット、または識別子空間を名付ける enum 値を受け入れ。
* **例ブロック**（メールアドレス、サンプル ID）のベンダー名は問題ありません。
* 不確かなとき、尋ねます: 「このフィールドまたは値は*プロトコルがすでに一般的概念を持つもののあるベンダーのバージョン*を表すか？」。もしそうなら、`ext.{vendor}` の下に属します。

## Reserved SDK-Internal Keys

**RULE**: トップレベルキー `ctx_metadata` は、SDK やプラットフォームアダプターが呼び出し間で運ぶ必要があるがバイヤーが見たり依存したりしてはならない（MUST NOT）状態のアダプター内部ラウンドトリップキャッシュとして、AdCP リソースオブジェクト上で予約されています。アダプターは、ワイヤー送出前に任意のペイロードから `ctx_metadata` を取り除かなければなりません（MUST）。取り除き時にキーが存在し空でなかった場合、アダプターは、オペレーターがカスタムアダプターコードとの偶発的なキー衝突を検出できるよう、warning レベルのログエントリを発しなければなりません（MUST）。（空または不在の `ctx_metadata` はサイレント — 空でない値のみが警告をトリガー。）

**Why**: プラットフォームアダプター（例: Google Ad Manager、Kevel、カスタムセラーインフラ）は、アダプター内部の識別子 — GAM 広告ユニット ID、キー/バリューペア、プレースメント ID — を、バイヤー向け SDK が返す AdCP リソースに関連付ける必要があることがよくあります。参照 Prebid `salesagent` Python 実装は、まさにこの目的のために Product モデルの `implementation_config` JSON カラムを使います。予約された名前がなければ、すべての SDK が独自のもの（`implementation_config`、`_internal`、`sdk_state` など）を発明します。4 番目の SDK が次にそれらの 1 つと衝突するか、同じ名前に収束する 2 つの SDK が曖昧なセマンティクスを生成します。1 つの予約された名前が調整問題を除去します。

**Scope**: 予約は、スキーマが `additionalProperties: true` を宣言する AdCP リソースオブジェクト — `Product`、`MediaBuy`、`Package`、`Creative`、`AudienceSegment`、`Signal`、`RightsGrant` を含む — に適用されます。予約は、それが現れるどこでもリソースとともに移動します: レスポンスエンベロープのトップレベル、別のリソース内にネスト（例: `MediaBuy` 内の `Package`）、またはリソースの配列内（例: `products: Product[]` の各要素）。アダプターは、最も外側だけでなく、すべての出現から送出前にキーを取り除かなければなりません（MUST）。

`PropertyList` と `CollectionList` は `additionalProperties: false` を宣言し、フォローアップ PR がそれらのスキーマを広げるまでスコープ外です。それまで、それらのリソースのラウンドトリップ状態を必要とするアダプターは帯域外で追跡すべきです。

**近隣の慣例との区別**:

* `ext.{vendor}` — ベンダー名前空間化、**バイヤーに見える**、ワイヤーを移動する。バイヤーが見るべきベンダー固有データに使う（例: `ext.gam.line_item_id`）。
* `context` / `context_id` — 呼び出し元がエコーする相関データ、これもワイヤーに見える。プレフィックス一致にもかかわらず、`ctx_metadata` はこれらのサブ名前空間ではありません — それらは無関係な概念で、異なる層を移動します。
* `ctx_metadata` — **アダプター内部のみ**、送出前に取り除かなければならず（MUST）、決してバイヤーに到達しません。

**Adapter conformance**:

```
1. Read ctx_metadata from inbound resource (publisher → SDK direction).
2. Carry it in adapter-local state.
3. Before serializing the resource for wire egress (SDK → buyer direction):
   a. Remove the ctx_metadata key.
   b. If the key was present and non-empty, emit a warning-level log:
      "stripping reserved ctx_metadata before egress on <resource_type>"
4. Buyer-facing surfaces MUST NOT expose ctx_metadata in any documentation,
   typed shape, or example.
```

**Reviewer checklist**:

* `ctx_metadata` をバイヤー可読フィールドとして推進する任意の仕様、スキーマ、または例を拒否。
* `ctx_metadata` をバイヤー向けの型付きリターンに表面化する任意の SDK 貢献を拒否。
* 送出取り除き + 警告ログのパスが整っていることを条件に、`ctx_metadata` をアダプター内部状態として読み書きする SDK コードを受け入れ。

## 破壊的変更

### 何が破壊的変更か

**メジャーバージョンアップが必要:**

* enum 値の削除
* フィールド名の変更
* フィールド型の変更
* オプションを必須へ変更
* フィールドの削除

**マイナーバージョンで許容:**

* 新しい enum 値の追加（追記のみ）
* 新しいオプションフィールドの追加
* 説明の明確化
* 新しいタスク/エンドポイントの追加

### マイグレーション戦略

破壊的変更を行う場合:

1. **v2 ディレクトリを作成**: `/schemas/v2/`
2. **v1 を維持**: 旧スキーマを動作状態で残す
3. **マイグレーションを記載**: 変更前後の例を提供します
4. **デプリケーション期間**: 定めた期間、両バージョンをサポートします

## JSON Schema Conventions

### Nullable Scalars

AdCP 3.x の draft-07 スキーマでは、null 許容のスカラーフィールドを JSON スキーマの型ユニオンとしてエンコードします。

```json theme={null}
{ "type": ["string", "null"] }
```

null 許容の数値、整数、ブール値、混合スカラー値バケットにも同じパターンを使います。ソーススキーマに OpenAPI スタイルの `nullable: true` を導入しないでください。それは JSON Schema Draft 07 の一部ではなく、一貫しない SDK 投影ルールを生みます。

null 許容の enum は、`type` ユニオンと `enum` 値セットの両方に `null` を含めなければなりません。

```json theme={null}
{
  "type": ["string", "null"],
  "enum": ["active", "paused", null]
}
```

JSON Schema Draft 07 では null 許容性と存在は別物です。

* `type: ["string", "null"]` は、フィールドが存在するとき `null` であってよいことを意味します。
* 囲むオブジェクトの `required` 配列が、フィールドが存在しなければならないかを制御します。
* したがって任意の null 許容フィールドは 3 つの状態を持ちます: 省略、`null` で存在、スカラー値で存在。
* 必須の null 許容フィールドは 2 つの状態を持ちます: `null` で存在、またはスカラー値で存在。

省略と明示的な `null` が異なるセマンティクスを運ぶ場合、SDK ジェネレーターがケースを潰さないよう、その区別をフィールドの説明で述べます。

## スキーマのテスト

すべてのスキーマ変更は以下を満たすこと:

1. ✅ JSON Schema Draft 07 で検証に通る
2. ✅ サンプルデータがバリデーションを通過します
3. ✅ Python/TypeScript で型生成に成功します
4. ✅ ドキュメントが変更に追随しています
5. ✅ 変更内容を示す changeset を含めます

## レビュー・チェックリスト

スキーマ変更をマージする前に確認します:

* [ ] 異なるファイル間で enum 名が重複していません
* [ ] あいまいなフィールド名（素の "type" など）がない
* [ ] すべての enum が `$ref` 参照になっている（インラインなし）
* [ ] 破壊的変更には適切なバージョニングが適用されています
* [ ] ドキュメントがスキーマに合わせて更新されています
* [ ] サンプルが新スキーマでバリデーションに通る
* [ ] 型生成テストが完了しています
* [ ] 適切なバージョンアップを含む changeset が作成されています

## 哲学

**「スキーマこそが仕様」**

ドキュメントはスキーマを反映すべきですが、真実のソースはスキーマです。ドキュメントとスキーマが乖離した場合はスキーマを優先します。つまり:

* スキーマに明確で詳細な説明を書く
* 自己説明的なセマンティックな名前を使います
* バリデーションだけでなく型生成も意識して設計します
* 言語間での開発者体験を考慮します

**「正しいことをしやすくする」**

良いスキーマ設計は実装者を正しい使い方へ導きます:

* 判別子を使い、型チェッカーが誤りを検出できるようにします
* セマンティックな名前でコードを読みやすくします
* enum を統合し、きれいな型を生成させる
* 必要な箇所だけ制限し、過剰に縛らない

## 質問があるとき

スキーマ設計で迷ったら:

1. `/schemas/v2/` の既存パターンを確認します
2. 型生成への影響を考える
3. 「この名前衝突は問題を起こさないか？」と自問します
4. 端的さよりも具体性を優先します
5. 将来のため、このファイルに判断理由を記録します
