{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cryptotaxedge.com/schema/cte-classification-v1.json",
  "title": "TransactionIntelligenceRecord",
  "description": "CryptoTaxEdge classification record, v1 (wire format cte-classification-v1). One record per classified transaction: the canonical event category, the US tax treatment with honesty semantics (confidence, needs_review, grey_area), and the per-leg asset breakdown. The treatment enum is closed; category is an open, additively growing vocabulary - branch exhaustive logic on treatment, display category.",
  "type": "object",
  "required": ["api_version", "hash", "chain", "category", "treatment", "taxable", "confidence", "needs_review"],
  "properties": {
    "api_version": { "type": "string", "const": "v1" },
    "id": { "type": ["string", "null"], "description": "Batch calls only: echoes the caller's tx_id for correlation. Absent on single classify." },
    "hash": { "type": "string", "description": "Transaction hash (0x-hex on EVM chains) or base58 signature (Solana)." },
    "chain": { "type": "string", "description": "Chain slug, e.g. ethereum, polygon, solana." },
    "category": { "type": "string", "description": "Canonical event type (swap, transfer, liquidity_add, reward, bridge, ...). Open vocabulary: new categories may be added; never branch exhaustive logic on this field." },
    "treatment": {
      "type": "string",
      "enum": ["disposal", "income", "non_taxable", "expense", "needs_review"],
      "description": "Closed US tax treatment enum. Safe for exhaustive branching. needs_review means no treatment is asserted."
    },
    "taxable": {
      "type": ["boolean", "null"],
      "description": "true = taxable event; false = positive non-taxable finding; null = taxability not asserted. null ALWAYS travels with needs_review: true - never treat null as false."
    },
    "confidence": { "type": "integer", "minimum": 0, "maximum": 100, "description": "Routing signal reflecting how strongly independent evidence agreed. Not an accuracy percentage." },
    "needs_review": { "type": "boolean", "description": "The honesty contract: true = the engine defers to a human instead of guessing. Route to a review queue, never to the books. A record with needs_review false is served as authoritative at any confidence." },
    "ledger_action": { "type": ["string", "null"], "description": "Suggested ledger label for tax-platform import (e.g. Trade, Reward)." },
    "protocol": { "type": ["string", "null"], "description": "Protocol attribution when identified." },
    "description": { "type": ["string", "null"], "description": "Plain-English reasoning behind the classification." },
    "review_note": { "type": ["string", "null"], "description": "Present when needs_review is true (and on grey-area context): why the row was deferred or flagged." },
    "grey_area": {
      "type": ["object", "null"],
      "description": "Present only on genuinely two-sided treatments (LP positions, wrapping, liquid staking, ...). Carries the basis for the split and the position not taken, so a reviewer can see and switch it. null on transactions with a single settled treatment.",
      "properties": {
        "note": { "type": "string", "description": "Basis for the two-sided treatment." },
        "alternate": { "type": "object", "description": "The defensible position not taken (its treatment fields)." }
      },
      "additionalProperties": true
    },
    "assets": {
      "type": ["object", "null"],
      "description": "Per-leg asset movements from the classified perspective.",
      "properties": {
        "sent": { "$ref": "#/$defs/legList" },
        "received": { "$ref": "#/$defs/legList" },
        "gas": { "type": ["object", "null"] }
      },
      "additionalProperties": true
    },
    "error": { "type": ["string", "null"], "description": "Batch items only: set when this item could not be classified (e.g. tx_not_retrievable). An item with error set is NOT a classification and never a result to book." }
  },
  "allOf": [
    {
      "if": { "properties": { "taxable": { "const": null } }, "required": ["taxable"] },
      "then": { "properties": { "needs_review": { "const": true } } }
    },
    {
      "if": { "properties": { "treatment": { "const": "needs_review" } }, "required": ["treatment"] },
      "then": { "properties": { "needs_review": { "const": true } } }
    }
  ],
  "additionalProperties": true,
  "$defs": {
    "legList": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["symbol", "amount"],
        "properties": {
          "symbol": { "type": "string" },
          "amount": { "type": "string", "description": "Decimal string. Never parse as float for accounting use." },
          "decimals": { "type": "integer" },
          "action": { "type": "string" },
          "token_address": { "type": ["string", "null"] },
          "to": { "type": "string" },
          "from": { "type": "string" }
        },
        "additionalProperties": true
      }
    }
  }
}
