{
  "id": "get_affiliate_report",
  "mcp_tool": "get_affiliate_report",
  "status": "approved",
  "source_system": "cake",
  "environment": ["staging", "prod"],
  "sharded": false,
  "connections": {
    "admin": "cake_admin_ro"
  },
  "objects": [
    "Admin.lucos_ro_affiliate_cpc_summary_daily",
    "Admin.lucos_ro_affiliate_directory"
  ],
  "parameters": {
    "affiliate_id": { "type": "int", "required": false },
    "publisher_id": { "type": "string", "required": false },
    "advertiser_id": { "type": "int", "required": false },
    "group_by": {
      "type": "enum",
      "required": false,
      "default": "date",
      "values": ["date", "advertiser"]
    },
    "date_from": { "type": "date", "required": false },
    "date_to": { "type": "date", "required": false }
  },
  "constraints": {
    "max_window_days": 92,
    "default_window_days": 31,
    "max_rows": 5000,
    "timeout_ms": 60000
  },
  "allow_fields": [
    "stat_date",
    "affiliate_id",
    "affiliate_name",
    "adv_id",
    "adv_name",
    "camp_id",
    "clicks",
    "affiliate_earning"
  ],
  "deny_fields": ["rev_share", "net_cpc", "cpc", "click_table_id"],
  "post_processing": [
    "Group rows by stat_date + advertiser, or advertiser only, per group_by. Mirrors the $datewise switch at getAffiliateStats line 30.",
    "When publisher_id (MNGT Affiliate.name) is passed instead of affiliate_id, resolve numeric affiliate_id via Admin.lucos_ro_affiliate_directory before querying earnings."
  ],
  "notes": "Exactly one of affiliate_id or publisher_id is required at runtime. The source method takes an affiliate and the view is pre-aggregated per affiliate, so an unfiltered call would return every publisher's earnings in one response — a bulk commercial-data export dressed up as a report. rev_share is applied inside Admin.lucos_ro_affiliate_cpc_summary_daily and never leaves the database; it is on deny_fields so a future view change exposing it fails the tool loudly instead of leaking it."
}
