MACH ODM logoGovernance

Two Verbs and a Dry Run: Governing a Standard You Do Not Own

Our ODM surface has exactly two verbs, and the distance between them is the entire governance argument.

Two Verbs and a Dry Run: Governing a Standard You Do Not Own

Our ODM surface has exactly two verbs, and the distance between them is the entire governance argument.

The first is convert. It turns a published entity document into a formal JSON Schema 2020-12 document and hands it back. It writes nothing, reads nothing from your graph, and needs only Viewer access on the project named in the route — the project scopes authorization and nothing else. Converting a public document is not a privilege; it is reading.

The second is import. It takes the same document and writes the resulting types and elements into a governed project. It requires Admin. Its dry-run mode — same endpoint, dryRun set to true — drops back to Viewer, because rehearsing a change is a different act from making one.

That split encodes our position on standards adoption: reading a standard should be frictionless; changing what your organization means should not be. A standard is still somebody else's decision arriving in your model — it deserves the same gate as any other meaning change, not a fast lane because it has a logo on it.

Rehearse, then write

The dry run is the intended first step, not a courtesy flag. Run the import with dryRun true and you get back a summary — how many types, elements, and taxonomies the entity would contribute — plus the complete lossiness ledger, and nothing is written. Read both, then decide.

This is what makes a pull request reviewable. Instead of asking a colleague to compare a Markdown document against a graph, attach the rehearsal: what the standard would add, and what it could not carry across. Approval then means something specific.

The write itself goes through the same profile layer every other CoreModels write uses — no privileged side door — and re-encoding is an upsert, not an append. Import a revised entity next quarter and it refines the same governed types rather than forking a parallel copy; node writes are keyed by identity and relation writes are guarded against duplicates. That property makes repeated adoption of a moving standard safe — the reason "just import it again" is a reasonable instruction rather than a dangerous one.

Provenance answers the question that always gets asked

Every ODM conversion is stamped: the produced schema carries x-odm-source naming the standards repository, an $id derived from the entity name, and each field's practice level as x-odm-practice. Months later, when someone asks why a field is required, that record can distinguish two very different answers — because the standard says MUST, or because your team decided so in a meeting. A model that cannot tell them apart forces every such conversation back into human memory.

Honest lossiness, including the unflattering kind

Every response from the transform surface carries a lossiness ledger — and it means the same thing everywhere: success: true says the operation ran, not that nothing changed. The ledger is the list of what could not be represented exactly, in four flavors — a structural drop, a type approximation, a constraint relaxation, or a semantic narrowing — each with a path and an explanation in plain language.

For ODM, the ledger carries the cases that would otherwise become silent bugs. A $ref pointing outside the document is preserved exactly as written and recorded as a narrowing, because it will not resolve where you are about to use it. A pointer aimed at a schema the document never defines is recorded as a dangling reference rather than quietly deleted. A sample-object block that is not valid JSON produces a note that no examples were attached, instead of a schema that silently lacks the standard's own worked example.

Batch conversion follows the same principle at a larger grain. Convert a set of entity documents in one call and a file that fails to convert becomes a named structural-drop entry in the ledger while the remaining entities proceed; documents with no schema section are skipped as what they are, not entity documents. The call fails outright only when nothing at all converted. You always know which files made it, and why the others did not.

Where we refuse to guess

Reporting is the right behavior for things that are merely lossy. For things that are wrong, the right behavior is to stop.

A document with no YAML Schema Definition section is rejected with a message saying it is not an ODM entity document — we do not scavenge whatever YAML the page contains elsewhere. A fenced block that is not valid YAML fails, naming which block. A section that parses but defines no named schemas fails, saying what shape was expected. An empty payload fails immediately.

These are boring behaviors, and that is the point. The alternative — a converter that produces something from any input — is exactly how a broken schema ends up in a repository with nobody's name on the decision.

Drift becomes evidence

A standard moves. Your model moves. The gap between them is not a failure; it is information — but only if you can see it.

Because conversion is a pure function of the document text (stateless, no network calls, no project state involved), it is safe to run on every revision, in CI. Two consecutive conversions of the same entity are diffable, and what shows up in the diff is semantic change rather than editing noise.

For the sharper question — what would this revision do to our model? — the mapping surface answers without writing anything. A map-import call with the entity document as its source and dryRun true aligns the revision onto the project's current schema and returns a summary, the ledger, and the executed plan as a replayable artifact. That plan is the reviewable object: approve it, and replaying it against the same source produces the same output, deterministically. Review, then deploy — with the thing you reviewed being the thing that runs.

The principle underneath

Machines should do the transcription. Humans should approve the meaning.

Everything above is that sentence made operational: a converter anyone can run because it changes nothing, a write path that requires authority, a rehearsal before every commitment, a ledger that reports rather than reassures, and hard failures where guessing would be worse than stopping.

The MACH Alliance authored the standard. Governing what it means inside your organization stays your job — and it should require a human to say yes.

For the dry-run and import request shapes, see the schema transform documentation in the CoreModels docs.