Specification · Section 7 of 13
Contracts calling contracts
Covers inter-contract topology through ports, trust via pinned identity and verified receipts, compensational (saga) execution instead of distributed ACID, the rejection of governing/middleware contracts, transport-agnostic messaging, call-outs to services, an import manifest for external functions, and compile-time modules - the standard library of law/ statute mirrors and std/ vetted reusable modules, flattened with provenance.
7.1 may call is the port model, one step up
A port’s from: today names a party. Generalized, it names a contract:
ports:
in order.receive from contract mk-se-2027-000042 port order.place # only THAT contract,
pinned sha256:9f2c44... # at that version
The chain CUSTOMER A -may call-> CONTRACT A -may call-> CONTRACT B is then readable off two port manifests, exactly as single-contract capabilities are readable off one (§1). And procurement already LIVES in this topology - we declare it, we do not invent it:
- ramavtal → avrop: the call-off contract is a child drawing on the parent’s pools. The takvolym is a shared place, and §3.1’s Petri nets are the sixty-year-old mathematics of exactly this - many child contracts drawing one parent pool without double-counting.
- huvudentreprenör → underentreprenör: back-to-back contracts. Flow-down clauses are lawyers hand-copying terms between contract layers; a mechanical back-to-back references the upstream terms it mirrors, by hash.
- factoring: assignment of a receivable = re-pointing an out-port’s
to:- a declared, signed, receipted event instead of a denuntiation letter.
7.2 Trust: pinned identity + verified receipts, never claims
A contract’s identity is its id + version hash + genesis seals - which is exactly an artifact’s identity, so §5’s trust machinery transfers verbatim: a referencing contract pins the counterpart’s hash (its amendments reach the reference only via your amendment) or tracks under declared bounds, and believes data-level seals over transport (§5.5). Messages between contracts travel as enveloped documents (§2) through ports - there is no RPC, no shared runtime, no synchronous call into another machine’s internals. Contract B believes a message from Contract A for one reason only: it carries A’s judgment receipt, verified offline against A’s pinned identity, chain and seal intact, before any of B’s rules run.
Honesty about the boundary: B verifies that A’s machine judged X under A’s signed rules - it cannot verify that A’s rules are wise, any more than a subcontractor can audit the head contract. That is what back-to-back drafting has always meant; the mechanical version makes the dependency explicit and the evidence checkable, nothing more.
(And the Solidity graveyard stays closed: cross-contract calls are asynchronous documents between separately-sealed logs - no reentrancy, no mid-call state to observe, nothing to flash-loan. The starvation diet of §9 extends across the contract boundary by construction.)
7.3 Transactions: ACID inside, sagas between (the smiley is correct)
- Inside one contract: full ACID, for free. The single-writer log of §3.3: one event = one atomic, serialized, durable, hash-chained transition. Every contract is its own serialization domain.
- Across contracts: no distributed ACID - by design, not by weakness. Two-phase commit needs a coordinator both organizations obey and locks held across autonomous parties’ books. That is a shared-infrastructure bet we decline. It does exist: Canton/Daml achieves atomic cross-contract composition - at the price of every party joining one synchronization domain (the same trade §12 cites it for on privacy). Autonomous parties keep autonomous logs.
- So: compensational execution - and the domain already standardized the compensations. Cross-contract flows are sagas (Garcia-Molina & Salem, 1987): sequences of locally-atomic steps with declared compensating actions. Procurement’s gift: the compensating documents ALREADY EXIST as standards - the kreditfaktura (EN 16931 credit note, type code 381) undoes an invoice, pacs.004 returns a payment, the Peppol order response cancels an order. Forty years of e-documents encoded “undo” as documents because commerce never had rollback - the law itself is compensational (remedies, damages, kreditfaktura; no court has ever un-executed anything). A contract system promising distributed ACID would be lying about the world it models.
- Where atomic-like coupling is genuinely needed: reservations, not locks. §3.4’s reserve-with-expiry IS try-confirm-cancel (TCC): B reserves (try), the draw confirms when A’s receipt exists (confirm), and the expiry auto-releases if it never does (cancel - a deterministic timeout by event math, no coordinator). The avrop shape exactly: the child’s order stands only when the parent-pool reservation receipt exists; the reservation dies quietly otherwise. Booking systems have run on reservations-instead-of-locks for decades.
- Failure handling is already in this document. A failed or timed-out saga leg is a thrown condition; §4.2’s escalation catches it; compensation legs are declared per port pair - signed contract terms, not an ops runbook - and
finallysurvival obligations run regardless. (§4.2 already flagged the saga pattern asfinally’s distributed-systems cousin; this section is that flag, cashed.)
Cross-contract consistency is therefore eventual and provable: a receipt embeds the hash of the foreign receipt it acted on, so any third party holding both chains can replay and verify that the saga either completed or compensated. A dispute over a broken flow is two receipt chains laid side by side, not two legal departments’ inbox archaeology. The slogan, honestly earned: ACID inside the contract, sagas between contracts, receipts everywhere.
Prior art: sagas (1987; revived wholesale by microservices), the TCC/reservation pattern (bookings, payment holds), 2PC/XA (the rejected road: blocking, coordinator trust), Canton synchronization domains (the accepted-cost counterexample), BPMN 2.0 compensation events (§4.2), and on the legal side: back-to-back/flow-down drafting, kreditfaktura practice, and ISDA close-out netting as industrial-strength compensational settlement.
7.3b Why we don’t support governing/middleware/proxy contracts - EVER
The tempting idea, recorded here so nobody re-invents it: a contract registers itself as MIDDLEWARE - binding to certain operations (financial pool ops, all call-outs), running in the same transaction as a recorder or decorator - a GOVERNING contract over many sub-contracts, where the subs don’t know about it: REQUEST => GOVERNOR => CONTRACT. The need is real, the mechanism is poison.
Four structural kills - each one fatal alone:
- It breaks replay, which breaks everything. Verdict = pure function of (contract, its own log) is THE covenant. A governor acting “in the same transaction” makes contract X’s outcome depend on state outside X’s signed document - and since a governor spans many subs, replaying X suddenly requires every sibling’s interleaved log. That is the global shared ledger rebuilt through a side door: the exact Canton trade §7.3 declines. One log per contract, or determinism dies. There is no halfway.
- An invisible governor IS the fraud we hunt. The thesis is absent port = prohibition; everything readable off the manifest; nothing moves silently. A layer the sub-contract “doesn’t know about” is a silent term - structurally identical to the negative-option renewal and the quietly-updated rate table, wearing an architecture diagram. And it murders pre-validation: the supplier runs the file, gets ACCEPTED, submits - a hidden layer vetoes. Pre-validation is the adoption story; middleware makes it a liar.
- “Same transaction” across two state domains = 2PC. Already litigated (§7.3). If the governor shares the child’s log it is not middleware, it is the same contract; if it doesn’t, “same transaction” needs the distributed coordinator we refused. The middle is marketing.
- The prior art is a graveyard. Solidity’s proxy/upgradeable pattern - an interceptable governing layer - is that ecosystem’s single richest source of catastrophic exploits and rug-pulls. Spring AOP taught a generation that invisible cross-cutting behavior is undebuggable. The ESB became the enterprise thing nobody could reason about. “A decorator you can’t see in the manifest” has been tried, repeatedly, expensively.
The salvage - every legitimate governor capability already has a declared, replay-safe mechanism:
| Middleware wants | The mechanical equivalent (already specified) |
|---|---|
| Observe/record every operation | Fold the receipts: envelope grammar (§2) + a borrow disclosure scope - the governor reads every child’s chain, computes cross-contract state, alerts. Zero interception; this is literally the referee posture. |
| Veto/gate operations at runtime | An approval leg naming the governor (§4.1): require approval of governing-contract, declared IN the child, verdict PENDING, governor answers through a port. Same power - visible, signed, replayable. |
| Shared limits across many subs | Parent pool draws (§7.1, ramavtal → avrop): the cross-contract ceiling is a declared draw on the governor’s pool; §3.1’s Petri math already handles parallel draws. |
| Inject policy into every contract | Profiles + tracked artifacts (§5.3, a rule stack): attestordning, LOU gates, org policy as artifacts the contracts track - updated once, under governance, receipted everywhere. |
| React to violations | Escalation (§4.2) + amendment offers, downstream of receipts. |
The principle, one line: governance flows DOWN through declared bindings and UP through receipts - never SIDEWAYS through interception. The governor sits before execution (genesis bindings) and after it (folding receipts), never inside it.
And the reason this is no compromise: it is how law itself works. Lex superior does not intercept. LOU has never sat inside an invoice transaction - it constrains what may validly be signed (ex ante) and supplies consequences from the record (ex post). The middleware instinct reaches for a governing layer; the law’s own architecture - constrain at formation, adjudicate from the record - is the mechanical answer, and both halves are already built.
7.4 Transport is not the contract’s business
The design already earns this: everything a transport would normally be trusted for lives ABOVE the pipe. Authenticity and integrity are in the envelope seal (§5.5’s rule - data-level signatures, never transport trust); duplicates are absorbed by idempotency keys; ordering belongs to the contract’s sequencer, not the wire; and all interaction is asynchronous documents, so latency is a quality, not a correctness, concern. The transport can be slow, lossy, duplicating, or actively hostile - the grammar doesn’t care. A port declares payload type + authorized sender, never a pipe.
“JSON in SMTP” is not even a joke - it is the industry’s actual history: AS1 is EDI over SMTP (RFC 3335), AS2 over HTTP (RFC 4130), AS3 over FTP, AS4 over web services - the same business documents, four standardized transports across three decades, and EDIFACT rode X.400 mail and VANs before that. Transport-agnostic payloads are how e-documents have always survived their pipes dying.
One EDIFACT lesson taken with it, so agnosticism doesn’t rot into fragmentation: the core is transport-free, but every PROFILE names a default rail (mk-se-public → Peppol eDelivery/AS4, because Swedish public sector is already on it; an mk-se-b2b pair may agree on a message queue or plain mail). “Any transport is possible” without a profile default is how the VAN-interconnect mess happened; a bound default with freedom to deviate bilaterally is how Peppol fixed it. Same CIUS discipline as everything else (§6).
7.5 Call-outs: contracts calling services (suspend and resume, blind to the clock)
Both points hold: tax computation does not belong in the contract (the industry already runs it as a service - Avalara, Vertex, Stripe Tax - and VAT-by-category is a moving regulatory target no signed document should embed), and the call-out needs no new suspend/resume machinery, because the design already contains it. A call-out decomposes into four things this document has:
emit tax.request (request-id, basket lines) an out-port emission
expect tax.response within 5 days §3.6 expectation ladder
park the triggering submission's receipt says PENDING is already a
verdict: PENDING (awaiting tax.response) first-class verdict
resume tax.response arrives through its in-port, a rule guarding on the
correlated by request-id -> rule completes, response event - resume
final receipt issued = the fold reads one more event
- §4.1’s approval was the special case all along. An approval is a call-out to a human or agent;
PENDING-APPROVALgeneralizes toPENDING (awaiting: X). One waiting mechanism, three kinds of callee: humans (approvals), other contracts (§7.1-7.3), services (this). The envelope’s verdict enum absorbs it without growing. - Why the contract cannot tell two days from 20 ms - by construction, not by discipline. “Suspended” is not a paused thread and the continuation is not stored program state: it is a state in the fold, and the resumption logic is just a rule that guards on the response event. HTTP-instant and two-day-batch produce identical logs modulo timestamps; the machine is structurally incapable of observing the difference. (If a deadline matters, it is declared on the expectation ladder and judged as an event-time predicate like every other timeout - §3.6.)
- The response is an input, not a computation. Like a fixing (§2), the tax answer enters the log as a signed fact from an executor-party (§3.6), under §5.5 trust anchors: store the response and its signature, never the URL. Replay reproduces the verdict bit-for-bit without re-calling the service - the two-day tax engine of 2027 need not exist in 2035 for the receipt chain to verify.
- Trusted for judgment, never obeyed blindly. The contract still guards what comes back:
if tax.response.rate not in declared-vat-rates -> reject; bounds, schema, cadence, all the usual gates. A compromised tax service can delay a contract; it cannot make one misprice.
Prior art: durable execution (Temporal, Azure Durable Functions, Restate - persist state, resume on external completion; our version is degenerate-simple because state IS the log), AWS Step Functions task tokens (§4.1 already borrowed them for human tasks - the same token-wait pattern for services), BPMN intermediate message events (the waiting node, standardized), async/await (the right intuition, minus the thread), and oracles (the industry’s word for signed external facts - ours are accountable parties with keys and obligations, not anonymous feeds).
7.6 External functions: the import manifest (the wasm model)
The wasm model is exact for this, so adopt it wholesale: a contract declares an import manifest - typed function slots whose signatures and bindings are contract terms while their implementations stay external. This is how every industry’s domain complexity (tax, freight rating, tariffs, payroll formulas, energy settlement) enters without ever polluting the starved core language:
imports:
some_tax_function:
mode: inline # runs INSIDE the evaluation step: pure,
has_side_effects: false # replay-safe, no state saved (inline
input: shape order-lines # REQUIRES false - sandbox enforces it)
output: shape taxed-lines # §8 shapes - checked like any port payload
binding: art:se-vat-engine pin v3 sha256:9e77... # WHO computes is a contract term
guards: output.vat-rates within declared-vat-rates, # the result is GUARDED,
sum(input.lines) + sum(output.tax) == output.total # never blindly trusted
freight_rating:
mode: deferred # result arrives as a LATER EVENT: the
has_side_effects: false # submission parks (PENDING) and resumes
input: shape shipment # on response - §7.5; §3.6 expectation
output: shape priced-shipment # ladder guards the wait. no side effects
binding: oracle party:dhl port freight.response # = a re-askable QUOTE
book_freight:
mode: deferred # changes the WORLD -> idempotency key is
has_side_effects: true # derived + attached AUTOMATICALLY:
input: shape shipment # sha256(contract-id, submission-id,
output: shape booking-confirmation # import-name, input-hash) - retries and
binding: oracle party:dhl port booking.response # crash re-emissions are safe
compensate: booking.cancel within 24h # the saga leg (§7.3), declared here
Two declarations, each naming exactly one property:
mode: inline | deferred- whether the machine must save state on the call.inlineexecutes within the evaluation step: nothing parks, nothing resumes, the fold never notices the function left the building.deferredmeans the result arrives as a later event - §7.5’s call-out: verdictPENDING, resume = the fold reading the response. Deliberately NOT called sync/async: the contract cannot care about latency (§7.5) and must not care about transport (§7.4) - it cares only about statefulness. (Kotlin’ssuspendfunctions are this same discrimination; we avoid the word because §4.2 uses “suspend” for escalation.)has_side_effects: false | true- whether calling it changes the world outside the contract. This is where idempotency becomes a first-class property of imports, not just of in-ports: a side-effecting call gets an idempotency key derived deterministically from the log -sha256(contract-id, submission-id, import-name, input-hash)- attached automatically, so retries, crash re-emissions, and replays hit the external system with the SAME key and the world changes at most once (the §1 submission-id mechanism, pointed outward; Stripe’s pattern, closed into a loop). Side-effecting imports must also declare their compensation (the §7.3 saga leg) - “what undoes this” is a contract term, not an ops runbook. The grid completes itself:inlineREQUIREShas_side_effects: false(the sandbox enforces what the declaration promises - a wasm blob has no ambient authority to break it);deferred + falseis a re-askable quote;deferred + trueis a world-changing act with a key and a declared undo.
Two binding modes behind the flags:
- Pure import (the wasm case). The implementation is a content-addressed pure function artifact - literally a deterministic wasm blob (no clock, no I/O, no ambient authority; the sandbox enforces what §1 promises), stored and governed exactly like a §5 artifact: versioned, hash-pinned or tracked, its updates under declared cadence/approval. Because the function is identified by hash, the evaluator may execute it synchronously, locally, anywhere and determinism survives replay by construction: same hash -> same function -> same result, in 2035 as in 2027. Complex tax “by description” is exactly this: the contract knows the signature, the binding, and the guards - never the tax law.
- Oracle import (the async case). The implementation is a party (Avalara-style tax service, a freight rater, Skatteverket one day) - which is just §7.5’s call-out and §3.6’s executor-as-party wearing a function signature: request out, PENDING, signed response in, guarded.
Strict linking - the machine REFUSES on any signature mismatch. Wasm’s instantiation rule, adopted verbatim: at genesis (and at every version change of contract OR binding), every import must resolve 100% exactly - the binding exists (artifact hash resolvable, or party+port declared), the input/output shapes match the declared signature precisely (no structural coercion, no best-effort mapping, no “close enough”), the guards are well-typed against those shapes. Any mismatch -> the contract cannot activate, with a link-error receipt naming the unresolved import. And it stays enforced at runtime: a track-bound function whose new version changes signature is an ILLEGAL update - rejected under §5.2’s rule, never becomes the bound version. A contract that cannot resolve its imports is not a contract that runs degraded; it is a contract that does not run.
The rest of the discipline: imports are declared like ports (absent import = the contract computes nothing externally - readable off the manifest), results are guarded like payloads (§8.2 - bounds, invariants, cross-sums; a compromised tax engine can stall a contract, never mis-tax it silently), and bindings are governed like artifacts (updating the tax function is a receipted governance event, not a deploy). Prior art is thick: wasm imports + the component-model WIT (typed interface declarations - our manifest verbatim), Ethereum precompiles (deterministic external functions at known addresses), deterministic-wasm chains (CosmWasm, Substrate chose wasm for exactly this replay property), SQL UDFs and XSLT extension functions (host languages importing typed externals for decades). The core stays if/which; the industries bring their math as sealed, pinned, guarded imports.
7.7 Modules: the standard library (compile-time composition, law/ and std/)
§7.6 imports an external function by hash; this imports an external fragment of contract by hash. A module is a governed template fragment - parameters plus declarations (ports, cadences, rules, pools, soft terms), no parties, not independently instantiable - that a template pulls in with one line and the machine flattens before signing. The consumer writes use module:std/se/angerratt@v1 with: {...}; the signed artifact is always the flat expansion, every flattened declaration carrying a from module:std/se/angerratt@v1 provenance annotation. This is the whole “reference, don’t copy-paste” goal: the human reads one line and knows the clause is the vetted online-sales clause; the machine gets the same bytes it would have if you had pasted it, minus the paste errors, plus a hash that proves which vetted version you pulled. Composition is compile-time only - the props-down/events-up mental model holds BETWEEN contracts (§7.3b), never as runtime interception INSIDE one.
Three namespaces, one binding mechanism (the §7.6/§5 binding verb, pointed at fragments):
| Namespace | Is | Tier weight | Carries | Governed by |
|---|---|---|---|---|
law/<jur>/* |
near-verbatim statute mirror (law/se/distansavtalslagen) |
almost all soft (§2 prose terms + law: anchors) |
the legal ground, signed and dormant - “what the law says”; runs nothing | the jurisdiction’s law-tracking body; a new statutory version = a new immutable module version |
std/<jur>/* |
the standard library: curated, tested, vetted, reusable modules | mostly executable (ports, state, cadence, rules) | the mechanism that operationalizes a statute (std/se/angerratt) OR a plain reusable pattern with no statute behind it (std/se/sjukhus-journal, a deposit-escrow) |
the profile’s standards body, under a vetting gate (§9) |
<publisher>/* |
third-party, publisher-sealed (market/deposit) |
either | anything the publisher ships, same machinery, private governance | the publisher’s own governance log |
The law/ ↔ std/ split is the executable/soft tier (§2) promoted from clause-level to namespace-level, and it is load-bearing for anti-bloat: the statute text lives once in law/, and every std/ module that operationalizes a slice of it references it rather than re-embedding it. Two reference strengths, deliberately distinct:
- Cite (the lean default). A
std/module points at the statute with alaw:anchor (law:se/sfs/2005:59#kap2-p10) - an interpretation anchor with zero execution semantics. The statute bytes are NOT copied into the consumer; the module stays small.std/se/angerrattgrounds onlaw/se/distansavtalslagenthis way. usethe law module (embed the text). When a contract must carry the verbatim statutory language in its own signed body - a consumer contract that has to display the withdrawal notice - ituses thelaw/module and the soft clauses flatten in like any other module, provenance-annotated. Same mechanism, heavier payload, chosen only when the contract’s readers need the words in-band.
std/ is a curated library, not an open namespace. Membership is earned, not claimed:
- Vetted. Admission to
std/is a governance act by the profile’s standards body, under the same discipline that gates new core primitives (§9): a module enters the library only when it is demonstrably correct and broadly reusable. A one-off clause that will never be reused stays in the contract that needs it. - Tested. A module ships with its own
example:doctests (§6.4’s executable examples, generalized) riding its rules; a module whose examples fail cannot be published, and a consumer’s flatten re-checks them - a broken module is caught at authoring time, never at dispute time. - Immutable + pinned. A version tag is an append-only binding in the module’s own governance log; re-pointing
@v1is structurally impossible, so the tag carries hash-grade holiness.usealways pins a version;@latestis illegal. New behaviour is a new version (or a new module), never a silent mutation of an old one. - Variants coexist under distinct names. The base statutory floor is
std/se/angerratt; a richer take - extended window, seller-paid return shipping - is a separate module (std/se/angerratt-extended), not a mutation of the base. Distinct designs get distinct names; distinct fixes to one design get distinct versions.
The merge rule is ADD-only - the §7.3b poison stays banished. Flattening a module is a union with hard conflict errors: two modules (or a module and its host) declaring the same port/pool/rule-id is a link error, not a silent last-writer-wins. Modules add declarations; they never override, wrap, or intercept a sibling’s. A module is strict about its seam: it declares requires: (events the host must produce, executors it must supply) and parameters: the host must wire, and if any are missing the flatten refuses - §7.6’s strict-linking rule applied to fragments (an unwired module is a contract that does not activate, not one that runs degraded). Everything the module does not require, the host wires; everything it requires is visible on its face.
# std/se/angerratt@v1 - the vetted online-sales clause, grounding on the statute mirror
parameters:
window duration >= 14 days default: 14 days # statutory FLOOR (law:se/sfs/2005:59):
refund-amount money-expr # widen yes, narrow never
buyer party-ref
seller party-ref
requires:
event delivery.confirm # the host must produce delivery; the module supplies the rest
executor psp
grounds: law:se/sfs/2005:59#kap2-p10 # CITES the law/ mirror - text lives once, in law/
ports:
in return.request from: {buyer} payload: signed-text
out refund.instruct to: executor:psp on: accepted-return
# ... rules, cadence ...
# in a consumer contract, one line pulls it in - the human reads a reference, not a paste:
use module:std/se/angerratt@v1
with: { window: 14 days, refund-amount: price + vat,
buyer: party:buyer, seller: party:seller }
implements: [#klausul-4] # flattens with `from module:std/se/angerratt@v1`
Profile-mandated modules make mandatory law enforceable. Because mandatory law can now be a vetted, versioned, immutable module, a profile can require one: mk-se-b2c refuses to lint a consumer template that lacks std/se/angerratt or an equivalent set of ports (§6, “constrain, never extend” - the profile narrows what is valid, it does not inject behaviour). Mandatory consumer terms arrive as reviewed modules, not as prose hopes someone forgot to paste. And the split naturalizes sub-clause tiering: a real clause mixes an executable spine with soft connective tissue, and a module boundary is exactly where that seam wants to fall - the soft statutory ground goes to law/, the executable spine to std/, each pinned, each cited from the other. Modules do not fully resolve the problem (a single indivisible clause that fuses tiers still needs sub-clause attribution), but they turn most of it into a namespace boundary.
Prior art: standardavtal clause libraries and incorporation by reference (AB 04, ISDA Definitions - the legal profession has referenced pinned clause books for a century; we make the pin a hash and the book testable), Terraform modules (input variables + strict wiring, flattened plan), Go module immutability (MVS, immutable tags, the checksum database - @latest-illegal is Go’s go.sum discipline), Docker image digests (pin by content, never by moving tag), package registries (npm/crates/pkg.go.dev - curated, versioned, tested, discoverable), and for law/: ELI, ECLI and Akoma Ntoso plus EUR-Lex and legislation.gov.uk’s “law as data” (statute already published as citable, versioned, machine-addressable text - law/ is that shelf, pinned into contracts). Honest creaks: (1) a vetted library implies a maintaining body per jurisdiction with an SLA on new law - real governance load (§9); (2) variant sprawl (angerratt vs angerratt-extended vs…) needs a discovery + deprecation discipline or the library rots into a junk drawer; (3) statute drift - when the source law changes, a new law/ version mints and every std/ module citing the old anchor must be re-vetted (a dependency graph to walk).
7.7b Compose, don’t extend - modules are the naming mechanism
A module is more than reuse convenience: it is how the standard grows expressiveness without growing the core. A higher-level mechanic - a condition precedent, an escrow, a dispute ladder - is never a new core verb; it is a named composition of the closed low-level verb set (§8.3 move/copy/borrow, the register record, the check guard, the §3.7 join, the §7.3 compensate). The worked case is a condition precedent: there is no condition keyword and never will be - a condition is a register field written by record on its triggering event and read by check at the gate; three primitives the core already had, packaged under one name. “Unwind the deal” is likewise not a verb: it is an explicit move of the deposit back to the payer. This is the compose-upward discipline of the Lisp family - a tiny core, everything else built and named on top - adopted deliberately, and just as deliberately without the Lisp runtime: no recursion, no unbounded loops, no runtime macros, because property 1 forbids them. So new expressiveness arrives two ways only: a vetted module composing existing primitives (the default), or - rarely, and only when a real corpus proves no composition suffices - a new primitive added to the core under §9’s vetting gate. When a proposed effect can be composed, it must be; the core stays boring on purpose. The honest gut-check that keeps this true: every construct must map to a defined primitive - if it does not resolve to something with meaning, it is a wish, not a mechanic.