Data Contract Doctrine
0. Purpose, Scope, and What This Is Not
Purpose
This doctrine canonizes one claim, one ladder, and one warning.
The claim: Everyone has a data contract. You may not know what it is - it may be nebulous, not well defined, very mushy - but you have it defined somewhere. Every system that exchanges data has contracts whether or not anyone wrote them down; the only choice available is between explicit, owned contracts and implicit, accidental ones. The SalesBlaster position: contracts are defined explicitly and consciously, in shared libraries, documented well, type-safe, and as abstract as their demonstrated use cases require - no more.
The ladder: abstraction in data modeling is a sequence of earned promotions, not a starting posture (§2).
The warning: the ladder's top rung - structure-as-content metamodeling, where data models host user-defined data models - is simultaneously the platform's deepest capability and the inner-platform effect's front door. The same restraint applies here at the model layer, and this doctrine is its canonical home (§3).
Scope
- The universal claim and its consequence: implicit contracts are still contracts (Hyrum's discipline, §1).
- The four-rung Abstraction Ladder, the ascent rule, and the descent test (§2).
- The Inner-Platform Warning and the counter-disciplines already in canon (§3).
- Where contracts live, by executor type and by layer - the contract trilogy plus the substrate forms (§4).
- Verification: contracts as falsifiable, observer-checked assumptions (§5).
- The direct-response layer: the contract story as mechanism differentiation for technical buyers (§6).
- First principles and anti-patterns (§7–8).
What This Is Not
- Not a schema reference. Field-level contract specifications live in their own companion specifications.
- Not a permission slip for metamodeling. §3 exists to make the top rung harder to reach, not easier to justify.
- Not new architecture. Every mechanism cited here already exists in canon; this doctrine supplies the philosophy that was distributed across them implicitly.
1. The Universal Claim
A data contract is the full set of expectations one party may rely on about the data another party produces or accepts - shape, types, semantics, nullability, ordering, timing, units, identity. Writing it down does not create it; consumption creates it. The moment any consumer depends on any observable property of your output, that property is contractual - this is Hyrum's discipline, and it has one operational consequence: undocumented contracts are not absent contracts; they are unmanaged liabilities. They live in the gap between what the producer believes it promised and what consumers actually rely on, and they are discovered at 3 a.m., by incident.
The mushy contract's lifecycle: an ad-hoc JSON shape ships → three consumers grow dependencies on incidental properties (key order, a string that's "always" numeric, a field that's "never" null) → the producer "fixes" something → consumers break in ways no test predicted → the post-incident patch hardens the accident into permanent load-bearing structure, still undocumented. Every system that has not consciously chosen otherwise is somewhere in this lifecycle right now.
The explicit alternative, already the standing convention here: contracts as typed artifacts in shared libraries (dependency direction makes ownership unambiguous - consumers depend on the contract, never on the producer's internals), Zod-validated at runtime where the boundary is stochastic or external, documented at the definition site, versioned by commit SHA (per OCP's versioning rule), and changed only through the owning artifact's mutation rule.
2. The Abstraction Ladder
Data models ascend through four rungs. Each promotion is earned by demonstrated variance - never by anticipated variance.
L0 - Implicit. The contract exists only as behavior. Status: forbidden as a steady state; tolerated only inside a single file's lifetime. The Tracer Bullet pattern permits pre-port shapes precisely because they are explicitly temporary and promotion-triggered.
L1 - Explicit and concrete. Typed, named, documented, in a shared location; models one use case faithfully. This is the default rung and the correct resting place for most models forever. A concrete model that three teams can read beats an abstract one that three teams must decode.
L2 - Abstract multi-use-case. One model consciously serving several proven consumers - campaign primitives serving accountability and marketing alike is the canonical promotion. Ascent rule: promotion to L2 requires the rule-of-three (or a documented two-instances-plus-meta-pattern case) in production, not in imagination.
L3 - Structure-as-content (metamodel). Models whose content is itself structure definitions: user-defined fields, user-defined entities, user-defined graphs - the rung where the platform can host a customer's own data model. This rung is real capability (it is what makes multi-tenant verticalization possible at all), and it is rationed: ascent requires three independent customers demonstrably blocked by L2's closed set, an explicit decision record, and a declared boundary stating which parts of the domain remain closed (a closed primitive set with an open frontmatter metadata: surface is the worked example of L3 done correctly: open extension surface, closed structural core).
The descent test: any model whose abstraction outruns its consumers gets demoted. If explaining the model takes longer than enumerating its concrete instances, it is on the wrong rung.
3. The Inner-Platform Warning
The inner-platform effect: rebuilding, inside your product, a worse version of the general-purpose system beneath it - an entity-attribute-value soup that re-implements Postgres in Postgres, a "flexible workflow engine" that re-implements the programming language it's written in. The metamodel rung is where it happens, because L3's pitch is always seductive and always the same: make it generic now and we'll never have to touch it again. The outcome is always the same too: every query gets harder, every invariant becomes unenforceable, every new engineer's onboarding doubles, and the domain's teeth dissolve into key-value mush.
The standing counter-disciplines, already canonical and hereby unified:
- Closed structural cores with open extension surfaces. OCP's artifact registry (five types, closed;
role:andmetadata:open) and a campaign kernel's closed primitive set are the same move at two layers. Extend at the declared surface; never reopen the core. - The kernel-layer twin. The kernel layer forbids metamodeling the engine so "one engine hosts every vertical"; this doctrine forbids the same move at model scale. The honest reuse unit is conventions and shared libraries, not a universal schema.
- Earned ascent only. The §2 ascent rules are the gate. "A future customer might need it" is the theoretical-modification trap wearing a type system.
- Invariants live in use cases, not in generic engines. The moment a rule can no longer be expressed as a typed domain invariant because the model got too generic, the model - not the rule - is wrong (runtime enforcement presumes expressible invariants).
L3 is not banned. It is priced. The platform that can host user-defined models is the enterprise moat - later, gated, and only where customers have proven the closed set insufficient.
4. Where Contracts Live - The Trilogy and the Substrate
Every executor type in the workflow taxonomy has a canonical contract form, and this doctrine is the claim they share:
- Agent executors → typed agent-tool contracts (a variable taxonomy and a coupling/invariant matrix), enforced at dispatch.
- Deterministic executors → application-layer ports; workflows and adapters are infrastructure satisfying port contracts.
- Human executors → human-in-the-loop handoff contracts; frontmatter-declared, parallel in spirit to the agent-tool form.
And the substrate forms beneath all three: persisted contracts as schema-per-bounded-context; published contracts as named, versioned events (an event name is a promise to every future subscriber); synchronous published contracts as request/response DTOs at the HTTP boundary (a request/response shape is a promise to every separately-deployed consumer, versioned from inception and additive-then-deprecate, identically to the event lifecycle); content contracts as Zod-validatable frontmatter (a kernel that cannot self-describe in frontmatter is not substrate-portable); boundary contracts at vendor seams, where vendor identity is a value, never structure (a vendor name in a domain type is a contract you don't own leaking into one you do).
One claim above all of them: same philosophy, eight surfaces (three executor forms + five substrate forms). Define explicitly, own in shared locations, type-check at boundaries, version by SHA, mutate by rule.
5. Verification - Contracts Are Falsifiable Assumptions
A contract no one can violate detectably is documentation, not a contract. Three standing disciplines apply:
- The falsifier-in-hand principle: every load-bearing contract assumption ships with the observation that would disprove it, checked before the assumption is built upon.
- The canonical-observer principle: conformance is verified through a reader independent of the writer - the producer's "it worked" is never the evidence.
- Drift detection: contracts and their consumers are audited for divergence as a process, because Hyrum guarantees divergence is always accumulating somewhere.
6. The Direct Response Layer
The technical-buyer opener (NEPQ problem-awareness, rendered in final form): You already have a data contract with every tool in your stack. You've just never read it, because nobody wrote it down - it's whatever your Zapier zaps and your CSV exports happen to rely on today. We didn't invent contracts for your business; we made yours explicit. That line works because it is true of every prospect without exception, it reframes the engagement from "adopt our schema" to "discover your own," and it converts an architecture lecture into a Voss-style accusation audit of their current stack.
Mechanism differentiation (Schwartz Stage 3–4): in the saturated agency-tools market, "AI that writes emails" is a dead Stage-1 claim; "a typed contract between every agent and every tool, enforced at dispatch, with your domain's invariants encoded" is a mechanism claim competitors cannot copy by prompt - it names why the system is trustworthy, which is the Stage 3–4 currency. The contract ladder is also the enterprise-pricing story in waiting: L3 hosting of customer-defined models is what justifies the top tier, when it is earned (§3).
Kennedy's measurement governance, restated in contract terms: a KPI is a data contract with reality - the KPI pre-commitment rule (no metric ships without its intervention) is exactly this doctrine applied to measurement: an unactionable metric is a mushy contract with your own dashboard.
7. First Principles
DC-1. Consumption creates contracts; documentation only manages them. Choose managed.
DC-2. The shared library is the contract's home; dependency direction is its ownership deed. Consumers import the contract; nobody imports the producer's internals.
DC-3. Concrete by default; abstract by promotion; metamodel by exception. The ladder ascends on production evidence only.
DC-4. Closed cores, open surfaces. Extension happens at declared extension points; structural reopening requires an ADR.
DC-5. Types are the cheapest enforcement layer; runtime validation guards every stochastic or external boundary. Compile-time inside the trust boundary, Zod at its edges.
DC-6. Every contract ships with its falsifier and its independent observer. Unverifiable promises are vibes.
DC-7. An abstraction that cannot name three live consumers is a speculation with a type signature.
8. Anti-Patterns
DC-AP1 - Mushy-contract denial. "We don't have a schema for that" - you do; it's just enforced by incident.
DC-AP2 - Premature metamodel. L3 reached on anticipated variance. The inner-platform effect's standard entrance (§3); rejected by the ascent rule.
DC-AP3 - Contract-by-vibes between agents. Two agents exchanging unvalidated free-text where a typed contract belongs - stochastic boundaries are exactly where runtime validation is non-negotiable.
DC-AP4 - Vendor nouns in domain types. The boundary contract leaking inward. Vendor identity is data.
DC-AP5 - The god-model. One L2/L3 model accreting every team's fields because "it's already abstract." Abstraction is not a landfill; bounded contexts exist to keep the same word from meaning five things.
DC-AP6 - Silent breaking change. Any contract mutation outside the owning artifact's declared mutation rule. The append-only and amendment-log disciplines exist precisely so contracts change in daylight.
End of Data Contract Doctrine v1.0.0.
You have a data contract whether you wrote it or not. Write it. Share it. Type it. Promote it only when production demands, and guard the top rung like the moat it is - because the inner platform is always one "let's just make it generic" away.