{
  "contract_id": "maestro.roas-reconciliation.v1",
  "contract_version": "1.0.0",
  "schema_version": "1.0.0",
  "currency_precision": "The evaluator does not perform foreign-exchange conversion. Every monetary input must already use the record currency. A conversion_policy may document upstream normalization only when source_currency equals target_currency; any differing currencies hold INVALID until the values are normalized outside this calculator.",
  "solve_modes": {
    "ROAS": {
      "known": [
        "selected_denominator",
        "selected_return"
      ],
      "solve": "selected_return / selected_denominator; selected_denominator is matching_platform_spend only for PLATFORM_ATTRIBUTED_VALUE, otherwise net_spend"
    },
    "RETURN": {
      "known": [
        "selected_denominator",
        "target_roas"
      ],
      "solve": "target_roas * selected_denominator; selected_denominator follows the same basis rule"
    },
    "SPEND": {
      "known": [
        "selected_return",
        "target_roas"
      ],
      "solve": "selected_return / target_roas"
    }
  },
  "value_state": {
    "allowed": [
      "OBSERVED",
      "UNKNOWN"
    ],
    "rules": [
      "OBSERVED requires a finite numeric value, including zero.",
      "UNKNOWN requires value null, a nonempty string reason, a nonempty string next_request, and owner as a string or null when no owner was supplied.",
      "A builder converts missing external evidence into an explicit UNKNOWN value object. A canonical record missing a required member is rejected; UNKNOWN never becomes zero.",
      "Instruction-like text remains inert data."
    ]
  },
  "return_basis": {
    "RECOGNIZED_REVENUE": {
      "label": "Recognized revenue ROAS",
      "qualifies_as_roas": true,
      "source_owner": "Finance"
    },
    "COLLECTED_CASH": {
      "label": "Collected cash ROAS",
      "qualifies_as_roas": true,
      "source_owner": "Finance"
    },
    "PLATFORM_ATTRIBUTED_VALUE": {
      "label": "Platform-attributed value / spend",
      "qualifies_as_roas": false,
      "source_owner": "Paid media or analytics"
    },
    "OPEN_PIPELINE": {
      "label": "Open pipeline / spend",
      "qualifies_as_roas": false,
      "source_owner": "Revenue operations"
    }
  },
  "formulas": {
    "net_spend": "gross_spend + included_fees - spend_credits - spend_refunds",
    "net_recognized_revenue": "gross_recognized_revenue - revenue_refunds + revenue_adjustments",
    "recognized_revenue_roas": "net_recognized_revenue / net_spend",
    "collected_cash_roas": "collected_cash / net_spend",
    "platform_attributed_value_multiple": "platform_attributed_value / matching_platform_spend",
    "open_pipeline_multiple": "open_pipeline / net_spend",
    "join_coverage": "matched_records / eligible_records",
    "selected_denominator": "matching_platform_spend for PLATFORM_ATTRIBUTED_VALUE; net_spend for every other basis"
  },
  "invalid_rules": [
    {
      "id": "ZERO_OR_NEGATIVE_SPEND",
      "when": "a ROAS or RETURN calculation uses selected_denominator <= 0; selected_denominator is matching_platform_spend for PLATFORM_ATTRIBUTED_VALUE and net_spend for every other basis",
      "request_id": "REQ-SPEND-NONZERO"
    },
    {
      "id": "TARGET_NOT_POSITIVE",
      "when": "RETURN or SPEND solve uses target_roas <= 0",
      "request_id": "REQ-TARGET-POSITIVE"
    },
    {
      "id": "CURRENCY_MISMATCH",
      "when": "any compared monetary input is not already normalized into the record currency",
      "request_id": "REQ-CURRENCY-MATCH"
    },
    {
      "id": "CHRONOLOGY",
      "when": "cohort_end < cohort_start, cutoff < cohort_end, or a required measured source through_date > observed_at. A required through_date before cutoff is a source-coverage gap that holds PROVISIONAL, not an impossible chronology.",
      "request_id": "REQ-DATES-REPAIR"
    },
    {
      "id": "NEGATIVE_NET_RETURN",
      "when": "the selected return used by ROAS or SPEND is negative",
      "request_id": "REQ-RETURN-REVIEW"
    },
    {
      "id": "JOIN_COUNTS",
      "when": "eligible_records < 0, matched_records < 0, unmatched_records < 0, matched_records > eligible_records, or matched_records + unmatched_records != eligible_records",
      "request_id": "REQ-JOIN-COVERAGE"
    },
    {
      "id": "UNSUPPORTED_FX",
      "when": "conversion_policy declares different source and target currencies, whether or not a rate is supplied",
      "request_id": "REQ-CURRENCY-MATCH"
    }
  ],
  "decision_precedence": [
    "INVALID",
    "INSUFFICIENT_EVIDENCE",
    "PENDING_MATURITY",
    "PROVISIONAL",
    "REVIEW_READY"
  ],
  "decision_rules": {
    "REVIEW_READY": "The selected basis is RECOGNIZED_REVENUE or COLLECTED_CASH; arithmetic is valid; cohort, spend scope, return population and currency match; maturity is MATURE; finance and spend sources are OBSERVED at or after the outcome cutoff; join counts are internally consistent; join coverage meets the explicitly supplied minimum_coverage; no invalid rule fires.",
    "PROVISIONAL": "Arithmetic is valid, but scope, source chronology or join coverage prevents REVIEW_READY; or the selected basis is PLATFORM_ATTRIBUTED_VALUE or OPEN_PIPELINE, which never qualifies as realized ROAS. A missing nonselected lane cannot block a selected realized-return lane.",
    "PENDING_MATURITY": "Arithmetic is valid and maturity is OPEN.",
    "INSUFFICIENT_EVIDENCE": "A value or source required for the selected lane or solve mode is UNKNOWN, or maturity is UNKNOWN.",
    "INVALID": "An invalid rule fires. Preserve every supplied fact and name the first request by validation order."
  },
  "validation_order": [
    "SCHEMA",
    "SOLVE_INPUTS",
    "SPEND",
    "TARGET",
    "CURRENCY",
    "CHRONOLOGY",
    "SCOPE",
    "MATURITY",
    "REQUIRED_SOURCES",
    "JOIN_COVERAGE",
    "ADJUSTMENTS"
  ],
  "request_map": {
    "REQ-SOLVE-INPUTS": {
      "owner": "Paid media",
      "text": "Supply exactly the two known values required by the selected solve mode."
    },
    "REQ-SPEND-NONZERO": {
      "owner": "Paid media",
      "text": "Supply matching net ad spend greater than zero or repair the spend adjustments."
    },
    "REQ-TARGET-POSITIVE": {
      "owner": "Budget owner",
      "text": "Supply a target ROAS greater than zero."
    },
    "REQ-CURRENCY-MATCH": {
      "owner": "Finance",
      "text": "Normalize every monetary input into one record currency outside this calculator, then supply that currency and the conversion provenance."
    },
    "REQ-DATES-REPAIR": {
      "owner": "Revenue operations",
      "text": "Repair the cohort, attribution, cutoff or evidence dates so the chronology is possible."
    },
    "REQ-SCOPE-MATCH": {
      "owner": "Paid media and revenue operations",
      "text": "Align the spend population, return population and cohort definition."
    },
    "REQ-MATURITY": {
      "owner": "Revenue operations",
      "text": "Supply the documented outcome horizon and next observation date, then rerun after the cohort is mature."
    },
    "REQ-SPEND-SOURCE": {
      "owner": "Paid media",
      "text": "Supply the spend source reference, covered campaigns, window, currency and cutoff."
    },
    "REQ-FINANCE-SOURCE": {
      "owner": "Finance",
      "text": "Supply the recognized-revenue or collected-cash source, rule, window, currency and cutoff."
    },
    "REQ-PLATFORM-SOURCE": {
      "owner": "Paid media or analytics",
      "text": "Supply platform, conversion actions, attribution model, conversion window and report date."
    },
    "REQ-PIPELINE-SOURCE": {
      "owner": "Revenue operations",
      "text": "Supply the CRM source, stage definition, cohort join key and cutoff."
    },
    "REQ-JOIN-COVERAGE": {
      "owner": "Revenue operations and finance",
      "text": "Supply eligible, matched and unmatched counts, the join key, exclusions and the accepted coverage rule."
    },
    "REQ-RETURN-REVIEW": {
      "owner": "Finance",
      "text": "Review negative net return and its source adjustments before using the ratio."
    },
    "REQ-SOURCE-CUTOFF": {
      "owner": "Source owner",
      "text": "Supply a source snapshot whose through date reaches the outcome cutoff and whose observation date is on or after that through date."
    },
    "REQ-JOIN-RULE": {
      "owner": "Revenue operations and finance",
      "text": "Supply the minimum accepted join coverage for this review as a number from 0 to 1 and state the review rule."
    }
  },
  "canonical_record_keys": [
    "contract_id",
    "contract_version",
    "record_id",
    "fictional",
    "solve_mode",
    "selected_return_basis",
    "currency",
    "cohort",
    "spend",
    "returns",
    "sources",
    "join_coverage",
    "maturity",
    "scope_match",
    "conversion_policy",
    "notes"
  ],
  "canonical_output_keys": [
    "contract_id",
    "contract_version",
    "record_id",
    "normalized_record",
    "calculation",
    "lanes",
    "decision",
    "canonical_reason",
    "requests",
    "next_action",
    "payload_sha256"
  ],
  "canonical_renderer_order": [
    "Record",
    "Cohort and cutoff",
    "Selected calculation",
    "Return lanes",
    "Adjustments",
    "Sources and join coverage",
    "Decision",
    "Evidence requests",
    "Next action"
  ],
  "export_contract": [
    "JSON must preserve the normalized record and canonical output losslessly.",
    "CSV and Markdown must contain every canonical renderer section and request id, owner, reason and exact request text.",
    "No exporter may relabel OPEN_PIPELINE or PLATFORM_ATTRIBUTED_VALUE as ROAS.",
    "Re-import of canonical JSON must reproduce the same output field for field, excluding only generated_at.",
    "Markdown renderer sections are exactly: Record; Cohort and cutoff; Selected calculation; Return lanes; Adjustments; Sources and join coverage; Decision; Evidence requests; Next action."
  ],
  "privacy": [
    "Use stable redacted references. Do not include names, contact details, raw CRM rows, credentials, tokens, signed URLs or private contracts."
  ],
  "source_boundary": "The contract calculates and validates supplied records. It does not authenticate source truth, choose an accounting policy or authorize budget changes.",
  "envelope_contract": {
    "keys": [
      "contract_id",
      "contract_version",
      "record_id",
      "payload",
      "payload_sha256"
    ],
    "payload_keys": [
      "normalized_record",
      "recomputed_output"
    ],
    "hash_scope": "SHA-256 of canonical JSON for payload only.",
    "import_rules": [
      "Reject duplicate decoded JSON keys before parsing.",
      "Require exact contract and record identity.",
      "Require payload hash match.",
      "Re-evaluate normalized_record and require recomputed output equality field by field.",
      "An accepted import returns the fresh recomputed output and a verification receipt."
    ]
  },
  "source_states": {
    "OBSERVED": "Requires owner, source_ref, observed_at, through_date and boundary.",
    "DECLARED": "A planning target or policy supplied by its owner; requires owner, source_ref, observed_at, through_date and boundary.",
    "UNKNOWN": "Requires owner when known, null source_ref/observed_at/through_date, and a boundary naming the missing evidence."
  },
  "date_rules": [
    "All dates are real ISO calendar dates in YYYY-MM-DD form.",
    "Cohort start <= cohort end <= outcome cutoff.",
    "For a measured ROAS solve, required spend and return sources must have through_date >= outcome_cutoff; observed_at may be later than through_date.",
    "MATURE requires documented_horizon and next_observation_date null.",
    "OPEN requires documented_horizon and next_observation_date later than outcome_cutoff.",
    "UNKNOWN maturity requires an evidence request and next_observation_date null."
  ],
  "solve_source_rules": {
    "ROAS": "Require spend source and selected return source. Platform value uses matching_platform_spend.",
    "RETURN": "Require spend source and a DECLARED or OBSERVED target source. The solved return is a planning requirement and cannot be REVIEW_READY realized ROAS.",
    "SPEND": "Require selected return source and a DECLARED or OBSERVED target source. The solved spend is a planning allowance and cannot be REVIEW_READY realized ROAS."
  },
  "scope_rules": {
    "unknown": "INSUFFICIENT_EVIDENCE",
    "explicit_false": "INVALID",
    "all_true": "eligible for further review"
  }
}
