{
  "schema_version": "1.0.0",
  "bot_id": "6.14",
  "bot_name": "AttributionRevenueReporter",
  "slug": "attributionrevenuereporter",
  "layer": "Governance",
  "layer_key": "gov",
  "bot_class": "Governance Service",
  "authority": [
    "Explain"
  ],
  "status": "planned",
  "readiness": "Spec started",
  "flagship": false,
  "is_reference": false,
  "public_export": false,
  "identity": {
    "layer": "Governance",
    "bot_class": "Governance Service",
    "authority": "Explain",
    "runs_before": "Nothing \u2014 runs daily post-close",
    "runs_after": "BuilderAttribution reconciliation cycle",
    "applies_to": "All builder-code attributed fills within the reporting window",
    "default_mode": "shadow_only",
    "user_visible": "summary-only",
    "developer_owner": "Polytraders core"
  },
  "purpose": "AttributionRevenueReporter reconciles builder-code rebates with internal fill records and publishes a daily auditable SettlementReport. Retained 7 years for financial and regulatory compliance.",
  "why_it_matters": [
    {
      "failure": "Rebate not reconciled",
      "consequence": "Builder-code fee rebates may be under- or over-reported; financial records are inaccurate."
    },
    {
      "failure": "Per-strategy slice missing",
      "consequence": "Revenue attribution to individual strategies is impossible; resource allocation decisions lack data."
    }
  ],
  "polymarket_inputs": [
    {
      "input": "Polymarket builder-code volume and rebate report",
      "source": "data",
      "required": true,
      "use": "Fetch official daily rebate figures for reconciliation."
    },
    {
      "input": "Internal fill records from attribution log",
      "source": "internal",
      "required": true,
      "use": "Compare with official report to compute drift."
    }
  ],
  "internal_inputs": [
    {
      "input": "BuilderAttribution reconciliation output",
      "source": "gov.builderattribution",
      "required": true,
      "use": "Source of quarantine status and drift delta for each reconciliation window."
    },
    {
      "input": "ExecutionReport stream",
      "source": "internal.report_bus",
      "required": true,
      "use": "Aggregate builder_fee_pusd per strategy and per user for the daily report."
    }
  ],
  "raw_params": [
    "report_cron \u00b7 cron",
    "drift_alert_pct \u00b7 0\u2013100",
    "publish_to \u00b7 list",
    "retain_days \u00b7 int"
  ],
  "parameters": [
    {
      "name": "report_cron",
      "default": "0 6 * * *",
      "warning": null,
      "hard": null,
      "controls": "Cron schedule for the daily attribution revenue report.",
      "why_default_matters": "6 AM UTC runs after the exchange's daily close and BuilderAttribution reconciliation.",
      "threshold_logic": [
        {
          "condition": "cron fires",
          "action": "Fetch official report; compute drift; emit SettlementReport"
        }
      ],
      "dev_check": "scheduler.register(p.report_cron, generateReport)",
      "user_facing": "Revenue attribution reports are published daily."
    },
    {
      "name": "drift_alert_pct",
      "default": 1.0,
      "warning": 2,
      "hard": 5,
      "controls": "Percentage drift between internal and official rebate figures that triggers an alert.",
      "why_default_matters": "1% drift is a reasonable threshold for fee reconciliation anomalies.",
      "threshold_logic": [
        {
          "condition": "drift_pct > drift_alert_pct",
          "action": "Emit REVENUE_DRIFT_DETECTED alert"
        }
      ],
      "dev_check": "if abs(drift_pct) > p.drift_alert_pct: emit('REVENUE_DRIFT_DETECTED')",
      "user_facing": ""
    }
  ],
  "default_config": {
    "bot_id": "gov.attributionrevenuereporter",
    "version": "0.1.0",
    "mode": "shadow_only",
    "defaults": {
      "report_cron": "0 6 * * *",
      "drift_alert_pct": 1.0,
      "publish_to": [
        "governance_audit",
        "finance_team"
      ],
      "retain_days": 2555
    }
  },
  "implementation_flow": [
    "On cron schedule, fetch the Polymarket builder-code volume and rebate report for the previous day.",
    "Aggregate internal fill records from the ExecutionReport stream by strategy and by user for the same window.",
    "Compare total rebate_pusd from official report against sum of builder_fee_pusd from internal records.",
    "If drift > drift_alert_pct, emit REVENUE_DRIFT_DETECTED alert and quarantine the report pending review.",
    "Emit SettlementReport(event_type=REVENUE_REPORT) with per-strategy slices, drift delta, and reconciliation status.",
    "Publish report to governance_audit and finance_team recipients."
  ],
  "decision_logic": {
    "approve": "Not applicable \u2014 AttributionRevenueReporter is a reporting and reconciliation service.",
    "reshape_required": "Not applicable.",
    "reject": "Quarantines the report if drift > drift_alert_pct.",
    "warning_only": "Emits REVENUE_DRIFT_DETECTED warn when drift is present but within manageable range."
  },
  "decision_output_schema": "SettlementReport",
  "decision_output_example": {
    "report_id": "stl_attributionrevenuereporter_01HX9Z",
    "bot_id": "gov.attributionrevenuereporter",
    "event_type": "REVENUE_REPORT",
    "report_date": "2026-05-08",
    "total_volume_pusd": 48320.5,
    "total_rebate_pusd": 120.8,
    "official_rebate_pusd": 120.8,
    "drift_pusd": 0.0,
    "drift_pct": 0.0,
    "drift_detected": false,
    "per_strategy": [
      {
        "strategy": "sports-model",
        "volume_pusd": 30000.0,
        "rebate_pusd": 75.0
      }
    ],
    "report_kind": "SettlementReport",
    "topic": "polytraders.reports.settlement",
    "retained_until": "2033-05-08"
  },
  "developer_log": {
    "bot_id": "gov.attributionrevenuereporter",
    "event_type": "REPORT_GENERATED",
    "report_date": "2026-05-08",
    "fetch_latency_ms": 230,
    "strategies_included": 3
  },
  "user_explanations": [
    {
      "situation": "Daily revenue report published",
      "message": "Today's builder attribution revenue report has been published. All records are available in the governance audit log."
    },
    {
      "situation": "Revenue drift detected",
      "message": "A discrepancy was found between internal records and the official rebate report. The affected records are under review."
    }
  ],
  "failure_modes": {
    "main_failure_mode": "Data API is unavailable at report time; official rebate figures cannot be fetched.",
    "false_positive_risk": "A temporary Data API format change causes a spurious drift detection.",
    "false_negative_risk": "Internal fill records are incomplete for the window, causing drift to appear smaller than it is.",
    "safe_fallback": "If Data API is unavailable, defer the report and retry hourly. Emit REPORT_DEFERRED alert.",
    "required_dependencies": [
      "Polymarket Data API (builder-code report)",
      "internal.report_bus (ExecutionReport)",
      "gov.builderattribution (reconciliation output)"
    ]
  },
  "acceptance_tests": {
    "unit": [
      {
        "test": "Drift detection fires when drift_pct exceeds threshold",
        "setup": "internal_rebate=120, official_rebate=122, drift_alert_pct=1.0",
        "expected": "REVENUE_DRIFT_DETECTED alert; report quarantined"
      },
      {
        "test": "Per-strategy slices sum to total volume",
        "setup": "3 strategies with volumes 30k, 12k, 6.3k",
        "expected": "total_volume_pusd = 48320 in SettlementReport"
      }
    ],
    "integration": [
      {
        "test": "End-to-end: cron fires \u2192 fetch official report \u2192 reconcile \u2192 SettlementReport emitted",
        "expected": "SettlementReport on polytraders.reports.settlement with report_kind=SettlementReport"
      }
    ],
    "property": [
      {
        "property": "Every daily report is retained for >= 2555 days",
        "required": "Always true"
      }
    ]
  },
  "checklist_overrides": {},
  "legacy_goal": "Reconcile builder-code rebates with internal records and publish a daily auditable report.",
  "legacy_pm_signals": [
    "BuilderAttribution (6.1) reconciliation output",
    "Polymarket builder report, internal fill records, drift",
    "Per-strategy and per-user attribution slices"
  ],
  "legacy_external_feeds": [],
  "reporting_groups": [
    "post_trade",
    "governance_audit"
  ],
  "network": [
    "polygon"
  ],
  "api_surface": [
    "data",
    "internal"
  ],
  "version": {
    "spec": "2.0.0",
    "implementation": "0.1.0",
    "schema": "2",
    "released": null,
    "planned_release": "Q4-2026"
  },
  "migration_history": [
    {
      "date": "2026-04-28",
      "from": "n/a",
      "to": "v2-spec",
      "reason": "Spec drafted post-CLOB-V2 cutover; bot not yet implemented",
      "action_taken": "Designed against V2 schema (pUSD, builder codes, V2 EIP-712 domain)"
    }
  ],
  "polymarket_v2_compat": {
    "clob_version": "v2",
    "collateral": "pUSD",
    "eip712_domain_version": "2",
    "builder_code_aware": true,
    "negrisk_aware": false,
    "multichain_ready": false,
    "sdk_used": "py-clob-client-v2",
    "settlement_contract": "CTFExchangeV2",
    "notes": "AttributionRevenueReporter reconciles builder-code rebates in pUSD; reads builder_fee_pusd from fill records."
  },
  "reference_implementation": {
    "pseudocode": "// ---- DAILY CRON JOB ----\nFUNCTION generateReport(reportDate):\n  window = {start: reportDate + T00:00Z, end: reportDate + T23:59Z}\n\n  // Fetch official Polymarket rebate report\n  official = FETCH data_api.GET(\n    '/builder-code-report?code=polytraders&from=' + window.start + '&to=' + window.end\n  )\n  IF official IS NULL:\n    scheduleRetry(generateReport, reportDate, delay=3600)\n    EMIT SettlementReport(event_type='REPORT_DEFERRED', report_date=reportDate)\n    RETURN\n\n  // Aggregate internal fill records\n  fills = postgres.select('attribution_log', WHERE fill_confirmed_at BETWEEN window)\n  internalRebate = SUM(f.builder_fee_pusd FOR f IN fills)\n  perStrategy = GROUP_BY(fills, 'strategy_slug', SUM('size_pusd'), SUM('builder_fee_pusd'))\n\n  // Compute drift\n  drift_pusd = abs(internalRebate - official.rebate_pusd)\n  drift_pct = drift_pusd / official.rebate_pusd * 100 IF official.rebate_pusd > 0 ELSE 0\n\n  IF drift_pct > config.drift_alert_pct:\n    alerting.emit('REVENUE_DRIFT_DETECTED', {drift_pct, drift_pusd})\n\n  // Emit SettlementReport\n  EMIT SettlementReport(event_type='REVENUE_REPORT',\n    report_date=reportDate,\n    total_volume_pusd=SUM(f.size_pusd),\n    total_rebate_pusd=internalRebate,\n    official_rebate_pusd=official.rebate_pusd,\n    drift_pusd=drift_pusd, drift_pct=drift_pct,\n    drift_detected=drift_pct > config.drift_alert_pct,\n    per_strategy=perStrategy,\n    retained_until=now() + days(config.retain_days))",
    "sdk_calls": [
      "data_api.GET('/builder-code-report?code=polytraders&from=...&to=...')",
      "postgres.select('attribution_log', WHERE fill_confirmed_at BETWEEN ...)",
      "alerting.emit('REVENUE_DRIFT_DETECTED', metadata)"
    ],
    "complexity": "O(F) per report where F = fill count in window"
  },
  "wire_examples": {
    "input": {
      "label": "Polymarket builder-code report",
      "source": "data_api",
      "payload": {
        "builder_code": "polytraders",
        "window_start": "2026-05-08T00:00:00Z",
        "window_end": "2026-05-08T23:59:59Z",
        "rebate_pusd": 120.8,
        "volume_pusd": 48320.5
      }
    },
    "output": {
      "label": "SettlementReport \u2014 REVENUE_REPORT",
      "payload": {
        "report_id": "stl_revenue_01HX9Z",
        "event_type": "REVENUE_REPORT",
        "drift_detected": false,
        "report_kind": "SettlementReport",
        "topic": "polytraders.reports.settlement",
        "retained_until": "2033-05-08"
      }
    }
  },
  "reason_codes": [
    {
      "code": "REVENUE_REPORT",
      "severity": "INFO",
      "meaning": "Daily attribution revenue report generated and emitted.",
      "action": "Log and store.",
      "user_message": ""
    },
    {
      "code": "REVENUE_DRIFT_DETECTED",
      "severity": "WARN",
      "meaning": "Drift between internal and official rebate figures exceeds threshold.",
      "action": "Emit alert; quarantine report pending review.",
      "user_message": "A discrepancy was found in today's revenue report."
    },
    {
      "code": "REPORT_DEFERRED",
      "severity": "WARN",
      "meaning": "Data API unavailable at report time; retry scheduled.",
      "action": "Emit WARN; schedule retry.",
      "user_message": ""
    },
    {
      "code": "RETENTION_BELOW_REGULATORY_MINIMUM",
      "severity": "WARN",
      "meaning": "retain_days < 2555.",
      "action": "Emit WARN; refuse config change.",
      "user_message": ""
    },
    {
      "code": "KILL_SWITCH_ACTIVE",
      "severity": "WARN",
      "meaning": "KillSwitch active; report notes trading was halted during window.",
      "action": "Include kill-switch note in report.",
      "user_message": ""
    }
  ],
  "metrics": {
    "emitted": [
      {
        "name": "polytraders_gov_attributionrevenuereporter_reports_total",
        "type": "counter",
        "unit": "count",
        "labels": [
          "status"
        ],
        "meaning": "Total daily reports generated by status (complete/deferred/quarantined)."
      },
      {
        "name": "polytraders_gov_attributionrevenuereporter_drift_pusd",
        "type": "gauge",
        "unit": "usd",
        "labels": [],
        "meaning": "Revenue drift in pUSD at last report."
      },
      {
        "name": "polytraders_gov_attributionrevenuereporter_rebate_pusd_total",
        "type": "counter",
        "unit": "usd",
        "labels": [],
        "meaning": "Cumulative rebate pUSD recorded."
      },
      {
        "name": "polytraders_gov_attributionrevenuereporter_deferred_reports",
        "type": "gauge",
        "unit": "count",
        "labels": [],
        "meaning": "Number of reports currently deferred pending Data API."
      }
    ],
    "alerts": [
      {
        "name": "AttributionRevenueDrift",
        "condition": "polytraders_gov_attributionrevenuereporter_drift_pusd > 0",
        "severity": "P1",
        "runbook": "#runbook-attributionrevenue-drift"
      },
      {
        "name": "AttributionRevenueDeferredReport",
        "condition": "polytraders_gov_attributionrevenuereporter_deferred_reports > 0",
        "severity": "P2",
        "runbook": "#runbook-attributionrevenue-deferred"
      }
    ]
  },
  "state": {
    "store": "postgres",
    "shape": "attribution_revenue_reports table: {report_id, report_date, total_volume_pusd, total_rebate_pusd, official_rebate_pusd, drift_pusd, drift_pct, per_strategy[], retained_until}",
    "ttl": "2555 days (7 years)",
    "recovery": "On restart, check for any deferred reports and retry immediately.",
    "size_estimate": "~10 KB per daily report; ~4 MB per year"
  },
  "concurrency": {
    "execution_model": "single scheduled job per day",
    "max_in_flight": 2,
    "idempotency_key": "report_date",
    "timeout_ms": 30000,
    "backpressure": "skip if previous job still running",
    "locking": "Postgres unique constraint on report_date"
  },
  "dependencies": {
    "depends_on": [
      {
        "bot_id": "gov.builderattribution",
        "why": "BuilderAttribution provides reconciliation status and quarantine counts.",
        "contract": "Reconciliation must complete before daily report runs."
      }
    ],
    "emits_to": [
      {
        "bot_id": "internal.post_trade_archive",
        "what": "SettlementReport with daily revenue figures and 7-year retention"
      }
    ],
    "sibling": [
      {
        "bot_id": "gov.posttradeexplainer",
        "why": "PostTradeExplainer provides per-fill explanation context referenced in revenue reports.",
        "contract": "SettlementReport includes builder_fee_pusd."
      }
    ],
    "external": [
      {
        "service": "Polymarket Data API",
        "endpoint": "https://data-api.polymarket.com",
        "sla": "99.9% / 500ms p99",
        "failure_mode": "Defer report; retry hourly; emit REPORT_DEFERRED."
      }
    ]
  },
  "security_surfaces": {
    "signs_orders": false,
    "private_key_access": "none",
    "abuse_vectors": [
      "Manipulating internal fill records to inflate reported rebate figures"
    ],
    "mitigations": [
      "Internal fill records are immutably written; any manipulation would show as drift against the official Polymarket report"
    ]
  },
  "failure_injection": [
    {
      "scenario": "DATA_API_UNAVAILABLE",
      "how_to_inject": "Block TCP to data-api.polymarket.com at report time",
      "expected_behaviour": "REPORT_DEFERRED emitted; retry scheduled hourly",
      "recovery": "Automatic when Data API recovers."
    },
    {
      "scenario": "REVENUE_DRIFT",
      "how_to_inject": "Insert synthetic fill with builder_fee_pusd=10 not in official report",
      "expected_behaviour": "REVENUE_DRIFT_DETECTED alert; report quarantined",
      "recovery": "Manual review; remove synthetic record; re-run report."
    },
    {
      "scenario": "DUPLICATE_REPORT_RUN",
      "how_to_inject": "Trigger two cron runs for the same report_date",
      "expected_behaviour": "Second run skipped via idempotency constraint; no duplicate report",
      "recovery": "Idempotent \u2014 no action needed."
    }
  ],
  "runbook": {
    "summary": "AttributionRevenueReporter incidents are usually revenue drift (P1) or deferred reports due to Data API unavailability.",
    "oncall_actions": [
      {
        "alert": "AttributionRevenueDrift",
        "first_action": "Review drift details in the SettlementReport; check BuilderAttribution quarantine count.",
        "escalate_to": "Governance pod lead; contact Polymarket support if drift is large"
      },
      {
        "alert": "AttributionRevenueDeferredReport",
        "first_action": "Check Data API health; verify retry is scheduled.",
        "escalate_to": "SRE on-call if Data API down > 1h"
      }
    ],
    "manual_overrides": [
      {
        "name": "rerun-report",
        "how": "polytraders gov attributionreporter rerun --date <YYYY-MM-DD>",
        "when": "Manual re-run needed after Data API recovery or record correction."
      }
    ],
    "healthcheck": "/internal/health/attributionrevenuereporter \u2192 green if Last report completed today; drift_pusd == 0; no deferred reports; red if Drift detected or report deferred for > 2h"
  },
  "promotion_gates": {
    "to_shadow": [
      {
        "gate": "Drift detection unit test passes",
        "how_measured": "CI",
        "threshold": "Pass"
      }
    ],
    "to_limited_live": [
      {
        "gate": "Daily report end-to-end test in staging produces correct per-strategy slices",
        "how_measured": "Integration test",
        "threshold": "Pass"
      }
    ],
    "to_general_live": [
      {
        "gate": "Finance team sign-off on revenue report format and 7-year retention",
        "how_measured": "Finance team review",
        "threshold": "Pass"
      }
    ]
  },
  "reporting": {
    "emits_kinds": [
      "SettlementReport"
    ],
    "topics": [
      "polytraders.reports.settlement"
    ],
    "cadence": "every-event",
    "retention_class": "7y",
    "sampling_rule": "emit-every",
    "bus_failure_action": "wal-then-retry",
    "user_visible": "summary-only",
    "consumes_kinds": [
      "ExecutionReport"
    ]
  },
  "capital_impact": "Indirect",
  "v3_status": {
    "phase": 3,
    "phase_name": "Reporting & event store",
    "docs": {
      "done": 27,
      "total": 27,
      "state": "done"
    },
    "impl": {
      "done": 0,
      "total": 15,
      "state": "pending"
    },
    "runtime": {
      "done": 0,
      "total": 8,
      "state": "pending"
    },
    "overall": "pending"
  }
}