@hyperscale0/udl 1.0.0-alpha.3 → 1.0.0-alpha.5
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 +63 -1
- package/README.md +12 -12
- package/dist/evolution.d.ts +21 -12
- package/dist/evolution.d.ts.map +1 -1
- package/dist/evolution.js +59 -15
- package/dist/evolution.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +207 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +205 -1
- package/dist/schema.js.map +1 -1
- package/dist/validation.d.ts +6 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +323 -14
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
- package/spec/README.md +11 -8
- package/spec/udl.schema.json +289 -0
- package/src/evolution.ts +104 -22
- package/src/index.ts +4 -1
- package/src/schema.ts +238 -1
- package/src/validation.ts +504 -19
package/spec/udl.schema.json
CHANGED
|
@@ -109,6 +109,14 @@
|
|
|
109
109
|
]
|
|
110
110
|
}
|
|
111
111
|
},
|
|
112
|
+
"computedMoneyRefs": {
|
|
113
|
+
"minItems": 1,
|
|
114
|
+
"type": "array",
|
|
115
|
+
"items": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
112
120
|
"description": {
|
|
113
121
|
"type": "string"
|
|
114
122
|
},
|
|
@@ -116,6 +124,46 @@
|
|
|
116
124
|
"type": "boolean",
|
|
117
125
|
"const": true
|
|
118
126
|
},
|
|
127
|
+
"derivedAmounts": {
|
|
128
|
+
"minItems": 1,
|
|
129
|
+
"maxItems": 4,
|
|
130
|
+
"type": "array",
|
|
131
|
+
"items": {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"properties": {
|
|
134
|
+
"field": {
|
|
135
|
+
"type": "string",
|
|
136
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
137
|
+
},
|
|
138
|
+
"rounding": {
|
|
139
|
+
"type": "string",
|
|
140
|
+
"const": "floor"
|
|
141
|
+
},
|
|
142
|
+
"rule": {
|
|
143
|
+
"type": "object",
|
|
144
|
+
"properties": {
|
|
145
|
+
"bps": {
|
|
146
|
+
"type": "integer",
|
|
147
|
+
"minimum": 1,
|
|
148
|
+
"maximum": 9999
|
|
149
|
+
},
|
|
150
|
+
"kind": {
|
|
151
|
+
"type": "string",
|
|
152
|
+
"const": "percentage_of"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"required": ["bps", "kind"],
|
|
156
|
+
"additionalProperties": false
|
|
157
|
+
},
|
|
158
|
+
"sourceField": {
|
|
159
|
+
"type": "string",
|
|
160
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"required": ["field", "rounding", "rule", "sourceField"],
|
|
164
|
+
"additionalProperties": false
|
|
165
|
+
}
|
|
166
|
+
},
|
|
119
167
|
"fields": {
|
|
120
168
|
"type": "object",
|
|
121
169
|
"propertyNames": {
|
|
@@ -338,6 +386,17 @@
|
|
|
338
386
|
"additionalProperties": {
|
|
339
387
|
"type": "object",
|
|
340
388
|
"properties": {
|
|
389
|
+
"captureInput": {
|
|
390
|
+
"type": "object",
|
|
391
|
+
"propertyNames": {
|
|
392
|
+
"type": "string",
|
|
393
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
394
|
+
},
|
|
395
|
+
"additionalProperties": {
|
|
396
|
+
"type": "string",
|
|
397
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
398
|
+
}
|
|
399
|
+
},
|
|
341
400
|
"deadline": {
|
|
342
401
|
"type": "object",
|
|
343
402
|
"properties": {
|
|
@@ -372,6 +431,59 @@
|
|
|
372
431
|
"required": ["capability", "deadlineMs", "onTimeout"],
|
|
373
432
|
"additionalProperties": false
|
|
374
433
|
},
|
|
434
|
+
"distribute": {
|
|
435
|
+
"type": "object",
|
|
436
|
+
"properties": {
|
|
437
|
+
"amountRef": {
|
|
438
|
+
"type": "string",
|
|
439
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
440
|
+
},
|
|
441
|
+
"onZero": {
|
|
442
|
+
"type": "string",
|
|
443
|
+
"enum": ["refuse", "skip_steps"]
|
|
444
|
+
},
|
|
445
|
+
"pool": {
|
|
446
|
+
"type": "object",
|
|
447
|
+
"properties": {
|
|
448
|
+
"from": {
|
|
449
|
+
"type": "string",
|
|
450
|
+
"const": "parent"
|
|
451
|
+
},
|
|
452
|
+
"path": {
|
|
453
|
+
"type": "string",
|
|
454
|
+
"pattern": "^[a-z][A-Za-z0-9]*(?:\\.[a-z][A-Za-z0-9]*)*$"
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
"required": ["from", "path"],
|
|
458
|
+
"additionalProperties": false
|
|
459
|
+
},
|
|
460
|
+
"refField": {
|
|
461
|
+
"type": "string",
|
|
462
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
463
|
+
},
|
|
464
|
+
"statuses": {
|
|
465
|
+
"minItems": 1,
|
|
466
|
+
"type": "array",
|
|
467
|
+
"items": {
|
|
468
|
+
"type": "string",
|
|
469
|
+
"pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$"
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
"weightField": {
|
|
473
|
+
"type": "string",
|
|
474
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
"required": [
|
|
478
|
+
"amountRef",
|
|
479
|
+
"onZero",
|
|
480
|
+
"pool",
|
|
481
|
+
"refField",
|
|
482
|
+
"statuses",
|
|
483
|
+
"weightField"
|
|
484
|
+
],
|
|
485
|
+
"additionalProperties": false
|
|
486
|
+
},
|
|
375
487
|
"description": {
|
|
376
488
|
"type": "string"
|
|
377
489
|
},
|
|
@@ -580,6 +692,49 @@
|
|
|
580
692
|
"additionalProperties": false
|
|
581
693
|
}
|
|
582
694
|
},
|
|
695
|
+
"payout": {
|
|
696
|
+
"type": "object",
|
|
697
|
+
"properties": {
|
|
698
|
+
"amount": {
|
|
699
|
+
"type": "string",
|
|
700
|
+
"pattern": "^(?:fields|refs)\\.[a-z][A-Za-z0-9]*$"
|
|
701
|
+
},
|
|
702
|
+
"beneficiaryField": {
|
|
703
|
+
"type": "string",
|
|
704
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
705
|
+
},
|
|
706
|
+
"beneficiaryPartyField": {
|
|
707
|
+
"type": "string",
|
|
708
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
709
|
+
},
|
|
710
|
+
"capture": {
|
|
711
|
+
"type": "string",
|
|
712
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
713
|
+
},
|
|
714
|
+
"currencyField": {
|
|
715
|
+
"type": "string",
|
|
716
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
717
|
+
},
|
|
718
|
+
"sourceAccountField": {
|
|
719
|
+
"type": "string",
|
|
720
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
721
|
+
},
|
|
722
|
+
"speed": {
|
|
723
|
+
"type": "string",
|
|
724
|
+
"const": "standard"
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
"required": [
|
|
728
|
+
"amount",
|
|
729
|
+
"beneficiaryField",
|
|
730
|
+
"beneficiaryPartyField",
|
|
731
|
+
"capture",
|
|
732
|
+
"currencyField",
|
|
733
|
+
"sourceAccountField",
|
|
734
|
+
"speed"
|
|
735
|
+
],
|
|
736
|
+
"additionalProperties": false
|
|
737
|
+
},
|
|
583
738
|
"port": {
|
|
584
739
|
"type": "object",
|
|
585
740
|
"properties": {
|
|
@@ -595,6 +750,11 @@
|
|
|
595
750
|
"required": ["allowedParties"],
|
|
596
751
|
"additionalProperties": false
|
|
597
752
|
},
|
|
753
|
+
"publicIntent": {
|
|
754
|
+
"description": "Author-approved public intent name; the containing verb key remains the lifecycle and execution identity",
|
|
755
|
+
"type": "string",
|
|
756
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
757
|
+
},
|
|
598
758
|
"requiresAggregate": {
|
|
599
759
|
"minItems": 1,
|
|
600
760
|
"type": "array",
|
|
@@ -758,6 +918,51 @@
|
|
|
758
918
|
"required": ["path"],
|
|
759
919
|
"additionalProperties": false
|
|
760
920
|
},
|
|
921
|
+
"requiresExposure": {
|
|
922
|
+
"minItems": 1,
|
|
923
|
+
"type": "array",
|
|
924
|
+
"items": {
|
|
925
|
+
"type": "object",
|
|
926
|
+
"properties": {
|
|
927
|
+
"amountField": {
|
|
928
|
+
"type": "string",
|
|
929
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
930
|
+
},
|
|
931
|
+
"anchorField": {
|
|
932
|
+
"type": "string",
|
|
933
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
934
|
+
},
|
|
935
|
+
"capField": {
|
|
936
|
+
"type": "string",
|
|
937
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
938
|
+
},
|
|
939
|
+
"capOnAnchor": {
|
|
940
|
+
"type": "boolean",
|
|
941
|
+
"const": true
|
|
942
|
+
},
|
|
943
|
+
"childNounId": {
|
|
944
|
+
"type": "string",
|
|
945
|
+
"pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$"
|
|
946
|
+
},
|
|
947
|
+
"statuses": {
|
|
948
|
+
"minItems": 1,
|
|
949
|
+
"type": "array",
|
|
950
|
+
"items": {
|
|
951
|
+
"type": "string",
|
|
952
|
+
"pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$"
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
},
|
|
956
|
+
"required": [
|
|
957
|
+
"amountField",
|
|
958
|
+
"anchorField",
|
|
959
|
+
"capField",
|
|
960
|
+
"childNounId",
|
|
961
|
+
"statuses"
|
|
962
|
+
],
|
|
963
|
+
"additionalProperties": false
|
|
964
|
+
}
|
|
965
|
+
},
|
|
761
966
|
"requiresRefs": {
|
|
762
967
|
"minItems": 1,
|
|
763
968
|
"type": "array",
|
|
@@ -811,6 +1016,21 @@
|
|
|
811
1016
|
"additionalProperties": false
|
|
812
1017
|
}
|
|
813
1018
|
},
|
|
1019
|
+
"requiresSettlement": {
|
|
1020
|
+
"type": "object",
|
|
1021
|
+
"properties": {
|
|
1022
|
+
"capture": {
|
|
1023
|
+
"type": "string",
|
|
1024
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
1025
|
+
},
|
|
1026
|
+
"payoutRef": {
|
|
1027
|
+
"type": "string",
|
|
1028
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
1029
|
+
}
|
|
1030
|
+
},
|
|
1031
|
+
"required": ["capture", "payoutRef"],
|
|
1032
|
+
"additionalProperties": false
|
|
1033
|
+
},
|
|
814
1034
|
"setsAt": {
|
|
815
1035
|
"type": "object",
|
|
816
1036
|
"properties": {
|
|
@@ -818,6 +1038,10 @@
|
|
|
818
1038
|
"type": "string",
|
|
819
1039
|
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
820
1040
|
},
|
|
1041
|
+
"marker": {
|
|
1042
|
+
"type": "boolean",
|
|
1043
|
+
"const": true
|
|
1044
|
+
},
|
|
821
1045
|
"offset": {
|
|
822
1046
|
"type": "string"
|
|
823
1047
|
}
|
|
@@ -825,6 +1049,71 @@
|
|
|
825
1049
|
"required": ["field", "offset"],
|
|
826
1050
|
"additionalProperties": false
|
|
827
1051
|
},
|
|
1052
|
+
"signedSum": {
|
|
1053
|
+
"type": "object",
|
|
1054
|
+
"properties": {
|
|
1055
|
+
"amountRef": {
|
|
1056
|
+
"type": "string",
|
|
1057
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
1058
|
+
},
|
|
1059
|
+
"onNegative": {
|
|
1060
|
+
"type": "string",
|
|
1061
|
+
"const": "refuse"
|
|
1062
|
+
},
|
|
1063
|
+
"onZero": {
|
|
1064
|
+
"type": "string",
|
|
1065
|
+
"enum": ["refuse", "skip_steps"]
|
|
1066
|
+
},
|
|
1067
|
+
"sources": {
|
|
1068
|
+
"minItems": 1,
|
|
1069
|
+
"type": "array",
|
|
1070
|
+
"items": {
|
|
1071
|
+
"type": "object",
|
|
1072
|
+
"properties": {
|
|
1073
|
+
"amountField": {
|
|
1074
|
+
"type": "string",
|
|
1075
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
1076
|
+
},
|
|
1077
|
+
"nounId": {
|
|
1078
|
+
"type": "string",
|
|
1079
|
+
"pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$"
|
|
1080
|
+
},
|
|
1081
|
+
"refField": {
|
|
1082
|
+
"type": "string",
|
|
1083
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
1084
|
+
},
|
|
1085
|
+
"sign": {
|
|
1086
|
+
"type": "string",
|
|
1087
|
+
"enum": ["add", "subtract"]
|
|
1088
|
+
},
|
|
1089
|
+
"statuses": {
|
|
1090
|
+
"minItems": 1,
|
|
1091
|
+
"type": "array",
|
|
1092
|
+
"items": {
|
|
1093
|
+
"type": "string",
|
|
1094
|
+
"pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$"
|
|
1095
|
+
}
|
|
1096
|
+
},
|
|
1097
|
+
"subtotalRef": {
|
|
1098
|
+
"type": "string",
|
|
1099
|
+
"pattern": "^[a-z][A-Za-z0-9]*$"
|
|
1100
|
+
}
|
|
1101
|
+
},
|
|
1102
|
+
"required": [
|
|
1103
|
+
"amountField",
|
|
1104
|
+
"nounId",
|
|
1105
|
+
"refField",
|
|
1106
|
+
"sign",
|
|
1107
|
+
"statuses",
|
|
1108
|
+
"subtotalRef"
|
|
1109
|
+
],
|
|
1110
|
+
"additionalProperties": false
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
},
|
|
1114
|
+
"required": ["amountRef", "onNegative", "onZero", "sources"],
|
|
1115
|
+
"additionalProperties": false
|
|
1116
|
+
},
|
|
828
1117
|
"steps": {
|
|
829
1118
|
"type": "array",
|
|
830
1119
|
"items": {
|
package/src/evolution.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UDL_LIMITS } from "./limits.js";
|
|
2
2
|
import type { UdlAggregate, UdlDocument, UdlNoun, UdlVerb } from "./schema.js";
|
|
3
|
-
import {
|
|
3
|
+
import { UdlError } from "./validation.js";
|
|
4
4
|
|
|
5
5
|
export interface EvolutionFieldSnapshot {
|
|
6
6
|
readonly required: boolean;
|
|
@@ -18,8 +18,12 @@ export interface EvolutionMoveSnapshot extends EvolutionStepSnapshot {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export interface EvolutionVerbSnapshot {
|
|
21
|
+
/** Missing on snapshots written before receipt-input capture existed. */
|
|
22
|
+
readonly captureInput?: unknown;
|
|
21
23
|
readonly deadline: unknown;
|
|
22
24
|
readonly decision: unknown;
|
|
25
|
+
/** Missing on snapshots written before weighted distribution existed. */
|
|
26
|
+
readonly distribute?: unknown;
|
|
23
27
|
readonly due: unknown;
|
|
24
28
|
readonly earnable: boolean;
|
|
25
29
|
readonly eventName: string | null;
|
|
@@ -30,11 +34,21 @@ export interface EvolutionVerbSnapshot {
|
|
|
30
34
|
* friends change what callers may send, so they are frozen once live.
|
|
31
35
|
*/
|
|
32
36
|
readonly inputConstraints: unknown;
|
|
37
|
+
/** Missing on snapshots written before payout intents existed. */
|
|
38
|
+
readonly payout?: unknown;
|
|
33
39
|
readonly port: unknown;
|
|
40
|
+
/** Missing on snapshots written before public intent metadata existed. */
|
|
41
|
+
readonly publicIntent?: string | null;
|
|
34
42
|
readonly requiresAggregate: unknown;
|
|
35
43
|
readonly requiresDrainedAccount: unknown;
|
|
44
|
+
/** Missing on snapshots written before exposure gates entered open UDL. */
|
|
45
|
+
readonly requiresExposure?: unknown;
|
|
36
46
|
readonly requiresRefs: unknown;
|
|
47
|
+
/** Missing on snapshots written before settlement evidence gates existed. */
|
|
48
|
+
readonly requiresSettlement?: unknown;
|
|
37
49
|
readonly setsAt: unknown;
|
|
50
|
+
/** Missing on snapshots written before signed child sums existed. */
|
|
51
|
+
readonly signedSum?: unknown;
|
|
38
52
|
readonly moves: readonly EvolutionMoveSnapshot[];
|
|
39
53
|
readonly steps: readonly EvolutionStepSnapshot[];
|
|
40
54
|
}
|
|
@@ -47,6 +61,9 @@ export interface EvolutionTransitionSnapshot {
|
|
|
47
61
|
/** The complete serializable algebra protected by append-only evolution. */
|
|
48
62
|
export interface NounEvolutionSnapshot {
|
|
49
63
|
readonly aggregateInvariants: readonly string[];
|
|
64
|
+
/** Missing on snapshots written before typed computed refs entered UDL. */
|
|
65
|
+
readonly computedMoneyRefs?: readonly string[];
|
|
66
|
+
readonly derivedAmounts: readonly string[];
|
|
50
67
|
readonly distinctParties?: true;
|
|
51
68
|
readonly fields: Readonly<Record<string, EvolutionFieldSnapshot>>;
|
|
52
69
|
readonly id: string;
|
|
@@ -70,6 +87,11 @@ export function snapshotUdlNoun(noun: UdlNoun): NounEvolutionSnapshot {
|
|
|
70
87
|
aggregateInvariants: (noun.aggregateInvariants ?? []).map(
|
|
71
88
|
aggregateInvariantKey,
|
|
72
89
|
),
|
|
90
|
+
computedMoneyRefs: [...(noun.computedMoneyRefs ?? [])].sort(),
|
|
91
|
+
derivedAmounts: (noun.derivedAmounts ?? []).map(
|
|
92
|
+
(amount) =>
|
|
93
|
+
`${amount.field}=floor(${amount.sourceField}*${amount.rule.bps}/10000)`,
|
|
94
|
+
),
|
|
73
95
|
...(noun.distinctParties ? { distinctParties: true as const } : {}),
|
|
74
96
|
fields: Object.fromEntries(
|
|
75
97
|
Object.entries(noun.fields).map(([field, schema]) => [
|
|
@@ -108,27 +130,10 @@ export function snapshotUdlNoun(noun: UdlNoun): NounEvolutionSnapshot {
|
|
|
108
130
|
/**
|
|
109
131
|
* Compare two product definitions under the append-only evolution law.
|
|
110
132
|
*
|
|
111
|
-
* Both
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* `resource_limit` issue for the same object.
|
|
116
|
-
*/
|
|
117
|
-
export function diffUdlEvolution(
|
|
118
|
-
previous: unknown,
|
|
119
|
-
next: unknown,
|
|
120
|
-
): readonly string[] {
|
|
121
|
-
return diffValidatedUdlEvolution(
|
|
122
|
-
assertValidUdl(previous),
|
|
123
|
-
assertValidUdl(next),
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* The same comparison for a caller holding two documents `validateUdl` has
|
|
129
|
-
* already admitted. Validation costs roughly twice what the diff costs, so a
|
|
130
|
-
* caller that has paid once should not pay again: `udl diff` parses both
|
|
131
|
-
* files and then takes this door.
|
|
133
|
+
* Both documents must already have passed `validateUdl`. The diff walks
|
|
134
|
+
* straight into `stableStringify`, so an unvalidated document with a cycle in
|
|
135
|
+
* it throws a RangeError out of here where the validator would have returned a
|
|
136
|
+
* clean `resource_limit` issue: parse first, then diff.
|
|
132
137
|
*/
|
|
133
138
|
export function diffValidatedUdlEvolution(
|
|
134
139
|
previous: UdlDocument,
|
|
@@ -252,6 +257,22 @@ export function diffNounEvolution(
|
|
|
252
257
|
violations.push(...diffVerbs(previous.verbs, next.verbs));
|
|
253
258
|
violations.push(...diffParties(previous.parties, next.parties));
|
|
254
259
|
violations.push(...diffAggregates(previous, next));
|
|
260
|
+
if (
|
|
261
|
+
stableStringify(previous.computedMoneyRefs ?? []) !==
|
|
262
|
+
stableStringify(next.computedMoneyRefs ?? [])
|
|
263
|
+
) {
|
|
264
|
+
violations.push(
|
|
265
|
+
"computed money refs changed; runtime-derived money surfaces are frozen once live",
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
if (
|
|
269
|
+
stableStringify(previous.derivedAmounts ?? []) !==
|
|
270
|
+
stableStringify(next.derivedAmounts ?? [])
|
|
271
|
+
) {
|
|
272
|
+
violations.push(
|
|
273
|
+
"derived amount rules changed; derived money arithmetic is frozen once live",
|
|
274
|
+
);
|
|
275
|
+
}
|
|
255
276
|
violations.push(
|
|
256
277
|
...removedSetEntries(
|
|
257
278
|
previous.partitions,
|
|
@@ -288,8 +309,10 @@ export function diffNounEvolution(
|
|
|
288
309
|
|
|
289
310
|
function snapshotUdlVerb(definition: UdlVerb): EvolutionVerbSnapshot {
|
|
290
311
|
return {
|
|
312
|
+
captureInput: definition.captureInput ?? null,
|
|
291
313
|
deadline: definition.deadline ?? null,
|
|
292
314
|
decision: definition.decision ?? null,
|
|
315
|
+
distribute: definition.distribute ?? null,
|
|
293
316
|
due: definition.due ?? null,
|
|
294
317
|
earnable: definition.earnable ?? false,
|
|
295
318
|
eventName: definition.eventName ?? null,
|
|
@@ -297,8 +320,11 @@ function snapshotUdlVerb(definition: UdlVerb): EvolutionVerbSnapshot {
|
|
|
297
320
|
inputConstraints: definition.input
|
|
298
321
|
? snapshotJsonSchemaConstraints(definition.input)
|
|
299
322
|
: null,
|
|
323
|
+
payout: definition.payout ?? null,
|
|
300
324
|
port: definition.port ?? null,
|
|
325
|
+
publicIntent: definition.publicIntent ?? null,
|
|
301
326
|
setsAt: definition.setsAt ?? null,
|
|
327
|
+
signedSum: definition.signedSum ?? null,
|
|
302
328
|
moves: definition.moves.map((move) => ({
|
|
303
329
|
bind: move.bind,
|
|
304
330
|
capture: move.capture ?? {},
|
|
@@ -307,7 +333,9 @@ function snapshotUdlVerb(definition: UdlVerb): EvolutionVerbSnapshot {
|
|
|
307
333
|
})),
|
|
308
334
|
requiresAggregate: definition.requiresAggregate ?? [],
|
|
309
335
|
requiresDrainedAccount: definition.requiresDrainedAccount ?? null,
|
|
336
|
+
requiresExposure: definition.requiresExposure ?? [],
|
|
310
337
|
requiresRefs: definition.requiresRefs ?? [],
|
|
338
|
+
requiresSettlement: definition.requiresSettlement ?? null,
|
|
311
339
|
steps: definition.steps.map((step) => ({
|
|
312
340
|
bind: step.bind,
|
|
313
341
|
capture: step.capture ?? {},
|
|
@@ -448,6 +476,26 @@ function diffVerbs(
|
|
|
448
476
|
) {
|
|
449
477
|
violations.push(`verb ${verb} changed its drained-account gate`);
|
|
450
478
|
}
|
|
479
|
+
if (
|
|
480
|
+
descriptor.requiresExposure !== undefined &&
|
|
481
|
+
stableStringify(descriptor.requiresExposure) !==
|
|
482
|
+
stableStringify(current.requiresExposure)
|
|
483
|
+
) {
|
|
484
|
+
violations.push(`verb ${verb} changed its exposure admission gates`);
|
|
485
|
+
}
|
|
486
|
+
if (
|
|
487
|
+
descriptor.requiresSettlement !== undefined &&
|
|
488
|
+
stableStringify(descriptor.requiresSettlement) !==
|
|
489
|
+
stableStringify(current.requiresSettlement)
|
|
490
|
+
) {
|
|
491
|
+
violations.push(`verb ${verb} changed its settlement evidence gate`);
|
|
492
|
+
}
|
|
493
|
+
if (
|
|
494
|
+
stableStringify(descriptor.payout ?? null) !==
|
|
495
|
+
stableStringify(current.payout ?? null)
|
|
496
|
+
) {
|
|
497
|
+
violations.push(`verb ${verb} changed its payout intent`);
|
|
498
|
+
}
|
|
451
499
|
if (descriptor.earnable !== current.earnable) {
|
|
452
500
|
violations.push(`verb ${verb} changed its earnable flag`);
|
|
453
501
|
}
|
|
@@ -467,14 +515,48 @@ function diffVerbs(
|
|
|
467
515
|
) {
|
|
468
516
|
violations.push(`verb ${verb} changed its provider decision`);
|
|
469
517
|
}
|
|
518
|
+
if (
|
|
519
|
+
stableStringify(descriptor.distribute) !==
|
|
520
|
+
stableStringify(current.distribute)
|
|
521
|
+
) {
|
|
522
|
+
violations.push(
|
|
523
|
+
`verb ${verb} changed its distribution rule; money distribution is frozen once live`,
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
if (
|
|
527
|
+
descriptor.captureInput !== undefined &&
|
|
528
|
+
stableStringify(descriptor.captureInput) !==
|
|
529
|
+
stableStringify(current.captureInput)
|
|
530
|
+
) {
|
|
531
|
+
violations.push(`verb ${verb} changed its captured receipt input`);
|
|
532
|
+
}
|
|
470
533
|
if (stableStringify(descriptor.port) !== stableStringify(current.port)) {
|
|
471
534
|
violations.push(`verb ${verb} changed its decision port`);
|
|
472
535
|
}
|
|
536
|
+
if (
|
|
537
|
+
descriptor.publicIntent != null &&
|
|
538
|
+
descriptor.publicIntent !== current.publicIntent
|
|
539
|
+
) {
|
|
540
|
+
violations.push(`verb ${verb} changed its public intent`);
|
|
541
|
+
}
|
|
473
542
|
if (
|
|
474
543
|
stableStringify(descriptor.setsAt) !== stableStringify(current.setsAt)
|
|
475
544
|
) {
|
|
476
545
|
violations.push(`verb ${verb} changed its computed timestamp`);
|
|
477
546
|
}
|
|
547
|
+
if (
|
|
548
|
+
descriptor.signedSum !== undefined &&
|
|
549
|
+
stableStringify(descriptor.signedSum) !==
|
|
550
|
+
stableStringify(current.signedSum)
|
|
551
|
+
) {
|
|
552
|
+
violations.push(`verb ${verb} changed its signed child sum`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
for (const [verb, descriptor] of Object.entries(next)) {
|
|
556
|
+
if (previous[verb] || descriptor.payout == null) continue;
|
|
557
|
+
violations.push(
|
|
558
|
+
`verb ${verb} added a payout intent; external money movement is frozen once live`,
|
|
559
|
+
);
|
|
478
560
|
}
|
|
479
561
|
return violations;
|
|
480
562
|
}
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,6 @@ export {
|
|
|
8
8
|
} from "./finance.js";
|
|
9
9
|
export {
|
|
10
10
|
diffNounEvolution,
|
|
11
|
-
diffUdlEvolution,
|
|
12
11
|
diffValidatedUdlEvolution,
|
|
13
12
|
snapshotUdlNoun,
|
|
14
13
|
} from "./evolution.js";
|
|
@@ -24,6 +23,7 @@ export {
|
|
|
24
23
|
UDL_FORMAT_VERSION,
|
|
25
24
|
udlDocumentSchema,
|
|
26
25
|
udlKernelOperationSchema,
|
|
26
|
+
udlPublicIntentSchema,
|
|
27
27
|
} from "./schema.js";
|
|
28
28
|
export type {
|
|
29
29
|
UdlAggregate,
|
|
@@ -40,6 +40,8 @@ export type {
|
|
|
40
40
|
UdlLifecycleTransition,
|
|
41
41
|
UdlNoun,
|
|
42
42
|
UdlNounSubject,
|
|
43
|
+
UdlPayout,
|
|
44
|
+
UdlRequiresSettlement,
|
|
43
45
|
UdlStep,
|
|
44
46
|
UdlSubject,
|
|
45
47
|
UdlUnwind,
|
|
@@ -50,6 +52,7 @@ export {
|
|
|
50
52
|
openReferenceShapeBudget,
|
|
51
53
|
UdlError,
|
|
52
54
|
validateUdl,
|
|
55
|
+
validateUdlJsonSchema,
|
|
53
56
|
validateUdlSchemaValue,
|
|
54
57
|
} from "./validation.js";
|
|
55
58
|
export type {
|