{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "BookmarkerProfile",
  "description": "1ユーザー分のプロフィールデータ。コード集計(computed)とLLM生成(generated)を1つにまとめ、図鑑カードテンプレートに渡す契約書。セクション番号はプロトタイプ(profile-sample.html)の 01〜10 に対応。",
  "type": "object",
  "required": ["userId", "computed", "generated"],
  "properties": {
    "userId":    { "type": "string", "description": "はてなID（例: hatena）" },
    "sourceUrl": { "type": "string", "description": "出典: https://b.hatena.ne.jp/{id}/" },

    "computed": {
      "description": "コードで集計する定量データ",
      "type": "object",
      "required": ["basic", "hourHistogram", "dayHistogram", "topMedia", "themes", "wordFreq", "styleStats", "stars"],
      "properties": {

        "basic": {
          "description": "01 基本データ（数値カード）",
          "type": "object",
          "required": ["totalBookmarks", "periodStart", "periodEnd", "activeDays"],
          "properties": {
            "totalBookmarks":     { "type": "integer", "description": "総ブックマーク数（件）" },
            "periodStart":        { "type": "string",  "description": "活動開始日（YYYY-MM-DD）" },
            "periodEnd":          { "type": "string",  "description": "最終活動日（YYYY-MM-DD）" },
            "activeYears":        { "type": "number",  "description": "活動期間（年, 小数第1位まで）" },
            "activeDays":         { "type": "integer", "description": "アクティブ日数（日）" },
            "activeRate":         { "type": "number",  "description": "期間内の稼働率（％, 0.0..100.0, 小数第1位まで）" },
            "commentRate":        { "type": "number",  "description": "コメント付き率（％, 0.0..100.0, 小数第1位まで）" },
            "commentMedianChars": { "type": "integer", "description": "コメント文字数の中央値（文字）" },
            "totalStars":         { "type": "integer", "description": "総スター数（個）" },
            "starredRate":        { "type": "number",  "description": "スター付き率（％, 0.0..100.0, 小数第1位まで）" },
            "avgStars":           { "type": "number",  "description": "平均スター数（個/ブックマーク, 小数第2位まで）" }
          }
        },

        "hourHistogram": {
          "description": "02 投稿時間帯（時間帯）。0..23時の投稿比率（％, 小数第1位まで）",
          "type": "array", "minItems": 24, "maxItems": 24,
          "items": { "type": "number" }
        },
        "dayHistogram": {
          "description": "02 投稿時間帯（曜日）。月〜日の投稿比率（％, 小数第1位まで）。土日はテンプレ側で色分け",
          "type": "array", "minItems": 7, "maxItems": 7,
          "items": { "type": "number" }
        },

        "topMedia": {
          "description": "03 よく参照する媒体（件数の多い順）",
          "type": "array",
          "items": {
            "type": "object",
            "required": ["domain", "count"],
            "properties": {
              "domain": { "type": "string" },
              "count":  { "type": "integer", "description": "ブックマーク件数（件）" }
            }
          }
        },

        "themes": {
          "description": "04 主要テーマ・関心",
          "type": "array",
          "items": {
            "type": "object",
            "required": ["name", "count", "ratio"],
            "properties": {
              "name":     { "type": "string" },
              "count":    { "type": "integer", "description": "該当件数（件）" },
              "ratio":    { "type": "number",  "description": "全体比（％, 0.0..100.0, 小数第1位まで）" },
              "avgStars": { "type": "number",  "description": "平均スター数（個/ブックマーク, 小数第2位まで）" }
            }
          }
        },

        "wordFreq": {
          "description": "05 頻出語（ワードクラウド。出現数でフォントサイズを段階化）",
          "type": "array",
          "items": {
            "type": "object",
            "required": ["word", "count"],
            "properties": {
              "word":  { "type": "string" },
              "count": { "type": "integer", "description": "出現回数（回）" }
            }
          }
        },

        "styleStats": {
          "description": "06 文体の特徴（特徴ラベルと件数のテーブル）",
          "type": "array",
          "items": {
            "type": "object",
            "required": ["label", "count"],
            "properties": {
              "label": { "type": "string" },
              "count": { "type": "integer", "description": "該当コメント数（件）" }
            }
          }
        },
        "attack": {
          "description": "06 攻撃性パネル（任意）。攻撃性が高いユーザーのみ出力。無い場合はパネル非表示",
          "type": "object",
          "required": ["terms"],
          "properties": {
            "terms": {
              "type": "array",
              "items": {
                "type": "object",
                "required": ["term", "count"],
                "properties": {
                  "term":  { "type": "string",  "description": "罵倒・皮肉・嘲笑の語（例: w, バカ）" },
                  "count": { "type": "integer", "description": "出現回数（回）" }
                }
              }
            }
          }
        },

        "stars": {
          "description": "07 スター分析",
          "type": "object",
          "required": ["topGivers", "byTheme"],
          "properties": {
            "topGivers": {
              "description": "上位スター付与者",
              "type": "array",
              "items": {
                "type": "object",
                "required": ["label", "count"],
                "properties": {
                  "label": { "type": "string",  "description": "表示名" },
                  "count": { "type": "integer", "description": "付与スター数（個）" }
                }
              }
            },
            "byTheme": {
              "description": "スターが付きやすい領域（平均スター）",
              "type": "array",
              "items": {
                "type": "object",
                "required": ["theme", "avgStars"],
                "properties": {
                  "theme":    { "type": "string" },
                  "avgStars": { "type": "number", "description": "平均スター数（個/ブックマーク, 小数第2位まで）" }
                }
              }
            }
          }
        },

        "timeline": {
          "description": "時系列の活動量（折れ線用）。任意。各要素は期間あたりの件数（件）",
          "type": "array",
          "items": { "type": "number" }
        }
      }
    },

    "generated": {
      "description": "LLMが生成する定性データ。各記述はcomputedや引用に根拠を持つこと。断定を避け『〜な傾向が見える』と書く。個人情報の特定は厳禁です。",
      "type": "object",
      "required": ["catchphrase", "types", "params", "commentary", "summaryProse"],
      "properties": {

        "catchphrase": { "type": "string", "description": "ヘッダーの一言キャッチ（例: 歯に衣着せぬウヨサヨ論客タイプ）" },
        "types": {
          "description": "そのユーザーをあらわす単語、TYPEバッジ（例: ジェンダー / 政治 / はてな / 論客）",
          "type": "array", "minItems": 1, "maxItems": 4,
          "items": { "type": "string" }
        },

        "params": {
          "description": "図鑑ステータス。基礎(全員共通)＋特性(可変・自動選出)。値はコードの代理指標から算出し、LLMは作らない",
          "type": "object",
          "required": ["base", "traits"],
          "properties": {
            "base": {
              "description": "全ユーザー共通の固定2軸。0-20（通常0-10。10より上は異常に値が高い場合）",
              "type": "array", "minItems": 2, "maxItems": 2,
              "items": {
                "type": "object",
                "required": ["key", "value"],
                "properties": {
                  "key":   { "type": "string", "enum": ["活動量", "影響力"] },
                  "value": { "type": "integer", "minimum": 0, "maximum": 20 }
                }
              }
            },
            "traits": {
              "description": "そのユーザーの特性軸。代理指標カタログから、全体中央値より突出した軸を2〜4個自動選出",
              "type": "array", "minItems": 2, "maxItems": 4,
              "items": {
                "type": "object",
                "required": ["key", "value"],
                "properties": {
                  "key":    { "type": "string",  "description": "皮肉度/攻撃力/論戦力/粘り強さ/瞬発力/偏執度/雑食度/報道追随度/ネット文化度/長文力/質問魔 など" },
                  "value":  { "type": "integer", "minimum": 0, "maximum": 10 },
                  "metric": { "type": "string",  "description": "算出に用いた代理指標の説明（根拠）" }
                }
              }
            }
          }
        },

        "commentary": {
          "description": "各データセクション直下の『解説』文（400字以内）。データのある節のみ。根拠なしの推測は書かない",
          "type": "object",
          "properties": {
            "basic": { "type": "string", "description": "01 基本データの解説" },
            "time":  { "type": "string", "description": "02 投稿時間帯の解説" },
            "media": { "type": "string", "description": "03 媒体の解説" },
            "theme": { "type": "string", "description": "04 テーマの解説" },
            "word":  { "type": "string", "description": "05 頻出語の解説" },
            "style": { "type": "string", "description": "06 文体の解説" },
            "star":  { "type": "string", "description": "07 スター分析の解説" }
          }
        },

        "ideologyProse":   { "type": "string", "description": "08 嗜好・思想・政治傾向（断定せず関心傾向として描写）" },
        "comparisonProse": { "type": "string", "description": "09 類似・敵対ユーザー比較。実データで照合できる場合のみ。任意" },
        "summaryProse":    { "type": "string", "description": "10 総合評価（〜400字）" },

        "evidenceQuote": {
          "description": "芸風の根拠となる実コメント引用（出所明示＝捏造防止）。任意",
          "type": "object",
          "required": ["comment", "date"],
          "properties": {
            "comment": { "type": "string" },
            "date":    { "type": "string" },
            "stars":   { "type": "integer", "description": "そのコメントが得たスター数（個）" },
            "domain":  { "type": "string" }
          }
        },

        "advice": { "type": "string", "description": "毒舌・攻撃系ユーザー向けの軽い改善案。任意・自省した方が良い点を指摘する（攻撃性が高い場合に表示）" },
        "praise": { "type": "string", "description": "穏健・良質なユーザーへの称賛。任意・褒めてあげる（攻撃性が低い場合に表示。adviceと排他）" }
      }
    }
  }
}
