@hyperscale0/udl 1.0.0-beta.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -25
- package/README.md +37 -99
- package/conformance/README.md +44 -41
- package/conformance/evolution/action-contract.expected.json +10 -0
- package/conformance/evolution/action-contract.live.udl +44 -0
- package/conformance/evolution/action-contract.next.udl +45 -0
- package/conformance/evolution/product-identity.expected.json +10 -0
- package/conformance/evolution/product-identity.live.udl +55 -0
- package/conformance/evolution/product-identity.next.udl +55 -0
- package/conformance/evolution/version-required.expected.json +10 -0
- package/conformance/evolution/version-required.live.udl +55 -0
- package/conformance/evolution/version-required.next.udl +58 -0
- package/conformance/invalid/action-without-transition.expected.json +10 -0
- package/conformance/invalid/{verb-without-transition.udl → action-without-transition.udl} +7 -2
- package/conformance/invalid/agent-description-too-long.expected.json +10 -0
- package/conformance/invalid/agent-description-too-long.udl +57 -0
- package/conformance/invalid/blank-title.expected.json +1 -1
- package/conformance/invalid/blank-title.udl +6 -2
- package/conformance/invalid/composition-dial-duplicate-key.expected.json +10 -0
- package/conformance/invalid/composition-dial-duplicate-key.udl +73 -0
- package/conformance/invalid/depth-budget.expected.json +1 -1
- package/conformance/invalid/duplicate-subject.expected.json +10 -0
- package/conformance/invalid/duplicate-subject.udl +230 -0
- package/conformance/invalid/forged-effects.expected.json +10 -0
- package/conformance/invalid/forged-effects.udl +76 -0
- package/conformance/invalid/format-version.expected.json +1 -1
- package/conformance/invalid/format-version.udl +6 -2
- package/conformance/invalid/instrument-id-not-snake-case.expected.json +10 -0
- package/conformance/invalid/{noun-id-not-snake-case.udl → instrument-id-not-snake-case.udl} +6 -2
- package/conformance/invalid/invalid-aggregate-gate-shape.expected.json +10 -0
- package/conformance/invalid/invalid-aggregate-gate-shape.udl +1819 -0
- package/conformance/invalid/invalid-check-duration.expected.json +10 -0
- package/conformance/invalid/invalid-check-duration.udl +219 -0
- package/conformance/invalid/invalid-dial-anchor.expected.json +10 -0
- package/conformance/invalid/invalid-dial-anchor.udl +219 -0
- package/conformance/invalid/invalid-exception-parent-ref.expected.json +10 -0
- package/conformance/invalid/invalid-exception-parent-ref.udl +2487 -0
- package/conformance/invalid/invalid-exposure-shape.expected.json +10 -0
- package/conformance/invalid/invalid-exposure-shape.udl +1819 -0
- package/conformance/invalid/invalid-remainder.expected.json +10 -0
- package/conformance/invalid/invalid-remainder.udl +220 -0
- package/conformance/invalid/invalid-schema-keyword.expected.json +10 -0
- package/conformance/invalid/invalid-schema-keyword.udl +220 -0
- package/conformance/invalid/invalid-utf8.expected.json +1 -1
- package/conformance/invalid/malformed-json.expected.json +1 -1
- package/conformance/invalid/missing-create-action.expected.json +10 -0
- package/conformance/invalid/{missing-create-verb.udl → missing-create-action.udl} +5 -2
- package/conformance/invalid/missing-exception-amount-field.expected.json +10 -0
- package/conformance/invalid/missing-exception-amount-field.udl +2487 -0
- package/conformance/invalid/missing-exception-contract.expected.json +14 -0
- package/conformance/invalid/missing-exception-contract.udl +2523 -0
- package/conformance/invalid/missing-exception-reason-field.expected.json +10 -0
- package/conformance/invalid/missing-exception-reason-field.udl +2487 -0
- package/conformance/invalid/not-an-object.expected.json +1 -1
- package/conformance/invalid/payout-reconcile-not-a-bank-debit.expected.json +10 -0
- package/conformance/invalid/payout-reconcile-not-a-bank-debit.udl +259 -0
- package/conformance/invalid/quote-freeze-set-incomplete.expected.json +10 -0
- package/conformance/invalid/quote-freeze-set-incomplete.udl +261 -0
- package/conformance/invalid/quote-named-reference-gate.expected.json +10 -0
- package/conformance/invalid/quote-named-reference-gate.udl +50 -0
- package/conformance/invalid/reconcile-named-reference-gate.expected.json +10 -0
- package/conformance/invalid/reconcile-named-reference-gate.udl +50 -0
- package/conformance/invalid/unknown-key.expected.json +1 -1
- package/conformance/invalid/unknown-key.udl +6 -2
- package/conformance/invalid/unknown-reference-gate-field.expected.json +10 -0
- package/conformance/invalid/unknown-reference-gate-field.udl +1819 -0
- package/conformance/invalid/unknown-required-field.expected.json +10 -0
- package/conformance/invalid/unknown-required-field.udl +220 -0
- package/conformance/invalid/unreachable-state.expected.json +2 -2
- package/conformance/invalid/unreachable-state.udl +6 -2
- package/conformance/invalid/wrong-exception-amount-field.expected.json +10 -0
- package/conformance/invalid/wrong-exception-amount-field.udl +2487 -0
- package/conformance/invalid/wrong-exception-reason-field.expected.json +10 -0
- package/conformance/invalid/wrong-exception-reason-field.udl +2487 -0
- package/conformance/valid/agent-description.expected.json +6 -0
- package/conformance/valid/agent-description.udl +66 -0
- package/conformance/valid/cards.expected.json +1 -0
- package/conformance/valid/cards.udl +843 -356
- package/conformance/valid/commerce-escrow.expected.json +1 -0
- package/conformance/valid/commerce-escrow.udl +792 -291
- package/conformance/valid/compiled-crowdfunding.expected.json +6 -0
- package/conformance/valid/compiled-crowdfunding.udl +1843 -0
- package/conformance/valid/compiled-watch-club.expected.json +6 -0
- package/conformance/valid/compiled-watch-club.udl +2486 -0
- package/conformance/valid/complete-contract.expected.json +6 -0
- package/conformance/valid/complete-contract.udl +218 -0
- package/conformance/valid/effect-signatures.expected.json +6 -0
- package/conformance/valid/effect-signatures.udl +75 -0
- package/conformance/valid/hand-edited.expected.json +1 -0
- package/conformance/valid/hand-edited.udl +1 -1
- package/conformance/valid/insured-car-marketplace.expected.json +1 -0
- package/conformance/valid/insured-car-marketplace.udl +534 -315
- package/conformance/valid/insured-travel.expected.json +2 -1
- package/conformance/valid/insured-travel.udl +1489 -641
- package/conformance/valid/minimal.expected.json +1 -0
- package/conformance/valid/minimal.udl +18 -14
- package/conformance/valid/protection.expected.json +1 -0
- package/conformance/valid/protection.udl +719 -304
- package/conformance/valid/string-escaping.expected.json +6 -0
- package/conformance/valid/string-escaping.udl +54 -0
- package/dist/canonical.d.ts +2 -0
- package/dist/canonical.d.ts.map +1 -1
- package/dist/canonical.js +7 -0
- package/dist/canonical.js.map +1 -1
- package/dist/check-profiles.d.ts +57 -0
- package/dist/check-profiles.d.ts.map +1 -0
- package/dist/check-profiles.js +62 -0
- package/dist/check-profiles.js.map +1 -0
- package/dist/cli.js +48 -4
- package/dist/cli.js.map +1 -1
- package/dist/diagnostics.d.ts +168 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +164 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/effects.d.ts +41 -0
- package/dist/effects.d.ts.map +1 -0
- package/dist/effects.js +110 -0
- package/dist/effects.js.map +1 -0
- package/dist/evolution.d.ts +51 -18
- package/dist/evolution.d.ts.map +1 -1
- package/dist/evolution.js +244 -102
- package/dist/evolution.js.map +1 -1
- package/dist/finance.d.ts +17 -13
- package/dist/finance.d.ts.map +1 -1
- package/dist/finance.js +165 -109
- package/dist/finance.js.map +1 -1
- package/dist/index.d.ts +12 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +2 -2
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +4 -3
- package/dist/limits.js.map +1 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +6 -16
- package/dist/parser.js.map +1 -1
- package/dist/schema.d.ts +2059 -135
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +759 -73
- package/dist/schema.js.map +1 -1
- package/dist/validation.d.ts +22 -9
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1463 -457
- package/dist/validation.js.map +1 -1
- package/docs/README.md +14 -0
- package/docs/guide/01-a-document.md +37 -0
- package/docs/guide/02-money-steps.md +23 -0
- package/docs/guide/03-laws.md +18 -0
- package/docs/guide/04-fees-and-remainder.md +15 -0
- package/docs/guide/05-checks-updates-dials.md +7 -0
- package/docs/guide/06-effects.md +11 -0
- package/docs/guide/07-evolution.md +11 -0
- package/docs/guide/08-implementing.md +13 -0
- package/docs/llms-full.txt +1241 -0
- package/docs/llms.txt +14 -0
- package/docs/reference/canonical.md +16 -0
- package/docs/reference/clauses.md +986 -0
- package/docs/reference/cli.md +22 -0
- package/docs/reference/diagnostics.md +32 -0
- package/package.json +6 -2
- package/skills/udl/SKILL.md +28 -0
- package/spec/README.md +82 -51
- package/spec/udl.schema.json +1191 -119
- package/src/canonical.ts +11 -0
- package/src/check-profiles.ts +80 -0
- package/src/cli.ts +49 -3
- package/src/diagnostics.ts +221 -0
- package/src/effects.ts +163 -0
- package/src/evolution.ts +375 -125
- package/src/finance.ts +255 -160
- package/src/index.ts +50 -14
- package/src/limits.ts +4 -3
- package/src/parser.ts +15 -18
- package/src/schema.ts +855 -81
- package/src/validation.ts +2666 -560
- package/conformance/invalid/missing-create-verb.expected.json +0 -10
- package/conformance/invalid/noun-id-not-snake-case.expected.json +0 -10
- package/conformance/invalid/verb-without-transition.expected.json +0 -10
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"issues": [
|
|
3
|
+
{
|
|
4
|
+
"code": "UDL5005",
|
|
5
|
+
"path": "$.instruments[0].actions.settle.reconcile[0].evidence"
|
|
6
|
+
}
|
|
7
|
+
],
|
|
8
|
+
"summary": "Bank evidence for payouts: an instrument that owns a payout closes it against a debit statement line, never against the provider confirmation of our own instruction.",
|
|
9
|
+
"verdict": "invalid"
|
|
10
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
{
|
|
2
|
+
"instruments": [
|
|
3
|
+
{
|
|
4
|
+
"actionOrder": [
|
|
5
|
+
"create",
|
|
6
|
+
"instruct",
|
|
7
|
+
"settle"
|
|
8
|
+
],
|
|
9
|
+
"actions": {
|
|
10
|
+
"create": {
|
|
11
|
+
"moves": [],
|
|
12
|
+
"publicAction": "createSupplierPayout",
|
|
13
|
+
"steps": [],
|
|
14
|
+
"summary": "Create a supplier payout"
|
|
15
|
+
},
|
|
16
|
+
"instruct": {
|
|
17
|
+
"moves": [],
|
|
18
|
+
"payout": {
|
|
19
|
+
"amount": "fields.netPayable",
|
|
20
|
+
"beneficiaryField": "supplierBeneficiaryId",
|
|
21
|
+
"beneficiaryPartyField": "supplierAccountId",
|
|
22
|
+
"capture": "payoutId",
|
|
23
|
+
"currencyField": "currency",
|
|
24
|
+
"sourceAccountField": "treasuryAccountId",
|
|
25
|
+
"speed": "standard"
|
|
26
|
+
},
|
|
27
|
+
"publicAction": "instructSupplierPayout",
|
|
28
|
+
"steps": [],
|
|
29
|
+
"summary": "Instruct the payout to the supplier"
|
|
30
|
+
},
|
|
31
|
+
"settle": {
|
|
32
|
+
"due": {
|
|
33
|
+
"field": "settleBy"
|
|
34
|
+
},
|
|
35
|
+
"moves": [],
|
|
36
|
+
"reconcile": [
|
|
37
|
+
{
|
|
38
|
+
"amount": "fields.netPayable",
|
|
39
|
+
"capture": "settlementEvidenceId",
|
|
40
|
+
"counterpartyRef": "payoutId",
|
|
41
|
+
"currencyField": "currency",
|
|
42
|
+
"direction": "debit",
|
|
43
|
+
"evidence": "provider_confirmation",
|
|
44
|
+
"exception": {
|
|
45
|
+
"amountField": "unmatchedAmount",
|
|
46
|
+
"childInstrumentId": "supplier_payout_break",
|
|
47
|
+
"maxOpen": 1,
|
|
48
|
+
"reasonField": "breakReason",
|
|
49
|
+
"refField": "supplierPayoutId"
|
|
50
|
+
},
|
|
51
|
+
"match": {
|
|
52
|
+
"dial": "settlement_tolerance",
|
|
53
|
+
"law": "tolerance",
|
|
54
|
+
"minorUnits": 100
|
|
55
|
+
},
|
|
56
|
+
"within": {
|
|
57
|
+
"field": "settleBy"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"steps": [],
|
|
62
|
+
"summary": "Match the bank's debit against what the instruction promised"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"description": "A payout the instrument owns end to end: one instruction, one expectation about the debit it will produce, and one break when the debit never matches",
|
|
66
|
+
"dials": [
|
|
67
|
+
{
|
|
68
|
+
"key": "settlement_tolerance",
|
|
69
|
+
"kind": "reconcile_tolerance",
|
|
70
|
+
"maxMinorUnits": 500,
|
|
71
|
+
"summary": "Largest difference between the instructed amount and the settled debit that still counts as matched.",
|
|
72
|
+
"title": "Settlement tolerance"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"fields": {
|
|
76
|
+
"currency": {
|
|
77
|
+
"description": "ISO 4217 currency code",
|
|
78
|
+
"maxLength": 3,
|
|
79
|
+
"minLength": 3,
|
|
80
|
+
"pattern": "^[A-Z]{3}$",
|
|
81
|
+
"type": "string"
|
|
82
|
+
},
|
|
83
|
+
"netPayable": {
|
|
84
|
+
"description": "Amount instructed to the supplier in minor units",
|
|
85
|
+
"pattern": "^[1-9][0-9]{0,17}$",
|
|
86
|
+
"type": "string"
|
|
87
|
+
},
|
|
88
|
+
"settleBy": {
|
|
89
|
+
"description": "Instant the expectation stops waiting and the unmatched amount becomes a break",
|
|
90
|
+
"format": "hyperscale-date-time",
|
|
91
|
+
"type": "string"
|
|
92
|
+
},
|
|
93
|
+
"supplierAccountId": {
|
|
94
|
+
"description": "The supplier account",
|
|
95
|
+
"pattern": "^acct_(sandbox|live)_[a-z0-9]{8,64}$",
|
|
96
|
+
"type": "string",
|
|
97
|
+
"x-hyperscale-reference-filter": {
|
|
98
|
+
"column": "role",
|
|
99
|
+
"values": [
|
|
100
|
+
"customer_balance"
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"supplierBeneficiaryId": {
|
|
105
|
+
"description": "Beneficiary ID for the payout instruction",
|
|
106
|
+
"pattern": "^ben_(sandbox|live)_[a-z0-9]{8,64}$",
|
|
107
|
+
"type": "string"
|
|
108
|
+
},
|
|
109
|
+
"treasuryAccountId": {
|
|
110
|
+
"description": "The treasury account the payout leaves",
|
|
111
|
+
"pattern": "^acct_(sandbox|live)_[a-z0-9]{8,64}$",
|
|
112
|
+
"type": "string",
|
|
113
|
+
"x-hyperscale-reference-filter": {
|
|
114
|
+
"column": "role",
|
|
115
|
+
"values": [
|
|
116
|
+
"customer_balance"
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"id": "supplier_payout",
|
|
122
|
+
"idPrefix": "sp",
|
|
123
|
+
"lifecycle": {
|
|
124
|
+
"initial": "created",
|
|
125
|
+
"states": [
|
|
126
|
+
"created",
|
|
127
|
+
"instructed",
|
|
128
|
+
"settled"
|
|
129
|
+
],
|
|
130
|
+
"transitions": {
|
|
131
|
+
"instruct": {
|
|
132
|
+
"from": [
|
|
133
|
+
"created"
|
|
134
|
+
],
|
|
135
|
+
"to": "instructed"
|
|
136
|
+
},
|
|
137
|
+
"settle": {
|
|
138
|
+
"from": [
|
|
139
|
+
"instructed"
|
|
140
|
+
],
|
|
141
|
+
"to": "settled"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"parties": {
|
|
146
|
+
"beneficiary": "supplierAccountId",
|
|
147
|
+
"payer": "treasuryAccountId"
|
|
148
|
+
},
|
|
149
|
+
"required": [
|
|
150
|
+
"netPayable",
|
|
151
|
+
"supplierAccountId",
|
|
152
|
+
"supplierBeneficiaryId",
|
|
153
|
+
"currency",
|
|
154
|
+
"treasuryAccountId",
|
|
155
|
+
"settleBy"
|
|
156
|
+
],
|
|
157
|
+
"summary": "Payout from treasury to supplier that is not done until the bank agrees",
|
|
158
|
+
"title": "Supplier payout"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"actionOrder": [
|
|
162
|
+
"create",
|
|
163
|
+
"carry"
|
|
164
|
+
],
|
|
165
|
+
"actions": {
|
|
166
|
+
"carry": {
|
|
167
|
+
"moves": [],
|
|
168
|
+
"publicAction": "carrySupplierPayoutBreak",
|
|
169
|
+
"requiresRefs": [
|
|
170
|
+
{
|
|
171
|
+
"field": "supplierPayoutId",
|
|
172
|
+
"match": {
|
|
173
|
+
"fields.currency": "fields.currency"
|
|
174
|
+
},
|
|
175
|
+
"statuses": [
|
|
176
|
+
"instructed"
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"steps": [],
|
|
181
|
+
"summary": "Carry the break to whoever owns it"
|
|
182
|
+
},
|
|
183
|
+
"create": {
|
|
184
|
+
"moves": [],
|
|
185
|
+
"publicAction": "createSupplierPayoutBreak",
|
|
186
|
+
"requiresRefs": [
|
|
187
|
+
{
|
|
188
|
+
"field": "supplierPayoutId",
|
|
189
|
+
"match": {
|
|
190
|
+
"fields.currency": "fields.currency"
|
|
191
|
+
},
|
|
192
|
+
"statuses": [
|
|
193
|
+
"instructed"
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
"steps": [],
|
|
198
|
+
"summary": "Raise a break against an instructed payout"
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"description": "One break raised when a payout expectation reached its window with no matching debit; it is carried, never silently dropped",
|
|
202
|
+
"fields": {
|
|
203
|
+
"breakReason": {
|
|
204
|
+
"description": "Why the expectation went unmatched",
|
|
205
|
+
"maxLength": 180,
|
|
206
|
+
"minLength": 1,
|
|
207
|
+
"type": "string"
|
|
208
|
+
},
|
|
209
|
+
"currency": {
|
|
210
|
+
"description": "ISO 4217 currency code",
|
|
211
|
+
"maxLength": 3,
|
|
212
|
+
"minLength": 3,
|
|
213
|
+
"pattern": "^[A-Z]{3}$",
|
|
214
|
+
"type": "string"
|
|
215
|
+
},
|
|
216
|
+
"supplierPayoutId": {
|
|
217
|
+
"description": "Payout whose expectation broke",
|
|
218
|
+
"pattern": "^sp_(sandbox|live)_[a-z0-9]{8,64}$",
|
|
219
|
+
"type": "string"
|
|
220
|
+
},
|
|
221
|
+
"unmatchedAmount": {
|
|
222
|
+
"description": "Difference between the instructed amount and the evidence, in minor units",
|
|
223
|
+
"pattern": "^[1-9][0-9]{0,17}$",
|
|
224
|
+
"type": "string"
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
"id": "supplier_payout_break",
|
|
228
|
+
"idPrefix": "spbk",
|
|
229
|
+
"lifecycle": {
|
|
230
|
+
"initial": "created",
|
|
231
|
+
"states": [
|
|
232
|
+
"created",
|
|
233
|
+
"carried"
|
|
234
|
+
],
|
|
235
|
+
"transitions": {
|
|
236
|
+
"carry": {
|
|
237
|
+
"from": [
|
|
238
|
+
"created"
|
|
239
|
+
],
|
|
240
|
+
"to": "carried"
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
"required": [
|
|
245
|
+
"breakReason",
|
|
246
|
+
"currency",
|
|
247
|
+
"unmatchedAmount",
|
|
248
|
+
"supplierPayoutId"
|
|
249
|
+
],
|
|
250
|
+
"summary": "Unmatched settlement expectation carried as its own row",
|
|
251
|
+
"title": "Supplier payout Break"
|
|
252
|
+
}
|
|
253
|
+
],
|
|
254
|
+
"product": "supplier_settlement",
|
|
255
|
+
"subjects": [],
|
|
256
|
+
"title": "Supplier settlement",
|
|
257
|
+
"udl": 1,
|
|
258
|
+
"version": 1
|
|
259
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"issues": [
|
|
3
|
+
{
|
|
4
|
+
"code": "UDL5006",
|
|
5
|
+
"path": "$.instruments[0].actions.quote.quote.baseField"
|
|
6
|
+
}
|
|
7
|
+
],
|
|
8
|
+
"summary": "Freeze set completeness: an offer must freeze the base amount it prices and the account it pays, or the commit fingerprints values the price never pinned.",
|
|
9
|
+
"verdict": "invalid"
|
|
10
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
{
|
|
2
|
+
"instruments": [
|
|
3
|
+
{
|
|
4
|
+
"actionOrder": [
|
|
5
|
+
"create",
|
|
6
|
+
"fund",
|
|
7
|
+
"dispute",
|
|
8
|
+
"quote",
|
|
9
|
+
"refund"
|
|
10
|
+
],
|
|
11
|
+
"actions": {
|
|
12
|
+
"create": {
|
|
13
|
+
"description": "Opens escrow against an active listing and provisions its dedicated product escrow account. The amount, currency, and seller are derived from the locked listing -- never caller-supplied -- so escrow economics are the listing's by construction.",
|
|
14
|
+
"moves": [],
|
|
15
|
+
"steps": [
|
|
16
|
+
{
|
|
17
|
+
"bind": {
|
|
18
|
+
"currency": {
|
|
19
|
+
"from": "instance",
|
|
20
|
+
"path": "fields.currency"
|
|
21
|
+
},
|
|
22
|
+
"owner.id": {
|
|
23
|
+
"from": "instance",
|
|
24
|
+
"path": "productId"
|
|
25
|
+
},
|
|
26
|
+
"owner.type": {
|
|
27
|
+
"from": "const",
|
|
28
|
+
"value": "product"
|
|
29
|
+
},
|
|
30
|
+
"productId": {
|
|
31
|
+
"from": "instance",
|
|
32
|
+
"path": "productId"
|
|
33
|
+
},
|
|
34
|
+
"role": {
|
|
35
|
+
"from": "const",
|
|
36
|
+
"value": "product_escrow"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"capture": {
|
|
40
|
+
"escrowAccountId": "accountId"
|
|
41
|
+
},
|
|
42
|
+
"operation": "account.escrow.provision"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"summary": "Create an escrow order"
|
|
46
|
+
},
|
|
47
|
+
"dispute": {
|
|
48
|
+
"description": "Freezes the fully funded escrow before either milestone releases, preserving the entire balance while the parties decide what happens next.",
|
|
49
|
+
"moves": [],
|
|
50
|
+
"steps": [],
|
|
51
|
+
"summary": "Dispute an escrow order"
|
|
52
|
+
},
|
|
53
|
+
"fund": {
|
|
54
|
+
"description": "Moves the full purchase amount from the buyer account into the dedicated escrow account while the listing remains active.",
|
|
55
|
+
"moves": [
|
|
56
|
+
{
|
|
57
|
+
"bind": {
|
|
58
|
+
"amount": {
|
|
59
|
+
"from": "instance",
|
|
60
|
+
"path": "fields.amount"
|
|
61
|
+
},
|
|
62
|
+
"currency": {
|
|
63
|
+
"from": "instance",
|
|
64
|
+
"path": "fields.currency"
|
|
65
|
+
},
|
|
66
|
+
"destinationAccountId": {
|
|
67
|
+
"from": "instance",
|
|
68
|
+
"path": "refs.escrowAccountId"
|
|
69
|
+
},
|
|
70
|
+
"productId": {
|
|
71
|
+
"from": "instance",
|
|
72
|
+
"path": "productId"
|
|
73
|
+
},
|
|
74
|
+
"sourceAccountId": {
|
|
75
|
+
"from": "instance",
|
|
76
|
+
"path": "fields.buyerAccountId"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"capture": {
|
|
80
|
+
"fundTransferId": "transferId"
|
|
81
|
+
},
|
|
82
|
+
"key": "transfer",
|
|
83
|
+
"operation": "internal_transfer.create"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"sandboxFailurePoint": "funding",
|
|
87
|
+
"steps": [],
|
|
88
|
+
"summary": "Fund an escrow order"
|
|
89
|
+
},
|
|
90
|
+
"quote": {
|
|
91
|
+
"description": "Calculates the full buyer refund while disputed and parks the escrow for explicit confirmation. No money moves at quote time.",
|
|
92
|
+
"moves": [],
|
|
93
|
+
"quote": {
|
|
94
|
+
"baseField": "amount",
|
|
95
|
+
"chargeRef": "unwindPenalty",
|
|
96
|
+
"charges": [
|
|
97
|
+
{
|
|
98
|
+
"bps": 0
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"expires": {
|
|
102
|
+
"offset": "PT15M"
|
|
103
|
+
},
|
|
104
|
+
"fixes": [
|
|
105
|
+
"buyerAccountId"
|
|
106
|
+
],
|
|
107
|
+
"netDestinationField": "buyerAccountId",
|
|
108
|
+
"netRef": "unwindRefund"
|
|
109
|
+
},
|
|
110
|
+
"steps": [],
|
|
111
|
+
"summary": "Quote an escrow refund"
|
|
112
|
+
},
|
|
113
|
+
"refund": {
|
|
114
|
+
"commit": "quote",
|
|
115
|
+
"description": "Confirms the quoted retreat and returns the full held amount from escrow to the buyer.",
|
|
116
|
+
"moves": [
|
|
117
|
+
{
|
|
118
|
+
"bind": {
|
|
119
|
+
"amount": {
|
|
120
|
+
"from": "instance",
|
|
121
|
+
"path": "refs.unwindRefund"
|
|
122
|
+
},
|
|
123
|
+
"currency": {
|
|
124
|
+
"from": "instance",
|
|
125
|
+
"path": "fields.currency"
|
|
126
|
+
},
|
|
127
|
+
"destinationAccountId": {
|
|
128
|
+
"from": "instance",
|
|
129
|
+
"path": "fields.buyerAccountId"
|
|
130
|
+
},
|
|
131
|
+
"productId": {
|
|
132
|
+
"from": "instance",
|
|
133
|
+
"path": "productId"
|
|
134
|
+
},
|
|
135
|
+
"sourceAccountId": {
|
|
136
|
+
"from": "instance",
|
|
137
|
+
"path": "refs.escrowAccountId"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"capture": {
|
|
141
|
+
"refundTransferId": "transferId"
|
|
142
|
+
},
|
|
143
|
+
"key": "transfer",
|
|
144
|
+
"operation": "internal_transfer.create"
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"steps": [],
|
|
148
|
+
"summary": "Refund an escrow order"
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"callerParkedStates": {
|
|
152
|
+
"created": "expire fires only when fundBy is set; without a funding deadline the escrow waits on the buyer to fund or cancel",
|
|
153
|
+
"disputed": "dispute resolution is a human judgment; the parties resume the escrow or quote a refund",
|
|
154
|
+
"funded": "releasing or disputing held value is a party decision; escrow deliberately holds until the parties act",
|
|
155
|
+
"refund_quoted": "a quoted refund moves money only when the caller confirms it"
|
|
156
|
+
},
|
|
157
|
+
"description": "An escrow order holds the full purchase amount and releases it to the seller exactly once. Before release, a dispute freezes the full balance until work resumes or a quoted refund is confirmed.",
|
|
158
|
+
"fields": {
|
|
159
|
+
"amount": {
|
|
160
|
+
"description": "Positive minor-unit integer amount serialized as a string (at most 18 digits)",
|
|
161
|
+
"pattern": "^[1-9][0-9]{0,17}$",
|
|
162
|
+
"type": "string"
|
|
163
|
+
},
|
|
164
|
+
"buyerAccountId": {
|
|
165
|
+
"description": "Hyperscale account ID",
|
|
166
|
+
"pattern": "^acct_(sandbox|live)_[a-z0-9]{8,64}$",
|
|
167
|
+
"type": "string",
|
|
168
|
+
"x-hyperscale-reference-filter": {
|
|
169
|
+
"column": "role",
|
|
170
|
+
"values": [
|
|
171
|
+
"customer_balance"
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
"currency": {
|
|
176
|
+
"description": "ISO 4217 currency code",
|
|
177
|
+
"maxLength": 3,
|
|
178
|
+
"minLength": 3,
|
|
179
|
+
"pattern": "^[A-Z]{3}$",
|
|
180
|
+
"type": "string"
|
|
181
|
+
},
|
|
182
|
+
"fundBy": {
|
|
183
|
+
"format": "hyperscale-date-time",
|
|
184
|
+
"type": "string"
|
|
185
|
+
},
|
|
186
|
+
"memo": {
|
|
187
|
+
"maxLength": 180,
|
|
188
|
+
"minLength": 1,
|
|
189
|
+
"type": "string"
|
|
190
|
+
},
|
|
191
|
+
"sellerAccountId": {
|
|
192
|
+
"description": "Hyperscale account ID",
|
|
193
|
+
"pattern": "^acct_(sandbox|live)_[a-z0-9]{8,64}$",
|
|
194
|
+
"type": "string",
|
|
195
|
+
"x-hyperscale-reference-filter": {
|
|
196
|
+
"column": "role",
|
|
197
|
+
"values": [
|
|
198
|
+
"customer_balance"
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
"id": "escrow_order",
|
|
204
|
+
"idPrefix": "eord",
|
|
205
|
+
"lifecycle": {
|
|
206
|
+
"initial": "created",
|
|
207
|
+
"states": [
|
|
208
|
+
"created",
|
|
209
|
+
"funded",
|
|
210
|
+
"disputed",
|
|
211
|
+
"refunded",
|
|
212
|
+
"refund_quoted"
|
|
213
|
+
],
|
|
214
|
+
"transitions": {
|
|
215
|
+
"dispute": {
|
|
216
|
+
"from": [
|
|
217
|
+
"funded"
|
|
218
|
+
],
|
|
219
|
+
"to": "disputed"
|
|
220
|
+
},
|
|
221
|
+
"fund": {
|
|
222
|
+
"from": [
|
|
223
|
+
"created"
|
|
224
|
+
],
|
|
225
|
+
"to": "funded"
|
|
226
|
+
},
|
|
227
|
+
"quote": {
|
|
228
|
+
"from": [
|
|
229
|
+
"disputed"
|
|
230
|
+
],
|
|
231
|
+
"to": "refund_quoted"
|
|
232
|
+
},
|
|
233
|
+
"refund": {
|
|
234
|
+
"from": [
|
|
235
|
+
"refund_quoted"
|
|
236
|
+
],
|
|
237
|
+
"to": "refunded"
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
"parties": {
|
|
242
|
+
"beneficiary": "sellerAccountId",
|
|
243
|
+
"payer": "buyerAccountId"
|
|
244
|
+
},
|
|
245
|
+
"required": [
|
|
246
|
+
"buyerAccountId",
|
|
247
|
+
"sellerAccountId",
|
|
248
|
+
"amount",
|
|
249
|
+
"currency"
|
|
250
|
+
],
|
|
251
|
+
"summary": "An escrow order whose refund quote omits its own base field.",
|
|
252
|
+
"templateId": "escrow",
|
|
253
|
+
"title": "Escrow order"
|
|
254
|
+
}
|
|
255
|
+
],
|
|
256
|
+
"product": "quote_freeze_set",
|
|
257
|
+
"subjects": [],
|
|
258
|
+
"title": "Quote freeze set",
|
|
259
|
+
"udl": 1,
|
|
260
|
+
"version": 1
|
|
261
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"instruments": [
|
|
3
|
+
{
|
|
4
|
+
"actionOrder": ["create", "quote"],
|
|
5
|
+
"actions": {
|
|
6
|
+
"create": {
|
|
7
|
+
"moves": [],
|
|
8
|
+
"steps": [],
|
|
9
|
+
"summary": "File the note."
|
|
10
|
+
},
|
|
11
|
+
"quote": {
|
|
12
|
+
"moves": [],
|
|
13
|
+
"requiresRefs": [
|
|
14
|
+
{
|
|
15
|
+
"field": "reference",
|
|
16
|
+
"statuses": ["open"]
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"steps": [],
|
|
20
|
+
"summary": "Close the note."
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"fields": {
|
|
24
|
+
"reference": {
|
|
25
|
+
"type": "string"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"id": "note",
|
|
29
|
+
"idPrefix": "note",
|
|
30
|
+
"lifecycle": {
|
|
31
|
+
"initial": "open",
|
|
32
|
+
"states": ["open", "closed"],
|
|
33
|
+
"transitions": {
|
|
34
|
+
"quote": {
|
|
35
|
+
"from": ["open"],
|
|
36
|
+
"to": "closed"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"required": ["reference"],
|
|
41
|
+
"summary": "A note a tenant files and later closes.",
|
|
42
|
+
"title": "Note"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"product": "quote_named_reference_gate",
|
|
46
|
+
"subjects": [],
|
|
47
|
+
"title": "Quote named reference gate",
|
|
48
|
+
"udl": 1,
|
|
49
|
+
"version": 1
|
|
50
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"instruments": [
|
|
3
|
+
{
|
|
4
|
+
"actionOrder": ["create", "reconcile"],
|
|
5
|
+
"actions": {
|
|
6
|
+
"create": {
|
|
7
|
+
"moves": [],
|
|
8
|
+
"steps": [],
|
|
9
|
+
"summary": "File the note."
|
|
10
|
+
},
|
|
11
|
+
"reconcile": {
|
|
12
|
+
"moves": [],
|
|
13
|
+
"requiresRefs": [
|
|
14
|
+
{
|
|
15
|
+
"field": "reference",
|
|
16
|
+
"statuses": ["open"]
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"steps": [],
|
|
20
|
+
"summary": "Close the note."
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"fields": {
|
|
24
|
+
"reference": {
|
|
25
|
+
"type": "string"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"id": "note",
|
|
29
|
+
"idPrefix": "note",
|
|
30
|
+
"lifecycle": {
|
|
31
|
+
"initial": "open",
|
|
32
|
+
"states": ["open", "closed"],
|
|
33
|
+
"transitions": {
|
|
34
|
+
"reconcile": {
|
|
35
|
+
"from": ["open"],
|
|
36
|
+
"to": "closed"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"required": ["reference"],
|
|
41
|
+
"summary": "A note a tenant files and later closes.",
|
|
42
|
+
"title": "Note"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"product": "reconcile_named_reference_gate",
|
|
46
|
+
"subjects": [],
|
|
47
|
+
"title": "Reconcile named reference gate",
|
|
48
|
+
"udl": 1,
|
|
49
|
+
"version": 1
|
|
50
|
+
}
|