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.
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
- One schema object, flat property names, headers that match those names.
- Allowed values as
invalidValues/validValues, so both the v3.1.0 schema and CsvPath accept them. - Patterns and bounds in
logicalTypeOptions, so a file check and an event check reject the same badorder_idor negativeamount. - File-only rules, such as
rowCount, stay on the batch side. Event-only rules, such as PII transforms and quarantine replay, stay on DataContractGate.
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.