{
  "$schema": "https://t2k.ai/schemas/t2k-ontology-pack.v1.schema.json",
  "manifestType": "t2k.ontology-pack",
  "manifestVersion": "1.0",
  "ontologyVersion": "1.0.0",
  "ontologyId": "example.invoices",
  "label": "Invoice and payment reconciliation",
  "description": "A reusable teaching ontology for recorded receivables balances and payment allocations.",
  "packKind": "workflow",
  "status": "draft",
  "scope": {
    "domain": "accounts_receivable",
    "description": "Read-only invoice review over a fictional receivables and payments snapshot.",
    "exclusions": [
      "Tax or accounting policy determination",
      "Ledger reconciliation or balance recomputation",
      "Currency conversion",
      "Collection communications or payment execution"
    ]
  },
  "objectTypes": [
    {
      "id": "customer",
      "label": "Customer",
      "family": "Billing organization",
      "nodeKind": "organization",
      "purpose": "The legal billing account identified in the receivables system.",
      "identity": [
        "customer_id"
      ],
      "properties": [
        {
          "id": "customer_id",
          "valueType": "string",
          "required": true,
          "description": "Stable source-system identifier; display labels are not identity.",
          "authorityDomain": "operations",
          "temporal": false
        },
        {
          "id": "display_name",
          "valueType": "string",
          "required": true,
          "description": "Customer display name.",
          "authorityDomain": "finance",
          "temporal": false
        }
      ]
    },
    {
      "id": "invoice",
      "label": "Invoice",
      "family": "Receivable",
      "nodeKind": "financial-event",
      "purpose": "An issued billing record with a source-recorded outstanding balance.",
      "identity": [
        "invoice_id"
      ],
      "properties": [
        {
          "id": "invoice_id",
          "valueType": "string",
          "required": true,
          "description": "Stable source-system identifier; display labels are not identity.",
          "authorityDomain": "operations",
          "temporal": false
        },
        {
          "id": "status",
          "valueType": "string",
          "required": true,
          "description": "Example invoice states: issued, paid or void.",
          "authorityDomain": "finance",
          "temporal": true
        },
        {
          "id": "currency",
          "valueType": "string",
          "required": true,
          "description": "Uppercase ISO currency code.",
          "authorityDomain": "finance",
          "temporal": false
        },
        {
          "id": "total_minor",
          "valueType": "integer",
          "required": true,
          "description": "Issued invoice total in declared minor currency units.",
          "authorityDomain": "finance",
          "temporal": false
        },
        {
          "id": "outstanding_minor",
          "valueType": "integer",
          "required": true,
          "description": "Balance explicitly recorded by the receivables source; this example does not derive it.",
          "authorityDomain": "finance",
          "temporal": true
        },
        {
          "id": "due_at_epoch_seconds",
          "valueType": "integer",
          "required": true,
          "description": "Due cutoff in UTC Unix seconds, prepared from the source\u2019s agreed due-time convention.",
          "authorityDomain": "finance",
          "temporal": false
        },
        {
          "id": "disputed",
          "valueType": "boolean",
          "required": true,
          "description": "Explicit recorded dispute state; absence is not treated as false.",
          "authorityDomain": "finance",
          "temporal": true
        }
      ]
    },
    {
      "id": "payment",
      "label": "Payment",
      "family": "Cash movement",
      "nodeKind": "financial-event",
      "purpose": "A payment record with a recorded settlement state; receipt is separate from allocation.",
      "identity": [
        "payment_id"
      ],
      "properties": [
        {
          "id": "payment_id",
          "valueType": "string",
          "required": true,
          "description": "Stable source-system identifier; display labels are not identity.",
          "authorityDomain": "operations",
          "temporal": false
        },
        {
          "id": "status",
          "valueType": "string",
          "required": true,
          "description": "Example states: pending, settled or reversed.",
          "authorityDomain": "treasury",
          "temporal": true
        },
        {
          "id": "currency",
          "valueType": "string",
          "required": true,
          "description": "Currency of the payment.",
          "authorityDomain": "treasury",
          "temporal": false
        },
        {
          "id": "amount_minor",
          "valueType": "integer",
          "required": true,
          "description": "Recorded payment amount, not necessarily fully allocated.",
          "authorityDomain": "treasury",
          "temporal": false
        }
      ]
    },
    {
      "id": "payment_allocation",
      "label": "Payment allocation",
      "family": "Receivables application",
      "nodeKind": "artifact",
      "purpose": "An explicit application of part of one payment to one invoice.",
      "identity": [
        "allocation_id"
      ],
      "properties": [
        {
          "id": "allocation_id",
          "valueType": "string",
          "required": true,
          "description": "Stable source-system identifier; display labels are not identity.",
          "authorityDomain": "operations",
          "temporal": false
        },
        {
          "id": "status",
          "valueType": "string",
          "required": true,
          "description": "Example states: posted or void; posting alone does not prove the payment settled.",
          "authorityDomain": "finance",
          "temporal": true
        },
        {
          "id": "currency",
          "valueType": "string",
          "required": true,
          "description": "Currency of the allocated amount.",
          "authorityDomain": "finance",
          "temporal": false
        },
        {
          "id": "amount_minor",
          "valueType": "integer",
          "required": true,
          "description": "Minor currency units allocated to the linked invoice.",
          "authorityDomain": "finance",
          "temporal": true
        }
      ]
    }
  ],
  "structuralRelationships": [
    {
      "from": "invoice",
      "property": "billed_to",
      "to": "customer",
      "cardinality": "many_to_one",
      "description": "Customer named by the invoice billing record."
    },
    {
      "from": "payment",
      "property": "received_from",
      "to": "customer",
      "cardinality": "many_to_one",
      "description": "Customer identity explicitly attached to the payment record."
    },
    {
      "from": "payment_allocation",
      "property": "applied_to",
      "to": "invoice",
      "cardinality": "many_to_one",
      "description": "One invoice receiving this allocation."
    },
    {
      "from": "payment_allocation",
      "property": "uses_payment",
      "to": "payment",
      "cardinality": "many_to_one",
      "description": "One payment from which this allocation is applied."
    }
  ],
  "reasoningFunctions": [
    {
      "id": "overdue_review",
      "input": "Customer ID, one currency and an explicit due-time cutoff in UTC Unix seconds.",
      "output": "Issued, undisputed invoices due before the cutoff with a positive source-recorded balance.",
      "humanCheckpoint": "Receivables staff review supporting records and contact policy before any collection action."
    },
    {
      "id": "settled_allocations",
      "input": "Invoice ID and one currency code.",
      "output": "Total posted allocation amount backed by payments currently recorded as settled.",
      "humanCheckpoint": "Finance reconciles allocations, reversals and ledger balances before financial reporting."
    }
  ],
  "normalizationRules": [
    "These are authoring requirements, not an executed ingestion or accounting pipeline. Fixtures are supplied normalized.",
    "Preserve invoice, payment and allocation source IDs. Do not identify an allocation solely by customer and amount.",
    "Use integer minor units and retain currency. This example uses cents for USD and EUR; never sum them together.",
    "Convert an agreed due-time instant to UTC Unix seconds before comparison. The sample due dates use midnight UTC solely as an example convention.",
    "Keep the receivables source\u2019s outstanding balance separate from payment receipts and payment allocations."
  ],
  "validationRules": [
    {
      "id": "balances_are_recorded",
      "level": "semantic",
      "severity": "review",
      "target": "example.invoices:invoice.outstanding_minor",
      "assertion": "Outstanding balance must be sourced explicitly and reconciled by the owning ledger process.",
      "message": "This query reads the recorded balance; it does not subtract payments, taxes or credit notes."
    },
    {
      "id": "allocation_scope",
      "level": "semantic",
      "severity": "review",
      "target": "example.invoices:payment_allocation",
      "assertion": "Allocated totals must respect payment and invoice currency, reversal policy and allocation limits.",
      "message": "The sample query checks currency, posted allocation status and settled payment status. Cross-record allocation limits require separate reconciliation and are not implemented here."
    },
    {
      "id": "due_cutoff",
      "level": "semantic",
      "severity": "review",
      "target": "example.invoices:invoice.due_at_epoch_seconds",
      "assertion": "Due-time conventions must be agreed before converting a date to an instant.",
      "message": "The sample query uses strictly before the supplied cutoff, with no implicit grace period or business calendar."
    },
    {
      "id": "no_collection_authority",
      "level": "semantic",
      "severity": "review",
      "target": "example.invoices:reasoning_function:overdue_review",
      "assertion": "An overdue-review result must not itself authorize customer contact or collection.",
      "message": "No connector write or message is part of these read-only functions."
    }
  ]
}
