{
  "policy_id": "line.events.v1",
  "name": "Yendoller（ドル円観測所） 配信規則",
  "version": "1.0",
  "status": "DRAFT",
  "effective_from": null,
  "published": "2026-08-15",
  "canonical": "https://yendoller.com/api/v0/distribution_policy.json",
  "principle": [
    "配信対象は本規則によって事前に定まる。運営者がその日に『重要そうだから送る』と判断する方式を採らない（会則第15条）。",
    "本所は重要度を判定しない。受信対象は観測者自身が選ぶ。",
    "LINE等の配信面に独立した情報を作らない。必ず先に yendoller.com 上にレコードを生成し、そのレコードを配信する。配信物には常に正本URLを含める（会則第36条 Canonical First）。",
    "配信本文に予想・見通し・売買判断を含めない（会則第12条・第14条）。",
    "本規則を変更する場合は新版を発行し、旧版を保存する（会則第46条）。"
  ],
  "eligibility_rule": {
    "description": "配信対象イベントは次の条件をすべて満たすものに限る。個別の判断を挟まない。",
    "conditions": [
      "publisher が publisher_whitelist に含まれること",
      "calendar における precision が exact であること（日付未確定のものは配信しない）",
      "status が SCHEDULED であること"
    ],
    "publisher_whitelist": [
      "財務省",
      "日本銀行",
      "内閣府",
      "総務省統計局",
      "厚生労働省",
      "Federal Reserve",
      "CFTC",
      "U.S. Department of the Treasury",
      "U.S. Bureau of Labor Statistics",
      "U.S. Census Bureau",
      "EIA"
    ]
  },
  "categories": {
    "description": "利用者はこの単位で受信対象を選ぶ。未選択の利用者には配信しない（オプトイン）。",
    "values": {
      "JP_POLICY": "日本銀行の金融政策決定会合・政策金利",
      "JP_STATS": "日本の公的統計（GDP・CPI・貿易統計・毎月勤労統計）",
      "JP_FLOW": "対外及び対内証券売買契約等（週次）",
      "JP_AUCTION": "国債入札（財務省）",
      "US_POLICY": "FOMC・議事要旨・政策金利",
      "US_STATS": "米国の公的統計（雇用・CPI・小売など）",
      "US_AUCTION": "米国債入札（U.S. Treasury）",
      "CFTC": "建玉報告（Commitments of Traders）",
      "INTERVENTION": "為替介入に関する一次資料（財務省・evidence_relation: DIRECT のみ）",
      "REVISION": "公表元による訂正・改訂（REVISED / SUPERSEDED / DELETED_BY_SOURCE の発生）"
    }
  },
  "message_types": {
    "WEEKLY": {
      "desc": "翌週の公式予定の一覧。掲載順は日時順に固定し、強調・並べ替えを行わない",
      "schedule": "毎週月曜 07:00 JST",
      "contains_importance": false
    },
    "AHEAD": {
      "desc": "公表前の事前通知。公表元・予定時刻・残り時間・一次資料URLのみ",
      "lead_minutes": [
        30
      ],
      "lead_note": "事前通知を出す分数。複数指定すると、そのつど通知する（例: [1440, 60, 30] で前日・1時間前・30分前）。通数が増える点に注意",
      "categories": null,
      "categories_note": "対象カテゴリ。null は全カテゴリ。絞る場合も運営者がその日に選ぶのではなく、規則で事前に定める（会則第15条）",
      "schedule": "cronで5〜10分ごとに実行し、lead分前を中心とした窓で拾う",
      "contains_importance": false
    },
    "RELEASED": {
      "desc": "公表を検知した旨の通知。取得した観測値と正本URL",
      "schedule": "取得完了時",
      "contains_importance": false
    },
    "REVISION": {
      "desc": "公表元による訂正の通知。旧値・新値・旧ハッシュ・新ハッシュ・record_id",
      "schedule": "検知時",
      "contains_importance": false,
      "note": "本所固有の配信種別。訂正が起きたこと自体を一級の情報として扱う（会則第31条）"
    }
  },
  "prohibited_in_messages": [
    "重要度の表示（★印・ランク・『注目』『警戒』等）",
    "予想・見通し・目標値",
    "売買推奨・シグナル",
    "煽動表現（『突破か』『急騰』『サプライズ』等）",
    "コンセンサス予想の掲載",
    "yendoller.com 上に対応するレコードが存在しない情報"
  ],
  "volume_note": "配信通数は『配信1回 × 受信した友だち人数』で計上される。全員一律配信は無料枠を直ちに超過するため、カテゴリ選択制（オプトイン）は会則第15条の要請であると同時に運用上の必然である。",
  "operator": "AIMQL合同会社",
  "contact": "info@yendoller.com",
  "system": "Yendoller",
  "line_account": {
    "status": "OPEN",
    "friend_add_url": "https://lin.ee/WuRkGDd",
    "opened": "2026-08-15",
    "note": "アカウントは開設済み。ただし本規則の status が DRAFT の間、規則に基づく自動配信は行わない（会則第46条）。友だち追加は受け付けている。"
  },
  "phases": {
    "v0.1": {
      "method": "broadcast",
      "audience": "ALL",
      "desc": "全友だちに同一内容を配信する。ユーザーDB・Webhookを用いない。カテゴリ選択は未提供のため、配信種別は WEEKLY / RELEASED / REVISION に限る",
      "status": "実装済み・未施行"
    },
    "v0.2": {
      "method": "multicast",
      "audience": "OPTED_IN",
      "desc": "Webhookで友だち追加を検知し、カテゴリ単位のオプトインに基づいて配信する。AHEAD を追加する",
      "status": "実装済み・未有効化"
    }
  },
  "idempotency": {
    "line": "X-Line-Retry-Key（UUID）を最初の送信から付与し、再試行時の二重配信を防ぐ",
    "yendoller": "distribution_id ↔ retry_key を1対1で対応させ、UNSENT → SENDING → SENT の状態遷移を持つ",
    "note": "LINE側と当所側の二重の冪等性を確保する",
    "format": "X-Line-Retry-Key は UUID 形式であることを要する。単に一意な文字列では受理されず、400 が返る。UUIDに連番や接尾辞を付けると形式が壊れるため、分割送信では分割ごとに新しいUUIDを発行する。"
  },
  "delivery_log": {
    "url": "https://yendoller.com/api/v0/distributions/index.json",
    "public": [
      "distribution_id",
      "distribution_type",
      "source_record_id",
      "canonical_url",
      "state",
      "sent_at",
      "payload_hash"
    ],
    "not_public": [
      "受信者のuser_id",
      "購読設定",
      "retry_key"
    ],
    "note": "何を・いつ・どの正本から配信したかを公開する。誰に送ったかは公開しない"
  },
  "default_subscriptions": {
    "note": "友だち追加時の既定値。既定値の設定自体が運営者による選択にあたるため明記する（会則第15条）",
    "on": [
      "WEEKLY",
      "RELEASED",
      "REVISION",
      "JP_POLICY",
      "JP_STATS",
      "US_POLICY",
      "CFTC",
      "INTERVENTION"
    ],
    "off": [
      "AHEAD",
      "JP_FLOW",
      "JP_AUCTION",
      "US_STATS",
      "US_AUCTION"
    ]
  },
  "test_delivery": {
    "purpose": "配信物の表示確認",
    "audience": "LINE_TEST_USER_ID に指定した1名のみ",
    "broadcast": "管理画面からは行わない。誤配信は取り消せないため",
    "source": "公開済みのレコード（events.json / changes.json / series）から組み立てる。LINE上に独立した情報を作らない",
    "marking": "配信物の見出しタグに ・TEST を付す",
    "policy_gate": "テスト配信は配信規則の施行を要しない。本番配信（Broadcast）は status が EFFECTIVE であることを要する"
  },
  "pre_send_validation": {
    "endpoint": "https://api.line.me/v2/bot/message/validate/push",
    "purpose": "送信せずに配信物の形式を検証する。通数を消費しない",
    "note": "配信規則の施行前でも実行できる。形式エラーはproperty単位で返る"
  },
  "volume_estimate": {
    "note": "通数は『配信1回 × 受信した友だち人数』。事前通知は件数が多いため、有効化の前に試算すること",
    "formula": "月間通数 ≒ (週次1 + 公表通知N + 事前通知M×lead数) × 友だち人数",
    "example": "月34イベント・友だち50人・30分前のみ → 事前通知だけで月1,700通。コミュニケーションプラン（月200通）では成立しない",
    "tool": "python3 ops/tools/notify_line.py --estimate"
  }
}