@hyperscale0/hsx 2.4.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/CHANGELOG.md +2 -408
  2. package/README.md +3 -92
  3. package/dist/src/ast.d.ts +99 -310
  4. package/dist/src/ast.d.ts.map +1 -1
  5. package/dist/src/ast.js +16 -69
  6. package/dist/src/ast.js.map +1 -1
  7. package/dist/src/cli.d.ts +6 -19
  8. package/dist/src/cli.d.ts.map +1 -1
  9. package/dist/src/cli.js +76 -315
  10. package/dist/src/cli.js.map +1 -1
  11. package/dist/src/compile.d.ts +23 -73
  12. package/dist/src/compile.d.ts.map +1 -1
  13. package/dist/src/compile.js +1113 -148
  14. package/dist/src/compile.js.map +1 -1
  15. package/dist/src/cost.d.ts +8 -77
  16. package/dist/src/cost.d.ts.map +1 -1
  17. package/dist/src/cost.js +13 -422
  18. package/dist/src/cost.js.map +1 -1
  19. package/dist/src/format.d.ts +8 -7
  20. package/dist/src/format.d.ts.map +1 -1
  21. package/dist/src/format.js +9 -175
  22. package/dist/src/format.js.map +1 -1
  23. package/dist/src/headers.d.ts +35 -0
  24. package/dist/src/headers.d.ts.map +1 -0
  25. package/dist/src/headers.js +108 -0
  26. package/dist/src/headers.js.map +1 -0
  27. package/dist/src/index.d.ts +6 -12
  28. package/dist/src/index.d.ts.map +1 -1
  29. package/dist/src/index.js +4 -9
  30. package/dist/src/index.js.map +1 -1
  31. package/dist/src/lex.d.ts +8 -28
  32. package/dist/src/lex.d.ts.map +1 -1
  33. package/dist/src/lex.js +88 -146
  34. package/dist/src/lex.js.map +1 -1
  35. package/dist/src/parse.d.ts +4 -17
  36. package/dist/src/parse.d.ts.map +1 -1
  37. package/dist/src/parse.js +402 -1040
  38. package/dist/src/parse.js.map +1 -1
  39. package/dist/src/std-bundle.d.ts.map +1 -1
  40. package/dist/src/std-bundle.js +12 -20
  41. package/dist/src/std-bundle.js.map +1 -1
  42. package/dist/src/std-library.d.ts +1 -1
  43. package/dist/src/std-library.d.ts.map +1 -1
  44. package/dist/src/std-library.js +1 -5
  45. package/dist/src/std-library.js.map +1 -1
  46. package/dist/src/tunables.d.ts +7 -0
  47. package/dist/src/tunables.d.ts.map +1 -0
  48. package/dist/src/tunables.js +26 -0
  49. package/dist/src/tunables.js.map +1 -0
  50. package/dist/src/version.d.ts +2 -4
  51. package/dist/src/version.d.ts.map +1 -1
  52. package/dist/src/version.js +2 -4
  53. package/dist/src/version.js.map +1 -1
  54. package/docs/README.md +179 -41
  55. package/docs/headers.md +44 -0
  56. package/examples/cost-table.json +99 -751
  57. package/examples/library.hsx +59 -0
  58. package/package.json +9 -17
  59. package/src/ast.ts +82 -441
  60. package/src/cli.ts +77 -362
  61. package/src/compile.ts +1535 -247
  62. package/src/cost.ts +28 -671
  63. package/src/format.ts +12 -256
  64. package/src/headers.ts +126 -0
  65. package/src/index.ts +7 -39
  66. package/src/lex.ts +99 -195
  67. package/src/parse.ts +403 -1209
  68. package/src/std-bundle.ts +12 -20
  69. package/src/std-library.ts +2 -7
  70. package/src/tunables.ts +31 -0
  71. package/src/version.ts +2 -5
  72. package/std/approvals.hsx +17 -0
  73. package/std/cards.hsx +63 -0
  74. package/std/collections.hsx +31 -0
  75. package/std/escrow.hsx +43 -0
  76. package/std/financing.hsx +372 -0
  77. package/std/insurance.hsx +59 -0
  78. package/std/lending.hsx +115 -0
  79. package/std/marketplace.hsx +24 -0
  80. package/std/money.hsx +195 -0
  81. package/std/savings.hsx +44 -0
  82. package/std/travel.hsx +98 -0
  83. package/std/wallet.hsx +41 -0
  84. package/dist/src/diagnostics.d.ts +0 -13
  85. package/dist/src/diagnostics.d.ts.map +0 -1
  86. package/dist/src/diagnostics.js +0 -587
  87. package/dist/src/diagnostics.js.map +0 -1
  88. package/dist/src/emit.d.ts +0 -51
  89. package/dist/src/emit.d.ts.map +0 -1
  90. package/dist/src/emit.js +0 -192
  91. package/dist/src/emit.js.map +0 -1
  92. package/dist/src/entry-overrides.d.ts +0 -58
  93. package/dist/src/entry-overrides.d.ts.map +0 -1
  94. package/dist/src/entry-overrides.js +0 -284
  95. package/dist/src/entry-overrides.js.map +0 -1
  96. package/dist/src/ir.d.ts +0 -73
  97. package/dist/src/ir.d.ts.map +0 -1
  98. package/dist/src/ir.js +0 -15
  99. package/dist/src/ir.js.map +0 -1
  100. package/dist/src/limits.d.ts +0 -23
  101. package/dist/src/limits.d.ts.map +0 -1
  102. package/dist/src/limits.js +0 -23
  103. package/dist/src/limits.js.map +0 -1
  104. package/dist/src/lsp/server.d.ts +0 -32
  105. package/dist/src/lsp/server.d.ts.map +0 -1
  106. package/dist/src/lsp/server.js +0 -391
  107. package/dist/src/lsp/server.js.map +0 -1
  108. package/dist/src/modules.d.ts +0 -38
  109. package/dist/src/modules.d.ts.map +0 -1
  110. package/dist/src/modules.js +0 -372
  111. package/dist/src/modules.js.map +0 -1
  112. package/dist/src/typecheck.d.ts +0 -8
  113. package/dist/src/typecheck.d.ts.map +0 -1
  114. package/dist/src/typecheck.js +0 -4160
  115. package/dist/src/typecheck.js.map +0 -1
  116. package/docs/guide/01-first-program.md +0 -24
  117. package/docs/guide/02-money.md +0 -25
  118. package/docs/guide/03-instruments.md +0 -93
  119. package/docs/guide/04-lifecycles.md +0 -40
  120. package/docs/guide/05-fees-and-splits.md +0 -45
  121. package/docs/guide/06-schedules.md +0 -26
  122. package/docs/guide/07-composition.md +0 -52
  123. package/docs/guide/08-writing-a-module.md +0 -85
  124. package/docs/guide/09-cost.md +0 -24
  125. package/docs/guide/10-diagnostics.md +0 -27
  126. package/docs/llms-full.txt +0 -3684
  127. package/docs/llms.txt +0 -44
  128. package/docs/piece-plans.md +0 -120
  129. package/docs/playground.md +0 -55
  130. package/docs/reference/cli.md +0 -36
  131. package/docs/reference/diagnostics.md +0 -901
  132. package/docs/reference/grammar.md +0 -38
  133. package/docs/reference/std/advance.md +0 -112
  134. package/docs/reference/std/cancellable_booking.md +0 -159
  135. package/docs/reference/std/captured_payment.md +0 -115
  136. package/docs/reference/std/conditional_disbursement.md +0 -101
  137. package/docs/reference/std/credit_facility.md +0 -108
  138. package/docs/reference/std/held_payment.md +0 -173
  139. package/docs/reference/std/instant_transfer.md +0 -97
  140. package/docs/reference/std/metered.md +0 -89
  141. package/docs/reference/std/pooled_split.md +0 -95
  142. package/docs/reference/std/premium_forward.md +0 -119
  143. package/docs/reference/std/reconciled_payout.md +0 -103
  144. package/docs/reference/std/rotating_pool.md +0 -130
  145. package/docs/reference/std/scheduled.md +0 -136
  146. package/docs/reference/std/security_deposit.md +0 -138
  147. package/docs/reference/std/settlement_batch.md +0 -123
  148. package/docs/reference/std/swap.md +0 -133
  149. package/docs/reference/std/threshold_pool.md +0 -138
  150. package/docs/reference/std/weighted_distribution.md +0 -135
  151. package/docs/reference/types.md +0 -61
  152. package/docs/reference/udl-output.md +0 -13
  153. package/examples/01-first-program/README.md +0 -45
  154. package/examples/01-first-program/tip-jar.hsx +0 -17
  155. package/examples/02-imports-and-modules/README.md +0 -96
  156. package/examples/02-imports-and-modules/photo-booth.hsx +0 -37
  157. package/examples/03-diagnostics/README.md +0 -68
  158. package/examples/03-diagnostics/corner-shop-fixed.hsx +0 -22
  159. package/examples/03-diagnostics/corner-shop.hsx +0 -19
  160. package/examples/04-complete-product/README.md +0 -84
  161. package/examples/04-complete-product/study-hall.hsx +0 -67
  162. package/examples/05-authored-instrument/README.md +0 -5
  163. package/examples/05-authored-instrument/payment.hsx +0 -37
  164. package/examples/05-watch-club/README.md +0 -6
  165. package/examples/05-watch-club/watch-club.hsx +0 -123
  166. package/examples/README.md +0 -48
  167. package/examples/advance/README.md +0 -3
  168. package/examples/advance/advance.hsx +0 -13
  169. package/examples/advance/advance.udl +0 -367
  170. package/examples/cancellable_booking/README.md +0 -3
  171. package/examples/cancellable_booking/cancellable_booking.hsx +0 -14
  172. package/examples/cancellable_booking/cancellable_booking.udl +0 -413
  173. package/examples/captured_payment/README.md +0 -3
  174. package/examples/captured_payment/captured_payment.hsx +0 -17
  175. package/examples/captured_payment/captured_payment.udl +0 -686
  176. package/examples/conditional_disbursement/README.md +0 -3
  177. package/examples/conditional_disbursement/conditional_disbursement.hsx +0 -15
  178. package/examples/conditional_disbursement/conditional_disbursement.udl +0 -418
  179. package/examples/credit_facility/README.md +0 -3
  180. package/examples/credit_facility/credit_facility.hsx +0 -24
  181. package/examples/credit_facility/credit_facility.udl +0 -1396
  182. package/examples/held_payment/README.md +0 -3
  183. package/examples/held_payment/held_payment.hsx +0 -13
  184. package/examples/held_payment/held_payment.udl +0 -569
  185. package/examples/instant_transfer/README.md +0 -3
  186. package/examples/instant_transfer/instant_transfer.hsx +0 -16
  187. package/examples/instant_transfer/instant_transfer.udl +0 -376
  188. package/examples/metered/README.md +0 -3
  189. package/examples/metered/metered.hsx +0 -13
  190. package/examples/metered/metered.udl +0 -253
  191. package/examples/pooled_split/README.md +0 -3
  192. package/examples/pooled_split/pooled_split.hsx +0 -15
  193. package/examples/pooled_split/pooled_split.udl +0 -432
  194. package/examples/premium_forward/README.md +0 -3
  195. package/examples/premium_forward/premium_forward.hsx +0 -19
  196. package/examples/premium_forward/premium_forward.udl +0 -604
  197. package/examples/reconciled_payout/README.md +0 -3
  198. package/examples/reconciled_payout/reconciled_payout.hsx +0 -13
  199. package/examples/reconciled_payout/reconciled_payout.udl +0 -312
  200. package/examples/rotating_pool/README.md +0 -3
  201. package/examples/rotating_pool/rotating_pool.hsx +0 -18
  202. package/examples/rotating_pool/rotating_pool.udl +0 -4370
  203. package/examples/scheduled/README.md +0 -3
  204. package/examples/scheduled/scheduled.hsx +0 -12
  205. package/examples/scheduled/scheduled.udl +0 -355
  206. package/examples/security_deposit/README.md +0 -3
  207. package/examples/security_deposit/security_deposit.hsx +0 -21
  208. package/examples/security_deposit/security_deposit.udl +0 -320
  209. package/examples/settlement_batch/README.md +0 -3
  210. package/examples/settlement_batch/settlement_batch.hsx +0 -19
  211. package/examples/settlement_batch/settlement_batch.udl +0 -757
  212. package/examples/swap/README.md +0 -3
  213. package/examples/swap/swap.hsx +0 -19
  214. package/examples/swap/swap.udl +0 -892
  215. package/examples/threshold_pool/README.md +0 -3
  216. package/examples/threshold_pool/threshold_pool.hsx +0 -16
  217. package/examples/threshold_pool/threshold_pool.udl +0 -680
  218. package/examples/weighted_distribution/README.md +0 -3
  219. package/examples/weighted_distribution/weighted_distribution.hsx +0 -20
  220. package/examples/weighted_distribution/weighted_distribution.udl +0 -348
  221. package/skills/hsx/SKILL.md +0 -449
  222. package/src/diagnostics.ts +0 -620
  223. package/src/emit.ts +0 -282
  224. package/src/entry-overrides.ts +0 -428
  225. package/src/ir.ts +0 -113
  226. package/src/limits.ts +0 -22
  227. package/src/lsp/server.ts +0 -460
  228. package/src/modules.ts +0 -452
  229. package/src/typecheck.ts +0 -5515
  230. package/std/SEMANTICS.md +0 -44
  231. package/std/money_flows/advance.hsx +0 -235
  232. package/std/money_flows/cancellable_booking.hsx +0 -402
  233. package/std/money_flows/captured_payment.hsx +0 -220
  234. package/std/money_flows/conditional_disbursement.hsx +0 -226
  235. package/std/money_flows/credit_facility.hsx +0 -214
  236. package/std/money_flows/held_payment.hsx +0 -812
  237. package/std/money_flows/index.hsx +0 -4
  238. package/std/money_flows/instant_transfer.hsx +0 -231
  239. package/std/money_flows/metered.hsx +0 -104
  240. package/std/money_flows/pooled_split.hsx +0 -109
  241. package/std/money_flows/premium_forward.hsx +0 -307
  242. package/std/money_flows/reconciled_payout.hsx +0 -119
  243. package/std/money_flows/rotating_pool.hsx +0 -305
  244. package/std/money_flows/scheduled.hsx +0 -599
  245. package/std/money_flows/security_deposit.hsx +0 -248
  246. package/std/money_flows/settlement_batch.hsx +0 -173
  247. package/std/money_flows/swap.hsx +0 -1192
  248. package/std/money_flows/threshold_pool.hsx +0 -307
  249. package/std/money_flows/weighted_distribution.hsx +0 -237
@@ -1,248 +0,0 @@
1
- module std.money_flows.security_deposit
2
-
3
- // Collateral deposit reserved against a payer's account in favor of a holder, returned in full or claimed against damages.
4
- //
5
- // ### Purpose
6
- // `security_deposit` reserves collateral funds for vehicle rentals, property leasing, equipment hire, and security bonds.
7
- // Funds remain held until the rental or lease concludes. The holder can either return the deposit in full
8
- // or assess damages, claim a decided partial amount, and return the exact unspent remainder.
9
- //
10
- // ### Selection guidance
11
- // - vs `held_payment`: `security_deposit` holds collateral where the standard outcome is returning 100% of the funds
12
- // to the payer, and claims are partial damage assessments. `held_payment` holds payment consideration where the
13
- // standard outcome is releasing 100% of the funds to the payee upon delivery.
14
- // - vs `cancellable_booking`: `cancellable_booking` holds booking fees and applies time-based cancellation penalties.
15
- // `security_deposit` holds damage collateral and supports arbitrary damage claims with remainder refund.
16
- //
17
- // ### Parameters
18
- // - `payer`: The customer providing the deposit collateral.
19
- // - `holder`: The merchant or owner holding the deposit rights.
20
- // - `amount`: Total reserved deposit amount in minor units of currency `C`.
21
- // - `claim`: Optional condition port triggering a damage claim.
22
- // - `return`: Optional condition port triggering full return of the deposit.
23
- // - `claim_amount`: Optional block defining partial claim logic (`field`, `bound`, `remainder`).
24
- // - `deadline`: Optional stored date anchor for automatic deposit release or expiry.
25
- // - `claim_to`: Optional alternate destination for claimed funds.
26
- // - `return_to`: Optional alternate destination for returned funds.
27
- // - `memo`: Optional memo text stored on the deposit record.
28
- // - `claim_input`: Optional custom input schema for the claim action.
29
- // - `claim_capture`: Optional capture mappings for claim evidence.
30
- // - `fund_failure_point`: Optional configuration for deposit funding failure.
31
- // - `id_prefix_override`: Optional custom prefix for generated instrument IDs.
32
- //
33
- // ### Decision ports
34
- // - `claim`: Port permitting the holder to submit a damage claim.
35
- // - `return`: Port permitting the holder to return the deposit to the payer.
36
- //
37
- // ### Example
38
- // ```hsx
39
- // program deposit_example "Deposit example"
40
- // import { security_deposit } from "std/money_flows"
41
- // party renter: person
42
- // party owner: business
43
- // settlement security_deposit = security_deposit {
44
- // payer: renter
45
- // holder: owner
46
- // amount: depositAmount: money(SAR)
47
- // claim: port assess_damage
48
- // claim_amount: decided {
49
- // field: damageAmount
50
- // bound: depositAmount
51
- // remainder: return
52
- // }
53
- // return: port return_deposit
54
- // }
55
- // port assess_damage {
56
- // allowed: [owner]
57
- // shape: { damageAmount: money(SAR), evidence: text }
58
- // }
59
- // port return_deposit { allowed: [owner] }
60
- // ```
61
- 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>) {
62
- let(claim_name): claim;
63
- let(return_name): return;
64
- let(payer_account_field): camel(concat(payer, "_account_id"));
65
- let(holder_account_field): camel(concat(holder, "_account_id"));
66
- let(claim_field): get(claim_amount, "field");
67
- let(claim_bound): get(claim_amount, "bound");
68
- let(claim_remainder): get(claim_amount, "remainder");
69
- let(deadline_field): concat(deadline);
70
- let(memo_field): concat(memo);
71
- 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.";
72
- summary: "Refundable deposit from {payer} held for {holder}";
73
- title: sentence(instrument);
74
- when(id_prefix_override) { id_prefix: id_prefix_override; }
75
- when_not(deadline) {
76
- when_not(claim_amount) {
77
- description: concat("Deposit: the ", amount, " is reserved against the ", payer, "'s account in the ", holder, "'s favor, then claimed or returned in full");
78
- }
79
- when(claim_amount) {
80
- description: concat("Deposit: the ", amount, " is reserved against the ", payer, "'s account in the ", holder, "'s favor, then ", claim_field, " is claimed and the exact remainder returned, or the deposit is returned in full");
81
- }
82
- }
83
- fields {
84
- when_not(deadline) {
85
- amount { type: money<C>; description: "The deposit amount in {C} minor units, reserved in full and fully accounted on claim or return"; }
86
- }
87
- when(deadline) {
88
- let(reference_filter_key): "x-hyperscale-reference-filter";
89
- amount { type: money<C>; description: "Positive minor-unit integer amount serialized as a string (at most 18 digits)"; }
90
- [deadline_field] { type: date; }
91
- [holder_account_field] { type: account<C>; description: "Hyperscale account ID"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }
92
- [payer_account_field] { type: account<C>; description: "Hyperscale account ID"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }
93
- when(memo) { [memo_field] { type: text; max_length: 180; min_length: 1; optional: true; } }
94
- }
95
- }
96
- lifecycle {
97
- when_not(deadline) {
98
- states created held claimed returned;
99
- initial created;
100
- on place_deposit: created -> held;
101
- on [claim_name]: held -> claimed;
102
- on [return_name]: held -> returned;
103
- }
104
- when(deadline) {
105
- states created held claimed returned expired canceled;
106
- initial created;
107
- on cancel: created -> canceled;
108
- on claim: held -> claimed;
109
- on expire: held -> expired;
110
- on fund: created -> held;
111
- on return: held -> returned;
112
- }
113
- }
114
- parties {
115
- payer: payer;
116
- beneficiary: holder;
117
- }
118
- when_not(deadline) {
119
- action create {
120
- agent_description: "Open the deposit row before anything is reserved. The caller supplies the {amount}, the currency, and the {payer} and {holder} accounts. Nothing is reserved yet, call place deposit next.";
121
- summary: concat("Create a ", words(instrument));
122
- moves: [];
123
- steps: [];
124
- }
125
- action place_deposit {
126
- agent_description: "Reserve the {amount} against the {payer}'s account in the {holder}'s favor. The deposit must be created. The money is held, not paid: the claim posts it to the {holder} and the return releases it back.";
127
- let(metadata_instrument): "metadata.instrumentId";
128
- let(metadata_instance): "metadata.instrumentInstanceId";
129
- let(metadata_phase): "metadata.phase";
130
- summary: "Reserve the {amount} against the {payer}'s account";
131
- 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; }; }];
132
- sandbox_failure_point: funding;
133
- steps: [];
134
- }
135
- action [claim_name] {
136
- 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.";
137
- summary: "Claim the deposit for the {holder} through {claim}";
138
- when(claim_allowed) { port { allowed_parties: claim_allowed; }; }
139
- when_not(claim_amount) {
140
- moves: [{ key: post; operation: internal_transfer.post; bind: { transferId: { from: instance; path: refs.placeDepositReservationTransferId; }; }; }];
141
- }
142
- when(claim_amount) {
143
- let(decided_clause): "decided amount";
144
- input {
145
- type: object;
146
- additional_properties: false;
147
- properties {
148
- for input_name in keys(claim_fields) {
149
- [input_name]: get(claim_fields, input_name);
150
- }
151
- }
152
- required: keys(claim_fields);
153
- }
154
- [decided_clause]: { field: claim_field; bound_field: claim_bound; remainder_action: return_name; };
155
- 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; }; }; }];
156
- }
157
- steps: [];
158
- }
159
- action [return_name] {
160
- 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.";
161
- summary: "Return the deposit to the {payer} through {return}";
162
- when(return_fields) {
163
- input {
164
- type: object;
165
- additional_properties: false;
166
- properties {
167
- for input_name in keys(return_fields) {
168
- [input_name]: get(return_fields, input_name);
169
- }
170
- }
171
- required: keys(return_fields);
172
- }
173
- capture_input: {
174
- for item in keys(return_fields) { [item]: item; }
175
- };
176
- }
177
- port { allowed_parties: return_allowed; };
178
- moves: [{ key: void; operation: internal_transfer.void; bind: { reason: { from: const; value: "Deposit returned in full"; }; transferId: { from: instance; path: refs.placeDepositReservationTransferId; }; }; }];
179
- steps: [];
180
- }
181
- }
182
- when(deadline) {
183
- required: [payer_account_field, holder_account_field, amount, currency, deadline_field];
184
- caller_parked_states: { created: "funding or canceling an unfunded hold is the payer's decision"; };
185
- distinct_parties: true;
186
- dials: [{ field: deadline_field; key: holding_window; kind: window; maxOffset: "P90D"; summary: "Maximum time before the machine returns an unclaimed hold."; title: "Holding window"; }];
187
- action create {
188
- agent_description: "Open the hold by recording the {payer}, the {holder}, the {amount}, and the deadline. No money moves here, so a created hold costs the {payer} nothing until fund runs. The deadline is when the machine returns anything still unclaimed.";
189
- deadline: { field: deadline_field; };
190
- summary: concat("Create a ", words(instrument));
191
- moves: [];
192
- steps: [];
193
- }
194
- action fund {
195
- agent_description: "Reserve the whole {amount} out of the {payer}'s balance for the {holder}. This moves money and the {payer} can no longer spend it. Only a created hold funds. The reservation carries no expiry of its own, so the hold's deadline governs when it comes back.";
196
- deadline: { field: deadline_field; };
197
- 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; }; }];
198
- when(fund_failure_point) { sandbox_failure_point: fund_failure_point; }
199
- when_not(fund_failure_point) { sandbox_failure_point: funding; }
200
- steps: [];
201
- summary: "Fund the security deposit";
202
- }
203
- action claim {
204
- when_not(claim_amount) {
205
- agent_description: "Post the whole reservation to the {holder}. This moves money and does not reverse. Only a funded hold claims.";
206
- moves: [{ key: "claim"; operation: internal_transfer.post; bind: { transferId: { from: instance; path: refs.holdTransferId; }; }; }];
207
- }
208
- deadline: { field: deadline_field; };
209
- when(claim_capture) { capture_input: claim_capture; }
210
- when(claim_amount) {
211
- 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}.";
212
- decided_amount: { field: claim_field; bound_field: claim_bound; remainder_action: claim_remainder; };
213
- sandbox_failure_point: "release";
214
- 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; }; }; }];
215
- }
216
- when(claim_input) { input: claim_input; }
217
- when(claim_allowed) { port { allowed_parties: claim_allowed; }; }
218
- when_not(claim_allowed) {
219
- when(claim_to) { port { allowed_parties: [claim_to]; }; }
220
- }
221
- steps: [];
222
- summary: "Claim the security deposit";
223
- }
224
- action return {
225
- 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.";
226
- deadline: { field: deadline_field; };
227
- when(return_allowed) { port { allowed_parties: return_allowed; }; }
228
- when_not(return_allowed) {
229
- when(return_to) { port { allowed_parties: [return_to]; }; }
230
- }
231
- moves: [{ key: "return"; operation: internal_transfer.void; bind: { reason: { from: const; value: "Deposit returned in full"; }; transferId: { from: instance; path: refs.holdTransferId; }; }; }];
232
- steps: [];
233
- summary: "Return the security deposit";
234
- }
235
- action expire {
236
- due: { field: deadline_field; };
237
- moves: [{ key: expire; operation: internal_transfer.void; bind: { reason: { from: const; value: "Deposit hold expired"; }; transferId: { from: instance; path: refs.holdTransferId; }; }; }];
238
- steps: [];
239
- summary: "Expire the security deposit";
240
- }
241
- action cancel {
242
- agent_description: "Close a hold before anyone funds it. No money has moved, so this is a lifecycle transition only. Only a created hold cancels. A funded hold refuses, because its money is already reserved. Claim it or return it instead.";
243
- moves: [];
244
- steps: [];
245
- summary: "Cancel the security deposit";
246
- }
247
- }
248
- }
@@ -1,173 +0,0 @@
1
- module std.money_flows.settlement_batch
2
-
3
- // Periodic aggregation of capture lineage, fee entries, and adjustments into a single net calculated payout.
4
- //
5
- // ### Purpose
6
- // `settlement_batch` settles merchant balances, marketplace vendor earnings, and partner clearing accounts.
7
- // Individual payment captures, platform fees, and reversal adjustments accumulate into an open batch over a period.
8
- // On `close_trigger`, the batch freezes. The platform calculates the signed net payable from gross captures plus credit
9
- // adjustments minus debit adjustments. If positive, an outbound bank payout is instructed and acknowledged.
10
- //
11
- // ### Selection guidance
12
- // - vs `reconciled_payout`: `settlement_batch` aggregates multiple transactions and adjustments over a billing cycle
13
- // to compute a single net payable. `reconciled_payout` manages bank instruction dispatch and statement line reconciliation
14
- // for an individual payout amount.
15
- // - vs `weighted_distribution`: `settlement_batch` consolidates many inbound transactions into one net outbound payout.
16
- // `weighted_distribution` splits one funding pool into many recipient payouts.
17
- //
18
- // ### Parameters
19
- // - `settlement_account`: The source clearing account holding captured funds and paying the batch.
20
- // - `source_capture_refs`: Binding name for gross capture references included in the batch.
21
- // - `fee_entries`: Binding name for fee deductions applied to the batch.
22
- // - `external_reversal_offsets`: Binding name for reversal adjustments applied to the batch.
23
- // - `close_trigger`: Date when the batch closes and ceases accepting new transaction entries.
24
- // - `payout_destination`: The merchant or partner account receiving the net payout.
25
- // - `negative_position`: Policy when calculated net payable is zero or negative (`reject`).
26
- // - `payout_acknowledgement`: Condition port confirming bank receipt of the payout.
27
- // - `payout_beneficiary_ref`: Beneficiary identifier for external bank dispatch.
28
- //
29
- // ### Decision ports
30
- // - `payout_acknowledgement`: Port recording external bank or partner receipt confirmation.
31
- //
32
- // ### Example
33
- // ```hsx
34
- // program settlement_batch_example "Settlement batch example"
35
- // import { settlement_batch } from "std/money_flows"
36
- // party settlement_account: business
37
- // party payout_destination: business
38
- // settlement batch = settlement_batch {
39
- // settlement_account: settlement_account
40
- // source_capture_refs: captureReference
41
- // fee_entries: feeReference
42
- // external_reversal_offsets: reversalReference
43
- // close_trigger: closeAt
44
- // payout_destination: payout_destination
45
- // negative_position: reject
46
- // payout_acknowledgement: port acknowledge_payout
47
- // payout_beneficiary_ref: payoutBeneficiaryId
48
- // }
49
- // port acknowledge_payout {
50
- // allowed: [payout_destination]
51
- // shape: { acknowledgementReference: text }
52
- // }
53
- // ```
54
- export instrument settlement_batch<C>(
55
- settlement_account: party,
56
- source_capture_refs: text,
57
- fee_entries: text,
58
- external_reversal_offsets: text,
59
- close_trigger: date,
60
- payout_destination: party,
61
- negative_position: text,
62
- payout_acknowledgement: condition,
63
- payout_beneficiary_ref: text,
64
- ) {
65
- fields {
66
- close_trigger { type: date; description: "Date the open batch freezes against later entries"; }
67
- currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
68
- payout_beneficiary_ref { type: text; description: "Beneficiary ID for the payout instruction"; pattern: "^ben_(sandbox|live)_[a-z0-9]{8,64}$"; }
69
- [payout_destination]AccountId { type: account<C>; description: concat("The ", words(payout_destination), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
70
- [settlement_account]AccountId { type: account<C>; description: concat("The ", words(settlement_account), " account"); "x-hyperscale-reference-filter": { column: role; values: [customer_balance]; }; }
71
- }
72
- lifecycle {
73
- states open closed calculated approved instructed acknowledged reconciled;
74
- initial open;
75
- on close: open -> closed;
76
- on calculate: closed -> calculated;
77
- on approve: calculated -> approved;
78
- on instruct: approved -> instructed;
79
- on [payout_acknowledgement]: instructed -> acknowledged;
80
- on reconcile: instructed|acknowledged -> reconciled;
81
- }
82
- parties { beneficiary: concat(camel(payout_destination), "AccountId"); payer: concat(camel(settlement_account), "AccountId"); }
83
- required: [concat(camel(payout_destination), "AccountId"), concat(camel(settlement_account), "AccountId"), close_trigger, currency, payout_beneficiary_ref];
84
- title: sentence(instrument);
85
- id_prefix: prefix(instrument);
86
- agent_description: "Reach for settlement batch when many charges over a period roll up into one payout. Capture entries and adjustments accrue against an open batch, the batch freezes on its close date, calculate proves one signed net payable, and instruct sends a single external payout. Weighted distribution goes the other way, one amount out to many recipients.";
87
- summary: concat("Payout batch from ", words(settlement_account), " to ", words(payout_destination));
88
- description: "Immutable batch of capture lineage and signed adjustments that creates one payout";
89
- action create { agent_description: "Open a batch that capture entries and adjustments can accrue into. No money moves. The batch keeps taking entries until its close date freezes it."; summary: concat("Open a ", words(instrument)); moves: []; steps: []; }
90
- action close { summary: "Freeze the batch and stop all new entries"; due { field: close_trigger; } moves: []; steps: []; }
91
- action calculate {
92
- agent_description: "Prove and freeze the one net payable from gross captures plus credit adjustments minus debit adjustments. The batch must be closed first. A zero or negative net is refused, so a batch in deficit never reaches a payout. No money moves.";
93
- summary: "Prove and freeze the one signed net payable amount";
94
- computes signed_sum {
95
- amountRef: netPayable; onNegative: refuse; onZero: refuse;
96
- sources: [
97
- { amountField: amount; instrumentId: concat(instrument, "_capture_entry"); refField: concat(camel(instrument), "Id"); sign: add; statuses: [accrued]; subtotalRef: grossCaptureAmount; },
98
- { amountField: amount; instrumentId: concat(instrument, "_credit_adjustment"); refField: concat(camel(instrument), "Id"); sign: add; statuses: [applied]; subtotalRef: creditAdjustmentAmount; },
99
- { amountField: amount; instrumentId: concat(instrument, "_debit_adjustment"); refField: concat(camel(instrument), "Id"); sign: subtract; statuses: [applied]; subtotalRef: debitAdjustmentAmount; },
100
- ];
101
- }
102
- moves: []; steps: [];
103
- }
104
- action approve { agent_description: "Sign off on the frozen net payable. The batch must already be calculated. Nothing is recomputed and no money moves. This is the gate instruct waits on."; summary: "Approve the frozen payable without recomputing it"; moves: []; steps: []; }
105
- action instruct {
106
- agent_description: "Create one external payout for the frozen net payable, drawn on the settlement account and sent to the stored beneficiary. The batch must be approved. This moves money off the platform and is idempotent, so a retry never pays twice.";
107
- summary: "Create one idempotent payout from the frozen net payable";
108
- payout { amount: "refs.netPayable"; beneficiaryField: payout_beneficiary_ref; beneficiaryPartyField: concat(camel(payout_destination), "AccountId"); capture: payoutId; currencyField: currency; sourceAccountField: concat(camel(settlement_account), "AccountId"); speed: standard; }
109
- moves: []; steps: [];
110
- }
111
- action [payout_acknowledgement] {
112
- agent_description: "Record the beneficiary confirmation that the payout landed, with the reference kept in the receipt. The batch must already be instructed. Only the payout destination may call it. No money moves.";
113
- summary: "Record the tenant's payout acknowledgement in the receipt";
114
- port { allowedParties: [beneficiary]; }
115
- input { type: object; properties: { acknowledgementReference: { type: string; description: "Required decision reference retained in the operation receipt"; minLength: 1; maxLength: 180; }; }; required: [acknowledgementReference]; additionalProperties: false; }
116
- capture_input { acknowledgementReference: acknowledgementReference; }
117
- moves: []; steps: [];
118
- }
119
- action reconcile {
120
- summary: "Match durable evidence that the payout settled";
121
- due { field: close_trigger; offset: "P30D"; }
122
- reconcile {
123
- amount: "refs.netPayable"; capture: settlementEvidenceId; counterpartyRef: payoutId;
124
- currencyField: currency; direction: debit; evidence: statement_line;
125
- exception { amountField: amount; childInstrumentId: concat(instrument, "_debit_adjustment"); maxOpen: 1; reasonField: adjustmentReference; refField: concat(camel(instrument), "Id"); }
126
- match { law: exact; }
127
- within { offset: "P30D"; }
128
- }
129
- moves: []; steps: [];
130
- }
131
- instruments {
132
- instrument {
133
- let(parent_name): instrument;
134
- id: concat(parent_name, "_capture_entry");
135
- id_prefix: concat(prefix(parent_name), "ce");
136
- fields {
137
- amount { type: money<C>; description: "Gross captured amount in minor units"; }
138
- [source_capture_refs] { type: text; description: "Immutable source capture reference"; minLength: 1; maxLength: 180; }
139
- currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
140
- [parent_name]Id { type: ref<parent_name>; description: "Open batch this capture entry accrues into"; pattern: concat("^", prefix(parent_name), "_(sandbox|live)_[a-z0-9]{8,64}$"); }
141
- }
142
- lifecycle { states created accrued; initial created; on accrue: created -> accrued; }
143
- required: [amount, currency, concat(camel(parent_name), "Id"), source_capture_refs];
144
- agent_description: "One gross capture that belongs to an open batch. Record one per source capture so the net payable keeps its lineage back to the original charge.";
145
- title: concat(sentence(parent_name), " Capture Entry"); summary: "Gross capture lineage entry"; description: "One gross capture entry linked to an open payout batch";
146
- action create { agent_description: "Record one capture with its source reference against an open batch. The batch must be open and share the currency. No money moves, and the entry counts toward the net payable only once it accrues."; summary: "Create a capture lineage entry on an open batch"; requires refs { field: concat(camel(parent_name), "Id"); statuses: [open]; match: { "fields.currency": "fields.currency"; }; } moves: []; steps: []; }
147
- action accrue { agent_description: "Count this capture toward the batch gross total. The entry must be created and its batch still open, because a closed batch admits nothing new. No money moves."; summary: "Accrue the capture entry into the open batch"; requires refs { field: concat(camel(parent_name), "Id"); statuses: [open]; match: { "fields.currency": "fields.currency"; }; } moves: []; steps: []; }
148
- }
149
- for adjustment_kind in [credit, debit] {
150
- instrument {
151
- let(parent_name): instrument;
152
- id: concat(parent_name, "_", adjustment_kind, "_adjustment");
153
- id_prefix: concat(prefix(parent_name), if_eq(adjustment_kind, "credit", "ca", "da"));
154
- fields {
155
- adjustmentReference { type: text; description: "Immutable explicit adjustment reference"; minLength: 1; maxLength: 180; }
156
- amount { type: money<C>; description: concat(title(adjustment_kind), " adjustment amount in minor units"); }
157
- [source_capture_refs] { type: text; description: "Original capture reference that this adjustment corrects"; minLength: 1; maxLength: 180; }
158
- currency { type: text; description: "ISO 4217 currency code"; minLength: 3; maxLength: 3; pattern: "^[A-Z]{3}$"; }
159
- [external_reversal_offsets] { type: text; description: "Optional externally decided reversal reference"; minLength: 1; maxLength: 180; optional: true; }
160
- [fee_entries] { type: text; description: "Optional fee entry reference"; minLength: 1; maxLength: 180; optional: true; }
161
- [parent_name]Id { type: ref<parent_name>; description: "Open batch this adjustment applies to"; pattern: concat("^", prefix(parent_name), "_(sandbox|live)_[a-z0-9]{8,64}$"); }
162
- }
163
- lifecycle { states created applied; initial created; on adjust: created -> applied; on correct: created -> applied; }
164
- required: [amount, currency, adjustmentReference, concat(camel(parent_name), "Id"), source_capture_refs];
165
- agent_description: concat("One ", adjustment_kind, " adjustment against an open batch, carrying the capture reference it corrects. Credit adjustments add to the net payable and debit adjustments subtract from it, so a late correction lands on the current open batch instead of reopening a closed one.");
166
- title: concat(sentence(parent_name), " ", title(adjustment_kind), " Adjustment"); summary: concat(title(adjustment_kind), " adjustment with capture lineage"); description: concat("One ", adjustment_kind, " adjustment linked to an open payout batch; closed batches stay unchanged");
167
- action create { agent_description: concat("Record a ", adjustment_kind, " adjustment on an open batch, naming the capture reference it corrects. The batch must be open and share the currency. No money moves, and the adjustment counts only once it is applied."); summary: concat("Create a ", adjustment_kind, " adjustment on an open batch"); requires refs { field: concat(camel(parent_name), "Id"); statuses: [open]; match: { "fields.currency": "fields.currency"; }; } moves: []; steps: []; }
168
- action adjust { agent_description: concat("Apply the ", adjustment_kind, " adjustment so calculate counts it. The adjustment must be created and its batch still open. No money moves. The effect shows up in the batch net payable."); summary: concat("Apply the ", adjustment_kind, " adjustment to the open batch"); requires refs { field: concat(camel(parent_name), "Id"); statuses: [open]; match: { "fields.currency": "fields.currency"; }; } moves: []; steps: []; }
169
- action correct { agent_description: "Apply this adjustment as a correction on the open batch it names. Use it when the batch carrying the original entry has already closed, because a closed batch never changes. The adjustment must be created and no money moves."; summary: "Record a later correction on this open batch instead of changing the closed source batch"; requires refs { field: concat(camel(parent_name), "Id"); statuses: [open]; match: { "fields.currency": "fields.currency"; }; } moves: []; steps: []; }
170
- }
171
- }
172
- }
173
- }