Commerce as a formal system.

Currency-safe, state-validated commerce types with a contract you can prove your code obeys — across 4 languages, from one frozen schema.

v1.1.0 · MIT · 4 bindings proven equivalent
the problem

Commerce code is full of mistakes that look correct.

None of these throw on a happy path. They pass review, ship, and surface later as reconciliation bugs — and they get sharper when the code is generated by an agent that has no innate sense that two currencies can’t be added.

Mixed currencies

A total is summed across two currencies as if they were the same number.

200 MAD + 30 EUR → 230 ?

Invalid transitions

An order is moved from Fulfilled back to Accepted — a state the machine forbids.

Fulfilled → Accepted

Tree drift

A parent order’s child commitments no longer sum to the parent after an edit.

Σ children ≠ parent
the model

A precise model of what commerce is.

Five primitives, six invariants, and one frozen schema — written down precisely enough that independent implementations produce the same answers. From that one schema Warp generates typed bindings in several languages, and a conformance suite checks that they agree.

5
primitives
Party · Value · Intent · Commitment · Fulfillment
6
invariants
The laws every valid commerce object obeys.
1
frozen schema
JSON Schema 2020-12 · v1.0.0
4
bindings, proven equal
TypeScript · Python · Rust · Go
PartyValueIntent CommitmentFulfillment
quickstart

Build an order. Audit it. In a few lines.

The order() builder composes a history-complete, auditable order and runs the headline check. A buggy order is returned as a result you handle — never coerced into a broken object.

order.ts
import { order } from "@warp-lang/commerce-types";

// Build a valid order: buyer, seller, a priced item, paid + fulfilled.
const built = order()
  .from("buyer_1")
  .to("seller_1")
  .item({ sku: "TSHIRT-RED-M", price: { amount: 200, currency: "MAD" } })
  .paid()
  .fulfilled()
  .build(); // Result<AuditedOrder> = { ok: true, value } | { ok: false, error }

if (built.ok) {
  const violations = built.value.audit(); // []  — the headline check, clean
}

// A buggy order — two currencies in one order — is surfaced as a Result,
// not coerced into a broken object.
const mixed = order()
  .from("buyer_1").to("seller_1")
  .value({ amount: 200, currency: "MAD" })
  .value({ amount: 30, currency: "EUR" })
  .build();

if (mixed.ok === false) {
  mixed.error; // "Order mixes currencies (MAD, EUR)… (Invariant 1: Value Conservation)"
}

Both samples run as written against the published packages — no ! assertions, no mocks.

what is actually enforced

Honest about what it checks — in two layers.

A project confident enough to show exactly what it does and doesn’t do is more trustworthy than one claiming it catches everything. Warp enforces the model in two places, and they’re not the same.

audit layer · all bindings

The runtime audit checks all six invariants, and the 4-way cross-check proves every binding returns the same verdict on every fixture.

  • I-1…I-6checked by auditCommerce() / the checkI* functions.
  • i1-currency-mixeda mixed-currency subject is rejected.
  • i2-backward-transitiona backward state move is rejected — across all bindings.

The table on the right is the second layer: what the DSL compiler catches statically, before anything runs.

idinvariant — compiler (static)status
I-3Capacity VerificationFails compile if a commitment reaches Accepted with no capacity-verification step.BLOCKING
I-4Temporal IntegrityFails compile when a fulfillment is ordered before its commitment forms.BLOCKING
I-5Identity PermanenceFails compile on duplicate stable identifiers.BLOCKING
I-6Tree ConsistencyFails compile when a child commitment value exceeds its parent.BLOCKING
I-1Value ConservationCompiles and warns when one node mixes currencies.WARNING
I-2State MonotonicityPlaceholder in the compiler; the audit layer enforces it via the transition table.NOT YET CHECKED

The compiler statically blocks four invariants, warns on one, and defers one to the audit layer, which checks all six at runtime. Both layers are real; neither is claimed to be the other.

conformance

Proven, not asserted.

A language-neutral suite of fixtures is what turns “a library you like” into “a model you can verify against.” Every binding runs the same fixtures and must give the same verdict.

51/51
fixtures pass against the canonical schema
45/45
4-way cross-check agrees (6 structural fixtures n/a)
22
commerce domains validated as case studies
3
real audit bugs locked out forever

The three locked regression bugs

TND ×10

Three-decimal currencies (TND/BHD/KWD) were treated as two-decimal — every amount 10× wrong.

locked by money-roundtrip-minor-units
adapter empty history

Final-state objects with empty histories that falsely passed or failed the auditor.

locked by order-paid-fulfilled + i4-empty-history-fulfilled
I-6 float equality

Tree consistency using exact float equality (0.1 + 0.2 ≠ 0.3).

locked by tree-float-0.1-plus-0.2 + i6-children-exceed-parent

Prove your own binding.

Generate types from the schema, run the same fixtures, and earn the compatibility badge. The Go binding was built exactly this way — as an outsider following the guide.

conformance: 51/51 (schema v1.0.0) Read the conformance guide ↗
the language

A DSL that compiles the model down.

Beyond the types, Warp has a small workflow language compiled by warp-core. Its type checker performs the static invariant checks shown above — capacity, temporal order, identity, and tree consistency block the build; currency mixing warns. The model stays the single source either way.

It’s a layer on top of the same frozen schema, not a replacement for it. If you only want typed, audited commerce objects, the packages are the whole story.

cart_recovery.warp
// a workflow over the same primitives the types describe
workflow cart_recovery {
  on intent.Abandoned {
    verify capacity(seller)        // I-3 — or the build fails
    commitment.propose(buyer, seller)
    await commitment.Accepted
    fulfillment.plan()             // must follow Accepted — I-4
  }
}
what’s next

Roadmap.

Stated in future tense, because it isn’t shipped yet.

next
In-browser playground

A live demo that runs the real published package — paste a commerce object, run the actual invariant checks, see real results. It will bundle real logic, never mock it.

planned
Compiler I-1 / I-2 hardening

Promote Value Conservation from a warning and implement the workflow-level State Monotonicity check, so the compiler statically blocks what the audit layer already enforces.

exploring
A semantic-integrity layer beneath payment-authorization protocols

Sitting under agentic-commerce protocols so the commerce a model or a human generates is structurally valid before it’s authorized.