One Standard ODCS v3.1 Contract: Batch Files with CsvPath, Live Events with DataContractGate

A nightly file and a live API event can share one definition of "a valid order." Write that definition as ODCS v3.1.0. CsvPath checks the file when it arrives. DataContractGate checks each event at ingest, and AISchemaGate can apply the same contract when a model emits JSON.

One document, two arrival paths
orders.odcs.yaml
apiVersion v3.1.0
kind: DataContract
→
CsvPath
CSV batch on arrival
file
DataContractGate
POST /v1/ingest
event

The contract both runtimes read

ODCS v3.1.0 has no property-level enum key. Allowed values are a library quality rule, metric: invalidValues, with arguments.validValues. Patterns and numeric bounds live in logicalTypeOptions. That is the shape CsvPath converts into row checks, and the shape DataContractGate imports as field rules. The playground emits this shape from a JSON or CSV sample.

apiVersion: v3.1.0
kind: DataContract
id: urn:example:contracts:orders
name: Orders
version: 1.0.0
status: active
schema:
  - name: orders
    logicalType: object
    properties:
      - name: order_id
        logicalType: string
        required: true
        unique: true
        logicalTypeOptions:
          pattern: "^ORD-[0-9]{8}$"
      - name: status
        logicalType: string
        required: true
        quality:
          - type: library
            metric: invalidValues
            arguments:
              validValues: [pending, paid, shipped, delivered, cancelled]
            mustBe: 0
      - name: amount
        logicalType: number
        required: true
        logicalTypeOptions:
          minimum: 0
      - name: email
        logicalType: string
        required: true
        classification: restricted
        logicalTypeOptions:
          format: email

Where each rule is enforced

ODCS v3.1.0 CsvPath on a CSV file DataContractGate on an event
logicalType, required Column present and typed Field present and typed on the JSON object
logicalTypeOptions.pattern, minimum, maximum, format Per-cell checks after conversion Per-event checks. email, uuid, and uri formats are enforced.
invalidValues + validValues Membership test on the cell Imported as an enum on the field
unique, duplicateValues Uniqueness inside the file Uniqueness rule on the field
Schema rowCount The file must contain rows Per-event ingest has no file row count. The rule stays with the batch runtime.
PII transform A file check can reject a bad email. It does not rewrite the cell for storage. mask, hash, or drop on the DataContractGate contract, before storage and on egress

Batch files with CsvPath

When a CSV lands, CsvPath loads the ODCS document, converts it, and collects the rows that match. A raw DataContractGate ODCS export validates against the official ODCS v3.1.0 JSON Schema, so CsvPath can load it without a shim. Use flat column names (customer_id). CsvPath matches headers literally, and a dotted name such as customer.id will miss the column. Keep the contract's property names equal to the CSV header.

from csvpath import CsvPath
from csvpath.odcs import OdcsContractLoader, OdcsConverter

odcs = OdcsContractLoader.from_path(path="orders.odcs.yaml")
conv = OdcsConverter(contract=odcs).convert(path="orders_sample.csv")
statement = next(iter(conv.csvpaths.values()))
matched = CsvPath().collect(statement)
# Rows that break pattern, enum, bounds, or email are absent from matched.

Schema-level rowCount belongs here. An empty file is a batch failure even though there is no event for DataContractGate to reject.

Live events with DataContractGate

Import the same YAML. DataContractGate reads native logicalTypeOptions (pattern, minimum, maximum, minLength, maxLength, format) and library quality (invalidValues becomes an enum, duplicateValues and unique become a uniqueness rule, nullValues becomes completeness). logicalType: timestamp maps to the timestamp field type and is checked as an RFC 3339 string. The import lands as a draft with review required. Promote it, then point producers at ingest:

curl -sS -X POST \
  "https://api.datacontractgate.com/v1/ingest/$CONTRACTGATE_CONTRACT_ID" \
  -H "X-Api-Key: $CONTRACTGATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"order_id":"ORD-00001001","status":"paid","amount":128.40,"email":"orders@example.com"}'

A passing event is the payload you forward, with string PII transforms already applied when the DataContractGate contract declares them. A failing event is quarantined. The same document's outbound path is POST /egress/{contract_id}. AISchemaGate uses that path to check JSON a model returns before your code acts on it.

Add PII actions in the playground when you want mask, hash, or drop on the DataContractGate YAML. Those transforms are a DataContractGate rule on top of the shared ODCS fields. CsvPath will still enforce the type, pattern, and format.

Keep the two runtimes on the same names

The joint example and captured CsvPath output live in examples/odcs-joint. Pair this with the OpenMetadata import when the catalog is the place the ODCS document is approved, and with the warehouse-test comparison when the file has already been loaded.