Seven Things Our ODCS Support Refuses to Do
We could describe how CoreModels handles data contracts as a list of capabilities. It is more useful to describe it as a list of refusals, because in governance the interesting question is never what a tool can do. It is what the tool will not do to your document when nobody is watching.
Seven Things Our ODCS Support Refuses to Do
We could describe how CoreModels handles data contracts as a list of capabilities. It is more useful to describe it as a list of refusals, because in governance the interesting question is never what a tool can do. It is what the tool will not do to your document when nobody is watching.
Here are seven, each one a decision we made and can point at.
1. We won't tell you the conversion was lossless
Formats have different vocabularies. An ODCS contract can express a quality check with a metric, a threshold, and a severity; SQL cannot. A governed model can express a controlled vocabulary; ODCS has no enum construct. Any tool claiming lossless conversion between formats of unequal expressive power is either lying or defining "lossless" privately.
So every import, export, and transformation returns a lossiness ledger next to its result: typed records, each with a kind, an exact path, and a plain-English explanation. Four kinds cover what can happen. A type approximation is close-but-inexact — the standard's time-of-day logical type has no counterpart in our model, so it decodes as a datetime, with the verbatim wire type kept so a re-export still says time. A semantic narrowing is meaning held less precisely — quality checks and foreign-key relationships are preserved word-for-word rather than structurally modeled, and the ledger says so per occurrence, with the path. A constraint relaxation is a rule the target cannot enforce — a governed controlled vocabulary exports as a plain string property, and the record names the taxonomy that was relaxed. A structural drop is the honest worst case: a construct with no home at all, named and reported.
A successful call with a non-empty ledger is the normal case. success: true means it ran, not that nothing changed.
2. We won't drop what we don't understand
The decoder walks a contract defensively rather than binding it to a fixed shape. A key it does not recognize — a vendor extension, a field from a newer revision of the standard, something a platform team added — cannot break the parse and cannot disappear. It is preserved verbatim in a raw channel on the node it belonged to, and summarized in the ledger with its path.
The same channel carries the sections our model does not hold structurally: servers, team, roles, SLA, support, pricing. They arrive, sit unmodified, and come back out in place when the document round-trips to ODCS — the contract you get back contains what you put in, including the parts we make no claim to understand. Re-importing is additive in the same spirit: writing a model into a project upserts against what is already there rather than duplicating it.
3. We won't invent keys to make ourselves look better
Our model holds things ODCS cannot express: controlled vocabularies, type inheritance, free-standing relations, projections, elements that belong to no object. It would be easy to emit those anyway under a x-coremodels-* key and call the export complete.
We don't. Each of those constructs produces a lossiness record naming exactly what was not represented, and nothing non-standard goes on the wire. The cost is that our export sometimes says "this did not fit"; the benefit is that the document stays the standard's rather than ours, readable by any conforming tool with no residue of us in it.
4. We won't upgrade your contract behind your back
A contract carrying a pre-v3 apiVersion is accepted and decoded with v3 semantics — and the ledger states plainly that a re-encode will emit v3.1.0. The same statement is made again at encode time, on the record. Nothing is silently modernized. If your document changes generation, that fact is in the report you already have to read.
5. We won't pretend a non-contract is a contract
A tool that best-effort imports whatever YAML it is handed will eventually import a Kubernetes manifest and present the wreckage as a data model. Our decoder refuses instead, with the reason: a document whose kind is not DataContract is rejected as such; a document carrying none of the standard's identifying marks — no kind, no apiVersion, no schema — is rejected as not being a contract; malformed YAML is rejected with the parser's own message.
An honest refusal beats a confident misreading, most of all when the caller is an automated pipeline that will not notice.
6. We won't change a governed model without a role and a look
Importing a contract into a project requires admin rights; exporting requires only read access. The stateless transformation endpoints write nothing at all — every call there is inherently a dry run. And when a contract is mapped onto a project's existing schema, the documented flow is dry-run first: plan, would-be result, and ledger before any write happens.
The division is deliberate. Machines gate syntax; humans gate meaning.
7. We won't trust a proposal because it sounds confident
Mappings can be authored explicitly, inferred from labels and types, or proposed by a model. All three produce a plan, and all three go through the identical validation gate before anything executes.
An explicit mapping guide with an unrecognized key is rejected with a path-carrying error rather than partially applied — a silently ignored typo would execute a mapping you did not intend. An AI-proposed plan gets no privileges: same gate, at most one repair attempt, and a rejected repair is a rejection. The confidence score a model reports about its own proposal is advisory only; the gate never reads it as permission. That path additionally requires elevated project membership and is flagged as sending schema content to an external model service, so nobody wanders into it unaware.
What the refusals buy: drift you can put in front of people
Those seven negatives add up to one positive property. Because the encoder is deterministic — same model in, byte-for-byte the same document out, and re-encoding its own output changes nothing — a diff between two exported contracts is pure signal. No reshuffled keys, no reformatting noise. The changed lines are the changed facts.
That is what turns drift from an argument into evidence. When a consumer says the data no longer matches the agreement, the conversation is a diff and a ledger, reviewed in the same pull request as the change that caused it. Everything kept is kept exactly; everything approximated is named; everything dropped is confessed; every write is gated.
None of that makes translation lossless. It makes it accountable, which is the property a contract actually needs.
For the response envelope and the full definition of the lossiness kinds, see the schema transform documentation in the CoreModels docs.