Obligation v0.1¶
Status: Experimental, adopted through proposal A202-0002. Mixed. Sections 2, 3, 4, 5, 6, and 7 are normative. Sections 1 and 8 are informative and state no requirement on an implementation.
Date: 27 July 2026
Revised: 28 July 2026, under A202-0010: the released terminal state and the obligation.released transition, so that a terminated transaction cannot strand an open obligation. Also under A202-0011: the waiver reaches asserted and rejected, which section 5.4 already described as available.
Scope: Synthetic pilot transactions only
Depends on: canonical commercial model v0.1, commercial mandate v0.1, pilot transaction state machine v0.1, evidence verification v0.1, determination and dispute v0.1
1. Purpose¶
A commitment produces obligations. A counterparty cannot discharge an obligation it cannot parse, and two organisations that agree on price and then disagree on what was owed have not agreed on anything durable.
This document defines four things and nothing else: what is owed, by whom, when it is due, and what counts as done.
Everything that happens around those four is outside this specification. Tracking an obligation, monitoring its due condition, reminding a party, escalating, and enforcing a failure are operator concerns. They are not published here and an implementation is not conformant or non-conformant by reference to them. What is published is the shape a counterparty parses, the transitions the shape may take, and the refusals that hold when the shape or the transition is wrong.
The relationship to the transaction aggregate is already fixed. obligation.activated moves the aggregate from committed to in_performance, and a dispute over an obligation is an exception that moves the aggregate to exception_open. This document specifies the object underneath those transitions rather than adding new aggregate states.
2. Conformance language¶
MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY are normative within this experimental specification.
An implementation conforms to this specification when it:
- validates
obligation,performance_event, andobligation_responseobjects against../schemas/v0.1/commercial-kernel.schema.json; - enforces the due-condition typing rules in section 4;
- enforces the discharge and acceptance rules in section 5;
- enforces the guarded transitions in section 6;
- returns the refusal codes in section 7 for the failures they name;
- passes the obligation fixtures in
../conformance/manifest-v0.1.json.
Schema validity is necessary and not sufficient. The rules in sections 4, 5, and 6 are cross-object and cannot be expressed in JSON Schema alone.
3. The obligation object¶
An obligation is a shared kernel object. It carries the common envelope defined in canonical-commercial-model-v0.1.md section 3, uses the obl_ identifier prefix, and is canonicalised, hashed, and signed under section 4 of that document. transaction_id is REQUIRED and non-null.
| Field | Type | Rule |
|---|---|---|
agreement_id |
agr_ identifier |
The agreement the obligation derives from. REQUIRED |
commitment_id |
cmt_ identifier |
The commitment this obligation decomposes. REQUIRED |
obligor |
partyRef |
The party that owes. REQUIRED |
obligee |
partyRef |
The party owed to. REQUIRED |
subject |
subjectRef |
What is owed, by reference. See section 3.1. REQUIRED |
due_condition |
dueCondition |
When it is due. See section 4. REQUIRED |
quantity |
quantityString |
How much is owed, in the same representation the kernel uses for terms. REQUIRED |
unit_code |
UN/ECE Recommendation 20 common code | REQUIRED. unit_name MAY accompany it and MUST NOT be used for matching or validation |
consideration |
money or null |
The consideration attached to this obligation, where the agreement attaches one. Null where it does not |
state |
enum | One of the states in section 6. REQUIRED |
obligor and obligee MUST both appear in the referenced agreement as buyer or supplier. An obligation naming a party that is not a party to the agreement is refused with A202-OBLIGATION-SUBJECT-UNREFERENCED.
Money uses the money type. Percentages, where a profile term expresses one, use percentString. An obligation MUST NOT introduce a parallel representation for either.
3.1 Subject is a reference, never a restatement¶
subject names what is owed by pointing at the agreement's terms. It does not copy them.
| Field | Type | Rule |
|---|---|---|
agreement_id |
agr_ identifier |
MUST equal the obligation's agreement_id |
terms_hash |
sha256Hex |
MUST equal the referenced agreement's terms_hash |
profile |
registered profile identifier | MUST equal the agreement's terms.profile |
term_path |
path expression | Addresses the term under $.terms.core or $.terms.profile_terms |
term_path uses the same path addressing as a mandate constraint path, so a term that a mandate constrains and a term that an obligation owes are named the same way. A path that addresses a term outside the referenced profile, or that does not resolve against the referenced terms, is refused with A202-OBLIGATION-SUBJECT-UNREFERENCED.
Restating a term inside the obligation would create a second copy that can drift from the agreement, and the drift would be invisible because both copies would be validly signed. Reference plus terms hash makes drift a hash mismatch instead.
An obligation MUST NOT carry any of the private data classes listed in canonical-commercial-model-v0.1.md section 13.
4. Due condition¶
due_condition is typed. It is never free text, because a due date a counterparty has to read in order to compute is a due date the counterparty's agent cannot act on.
Three condition types are registered in v0.1, plus one composition.
type |
Fields | Meaning |
|---|---|---|
due_at_time |
at, RFC 3339 timestamp in UTC, or a date with a named business calendar reference |
Due at a stated time |
due_on_event |
act_ref, or evidence_type, exactly one of the two |
Due when the referenced act appends, or when evidence of the referenced registered type is presented and verifies |
due_on_discharge |
obligation_id |
Due when the named obligation reaches discharged. This is how ordering between obligations is expressed |
all_of |
conditions, at least two entries |
Due when every listed condition is met |
Rules:
- Conditions compose with AND only. There is no OR and no NOT in v0.1. A disjunction is expressible as two obligations, and stating that explicitly is what makes the record replayable.
all_ofMUST NOT nest more than one level deep. A nested conjunction is a flat conjunction written twice.due_on_eventMUST reference an act by content hash, or an evidence type from the registered evidence type list defined in evidence-verification-v0.1.md section 3. An unregistered evidence type fails closed.due_on_dischargeMUST reference an obligation on the sametransaction_id. A cycle amongdue_on_dischargereferences is refused: no obligation in the cycle can ever become due, so accepting the cycle would create an obligation set that is permanently unsatisfiable and silently so.- A
due_at_timevalue expressed in business days MUST name a calendar, as required by canonical-commercial-model-v0.1.md section 7. A duration in business days with no named calendar is not a term.
An unknown type, or a registered type with fields belonging to a different one, fails closed with A202-OBLIGATION-CONDITION-UNKNOWN. The registry is closed in v0.1 and is enforced at validation and independently at evaluation, so that adding a member to the schema enum without an evaluator implementation cannot cause an obligation to become due.
5. Discharge and acceptance¶
Performance and acceptance are two acts by two parties. Collapsing them lets the obligor declare its own obligation discharged.
5.1 Assertion¶
The obligor asserts performance by appending a performance_event object that:
- names the obligation in
obligation_id; - carries at least one evidence reference in
evidence_refs, in the shape defined in evidence-verification-v0.1.md section 3; - states
asserted_quantityandunit_code, whereunit_codeequals the obligation's; - is signed by the obligor.
An assertion with no evidence reference is refused with A202-OBLIGATION-ASSERTION-UNEVIDENCED. An assertion carries a claim about the world, and a claim with nothing behind it cannot be checked by the obligee now or by a third party later.
The assertion's content_hash is the assertion hash. It is the value the obligee's response binds to.
5.2 Response¶
The obligee responds by appending an obligation_response object, signed by the obligee, with response_type one of accept, reject, or waive.
| Field | Rule |
|---|---|
obligation_id |
REQUIRED. The obligation responded to |
response_type |
REQUIRED. accept, reject, or waive |
assertion_id |
REQUIRED for accept and reject. Absent for waive |
assertion_hash |
REQUIRED for accept and reject. MUST equal the referenced assertion's content_hash |
accepted_quantity |
REQUIRED for accept. A quantityString at or below the asserted quantity |
remainder_obligation_id |
REQUIRED for accept where accepted_quantity is below the obligation's quantity. Absent otherwise |
reason_code |
REQUIRED for reject. From the closed list in section 5.5 |
Four rules hold and an implementation MUST enforce each independently.
- Acceptance is a distinct signed act by the obligee. A response signed by any party other than the obligee named on the obligation is refused with
A202-OBLIGATION-RESPONSE-UNAUTHORIZED. This holds forwaiveas well as foraccept. - Acceptance binds an exact assertion.
assertion_hashMUST equal thecontent_hashof the assertion named inassertion_id. A mismatch is refused withA202-OBLIGATION-RESPONSE-HASH-MISMATCH. Changing one byte of the assertion invalidates the response, exactly as changing one byte of an action invalidates an approval under commercial-mandate-v0.1.md section 8. - Partial acceptance creates a new obligation. Where
accepted_quantityis below the obligation'squantity, the response MUST name aremainder_obligation_id, and that obligation MUST reference the sameagreement_id, the samesubject, and aquantityequal to the difference. A partial acceptance with no remainder named is refused withA202-OBLIGATION-REMAINDER-MISSING. - No response mutates the obligation. An obligation's
subject,due_condition,quantity,unit_code, andconsiderationare fixed at issue. A response that would alter any of them is refused withA202-OBLIGATION-TERMS-MUTATED. Changed terms are a new obligation under an amended agreement, never a new version of this one.
5.3 Why partial acceptance is never a mutation¶
If accepting eight of ten units rewrote the obligation to say eight, the record would afterwards show an obligation that was fully performed. The two units that were not delivered would have left no trace, and the party that most needs to prove they were owed would be the party whose evidence had been edited away. Splitting into an accepted obligation and a remainder obligation keeps both facts, and both remain independently verifiable.
5.4 Rejection¶
A rejection carries a reason_code and leaves the obligation's terms untouched. It moves the obligation to rejected and opens the dispute path defined in determination-v0.1.md. It does not renegotiate the obligation, and it does not by itself determine anything: a rejection is one party's position, and a determination is what resolves a contested one.
The obligor MAY assert again against the same obligation. Each assertion is a new object with its own hash, and each response binds exactly one of them.
5.5 Rejection reason codes¶
The list is closed in v0.1. An unregistered value is refused with A202-OBLIGATION-REJECTION-REASON-UNKNOWN.
reason_code |
Meaning |
|---|---|
evidence_insufficient |
The evidence presented does not support the assertion |
evidence_unverified |
Required evidence is absent or failed verification |
quantity_short |
The asserted quantity is below what the obligation owes and no remainder was accepted |
subject_not_as_agreed |
What was performed does not match the referenced term |
due_condition_not_met |
The obligation was not due when the assertion was made |
assertion_unauthorized |
The assertion was not signed under a mandate covering the obligor's act |
Each value is stated from the obligee's own position. None of them discloses the identity, price, count, or timing of any other party's activity on the transaction, and an implementation MUST NOT extend the list with a value that would.
6. States and transitions¶
| State | Meaning |
|---|---|
pending |
The obligation exists and its due condition is not met |
due |
The due condition is met and no assertion is outstanding |
asserted |
The obligor asserted performance and the obligee has not responded |
accepted |
The obligee accepted an assertion |
rejected |
The obligee rejected an assertion |
disputed |
A dispute has been raised on the obligation |
discharged |
Nothing further is owed under this obligation |
waived |
The obligee released the obligor by signed act |
expired |
A deadline elapsed before the obligation was discharged or waived |
released |
The transaction ended through an authorized termination whose record named this obligation's disposition |
discharged, waived, expired, and released are terminal in v0.1.
released exists because a terminated transaction must not strand its obligations. It is distinct from waived because the release is carried by the termination record both parties signed, not by a unilateral obligee response, and distinct from discharged because nothing was performed. The record shows that the duty ended with the transaction, which is a different fact from the duty having been met.
6.1 Transition table¶
| Current | Event | Guard | Next |
|---|---|---|---|
| none | obligation.activated |
Obligation derives from a committed agreement; subject.terms_hash equals the agreement's terms_hash |
pending |
pending |
obligation.due |
Every clause of due_condition evaluates true against a referenced act, evidence, discharge, or the authoritative clock |
due |
pending, due, asserted, or rejected |
obligation.waived |
Response signed by the obligee with response_type waive |
waived |
pending or due |
deadline.elapsed |
Authoritative clock passed the agreement or transaction deadline governing this obligation | expired |
due |
performance.declared |
Assertion names this obligation, carries at least one evidence reference, and is signed by the obligor | asserted |
asserted |
acceptance.granted |
Response signed by the obligee; response_type accept; assertion_hash matches; remainder named where the accepted quantity is short |
accepted |
asserted |
acceptance.rejected |
Response signed by the obligee; response_type reject; assertion_hash matches; reason_code registered |
rejected |
asserted, accepted, or rejected |
dispute.raised |
Dispute references this obligation's state by content hash and is raised inside the window in force | disputed |
rejected |
performance.declared |
A new assertion, with its own hash, naming the same obligation | asserted |
accepted |
obligation.discharged |
accepted_quantity equals quantity, or a remainder obligation exists and is named |
discharged |
disputed |
determination.recorded |
The determination's stated effect is binding on this question under the rules in force at the time |
the state the determination states |
disputed |
determination.recorded |
The determination's stated effect is advisory or presumptive |
disputed |
pending, due, asserted, rejected, or disputed |
obligation.released |
The transaction appended termination.agreed or transaction.terminated, and the termination record names this obligation's disposition |
released |
Two guards carry most of the weight and are stated separately because they are easy to lose.
A determination moves state only where the rules granted it that effect. An advisory or presumptive determination is evidence and is recorded as evidence. It does not move the obligation, and an implementation that lets it move the obligation has given a determination an effect the parties did not agree to. This fails closed: where the effect is unstated or does not resolve, the obligation does not move.
A rejection does not end the obligation. rejected is not terminal. The obligation is still owed, and the path forward is a further assertion, a waiver, a determination, or expiry.
A waiver is available wherever the obligation is still owed. The obligee may release the obligor from pending, due, asserted, and rejected. Restricting the waiver to the states before an assertion would mean that an obligee who wished to release its counterparty after seeing a partial or unsatisfactory assertion had no way to say so: it would have to accept performance it did not receive, or reject and wait for a deadline it did not want to enforce. Both would put a false record on the transaction, and the second leaves the obligation owed until it expires, which is a worse outcome for the obligor the waiver was meant to benefit.
A waiver is deliberately not available from disputed. A dispute is a contested question already before a determiner, and a unilateral release while it is open would moot a determination the other party is entitled to receive. The obligee that wishes to release a disputed obligation withdraws its position through the dispute path, and the determination records what happened.
6.2 Relationship to the aggregate¶
The aggregate transitions are unchanged by this document.
| Obligation event | Aggregate effect under pilot-transaction-state-machine-v0.1.md |
|---|---|
obligation.activated |
committed to in_performance |
performance.declared |
in_performance to acceptance_pending |
acceptance.granted |
acceptance_pending to settlement_pending |
acceptance.rejected |
acceptance_pending to in_performance |
dispute.raised on an obligation |
exception.opened, reaching exception_open |
obligation.released |
None. The aggregate already moved to terminated; the release is the obligation-level consequence, not a further aggregate event |
An obligation reaching disputed is the object-level fact behind exception.opened. The aggregate carries one exception state; an obligation set may carry several disputed obligations at once, and the aggregate leaves exception_open only when the events for that transition append.
An illegal transition returns A202-STATE-TRANSITION-DENIED, the existing code, rather than a new one. There is one state machine vocabulary and this document joins it.
7. Refusal codes¶
All fail closed. These extend the table in pilot-transaction-state-machine-v0.1.md section 10.
| Code | Meaning |
|---|---|
A202-OBLIGATION-CONDITION-UNKNOWN |
A due condition names an unregistered type, or a registered type with fields belonging to a different one |
A202-OBLIGATION-CONDITION-CYCLIC |
A set of due_on_discharge conditions forms a cycle, so no obligation in it can become due |
A202-OBLIGATION-SUBJECT-UNREFERENCED |
subject does not resolve against the referenced agreement, its terms hash differs, or a named party is not a party to the agreement |
A202-OBLIGATION-ASSERTION-UNEVIDENCED |
An assertion carries no evidence reference |
A202-OBLIGATION-RESPONSE-UNAUTHORIZED |
A response was signed by a party other than the obligee |
A202-OBLIGATION-RESPONSE-HASH-MISMATCH |
A response references different assertion bytes |
A202-OBLIGATION-REMAINDER-MISSING |
A partial acceptance names no remainder obligation |
A202-OBLIGATION-TERMS-MUTATED |
An act would alter an obligation's subject, due condition, quantity, unit code, or consideration |
A202-OBLIGATION-REJECTION-REASON-UNKNOWN |
A rejection carries a reason code outside the closed list |
Codes reused unchanged from existing specifications, rather than duplicated here: A202-STATE-TRANSITION-DENIED for an illegal transition, A202-SEQUENCE-CONFLICT for a stream conflict, A202-EVIDENCE-UNVERIFIED for absent or failed evidence, A202-MANDATE-INACTIVE for an act under an inactive mandate, and A202-AGREEMENT-HASH-MISMATCH for an agreement hash that does not match.
8. Explicit non-goals¶
None of the following is specified here, and an implementation is neither conformant nor non-conformant by reference to any of them.
- Delivery logistics. Routing, carriage, handover, custody, and the operational sequence by which performance actually happens.
- Quality standards. What counts as acceptable quality for a given subject. That belongs to the transaction profile, to a referenced external standard, or to the agreement's own terms, and this document only carries the reference.
- Tracking. Holding obligation state, watching due conditions, and computing what is outstanding across a portfolio.
- Reminders and notification. Who is told what, when, and through which channel.
- Enforcement. What happens when an obligation is not performed. This document defines the states a failure produces and the record it leaves. It does not define a remedy, and nothing here makes any obligation enforceable at law.
Each is named because a reader would otherwise reasonably expect to find it in a document about obligations. A non-goal is a statement about this specification's scope, not a claim that the excluded capability is unimportant.