{
  "id": "get_campaign_performance_report",
  "mcp_tool": "get_campaign_performance_report",
  "status": "approved",
  "source_system": "cake",
  "environment": ["staging", "prod"],
  "sharded": false,
  "connections": {
    "whale": "cake_whale_ro",
    "admin": "cake_admin_ro"
  },
  "objects": [
    "whale.lucos_ro_advertiser_stats_daily",
    "Admin.lucos_ro_adv_campaign_performance_daily",
    "Admin.lucos_ro_advertiser_goals",
    "Admin.lucos_ro_advertiser_categories"
  ],
  "parameters": {
    "advertiser_id": { "type": "int", "required": false },
    "campaign_id": { "type": "int", "required": false },
    "date_from": { "type": "date", "required": false },
    "date_to": { "type": "date", "required": false },
    "compare_from": { "type": "date", "required": false },
    "compare_to": { "type": "date", "required": false },
    "baseline_from": { "type": "date", "required": false },
    "baseline_to": { "type": "date", "required": false },
    "sort_by": {
      "type": "enum",
      "required": false,
      "default": "spend",
      "values": ["spend", "sales_revenue", "roas", "cos_pct", "clicks", "advertiser_conversions"]
    },
    "sort_dir": {
      "type": "enum",
      "required": false,
      "default": "desc",
      "values": ["desc", "asc"]
    },
    "min_clicks": { "type": "int", "required": false },
    "min_cos_pct": { "type": "int", "required": false },
    "limit": { "type": "int", "required": false, "default": 50 },
    "roas_underperform_pct": { "type": "int", "required": false, "default": 15 },
    "analysis": {
      "type": "enum",
      "required": false,
      "values": [
        "volatile_conversions",
        "stable_traffic_decline",
        "historical_deterioration",
        "budget_increase_allocation",
        "spend_opportunity"
      ]
    },
    "traffic_cv_max": { "type": "number", "required": false, "default": 0.25 },
    "conversion_cv_min": { "type": "number", "required": false, "default": 0.5 },
    "decline_pct": { "type": "int", "required": false, "default": 20 },
    "budget_increase_pct": { "type": "int", "required": false, "default": 30 },
    "include_publisher_mix": { "type": "int", "required": false, "default": 1 }
  },
  "constraints": {
    "max_window_days": 92,
    "default_window_days": 31,
    "max_rows": 500,
    "timeout_ms": 60000
  },
  "allow_fields": [
    "camp_id",
    "campaign_name",
    "adv_id",
    "adv_name",
    "clicks",
    "estimated_conversions",
    "advertiser_conversions",
    "sales_revenue",
    "spend",
    "roas",
    "roas_source",
    "cos_pct",
    "cos_source",
    "kpi",
    "goal_value",
    "goal_type",
    "category",
    "compare_spend",
    "compare_advertiser_conversions",
    "compare_estimated_conversions",
    "baseline_roas",
    "baseline_spend",
    "baseline_sales_revenue",
    "baseline_advertiser_conversions",
    "analysis",
    "clicks_cv",
    "cvr_cv",
    "weekly",
    "decline_start_week",
    "onset_level",
    "publisher_mix_shift",
    "recommended_spend",
    "incremental_spend",
    "share_pct",
    "rationale",
    "opportunity_score",
    "opportunity_source",
    "first_half_roas",
    "second_half_roas"
  ],
  "deny_fields": ["aov", "rev_share", "postback_url", "ip"],
  "post_processing": [
    "Merge whale stats with Admin conversions on (adv_id, camp_id). Cross-instance, so it cannot be a join — docs/CAKE-OPEN-DECISIONS.md OD-1.",
    "sales_revenue = ROUND(SUM(conversion_value), 2). Rounded once after summing, matching the PHP.",
    "roas = sales_revenue / spend when spend > 0 else null; cos_pct = spend / sales_revenue * 100 when sales_revenue > 0 else null. Totals are window sums, not mean of daily ratios.",
    "KPI = (goal / actual_CPA) * 100 when goal_type is CPA, else (actual_ROAS / goal) * 100. Goal is advertiser-level.",
    "Optional compare_from/compare_to: keep rows where spend increased and estimated_conversions decreased (compare_spend > 0 and compare_estimated_conversions > 0).",
    "Optional baseline_from/baseline_to: keep rows where roas < baseline_roas * (1 - roas_underperform_pct/100).",
    "min_clicks applied as SQL HAVING; min_cos_pct / sort / limit applied after merge.",
    "Optional analysis modes use a daily series (GROUP BY camp_id, stat_date), keep daily rows internal, and return ≤50 campaign summaries. Default window for analysis (when date_from/date_to omitted) is 28 days. Traffic proxy is clicks (Cake has no impressions). No campaign settings change-history — onset/mix are inference only.",
    "historical_deterioration uses ROAS when the advertiser has sales_revenue; otherwise conversions/CPA (zero-revenue CPA advertisers). Always attaches weekly + decline_start_week.",
    "stable_traffic_decline uses conversion+revenue drop when the advertiser has sales_revenue; otherwise conversions-only (CPA). Empty matches stamp skip_reason, never a silent [].",
    "volatile_conversions / stable_traffic_decline / historical_deterioration may omit advertiser_id: analysis runs for the top 3 spend advertisers only (not allocate/spend_opportunity)."
  ],
  "notes": "Campaign-grain sibling of get_advertiser_report (TW-329). Does not return pub_earnings — lucos_ro_publisher_earnings_daily has no camp_id. advertiser_id is optional: omit it to rank campaigns across advertisers (SQL LIMIT is the caller limit, max 50). analysis budget_increase_allocation / spend_opportunity still require advertiser_id; volatile/decline/deterioration unscoped = top-3 spend. clicks_source is whale.advertiser_stats_report. Analysis modes: volatile_conversions, stable_traffic_decline, historical_deterioration, budget_increase_allocation, spend_opportunity."
}
