@hyperscale0/udl 2.3.0 → 2.4.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.
Files changed (86) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +5 -1
  3. package/conformance/invalid/invalid-journeys.expected.json +3 -19
  4. package/conformance/invalid/invalid-journeys.udl +47 -49
  5. package/conformance/valid/attested.expected.json +6 -0
  6. package/conformance/valid/attested.udl +251 -0
  7. package/conformance/valid/hand-edited.expected.json +1 -1
  8. package/conformance/valid/hand-edited.udl +1 -1
  9. package/conformance/valid/minimal.expected.json +1 -1
  10. package/conformance/valid/minimal.udl +0 -15
  11. package/conformance/valid/vocabulary.expected.json +6 -0
  12. package/conformance/valid/vocabulary.udl +1999 -0
  13. package/dist/allocation.d.ts +60 -0
  14. package/dist/allocation.d.ts.map +1 -0
  15. package/dist/allocation.js +177 -0
  16. package/dist/allocation.js.map +1 -0
  17. package/dist/diagnostics.d.ts +1 -31
  18. package/dist/diagnostics.d.ts.map +1 -1
  19. package/dist/diagnostics.js +0 -30
  20. package/dist/diagnostics.js.map +1 -1
  21. package/dist/distribution.d.ts +15 -0
  22. package/dist/distribution.d.ts.map +1 -0
  23. package/dist/distribution.js +49 -0
  24. package/dist/distribution.js.map +1 -0
  25. package/dist/effects.d.ts.map +1 -1
  26. package/dist/effects.js +23 -1
  27. package/dist/effects.js.map +1 -1
  28. package/dist/evolution.d.ts +12 -0
  29. package/dist/evolution.d.ts.map +1 -1
  30. package/dist/evolution.js +42 -1
  31. package/dist/evolution.js.map +1 -1
  32. package/dist/finance.d.ts +18 -1
  33. package/dist/finance.d.ts.map +1 -1
  34. package/dist/finance.js +158 -27
  35. package/dist/finance.js.map +1 -1
  36. package/dist/index.d.ts +8 -2
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +5 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/instrument-references.d.ts +5 -0
  41. package/dist/instrument-references.d.ts.map +1 -0
  42. package/dist/instrument-references.js +69 -0
  43. package/dist/instrument-references.js.map +1 -0
  44. package/dist/limits.d.ts +3 -3
  45. package/dist/limits.d.ts.map +1 -1
  46. package/dist/limits.js +3 -7
  47. package/dist/limits.js.map +1 -1
  48. package/dist/reference.d.ts +3 -0
  49. package/dist/reference.d.ts.map +1 -0
  50. package/dist/reference.js +28 -0
  51. package/dist/reference.js.map +1 -0
  52. package/dist/schema.d.ts +1232 -83
  53. package/dist/schema.d.ts.map +1 -1
  54. package/dist/schema.js +398 -60
  55. package/dist/schema.js.map +1 -1
  56. package/dist/validation.d.ts +14 -0
  57. package/dist/validation.d.ts.map +1 -1
  58. package/dist/validation.js +75 -131
  59. package/dist/validation.js.map +1 -1
  60. package/dist/vocabulary.d.ts +23 -0
  61. package/dist/vocabulary.d.ts.map +1 -0
  62. package/dist/vocabulary.js +965 -0
  63. package/dist/vocabulary.js.map +1 -0
  64. package/docs/README.md +2 -1
  65. package/docs/funding-custody.md +165 -0
  66. package/docs/guide/09-schedules-and-allocation.md +130 -0
  67. package/docs/llms-full.txt +620 -101
  68. package/docs/llms.txt +1 -1
  69. package/docs/reference/clauses.md +451 -63
  70. package/docs/reference/cli.md +3 -1
  71. package/docs/reference/diagnostics.md +33 -38
  72. package/package.json +5 -6
  73. package/spec/udl.schema.json +1095 -118
  74. package/src/allocation.ts +259 -0
  75. package/src/diagnostics.ts +0 -32
  76. package/src/distribution.ts +61 -0
  77. package/src/effects.ts +27 -1
  78. package/src/evolution.ts +63 -3
  79. package/src/finance.ts +218 -24
  80. package/src/index.ts +30 -3
  81. package/src/instrument-references.ts +98 -0
  82. package/src/limits.ts +3 -7
  83. package/src/reference.ts +31 -0
  84. package/src/schema.ts +417 -66
  85. package/src/validation.ts +112 -182
  86. package/src/vocabulary.ts +1508 -0
package/CHANGELOG.md CHANGED
@@ -8,6 +8,32 @@ Format version and package version are different numbers.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ - `attests.forAction` lets a declined decision close the same assessed request through its declared refusal action.
12
+
13
+ - Add reference age gates with fixed durations and allocation gates over a named slice.
14
+ - Refuse fee plus VAT ratios above distributable profit and impossible constant partitions.
15
+ - Derive published instrument dependencies and tenant scoping from the same schema annotations.
16
+
17
+ ### Added
18
+
19
+ - Request authority binds a server-computed decision digest to a frozen target action and its material input.
20
+ - Instrument reference annotations drive tenant scoping through the document schema, including allocation and funding references.
21
+
22
+ ## [2.4.0] - 2026-09-15
23
+
24
+ ### Added
25
+
26
+ - Allocation vocabulary: `allocation`, `requiresAllocation`, self allocation, shared consumption and children buckets; `templateBinding` preserves template identity. Unique constraints accept account fields, and exposure can measure allocation-backed remaining balances.
27
+ - Signed schedules, stored rates, equal partitions, contributions, referenced transitions and attested decisions with subject and party binding.
28
+ - Custody clauses: `shift_date`, `requiresExposure.groupField` and `minimumField`, `funding` snapshots and `receiptDistribution` for repeated receipt-backed cash and noncash loss allocation.
29
+ - Assessment refunds across receipts and collection against remaining balances.
30
+
31
+ ### Changed
32
+
33
+ - Regenerate the schema specification and public clause reference for this vocabulary. Document checkout validation and the matching HSX 2.2.0 release.
34
+ - Remove the retired journeys clause and Blueprint cost dimension.
35
+ - Clarify that catalogue slices must include clause-referenced instruments, including optional references, and use the sealed public ID grammar.
36
+
11
37
  ## [2.3.0] - 2026-09-14
12
38
 
13
39
  ### Added
package/README.md CHANGED
@@ -56,7 +56,11 @@ Save this document as `note.udl`:
56
56
  }
57
57
  ```
58
58
 
59
- Check the document with the CLI:
59
+ In the full repository checkout, the UDL CLI entrypoint is `open/udl/src/cli.ts`. Validate local compiler output with `bun open/udl/src/cli.ts validate note.udl` from the repository root so the compiler and validator use the same source revision. In a standalone UDL package checkout, use `bun src/cli.ts validate note.udl`.
60
+
61
+ For npm installations, pair HSX 2.2.0 with UDL 2.4.0. HSX 2.1.1 as published pairs with UDL 2.3.0; a checkout with later clauses such as `templateBinding` needs the local validator even if its package version has not yet changed. These are package versions; the UDL document format remains version 1.
62
+
63
+ Check the document with the installed CLI:
60
64
 
61
65
  ```bash
62
66
  npx @hyperscale0/udl validate note.udl
@@ -1,26 +1,10 @@
1
1
  {
2
- "summary": "Authored journeys reject unknown operations, unknown examples, missing bindings, invalid transitions, and duplicate step ids.",
2
+ "summary": "The retired journeys clause is refused rather than ignored.",
3
3
  "verdict": "invalid",
4
4
  "issues": [
5
5
  {
6
- "code": "journey_unknown_operation",
7
- "path": "$.instruments[0].journeys[0].steps[0].operation"
8
- },
9
- {
10
- "code": "journey_unknown_example",
11
- "path": "$.instruments[0].journeys[1].steps[0].example"
12
- },
13
- {
14
- "code": "journey_unbound_reference",
15
- "path": "$.instruments[0].journeys[2].steps[1].bind.noteId"
16
- },
17
- {
18
- "code": "journey_invalid_transition",
19
- "path": "$.instruments[0].journeys[3].steps[2].operation"
20
- },
21
- {
22
- "code": "journey_duplicate_step_id",
23
- "path": "$.instruments[0].journeys[4].steps[1].id"
6
+ "code": "UDL1003",
7
+ "path": "$.instruments[0]"
24
8
  }
25
9
  ]
26
10
  }
@@ -1,79 +1,77 @@
1
1
  {
2
2
  "instruments": [
3
3
  {
4
- "actionOrder": ["create", "close"],
4
+ "actionOrder": [
5
+ "close",
6
+ "create"
7
+ ],
5
8
  "actions": {
6
- "create": {
7
- "examples": [{ "input": { "reference": "example" }, "name": "default" }],
9
+ "close": {
8
10
  "moves": [],
9
11
  "steps": [],
10
- "summary": "File the note."
12
+ "summary": "Close the note."
11
13
  },
12
- "close": {
13
- "examples": [{ "input": {}, "name": "default" }],
14
+ "create": {
15
+ "examples": [
16
+ {
17
+ "input": {
18
+ "reference": "example"
19
+ },
20
+ "name": "default"
21
+ }
22
+ ],
14
23
  "moves": [],
15
24
  "steps": [],
16
- "summary": "Close the note."
25
+ "summary": "File the note."
26
+ }
27
+ },
28
+ "fields": {
29
+ "reference": {
30
+ "type": "string"
17
31
  }
18
32
  },
19
- "fields": { "reference": { "type": "string" } },
20
33
  "id": "note",
21
34
  "idPrefix": "note",
22
35
  "journeys": [
23
36
  {
24
- "id": "unknown_operation",
25
- "label": "Unknown operation",
26
- "steps": [{ "bind": {}, "example": "default", "operation": "note.missing" }],
27
- "summary": "Refuse an unknown operation."
28
- },
29
- {
30
- "id": "unknown_example",
31
- "label": "Unknown example",
32
- "steps": [{ "bind": {}, "example": "missing", "operation": "note.create" }],
33
- "summary": "Refuse an unknown example."
34
- },
35
- {
36
- "id": "unbound_reference",
37
- "label": "Unbound reference",
38
- "steps": [
39
- { "bind": {}, "example": "default", "id": "note", "operation": "note.create" },
40
- { "bind": {}, "example": "default", "operation": "note.close" }
41
- ],
42
- "summary": "Refuse an unbound reference."
43
- },
44
- {
45
- "id": "invalid_transition",
46
- "label": "Invalid transition",
37
+ "id": "file_note",
38
+ "label": "File a note",
47
39
  "steps": [
48
- { "bind": {}, "example": "default", "id": "note", "operation": "note.create" },
49
- { "bind": { "noteId": "note" }, "example": "default", "operation": "note.close" },
50
- { "bind": { "noteId": "note" }, "example": "default", "operation": "note.close" }
40
+ {
41
+ "bind": {},
42
+ "example": "default",
43
+ "id": "note",
44
+ "operation": "note.create"
45
+ }
51
46
  ],
52
- "summary": "Refuse an invalid transition."
53
- },
54
- {
55
- "id": "duplicate_step_id",
56
- "label": "Duplicate step id",
57
- "steps": [
58
- { "bind": {}, "example": "default", "id": "duplicate", "operation": "note.create" },
59
- { "bind": {}, "example": "default", "id": "duplicate", "operation": "note.create" }
60
- ],
61
- "summary": "Refuse a duplicate step id."
47
+ "summary": "File a note."
62
48
  }
63
49
  ],
64
50
  "lifecycle": {
65
51
  "initial": "open",
66
- "states": ["open", "closed"],
67
- "transitions": { "close": { "from": ["open"], "to": "closed" } }
52
+ "states": [
53
+ "open",
54
+ "closed"
55
+ ],
56
+ "transitions": {
57
+ "close": {
58
+ "from": [
59
+ "open"
60
+ ],
61
+ "to": "closed"
62
+ }
63
+ }
68
64
  },
69
- "required": ["reference"],
65
+ "required": [
66
+ "reference"
67
+ ],
70
68
  "summary": "A note a tenant files and later closes.",
71
69
  "title": "Note"
72
70
  }
73
71
  ],
74
- "product": "invalid_journeys",
72
+ "product": "minimal",
75
73
  "subjects": [],
76
- "title": "Invalid journeys",
74
+ "title": "Minimal",
77
75
  "udl": 1,
78
76
  "version": 1
79
77
  }
@@ -0,0 +1,6 @@
1
+ {
2
+ "canonical": "attested.udl",
3
+ "digest": "aa584ac3a220b85cff4c2f36ae56324427b5905ac549a89f7be4a403c3ce006d",
4
+ "summary": "Server-bound request authority and one approved decision with engine-owned consumption",
5
+ "verdict": "valid"
6
+ }
@@ -0,0 +1,251 @@
1
+ {
2
+ "instruments": [
3
+ {
4
+ "actionOrder": [
5
+ "create",
6
+ "approve",
7
+ "consume"
8
+ ],
9
+ "actions": {
10
+ "approve": {
11
+ "agentDescription": "Record the bound deciding account.",
12
+ "effects": {
13
+ "decides": [
14
+ {
15
+ "signature": "decides.tenant_port",
16
+ "source": "port"
17
+ }
18
+ ]
19
+ },
20
+ "moves": [],
21
+ "port": {
22
+ "allowedParties": [
23
+ "decider"
24
+ ],
25
+ "capture": "decidedBy"
26
+ },
27
+ "steps": [],
28
+ "summary": "Approve instrument"
29
+ },
30
+ "consume": {
31
+ "agentDescription": "Consume this approval within the admitted operation.",
32
+ "captureEngine": {
33
+ "consumedByOperationId": "operationId"
34
+ },
35
+ "engineOwned": true,
36
+ "moves": [],
37
+ "steps": [],
38
+ "summary": "Consume instrument"
39
+ },
40
+ "create": {
41
+ "agentDescription": "Store the immutable request terms.",
42
+ "moves": [],
43
+ "requestAuthority": {
44
+ "actionField": "actionName",
45
+ "digestField": "digest",
46
+ "expiresField": "expiry",
47
+ "inputField": "requestInput",
48
+ "instanceField": "requestId",
49
+ "instrumentField": "requestInstrument",
50
+ "party": "decider",
51
+ "roleField": "role"
52
+ },
53
+ "steps": [],
54
+ "summary": "Create instrument"
55
+ }
56
+ },
57
+ "agentDescription": "Record approval for one exact request.",
58
+ "fields": {
59
+ "actionName": {
60
+ "type": "string"
61
+ },
62
+ "decidedBy": {
63
+ "pattern": "^acct_(sandbox|live)_[a-z0-9]{8,64}$",
64
+ "type": "string"
65
+ },
66
+ "deciderAccount": {
67
+ "pattern": "^acct_(sandbox|live)_[a-z0-9]{8,64}$",
68
+ "type": "string"
69
+ },
70
+ "digest": {
71
+ "pattern": "^[a-f0-9]{64}$",
72
+ "type": "string"
73
+ },
74
+ "expiry": {
75
+ "format": "hyperscale-date-time",
76
+ "type": "string"
77
+ },
78
+ "requestId": {
79
+ "type": "string"
80
+ },
81
+ "requestInput": {
82
+ "additionalProperties": true,
83
+ "type": "object"
84
+ },
85
+ "requestInstrument": {
86
+ "type": "string"
87
+ },
88
+ "role": {
89
+ "type": "string"
90
+ }
91
+ },
92
+ "id": "approval",
93
+ "idPrefix": "apr",
94
+ "lifecycle": {
95
+ "initial": "requested",
96
+ "states": [
97
+ "requested",
98
+ "approved",
99
+ "consumed"
100
+ ],
101
+ "transitions": {
102
+ "approve": {
103
+ "from": [
104
+ "requested"
105
+ ],
106
+ "to": "approved"
107
+ },
108
+ "consume": {
109
+ "from": [
110
+ "approved"
111
+ ],
112
+ "to": "consumed"
113
+ }
114
+ }
115
+ },
116
+ "parties": {
117
+ "decider": "deciderAccount"
118
+ },
119
+ "required": [
120
+ "deciderAccount",
121
+ "requestId",
122
+ "requestInstrument",
123
+ "actionName",
124
+ "digest",
125
+ "role",
126
+ "expiry"
127
+ ],
128
+ "summary": "Approval instrument",
129
+ "title": "Approval"
130
+ },
131
+ {
132
+ "actionOrder": [
133
+ "create",
134
+ "accept"
135
+ ],
136
+ "actions": {
137
+ "accept": {
138
+ "agentDescription": "Accept the exact approved amount once.",
139
+ "effects": {
140
+ "decides": [
141
+ {
142
+ "signature": "decides.referenced_transition",
143
+ "source": "transitionsRefs[0]"
144
+ }
145
+ ],
146
+ "reads": [
147
+ {
148
+ "signature": "reads.requires_refs",
149
+ "source": "requiresRefs"
150
+ }
151
+ ]
152
+ },
153
+ "input": {
154
+ "additionalProperties": false,
155
+ "properties": {
156
+ "amount": {
157
+ "pattern": "^[1-9][0-9]{0,17}$",
158
+ "type": "string",
159
+ "x-hyperscale-currency": "SAR"
160
+ }
161
+ },
162
+ "required": [
163
+ "amount"
164
+ ],
165
+ "type": "object"
166
+ },
167
+ "moves": [],
168
+ "requiresInput": {
169
+ "amount": "fields.amount"
170
+ },
171
+ "requiresRefs": [
172
+ {
173
+ "attests": {
174
+ "action": "fields.actionName",
175
+ "consume": "consume",
176
+ "digest": "fields.digest",
177
+ "expiresAt": "fields.expiry",
178
+ "instrument": "fields.requestInstrument",
179
+ "party": "decider",
180
+ "role": "fields.role"
181
+ },
182
+ "field": "approvalId",
183
+ "match": {
184
+ "instrumentInstanceId": "fields.requestId"
185
+ },
186
+ "statuses": [
187
+ "approved"
188
+ ]
189
+ }
190
+ ],
191
+ "steps": [],
192
+ "summary": "Accept instrument"
193
+ },
194
+ "create": {
195
+ "agentDescription": "Store the immutable request terms.",
196
+ "moves": [],
197
+ "steps": [],
198
+ "summary": "Create instrument"
199
+ }
200
+ },
201
+ "agentDescription": "Admit only the independently approved request.",
202
+ "fields": {
203
+ "amount": {
204
+ "pattern": "^[1-9][0-9]{0,17}$",
205
+ "type": "string",
206
+ "x-hyperscale-currency": "SAR"
207
+ },
208
+ "approvalId": {
209
+ "pattern": "^apr_(sandbox|live)_[a-z0-9]{8,64}$",
210
+ "type": "string"
211
+ },
212
+ "currency": {
213
+ "description": "ISO 4217 currency code",
214
+ "maxLength": 3,
215
+ "minLength": 3,
216
+ "pattern": "^[A-Z]{3}$",
217
+ "type": "string"
218
+ }
219
+ },
220
+ "id": "request",
221
+ "idPrefix": "req",
222
+ "lifecycle": {
223
+ "initial": "open",
224
+ "states": [
225
+ "open",
226
+ "done"
227
+ ],
228
+ "transitions": {
229
+ "accept": {
230
+ "from": [
231
+ "open"
232
+ ],
233
+ "to": "done"
234
+ }
235
+ }
236
+ },
237
+ "required": [
238
+ "approvalId",
239
+ "amount",
240
+ "currency"
241
+ ],
242
+ "summary": "Request instrument",
243
+ "title": "Request"
244
+ }
245
+ ],
246
+ "product": "attested",
247
+ "subjects": [],
248
+ "title": "Attested action",
249
+ "udl": 1,
250
+ "version": 1
251
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "canonical": "minimal.udl",
3
- "digest": "d7a742548bf559eaa3101e09e0c404190957e34854b220ca010d145d4fd9cae6",
3
+ "digest": "7933986489470a2e95e316c854077b6f970b1228679ea86d71d8c4c276e89624",
4
4
  "summary": "Compact, reverse-ordered bytes canonicalize to minimal.udl.",
5
5
  "verdict": "valid"
6
6
  }
@@ -1 +1 @@
1
- {"version":1,"udl":1,"title":"Minimal","subjects":[],"product":"minimal","instruments":[{"fields":{"reference":{"type":"string"}},"id":"note","idPrefix":"note","journeys":[{"id":"file_note","label":"File a note","steps":[{"bind":{},"example":"default","id":"note","operation":"note.create"}],"summary":"File a note."}],"lifecycle":{"initial":"open","states":["open","closed"],"transitions":{"close":{"from":["open"],"to":"closed"}}},"required":["reference"],"summary":"A note a tenant files and later closes.","title":"Note","actionOrder":["close","create"],"actions":{"close":{"moves":[],"steps":[],"summary":"Close the note."},"create":{"examples":[{"input":{"reference":"example"},"name":"default"}],"moves":[],"steps":[],"summary":"File the note."}}}]}
1
+ {"version":1,"udl":1,"title":"Minimal","subjects":[],"product":"minimal","instruments":[{"fields":{"reference":{"type":"string"}},"id":"note","idPrefix":"note","lifecycle":{"initial":"open","states":["open","closed"],"transitions":{"close":{"from":["open"],"to":"closed"}}},"required":["reference"],"summary":"A note a tenant files and later closes.","title":"Note","actionOrder":["close","create"],"actions":{"close":{"moves":[],"steps":[],"summary":"Close the note."},"create":{"examples":[{"input":{"reference":"example"},"name":"default"}],"moves":[],"steps":[],"summary":"File the note."}}}]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "canonical": "minimal.udl",
3
- "digest": "d7a742548bf559eaa3101e09e0c404190957e34854b220ca010d145d4fd9cae6",
3
+ "digest": "7933986489470a2e95e316c854077b6f970b1228679ea86d71d8c4c276e89624",
4
4
  "summary": "The smallest document the grammar and the semantic laws both accept.",
5
5
  "verdict": "valid"
6
6
  }
@@ -32,21 +32,6 @@
32
32
  },
33
33
  "id": "note",
34
34
  "idPrefix": "note",
35
- "journeys": [
36
- {
37
- "id": "file_note",
38
- "label": "File a note",
39
- "steps": [
40
- {
41
- "bind": {},
42
- "example": "default",
43
- "id": "note",
44
- "operation": "note.create"
45
- }
46
- ],
47
- "summary": "File a note."
48
- }
49
- ],
50
35
  "lifecycle": {
51
36
  "initial": "open",
52
37
  "states": [
@@ -0,0 +1,6 @@
1
+ {
2
+ "canonical": "vocabulary.udl",
3
+ "digest": "c4d53928531382cf5e24bcb52c5350889531a8d978252b34f5416f87146bae1a",
4
+ "summary": "Schedules, allocation, grouped ticket admission, funding snapshots and receipt distributions",
5
+ "verdict": "valid"
6
+ }