{
  "id": "get_cpa_publisher_report",
  "mcp_tool": "get_cpa_publisher_report",
  "status": "approved",
  "source_system": "cake",
  "environment": [
    "staging",
    "prod"
  ],
  "sharded": true,
  "shard_schema": "lucos_ro_members",
  "shard_view_prefix": "lucos_ro_cpa",
  "connections": {
    "admin": "cake_admin_ro",
    "keywords": "cake_keywords_ro"
  },
  "objects": [
    "lucos_ro_members.lucos_ro_cpa_*",
    "Admin.lucos_ro_affiliate_directory",
    "Admin.lucos_ro_publisher_clicks",
    "Admin.lucos_ro_publisher_merchant_daily"
  ],
  "parameters": {
    "publisher": {
      "type": "string",
      "required": false
    },
    "group_by": {
      "type": "enum",
      "required": false,
      "default": "publisher",
      "values": [
        "publisher",
        "advertiser",
        "day"
      ]
    },
    "sort_by": {
      "type": "enum",
      "required": false,
      "values": [
        "date",
        "cost",
        "clicks",
        "conversions",
        "cvr",
        "cost_per_conversion"
      ]
    },
    "date_from": {
      "type": "date",
      "required": false
    },
    "date_to": {
      "type": "date",
      "required": false
    },
    "limit": {
      "type": "int",
      "required": false,
      "default": 50
    }
  },
  "constraints": {
    "max_window_days": 92,
    "default_window_days": 30,
    "max_rows": 500,
    "timeout_ms": 60000
  },
  "allow_fields": [
    "date",
    "publisher_id",
    "publisher_name",
    "adv_id",
    "camp_id",
    "clicks",
    "impressions",
    "conversions",
    "cost",
    "cvr",
    "cost_per_conversion"
  ],
  "deny_fields": [
    "commission",
    "unit",
    "rev_share",
    "aff_rev_share",
    "net_cpc"
  ],
  "post_processing": [
    "Answers 'which CPA publisher earns most' and per-publisher CPA performance, reproducing stats_model.php getCPAStats (2015), getCPAConversionRecord (2203) and aggregateConversionData (3375). Source: keywords cpa_aff_<affiliateid>_<YYYYMM>, read through the generated monthly view lucos_ro_members.lucos_ro_cpa_YYYYMM.",
    "THE UNION IS THE POINT: those tables carry no publisher column - the id is only in the table name - so the nightly job rebuilds a per-month view that UNIONs every CPA publisher's table with its id added back as a literal. Without it a cross-publisher comparison is impossible.",
    "CAMPAIGN GRAIN: campaign is part of every grouping, because the portal's rollup key is period + advertiser + campaign (stats_model.php:3478) and its daily grain is date + campaign (:2252) - campaigns are never merged, even in a monthly rollup.",
    "REPRODUCES PORTAL ARITHMETIC: cost_per_conversion is IF(cost > 0, ROUND(cost/conversions, 2), 0) per (date, campaign) (:2252), SUMMED over the period (:3504) and rounded to 2dp (:3535) - NOT the period's cost divided by its conversions. The guard is on the cost, so cost > 0 with conversions = 0 divides by zero and stays null, while cost = 0 is a literal 0.",
    "REPRODUCES PORTAL ARITHMETIC: cvr at group_by=day is the STORED adv_cmp_performance value for (date, campaign), read from Admin.lucos_ro_publisher_merchant_daily (:2222-2231, :2273) and null when there is no row; at the rolled-up grains it is ROUND(conversions/clicks*100, 2), and 0 rather than null with no clicks (:3515-3519). Rounding follows :3529-3537 - clicks 2dp, conversions 4dp, money 2dp.",
    "REPRODUCES THE TODAY/YESTERDAY OVERRIDE: before 14:00 on the reporting database's clock (US Pacific, routinely a day behind a UTC caller) both today and yesterday are dropped from the CPA tables; from 14:00 only today is (:2242-2249, :2252). The dropped dates are replaced by a raw click count from Admin.lucos_ro_publisher_clicks with conversions, cost, cost_per_conversion and cvr forced to 0 (:2318-2337). REPRODUCES THE BUG at :2289-2296: before 14:00 with date_to = today, yesterday is dropped but never backfilled, so that day is missing from the report.",
    "REPRODUCES THE MISSING-TABLE FALLBACK: a month whose CPA view does not exist, or which returns no rows for this publisher, falls back to the same click count with conversions and revenue forced to 0 (:2045-2060) instead of returning nothing. months_click_fallback lists those months. One divergence: Admin.lucos_ro_publisher_clicks filters status > 0, which matches :2321 exactly but is stricter than :2048, where the portal counts every row.",
    "cost is the publisher payout (aff_cost). commission and unit are not exposed: they are the advertiser-side rate card, and the portal uses them only to derive an advertiser revenue estimate."
  ],
  "notes": "CPA publisher performance, across publishers or scoped to one: clicks, conversions, payout and cost per conversion, per campaign. Omit publisher to rank CPA publishers by payout."
}
