@hyperscale0/hsx 1.0.0 → 2.0.1

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 (166) hide show
  1. package/CHANGELOG.md +28 -4
  2. package/README.md +58 -38
  3. package/dist/src/ast.d.ts +4 -2
  4. package/dist/src/ast.d.ts.map +1 -1
  5. package/dist/src/cli.d.ts +1 -1
  6. package/dist/src/cli.js.map +1 -1
  7. package/dist/src/compile.d.ts +8 -2
  8. package/dist/src/compile.d.ts.map +1 -1
  9. package/dist/src/compile.js +8 -1
  10. package/dist/src/compile.js.map +1 -1
  11. package/dist/src/cost.d.ts +3 -1
  12. package/dist/src/cost.d.ts.map +1 -1
  13. package/dist/src/cost.js +124 -94
  14. package/dist/src/cost.js.map +1 -1
  15. package/dist/src/diagnostics.d.ts.map +1 -1
  16. package/dist/src/diagnostics.js +96 -5
  17. package/dist/src/diagnostics.js.map +1 -1
  18. package/dist/src/emit.d.ts +3 -1
  19. package/dist/src/emit.d.ts.map +1 -1
  20. package/dist/src/emit.js +27 -10
  21. package/dist/src/emit.js.map +1 -1
  22. package/dist/src/format.js.map +1 -1
  23. package/dist/src/index.d.ts +2 -2
  24. package/dist/src/index.d.ts.map +1 -1
  25. package/dist/src/index.js +1 -1
  26. package/dist/src/index.js.map +1 -1
  27. package/dist/src/ir.d.ts.map +1 -1
  28. package/dist/src/lex.d.ts.map +1 -1
  29. package/dist/src/lsp/server.js.map +1 -1
  30. package/dist/src/modules.js +7 -3
  31. package/dist/src/modules.js.map +1 -1
  32. package/dist/src/parse.js +3 -3
  33. package/dist/src/parse.js.map +1 -1
  34. package/dist/src/std-bundle.js +41 -41
  35. package/dist/src/std-bundle.js.map +1 -1
  36. package/dist/src/std-library.js +2 -2
  37. package/dist/src/typecheck.d.ts.map +1 -1
  38. package/dist/src/typecheck.js +948 -157
  39. package/dist/src/typecheck.js.map +1 -1
  40. package/dist/src/version.d.ts +1 -1
  41. package/dist/src/version.js +1 -1
  42. package/docs/README.md +10 -1
  43. package/docs/assets/hsx.svg +18 -0
  44. package/docs/guide/01-first-program.md +1 -1
  45. package/docs/guide/02-money.md +1 -1
  46. package/docs/guide/03-instruments.md +44 -3
  47. package/docs/guide/04-lifecycles.md +18 -3
  48. package/docs/guide/05-fees-and-splits.md +2 -2
  49. package/docs/guide/06-schedules.md +1 -1
  50. package/docs/guide/07-composition.md +8 -2
  51. package/docs/guide/08-writing-a-module.md +13 -2
  52. package/docs/guide/09-cost.md +3 -3
  53. package/docs/guide/10-diagnostics.md +1 -1
  54. package/docs/llms-full.txt +473 -190
  55. package/docs/llms.txt +2 -2
  56. package/docs/playground.md +4 -3
  57. package/docs/reference/cli.md +2 -2
  58. package/docs/reference/diagnostics.md +243 -37
  59. package/docs/reference/grammar.md +2 -2
  60. package/docs/reference/std/advance.md +2 -2
  61. package/docs/reference/std/cancellable_booking.md +10 -10
  62. package/docs/reference/std/captured_payment.md +14 -14
  63. package/docs/reference/std/conditional_disbursement.md +3 -3
  64. package/docs/reference/std/credit_facility.md +2 -2
  65. package/docs/reference/std/held_payment.md +37 -33
  66. package/docs/reference/std/instant_transfer.md +8 -8
  67. package/docs/reference/std/metered.md +2 -2
  68. package/docs/reference/std/pooled_split.md +2 -2
  69. package/docs/reference/std/premium_forward.md +13 -13
  70. package/docs/reference/std/reconciled_payout.md +2 -2
  71. package/docs/reference/std/recurring_collection.md +2 -2
  72. package/docs/reference/std/rotating_pool.md +2 -2
  73. package/docs/reference/std/scheduled.md +18 -18
  74. package/docs/reference/std/security_deposit.md +14 -14
  75. package/docs/reference/std/settlement_batch.md +2 -2
  76. package/docs/reference/std/swap.md +18 -18
  77. package/docs/reference/std/threshold_pool.md +2 -2
  78. package/docs/reference/std/weighted_distribution.md +2 -2
  79. package/docs/reference/types.md +1 -1
  80. package/docs/reference/udl-output.md +1 -1
  81. package/examples/01-first-program/README.md +1 -1
  82. package/examples/01-first-program/tip-jar.hsx +1 -1
  83. package/examples/02-imports-and-archetypes/photo-booth.hsx +1 -1
  84. package/examples/03-diagnostics/corner-shop-fixed.hsx +1 -1
  85. package/examples/03-diagnostics/corner-shop.hsx +1 -1
  86. package/examples/04-complete-product/study-hall.hsx +1 -1
  87. package/examples/05-watch-club/README.md +0 -3
  88. package/examples/05-watch-club/watch-club.hsx +1 -1
  89. package/examples/README.md +35 -4
  90. package/examples/advance/advance.hsx +1 -1
  91. package/examples/advance/advance.udl +16 -11
  92. package/examples/cancellable_booking/cancellable_booking.hsx +1 -1
  93. package/examples/cancellable_booking/cancellable_booking.udl +13 -11
  94. package/examples/captured_payment/captured_payment.hsx +1 -1
  95. package/examples/captured_payment/captured_payment.udl +10 -7
  96. package/examples/conditional_disbursement/conditional_disbursement.hsx +1 -1
  97. package/examples/conditional_disbursement/conditional_disbursement.udl +7 -5
  98. package/examples/cost-table.json +1542 -382
  99. package/examples/credit_facility/credit_facility.hsx +1 -1
  100. package/examples/credit_facility/credit_facility.udl +26 -19
  101. package/examples/held_payment/held_payment.hsx +1 -1
  102. package/examples/held_payment/held_payment.udl +61 -15
  103. package/examples/instant_transfer/instant_transfer.hsx +1 -1
  104. package/examples/instant_transfer/instant_transfer.udl +17 -11
  105. package/examples/metered/metered.hsx +1 -1
  106. package/examples/metered/metered.udl +8 -6
  107. package/examples/pooled_split/pooled_split.hsx +1 -1
  108. package/examples/pooled_split/pooled_split.udl +16 -13
  109. package/examples/premium_forward/premium_forward.hsx +1 -1
  110. package/examples/premium_forward/premium_forward.udl +22 -16
  111. package/examples/reconciled_payout/reconciled_payout.hsx +1 -1
  112. package/examples/reconciled_payout/reconciled_payout.udl +4 -2
  113. package/examples/recurring_collection/recurring_collection.hsx +1 -1
  114. package/examples/recurring_collection/recurring_collection.udl +20 -15
  115. package/examples/rotating_pool/rotating_pool.hsx +1 -1
  116. package/examples/rotating_pool/rotating_pool.udl +92 -82
  117. package/examples/scheduled/scheduled.hsx +1 -1
  118. package/examples/scheduled/scheduled.udl +15 -10
  119. package/examples/security_deposit/security_deposit.hsx +1 -1
  120. package/examples/security_deposit/security_deposit.udl +19 -5
  121. package/examples/settlement_batch/settlement_batch.hsx +1 -1
  122. package/examples/swap/swap.hsx +1 -1
  123. package/examples/swap/swap.udl +34 -28
  124. package/examples/threshold_pool/threshold_pool.hsx +1 -1
  125. package/examples/threshold_pool/threshold_pool.udl +14 -12
  126. package/examples/weighted_distribution/weighted_distribution.hsx +1 -1
  127. package/examples/weighted_distribution/weighted_distribution.udl +6 -4
  128. package/package.json +6 -5
  129. package/skills/hsx/SKILL.md +26 -26
  130. package/src/ast.ts +4 -2
  131. package/src/cli.ts +4 -4
  132. package/src/compile.ts +14 -3
  133. package/src/cost.ts +176 -104
  134. package/src/diagnostics.ts +99 -4
  135. package/src/emit.ts +32 -18
  136. package/src/index.ts +2 -1
  137. package/src/modules.ts +9 -3
  138. package/src/parse.ts +3 -3
  139. package/src/std-bundle.ts +41 -41
  140. package/src/std-library.ts +2 -2
  141. package/src/typecheck.ts +1251 -235
  142. package/src/version.ts +1 -1
  143. package/std/SEMANTICS.md +12 -3
  144. package/std/{settlements → money_flows}/advance.hsx +1 -1
  145. package/std/{settlements → money_flows}/cancellable_booking.hsx +4 -3
  146. package/std/{settlements → money_flows}/captured_payment.hsx +35 -6
  147. package/std/{settlements → money_flows}/conditional_disbursement.hsx +17 -16
  148. package/std/{settlements → money_flows}/credit_facility.hsx +1 -2
  149. package/std/{settlements → money_flows}/held_payment.hsx +61 -25
  150. package/std/money_flows/index.hsx +3 -0
  151. package/std/{settlements → money_flows}/instant_transfer.hsx +2 -3
  152. package/std/{settlements → money_flows}/metered.hsx +1 -1
  153. package/std/{settlements → money_flows}/pooled_split.hsx +3 -3
  154. package/std/{settlements → money_flows}/premium_forward.hsx +22 -23
  155. package/std/{settlements → money_flows}/reconciled_payout.hsx +3 -3
  156. package/std/{settlements → money_flows}/recurring_collection.hsx +1 -1
  157. package/std/{settlements → money_flows}/rotating_pool.hsx +8 -6
  158. package/std/{settlements → money_flows}/scheduled.hsx +22 -27
  159. package/std/{settlements → money_flows}/security_deposit.hsx +38 -14
  160. package/std/{settlements → money_flows}/settlement_batch.hsx +3 -3
  161. package/std/{settlements → money_flows}/swap.hsx +41 -16
  162. package/std/{settlements → money_flows}/threshold_pool.hsx +5 -5
  163. package/std/{settlements → money_flows}/weighted_distribution.hsx +6 -6
  164. package/docs/sessions/2026-09-02-two-instruments.hsx +0 -21
  165. package/docs/sessions/2026-09-02-two-instruments.md +0 -41
  166. package/std/settlements/index.hsx +0 -3
@@ -1,4 +1,4 @@
1
- module std.settlements.reconciled_payout
1
+ module std.money_flows.reconciled_payout
2
2
 
3
3
  export instrument reconciled_payout<C>(
4
4
  payer: party,
@@ -17,8 +17,8 @@ export instrument reconciled_payout<C>(
17
17
  currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
18
18
  settle_by { type: date; description: "Instant the expectation stops waiting and the unmatched amount becomes a break"; }
19
19
  beneficiary_ref { type: text; description: "Beneficiary ID for the payout instruction"; pattern: "^ben_(sandbox|live)_[a-z0-9]{8,64}$"; }
20
- [beneficiary_account_field] { type: account<C>; description: concat("The ", words(beneficiary), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }
21
- [payer_account_field] { type: account<C>; description: concat("The ", words(payer), " account the payout leaves"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }
20
+ [beneficiary_account_field] { type: account<C>; description: concat("The ", words(beneficiary), " account"); [reference_filter_key]: { column: role; values: [customer_balance]; }; }
21
+ [payer_account_field] { type: account<C>; description: concat("The ", words(payer), " account the payout leaves"); [reference_filter_key]: { column: role; values: [customer_balance]; }; }
22
22
  }
23
23
  lifecycle {
24
24
  states created instructed settled;
@@ -1,4 +1,4 @@
1
- module std.settlements.recurring_collection
1
+ module std.money_flows.recurring_collection
2
2
 
3
3
  export instrument recurring_collection(marker: optional<text>) {
4
4
  agent_description: concat("Reach for ", words(instrument), " to track a bounded run of scheduled collections, one call per recorded installment. It carries no amount and no account, and every action only advances its own state. A settlement that debits an account on a schedule is a different shape.");
@@ -1,4 +1,4 @@
1
- module std.settlements.rotating_pool
1
+ module std.money_flows.rotating_pool
2
2
 
3
3
  export instrument rotating_pool<C>(members: optional<list<party>>, contribution: money<C>, count: integer, every: optional<text>, first_due: date, payout_order: optional<list<party>>, default_policy: optional<text>, guarantee_policy: optional<text>, guarantor: optional<party>, exit_policy: optional<text>, memo: optional<text>, membership: optional<block>) {
4
4
  when_not(membership) {
@@ -9,8 +9,8 @@ export instrument rotating_pool<C>(members: optional<list<party>>, contribution:
9
9
  let(parent_ref_field): concat(camel(instrument), "Id");
10
10
  let(reference_filter): "x-hyperscale-reference-filter";
11
11
  fields {
12
- for member in members { [member]AccountId { type: account<C>; description: concat("The ", words(member), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; [reference_filter]: { column: role; values: [customer_balance]; }; } }
13
- [guarantor_field] { type: account<C>; description: concat("The ", words(guarantor), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; [reference_filter]: { column: role; values: [customer_balance]; }; }
12
+ for member in members { [member]AccountId { type: account<C>; description: concat("The ", words(member), " account"); [reference_filter]: { column: role; values: [customer_balance]; }; } }
13
+ [guarantor_field] { type: account<C>; description: concat("The ", words(guarantor), " account"); [reference_filter]: { column: role; values: [customer_balance]; }; }
14
14
  [contribution_field] { type: money<C>; description: "Exact contribution in {C} minor units"; }
15
15
  currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
16
16
  [first_due_field] { type: date; description: "Stored first contribution due date"; }
@@ -83,8 +83,8 @@ export instrument rotating_pool<C>(members: optional<list<party>>, contribution:
83
83
  summary: concat(words(member), " contribution row");
84
84
  description: concat("Fixed contribution row for ", words(member));
85
85
  fields {
86
- for roster_member in payout_order { [roster_member]AccountId { type: account<C>; description: concat("The ", words(roster_member), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; [reference_filter]: { column: role; values: [customer_balance]; }; } }
87
- [guarantor_field] { type: account<C>; description: concat("The ", words(guarantor), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; [reference_filter]: { column: role; values: [customer_balance]; }; }
86
+ for roster_member in payout_order { [roster_member]AccountId { type: account<C>; description: concat("The ", words(roster_member), " account"); [reference_filter]: { column: role; values: [customer_balance]; }; } }
87
+ [guarantor_field] { type: account<C>; description: concat("The ", words(guarantor), " account"); [reference_filter]: { column: role; values: [customer_balance]; }; }
88
88
  [contribution_field] { type: money<C>; description: "Exact contribution amount shared by every cycle"; }
89
89
  currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
90
90
  [first_due_field] { type: date; description: "First due anchor derived from the pool"; }
@@ -140,7 +140,7 @@ export instrument rotating_pool<C>(members: optional<list<party>>, contribution:
140
140
  action contribute_cycle_[cycle] {
141
141
  summary: concat("Fund ", words(member), "'s cycle ", cycle, " contribution");
142
142
  let(first): if_eq(cycle, 1, true, false);
143
- when(first) { due: { field: first_due_field; }; }
143
+ when(first) { due: { field: first_due_field; }; sandbox_failure_point: funding; }
144
144
  when_not(first) { due: { field: first_due_field; offset: due_offset; }; }
145
145
  requires refs { field: parent_ref_field; statuses: [active_state]; }
146
146
  moves: [{ key: "contribution"; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", contribution_field); }; currency: { from: instance; path: "fields.currency"; }; destinationAccountId: { from: instance; path: "refs.escrowAccountId"; }; "metadata.instrumentId": { from: const; value: child_id; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: contribute_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", camel(member), "AccountId"); }; }; capture: { [contribute_capture]: transferId; }; }];
@@ -167,6 +167,8 @@ export instrument rotating_pool<C>(members: optional<list<party>>, contribution:
167
167
  summary: concat("Pay this member's stored contribution into cycle ", cycle, "'s shared pot recipient");
168
168
  requires refs { field: parent_ref_field; statuses: [ready_state]; }
169
169
  moves: [{ key: payout; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", contribution_field); }; currency: { from: instance; path: "fields.currency"; }; destinationAccountId: { from: instance; path: concat("fields.", payout_field); }; "metadata.instrumentId": { from: const; value: child_id; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: pay_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: "refs.escrowAccountId"; }; }; capture: { [pay_capture]: transferId; }; }];
170
+ let(first): if_eq(cycle, 1, true, false);
171
+ when(first) { sandbox_failure_point: "release"; }
170
172
  steps: [];
171
173
  }
172
174
  action pay_guaranteed_cycle_[cycle] {
@@ -1,4 +1,4 @@
1
- module std.settlements.scheduled
1
+ module std.money_flows.scheduled
2
2
 
3
3
  export instrument scheduled<C>(
4
4
  payer: party,
@@ -76,7 +76,7 @@ export instrument scheduled<C>(
76
76
  let(offset): scale_duration(every, sub(i, 1));
77
77
  let(installment_field): concat("installment", i, "Amount");
78
78
  summary: "Collect installment {i} of {count}";
79
- when(first) { due: { field: first_due; }; }
79
+ when(first) { due: { field: first_due; }; sandbox_failure_point: funding; }
80
80
  when_not(first) { due: { field: first_due; offset: offset; }; }
81
81
  moves: [{ amount: installment_field; from: payer; to: beneficiary; key: transfer; }];
82
82
  steps: [];
@@ -194,7 +194,6 @@ export instrument scheduled<C>(
194
194
  [payee_field]: {
195
195
  type: account;
196
196
  description: "The {payee_words} account";
197
- pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$";
198
197
  [reference_filter_key]: { column: role; values: [customer_balance]; };
199
198
  }
200
199
  }
@@ -202,7 +201,6 @@ export instrument scheduled<C>(
202
201
  [payer_field]: {
203
202
  type: account;
204
203
  description: "The {payer_words} account";
205
- pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$";
206
204
  [reference_filter_key]: { column: role; values: [customer_balance]; };
207
205
  }
208
206
  }
@@ -210,7 +208,6 @@ export instrument scheduled<C>(
210
208
  [debtor_field]: {
211
209
  type: account;
212
210
  description: "The {debtor_words} account";
213
- pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$";
214
211
  [reference_filter_key]: { column: role; values: [customer_balance]; };
215
212
  }
216
213
  }
@@ -218,7 +215,6 @@ export instrument scheduled<C>(
218
215
  platform_account_id: {
219
216
  type: account;
220
217
  description: "The product fee collection account";
221
- pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$";
222
218
  [fee_port_key]: true;
223
219
  [reference_filter_key]: { column: role; values: [customer_balance, product_revenue]; };
224
220
  }
@@ -471,7 +467,7 @@ export instrument scheduled<C>(
471
467
  steps: [];
472
468
  }
473
469
  action repay {
474
- agent_description: concat("Pay this record's amount toward installment ", i, ". The record must be created and its obligation live. Refused when this amount plus the records already paid against that installment would pass the stored amount. This moves the payer's money. Where a mandate applies, only the payer may call it and an evidence reference is required.");
470
+ agent_description: concat("Pay this record's amount toward installment ", i, ". The record must be created and its obligation live. Refused when this amount plus the records already paid against that installment would pass the stored amount. This moves the payer's money. Where a mandate applies, its declared parties may call it and an evidence reference is required.");
475
471
  summary: concat("Pay a partial or full amount against installment ", i);
476
472
  when(has_mandate) {
477
473
  input: {
@@ -488,7 +484,7 @@ export instrument scheduled<C>(
488
484
  type: object;
489
485
  };
490
486
  capture_input: { mandate_evidence_reference: evidenceReference; };
491
- port: { allowed_parties: ["payer"]; };
487
+ port: { allowed_parties: mandate_allowed; };
492
488
  }
493
489
  requires refs: {
494
490
  field: parent_ref_field;
@@ -591,7 +587,7 @@ export instrument scheduled<C>(
591
587
  }
592
588
 
593
589
  action collect_period {
594
- agent_description: "Collect one open period charge from the payer, with the mandate evidence reference kept in the receipt. A period must be open. Only the payer may call it. This moves the period amount and does not reverse.";
590
+ agent_description: "Collect one open period charge from the payer, with the mandate evidence reference kept in the receipt. A period must be open. The mandate's declared parties may call it, or the payer when no mandate is wired. This moves the period amount and does not reverse.";
595
591
  summary: "Collect one authored period charge with mandate evidence";
596
592
  input: {
597
593
  additional_properties: false;
@@ -607,33 +603,32 @@ export instrument scheduled<C>(
607
603
  type: object;
608
604
  };
609
605
  capture_input: { mandate_evidence_reference: evidenceReference; };
610
- port: { allowed_parties: ["payer"]; };
606
+ when(mandate) { port: { allowed_parties: mandate_allowed; }; }
607
+ when_not(mandate) { port: { allowed_parties: [payer]; }; }
611
608
  moves: [{ amount: amount_field; from: payer; to: beneficiary; key: period_collection; }];
609
+ sandbox_failure_point: funding;
612
610
  steps: [];
613
611
  }
614
612
 
615
613
  action [until] {
616
614
  agent_description: "Cancel the open schedule for good and drain any period liability still standing. Only the payer may call it, and the reference fields the port declares are required. No further period opens and there is no reactivation.";
617
615
  summary: "Cancel the open schedule and drain any period liability";
618
- input: {
619
- additional_properties: false;
620
- properties: {
621
- for item in keys(until_fields) {
622
- [item]: {
623
- description: "Required decision reference retained in the operation receipt";
624
- max_length: 180;
625
- min_length: 1;
626
- type: string;
616
+ when(until_fields) {
617
+ input: {
618
+ additional_properties: false;
619
+ properties: {
620
+ for item in keys(until_fields) {
621
+ [item]: get(until_fields, item);
627
622
  }
628
- }
623
+ };
624
+ required: keys(until_fields);
625
+ type: object;
629
626
  };
630
- required: keys(until_fields);
631
- type: object;
632
- };
633
- capture_input: {
634
- for item in keys(until_fields) { [item]: item; }
635
- };
636
- port: { allowed_parties: ["payer"]; };
627
+ capture_input: {
628
+ for item in keys(until_fields) { [item]: item; }
629
+ };
630
+ }
631
+ port { allowed_parties: until_allowed; };
637
632
  steps: [];
638
633
  }
639
634
  }
@@ -1,19 +1,15 @@
1
- module std.settlements.security_deposit
1
+ module std.money_flows.security_deposit
2
2
 
3
3
  export instrument security_deposit<C>(payer: party, holder: party, amount: money<C>, claim: optional<condition>, return: optional<condition>, claim_amount: optional<block>, deadline: optional<date>, claim_to: optional<party>, return_to: optional<party>, memo: optional<text>, claim_input: optional<block>, claim_capture: optional<block>, fund_failure_point: optional<text>, id_prefix_override: optional<text>) {
4
4
  let(claim_name): claim;
5
5
  let(return_name): return;
6
6
  let(payer_account_field): camel(concat(payer, "_account_id"));
7
7
  let(holder_account_field): camel(concat(holder, "_account_id"));
8
- let(claim_actor): at(claim_allowed, 1);
9
- let(claim_role): if_eq(claim_actor, payer, "payer", "beneficiary");
10
8
  let(claim_field): get(claim_amount, "field");
11
9
  let(claim_bound): get(claim_amount, "bound");
12
10
  let(claim_remainder): get(claim_amount, "remainder");
13
11
  let(deadline_field): concat(deadline);
14
12
  let(memo_field): concat(memo);
15
- let(claim_to_role): if_eq(claim_to, payer, "payer", "beneficiary");
16
- let(return_to_role): if_eq(return_to, payer, "payer", "beneficiary");
17
13
  agent_description: "Reach for security deposit when money is reserved against the {payer} in the {holder}'s favor and later claimed or returned. The funds stay reserved and move only on the claim. Pick captured payment when the holder takes the money in slices, and instant transfer when nothing is held.";
18
14
  summary: "Refundable deposit from {payer} held for {holder}";
19
15
  title: sentence(instrument);
@@ -34,8 +30,8 @@ export instrument security_deposit<C>(payer: party, holder: party, amount: money
34
30
  let(reference_filter_key): "x-hyperscale-reference-filter";
35
31
  amount { type: money<C>; description: "Positive minor-unit integer amount serialized as a string (at most 18 digits)"; }
36
32
  [deadline_field] { type: date; }
37
- [holder_account_field] { type: account<C>; description: "Hyperscale account ID"; pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }
38
- [payer_account_field] { type: account<C>; description: "Hyperscale account ID"; pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }
33
+ [holder_account_field] { type: account<C>; description: "Hyperscale account ID"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }
34
+ [payer_account_field] { type: account<C>; description: "Hyperscale account ID"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }
39
35
  when(memo) { [memo_field] { type: text; max_length: 180; min_length: 1; optional: true; } }
40
36
  }
41
37
  }
@@ -75,11 +71,13 @@ export instrument security_deposit<C>(payer: party, holder: party, amount: money
75
71
  let(metadata_phase): "metadata.phase";
76
72
  summary: "Reserve the {amount} against the {payer}'s account";
77
73
  moves: [{ key: reservation; operation: internal_transfer.reserve; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", holder_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: place_deposit; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { placeDepositReservationTransferId: transferId; }; }];
74
+ sandbox_failure_point: funding;
78
75
  steps: [];
79
76
  }
80
77
  action [claim_name] {
81
78
  agent_description: "Claim the held deposit for the {holder}. The deposit must be in held. The reservation settles here, whole or up to the decided amount with the exact remainder released back to the {payer}. There is no return afterwards.";
82
79
  summary: "Claim the deposit for the {holder} through {claim}";
80
+ when(claim_allowed) { port { allowed_parties: claim_allowed; }; }
83
81
  when_not(claim_amount) {
84
82
  moves: [{ key: post; operation: internal_transfer.post; bind: { transferId: { from: instance; path: refs.placeDepositReservationTransferId; }; }; }];
85
83
  }
@@ -90,14 +88,12 @@ export instrument security_deposit<C>(payer: party, holder: party, amount: money
90
88
  additional_properties: false;
91
89
  properties {
92
90
  for input_name in keys(claim_fields) {
93
- [input_name] { type: string; description: "Required decision reference retained in the operation receipt"; max_length: 180; min_length: 1; }
91
+ [input_name]: get(claim_fields, input_name);
94
92
  }
95
- [claim_field] { type: string; description: "Caller-decided amount in minor units"; pattern: "^(0|[1-9][0-9]{0,17})$"; }
96
93
  }
97
94
  required: keys(claim_fields);
98
95
  }
99
96
  [decided_clause]: { field: claim_field; bound_field: claim_bound; remainder_action: return_name; };
100
- port { allowed_parties: [claim_role]; };
101
97
  moves: [{ key: post; operation: internal_transfer.post; bind: { amount: { from: input; path: claim_field; }; currency: { from: instance; path: fields.currency; }; postMode: { from: const; value: partial_only; }; transferId: { from: instance; path: refs.placeDepositReservationTransferId; }; }; }, { key: remainder; operation: internal_transfer.void; bind: { reason: { from: const; value: "Return the unclaimed deposit remainder"; }; transferId: { from: instance; path: refs.placeDepositReservationTransferId; }; }; }];
102
98
  }
103
99
  steps: [];
@@ -105,6 +101,22 @@ export instrument security_deposit<C>(payer: party, holder: party, amount: money
105
101
  action [return_name] {
106
102
  agent_description: "Return the held deposit to the {payer}. The deposit must be in held and unclaimed. This releases the reservation whole and the {holder} receives nothing.";
107
103
  summary: "Return the deposit to the {payer} through {return}";
104
+ when(return_fields) {
105
+ input {
106
+ type: object;
107
+ additional_properties: false;
108
+ properties {
109
+ for input_name in keys(return_fields) {
110
+ [input_name]: get(return_fields, input_name);
111
+ }
112
+ }
113
+ required: keys(return_fields);
114
+ }
115
+ capture_input: {
116
+ for item in keys(return_fields) { [item]: item; }
117
+ };
118
+ }
119
+ port { allowed_parties: return_allowed; };
108
120
  moves: [{ key: void; operation: internal_transfer.void; bind: { reason: { from: const; value: "Deposit returned in full"; }; transferId: { from: instance; path: refs.placeDepositReservationTransferId; }; }; }];
109
121
  steps: [];
110
122
  }
@@ -126,26 +138,38 @@ export instrument security_deposit<C>(payer: party, holder: party, amount: money
126
138
  deadline: { field: deadline_field; };
127
139
  moves: [{ key: reservation; operation: internal_transfer.reserve; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", holder_account_field); }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { holdTransferId: transferId; }; }];
128
140
  when(fund_failure_point) { sandbox_failure_point: fund_failure_point; }
141
+ when_not(fund_failure_point) { sandbox_failure_point: funding; }
129
142
  steps: [];
130
143
  summary: "Fund the security deposit";
131
144
  }
132
145
  action claim {
133
- agent_description: "Post the {holder}'s decided amount out of the reservation and void the remainder back to the {payer} in one linked group. This moves money and does not reverse. Only a funded hold claims, and the claimed amount cannot exceed the held {amount}.";
146
+ when_not(claim_amount) {
147
+ agent_description: "Post the whole reservation to the {holder}. This moves money and does not reverse. Only a funded hold claims.";
148
+ moves: [{ key: "claim"; operation: internal_transfer.post; bind: { transferId: { from: instance; path: refs.holdTransferId; }; }; }];
149
+ }
134
150
  deadline: { field: deadline_field; };
135
151
  when(claim_capture) { capture_input: claim_capture; }
136
152
  when(claim_amount) {
153
+ agent_description: "Post the {holder}'s decided amount out of the reservation and void the remainder back to the {payer} in one linked group. This moves money and does not reverse. Only a funded hold claims, and the claimed amount cannot exceed the held {amount}.";
137
154
  decided_amount: { field: claim_field; bound_field: claim_bound; remainder_action: claim_remainder; };
155
+ sandbox_failure_point: "release";
156
+ moves: [{ key: "claim"; operation: internal_transfer.post; bind: { amount: { from: input; path: claim_field; }; currency: { from: instance; path: fields.currency; }; postMode: { from: const; value: partial_only; }; transferId: { from: instance; path: refs.holdTransferId; }; }; }, { key: remainder; operation: internal_transfer.void; bind: { reason: { from: const; value: "Return unclaimed deposit remainder"; }; transferId: { from: instance; path: refs.holdTransferId; }; }; }];
138
157
  }
139
158
  when(claim_input) { input: claim_input; }
140
- when(claim_to) { port { allowed_parties: [claim_to_role]; }; }
141
- moves: [{ key: "claim"; operation: internal_transfer.post; bind: { amount: { from: input; path: claim_field; }; currency: { from: instance; path: fields.currency; }; postMode: { from: const; value: partial_only; }; transferId: { from: instance; path: refs.holdTransferId; }; }; }, { key: remainder; operation: internal_transfer.void; bind: { reason: { from: const; value: "Return unclaimed deposit remainder"; }; transferId: { from: instance; path: refs.holdTransferId; }; }; }];
159
+ when(claim_allowed) { port { allowed_parties: claim_allowed; }; }
160
+ when_not(claim_allowed) {
161
+ when(claim_to) { port { allowed_parties: [claim_to]; }; }
162
+ }
142
163
  steps: [];
143
164
  summary: "Claim the security deposit";
144
165
  }
145
166
  action return {
146
167
  agent_description: "Void the whole reservation so the {payer} gets every unit back. Use this when the {holder} decides to keep nothing. This moves money and does not reverse. Only a funded hold returns.";
147
168
  deadline: { field: deadline_field; };
148
- when(return_to) { port { allowed_parties: [return_to_role]; }; }
169
+ when(return_allowed) { port { allowed_parties: return_allowed; }; }
170
+ when_not(return_allowed) {
171
+ when(return_to) { port { allowed_parties: [return_to]; }; }
172
+ }
149
173
  moves: [{ key: "return"; operation: internal_transfer.void; bind: { reason: { from: const; value: "Deposit returned in full"; }; transferId: { from: instance; path: refs.holdTransferId; }; }; }];
150
174
  steps: [];
151
175
  summary: "Return the security deposit";
@@ -1,4 +1,4 @@
1
- module std.settlements.settlement_batch
1
+ module std.money_flows.settlement_batch
2
2
 
3
3
  export instrument settlement_batch<C>(
4
4
  settlement_account: party,
@@ -15,8 +15,8 @@ export instrument settlement_batch<C>(
15
15
  close_trigger { type: date; description: "Date the open batch freezes against later entries"; }
16
16
  currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
17
17
  payout_beneficiary_ref { type: text; description: "Beneficiary ID for the payout instruction"; pattern: "^ben_(sandbox|live)_[a-z0-9]{8,64}$"; }
18
- [payout_destination]AccountId { type: account<C>; description: concat("The ", words(payout_destination), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
19
- [settlement_account]AccountId { type: account<C>; description: concat("The ", words(settlement_account), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
18
+ [payout_destination]AccountId { type: account<C>; description: concat("The ", words(payout_destination), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
19
+ [settlement_account]AccountId { type: account<C>; description: concat("The ", words(settlement_account), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
20
20
  }
21
21
  lifecycle {
22
22
  states open closed calculated approved instructed acknowledged reconciled;
@@ -1,4 +1,4 @@
1
- module std.settlements.swap;
1
+ module std.money_flows.swap;
2
2
  export instrument swap<C>(between: list<party>, amounts: block, fees: block, release: condition, dispute: condition, side_names: optional<block>, lifecycle_state_order: optional<list<text>>, action_bindings: optional<block>, parked_states: optional<block>, fixed_prefix: optional<text>) {
3
3
  let(side_a): at(between, 1);
4
4
  let(side_b): at(between, 2);
@@ -29,8 +29,8 @@ export instrument swap<C>(between: list<party>, amounts: block, fees: block, rel
29
29
  distinct_parties: true;
30
30
  when(side_names) {
31
31
  parties {
32
- payer: side_a_account;
33
- beneficiary: side_b_account;
32
+ payer: { party: side_a; account: side_a_account; };
33
+ beneficiary: { party: side_b; account: side_b_account; };
34
34
  }
35
35
  }
36
36
  when_not(side_names) {
@@ -82,7 +82,6 @@ export instrument swap<C>(between: list<party>, amounts: block, fees: block, rel
82
82
  "[side_a_account]" {
83
83
  type: account<C>;
84
84
  description: "First trade party and funder";
85
- pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$";
86
85
  "x-hyperscale-reference-filter" {
87
86
  column: role;
88
87
  values: [customer_balance];
@@ -99,7 +98,6 @@ export instrument swap<C>(between: list<party>, amounts: block, fees: block, rel
99
98
  "[side_b_account]" {
100
99
  type: account<C>;
101
100
  description: "Second trade party and funder";
102
- pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$";
103
101
  "x-hyperscale-reference-filter" {
104
102
  column: role;
105
103
  values: [customer_balance];
@@ -144,7 +142,6 @@ export instrument swap<C>(between: list<party>, amounts: block, fees: block, rel
144
142
  when_not(side_names) {
145
143
  description: "The product fee collection account";
146
144
  }
147
- pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$";
148
145
  "x-hyperscale-fee-collection-port": true;
149
146
  "x-hyperscale-reference-filter" {
150
147
  column: role;
@@ -240,15 +237,28 @@ export instrument swap<C>(between: list<party>, amounts: block, fees: block, rel
240
237
  }];
241
238
  }
242
239
  action dispute {
243
- agent_description: "Claw back a released trade inside its dispute window. Both cross-payment reservations void and both principals return from escrow in one batch. The trade must be released and the clawback moment must not have passed. Either trading party may call it.";
240
+ agent_description: "Claw back a released trade inside its dispute window. Both cross-payment reservations void and both principals return from escrow in one batch. The trade must be released and the clawback moment must not have passed. The dispute port's declared parties may call it.";
244
241
  summary: "Void both reservations, then refund both principals atomically";
245
242
  public_action: concat("dispute", title(camel(instrument)));
246
243
  deadline {
247
244
  field: clawbackAt;
248
245
  }
249
- port {
250
- allowedParties: [payer, beneficiary];
246
+ when(dispute_fields) {
247
+ input {
248
+ type: object;
249
+ additional_properties: false;
250
+ properties {
251
+ for input_name in keys(dispute_fields) {
252
+ [input_name]: get(dispute_fields, input_name);
253
+ }
254
+ }
255
+ required: keys(dispute_fields);
256
+ }
257
+ capture_input: {
258
+ for item in keys(dispute_fields) { [item]: item; }
259
+ };
251
260
  }
261
+ port { allowedParties: dispute_allowed; }
252
262
  moves: [{
253
263
  bind {
254
264
  reason {
@@ -370,6 +380,7 @@ export instrument swap<C>(between: list<party>, amounts: block, fees: block, rel
370
380
  agent_description: "Fund both sides at once. Each side pays its principal into escrow and its service fee to the platform account, four transfers in one batch. The trade must be created and unfunded. This moves real money from both parties.";
371
381
  summary: "Fund both trade sides and collect on-top fees atomically";
372
382
  public_action: concat("fund", title(camel(instrument)));
383
+ sandbox_failure_point: "funding";
373
384
  moves: [{
374
385
  amount: concat(side_a_amount);
375
386
  from: side_a;
@@ -420,12 +431,13 @@ export instrument swap<C>(between: list<party>, amounts: block, fees: block, rel
420
431
  steps: [];
421
432
  }
422
433
  action release {
423
- agent_description: "Reserve each side's principal for the other side and start the dispute window. The trade must be funded. Money is reserved, not settled. It posts on its own when the window matures, and dispute unwinds it before then. Either trading party may call it.";
434
+ agent_description: "Reserve each side's principal for the other side and start the dispute window. The trade must be funded. Money is reserved, not settled. It posts on its own when the window matures, and dispute unwinds it before then. The release port's declared parties may call it.";
424
435
  summary: "Reserve both cross-payments for the whole-trade clawback window";
425
436
  public_action: concat("release", title(camel(instrument)));
426
437
  port {
427
- allowedParties: [payer, beneficiary];
438
+ allowedParties: release_allowed;
428
439
  }
440
+ sandbox_failure_point: "release";
429
441
  sets_at {
430
442
  field: clawbackAt;
431
443
  offset: dispute_within;
@@ -753,12 +765,12 @@ export instrument swap<C>(between: list<party>, amounts: block, fees: block, rel
753
765
  steps: [];
754
766
  }
755
767
  action release {
756
- agent_description: "Reserve each side's principal for the other side and start the dispute window. The trade must be funded. Money is reserved, not settled. It posts on its own when the window matures, and dispute unwinds it before then. Either trading party may call it.";
768
+ agent_description: "Reserve each side's principal for the other side and start the dispute window. The trade must be funded. Money is reserved, not settled. It posts on its own when the window matures, and dispute unwinds it before then. The release port's declared parties may call it.";
757
769
  summary: "Reserve both cross-payments for the whole-trade clawback window";
758
770
  public_action: concat("release", title(camel(instrument)));
759
771
  event_name: concat(event_prefix, ".released");
760
772
  port {
761
- allowedParties: [payer, beneficiary];
773
+ allowedParties: release_allowed;
762
774
  }
763
775
  sandbox_failure_point: "release";
764
776
  sets_at {
@@ -884,16 +896,29 @@ export instrument swap<C>(between: list<party>, amounts: block, fees: block, rel
884
896
  steps: [];
885
897
  }
886
898
  action dispute {
887
- agent_description: "Claw back a released trade inside its dispute window. Both cross-payment reservations void and both principals return from escrow in one batch. The trade must be released and the clawback moment must not have passed. Either trading party may call it.";
899
+ agent_description: "Claw back a released trade inside its dispute window. Both cross-payment reservations void and both principals return from escrow in one batch. The trade must be released and the clawback moment must not have passed. The dispute port's declared parties may call it.";
888
900
  summary: "Void both reservations, then refund both principals atomically";
889
901
  public_action: concat("dispute", title(camel(instrument)));
890
902
  event_name: concat(event_prefix, ".clawed_back");
891
903
  deadline {
892
904
  field: clawbackAt;
893
905
  }
894
- port {
895
- allowedParties: [payer, beneficiary];
906
+ when(dispute_fields) {
907
+ input {
908
+ type: object;
909
+ additional_properties: false;
910
+ properties {
911
+ for input_name in keys(dispute_fields) {
912
+ [input_name]: get(dispute_fields, input_name);
913
+ }
914
+ }
915
+ required: keys(dispute_fields);
916
+ }
917
+ capture_input: {
918
+ for item in keys(dispute_fields) { [item]: item; }
919
+ };
896
920
  }
921
+ port { allowedParties: dispute_allowed; }
897
922
  moves: [{
898
923
  bind {
899
924
  reason {
@@ -1,4 +1,4 @@
1
- module std.settlements.threshold_pool
1
+ module std.money_flows.threshold_pool
2
2
 
3
3
  export instrument threshold_pool<C>(
4
4
  contributor: optional<party>,
@@ -29,7 +29,7 @@ export instrument threshold_pool<C>(
29
29
  agent_description: "Reach for threshold pool when many contributors commit toward one target and nothing is collected unless the pool reaches it by the close date. Commitments sit in escrow until the pool activates or fails. Pick weighted distribution to pay a pool out and instant transfer for a single payment.";
30
30
  when_not(contribution_instrument) {
31
31
  fields {
32
- [beneficiary]AccountId { type: account<C>; description: concat("The ", words(beneficiary), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
32
+ [beneficiary]AccountId { type: account<C>; description: concat("The ", words(beneficiary), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
33
33
  close_by { type: date; description: "Stored close anchor"; }
34
34
  currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
35
35
  maxContributors { type: integer; description: concat("Exactly ", max_contributors, " admitted contributors"); const: max_contributors; }
@@ -90,9 +90,9 @@ export instrument threshold_pool<C>(
90
90
  generatedPrefix: true;
91
91
  fields {
92
92
  amount { type: money<C>; description: "One whole commitment amount"; }
93
- [beneficiary]AccountId { type: account<C>; description: concat("The ", words(beneficiary), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
93
+ [beneficiary]AccountId { type: account<C>; description: concat("The ", words(beneficiary), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
94
94
  [parent_name]Id { type: ref<parent_name>; description: concat("The exact ", parent_name); pattern: concat("^", prefix(parent_name), "_(sandbox|live)_[a-z0-9]{8,64}$"); }
95
- [contributor]AccountId { type: account<C>; description: concat("The ", words(contributor), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
95
+ [contributor]AccountId { type: account<C>; description: concat("The ", words(contributor), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
96
96
  currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
97
97
  }
98
98
  lifecycle {
@@ -168,7 +168,7 @@ export instrument threshold_pool<C>(
168
168
  let(close_field): camel(close_by);
169
169
 
170
170
  fields {
171
- [beneficiary_account_field] { type: account<C>; description: beneficiary_account_description; pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
171
+ [beneficiary_account_field] { type: account<C>; description: beneficiary_account_description; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
172
172
  [close_field] { type: date; }
173
173
  currency { type: text; description: currency_description; maxLength: 3; minLength: 3; pattern: "^[A-Z]{3}$"; }
174
174
  when(memo) { [memo] { type: text; optional: true; maxLength: 180; minLength: 1; } }
@@ -1,4 +1,4 @@
1
- module std.settlements.weighted_distribution
1
+ module std.money_flows.weighted_distribution
2
2
 
3
3
  export instrument weighted_distribution<C>(
4
4
  source: party,
@@ -18,7 +18,7 @@ export instrument weighted_distribution<C>(
18
18
  fields {
19
19
  currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
20
20
  amount { type: money<C>; description: "Distribution pool in {C} minor units"; }
21
- [source]AccountId { type: account<C>; description: concat("The ", words(source), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
21
+ [source]AccountId { type: account<C>; description: concat("The ", words(source), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
22
22
  maxRecipients { type: integer; description: concat("Exactly ", max_recipients, " frozen entitlement rows"); const: max_recipients; }
23
23
  record_at { type: date; description: "Stored record date"; }
24
24
  }
@@ -48,10 +48,10 @@ export instrument weighted_distribution<C>(
48
48
  generatedPrefix: true;
49
49
  fields {
50
50
  currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
51
- [source]AccountId { type: account<C>; description: concat("The ", words(source), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
51
+ [source]AccountId { type: account<C>; description: concat("The ", words(source), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
52
52
  [weight] { type: money<C>; description: "Stored non-negative entitlement weight"; }
53
53
  [parent_name]Id { type: ref<parent_name>; description: concat("The exact ", parent_name); pattern: concat("^", prefix(parent_name), "_(sandbox|live)_[a-z0-9]{8,64}$"); }
54
- [recipient]AccountId { type: account<C>; description: concat("The ", words(recipient), " account"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
54
+ [recipient]AccountId { type: account<C>; description: concat("The ", words(recipient), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
55
55
  }
56
56
  lifecycle { states recorded paid; initial recorded; on payout: recorded -> paid; }
57
57
  parties { beneficiary: concat(camel(recipient), "AccountId"); payer: concat(camel(source), "AccountId"); }
@@ -106,8 +106,8 @@ export instrument weighted_distribution<C>(
106
106
  currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
107
107
  [weight_ref] { type: weight_ref; description: get(weight_source, "description"); pattern: get(weight_source, "pattern"); }
108
108
  [group_ref] { type: group_ref; description: get(group, "description"); pattern: get(group, "pattern"); }
109
- [recipient]AccountId { type: account<C>; description: get(flat, "recipient_account_description"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
110
- [source]AccountId { type: account<C>; description: get(flat, "source_account_description"); pattern: "^acct_(sandbox|live)_[a-z0-9]{8,64}$"; "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
109
+ [recipient]AccountId { type: account<C>; description: get(flat, "recipient_account_description"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
110
+ [source]AccountId { type: account<C>; description: get(flat, "source_account_description"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
111
111
  }
112
112
  lifecycle { states claimed paid; initial claimed; on payout: claimed -> paid; }
113
113
  parties { beneficiary: recipient_account_field; }
@@ -1,21 +0,0 @@
1
- program juniper_forge_contract "Juniper Forge contract"
2
- import { instant_transfer, scheduled } from "std/settlements"
3
-
4
- party samira_nassar: person
5
- party juniper_forge_interiors: business
6
-
7
- settlement concept_fee = instant_transfer {
8
- payer: samira_nassar
9
- payee: juniper_forge_interiors
10
- amount: conceptFee: money(SAR)
11
- fees { samira_nassar: 1% }
12
- }
13
-
14
- settlement build_installments = scheduled {
15
- payer: samira_nassar
16
- payee: juniper_forge_interiors
17
- amount: buildPrice: money(SAR)
18
- count: 3
19
- every: P30D
20
- first_due: firstBuildPaymentAt
21
- }
@@ -1,41 +0,0 @@
1
- # Two-instrument reading session, 2026-09-02
2
-
3
- The reader worked only inside the HSX public export. It read the README, skill,
4
- guide, grammar, types, and generated standard-library pages.
5
-
6
- ## First run
7
-
8
- Attempts: 3. Result: environment refusal before language checking.
9
-
10
- ```text
11
- $ hsx check reading-test.hsx
12
- zsh: command not found: hsx
13
- exit 127
14
-
15
- $ npm exec --offline --package=. -- hsx check reading-test.hsx
16
- sh: hsx: command not found
17
- exit 127
18
-
19
- $ bun run src/cli.ts check reading-test.hsx
20
- SyntaxError: Export named 'udlEffectKinds' not found in the cached UDL beta package
21
- exit 1
22
- ```
23
-
24
- The public docs did not distinguish the installed command from the source
25
- checkout command. The provisional pre-publication clone also resolved an old
26
- UDL package. The README and first-program guide now name the exact checkout
27
- command. The rerun used the local UDL rc.1 package already proved by the
28
- exporter.
29
-
30
- ## Rerun after the docs repair
31
-
32
- Attempts: 1. Result: accepted with no diagnostics.
33
-
34
- ```text
35
- $ bun run bin/hsx.ts check reading-test.hsx
36
- [no diagnostics]
37
- exit 0
38
- ```
39
-
40
- The accepted program is in
41
- [`2026-09-02-two-instruments.hsx`](./2026-09-02-two-instruments.hsx).