@hyperscale0/hsx 2.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 (62) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/src/cli.d.ts +1 -1
  3. package/dist/src/diagnostics.d.ts.map +1 -1
  4. package/dist/src/diagnostics.js +7 -0
  5. package/dist/src/diagnostics.js.map +1 -1
  6. package/dist/src/std-bundle.js +1 -1
  7. package/dist/src/std-bundle.js.map +1 -1
  8. package/dist/src/typecheck.js +89 -1
  9. package/dist/src/typecheck.js.map +1 -1
  10. package/dist/src/version.d.ts +1 -1
  11. package/dist/src/version.js +1 -1
  12. package/docs/guide/09-cost.md +1 -1
  13. package/docs/llms-full.txt +25 -5
  14. package/docs/llms.txt +2 -2
  15. package/docs/reference/cli.md +2 -2
  16. package/docs/reference/diagnostics.md +21 -1
  17. package/docs/reference/grammar.md +1 -1
  18. package/docs/reference/std/advance.md +1 -1
  19. package/docs/reference/std/cancellable_booking.md +1 -1
  20. package/docs/reference/std/captured_payment.md +1 -1
  21. package/docs/reference/std/conditional_disbursement.md +1 -1
  22. package/docs/reference/std/credit_facility.md +1 -1
  23. package/docs/reference/std/held_payment.md +3 -3
  24. package/docs/reference/std/instant_transfer.md +1 -1
  25. package/docs/reference/std/metered.md +1 -1
  26. package/docs/reference/std/pooled_split.md +1 -1
  27. package/docs/reference/std/premium_forward.md +1 -1
  28. package/docs/reference/std/reconciled_payout.md +1 -1
  29. package/docs/reference/std/recurring_collection.md +1 -1
  30. package/docs/reference/std/rotating_pool.md +1 -1
  31. package/docs/reference/std/scheduled.md +1 -1
  32. package/docs/reference/std/security_deposit.md +1 -1
  33. package/docs/reference/std/settlement_batch.md +1 -1
  34. package/docs/reference/std/swap.md +1 -1
  35. package/docs/reference/std/threshold_pool.md +1 -1
  36. package/docs/reference/std/weighted_distribution.md +1 -1
  37. package/docs/reference/types.md +1 -1
  38. package/docs/reference/udl-output.md +1 -1
  39. package/examples/advance/advance.udl +6 -6
  40. package/examples/cancellable_booking/cancellable_booking.udl +10 -10
  41. package/examples/captured_payment/captured_payment.udl +6 -6
  42. package/examples/conditional_disbursement/conditional_disbursement.udl +2 -2
  43. package/examples/cost-table.json +18 -78
  44. package/examples/credit_facility/credit_facility.udl +10 -10
  45. package/examples/held_payment/held_payment.udl +23 -12
  46. package/examples/instant_transfer/instant_transfer.udl +6 -6
  47. package/examples/metered/metered.udl +4 -4
  48. package/examples/pooled_split/pooled_split.udl +10 -10
  49. package/examples/premium_forward/premium_forward.udl +12 -12
  50. package/examples/recurring_collection/recurring_collection.udl +8 -8
  51. package/examples/rotating_pool/rotating_pool.udl +78 -78
  52. package/examples/scheduled/scheduled.udl +6 -6
  53. package/examples/security_deposit/security_deposit.udl +2 -2
  54. package/examples/swap/swap.udl +22 -22
  55. package/examples/threshold_pool/threshold_pool.udl +10 -10
  56. package/examples/weighted_distribution/weighted_distribution.udl +2 -2
  57. package/package.json +3 -3
  58. package/src/diagnostics.ts +10 -0
  59. package/src/std-bundle.ts +1 -1
  60. package/src/typecheck.ts +105 -1
  61. package/src/version.ts +1 -1
  62. package/std/money_flows/held_payment.hsx +2 -0
package/CHANGELOG.md CHANGED
@@ -9,6 +9,19 @@ independently of the package version.
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [2.0.1] - 2026-09-10
13
+
14
+ Published in lockstep with UDL 2.0.1.
15
+
16
+ ### Added
17
+
18
+ - Pinned the currency of every move of a `money<CUR>` field, and of every account step in a fixed-currency instrument, to the constant `CUR` in the lowered document; a binding that reads the instrument's currency field is rewritten, and one the compiler cannot pin (an input, a ref, or a constant naming another currency) reports `HSX1306`.
19
+
20
+ ### Changed
21
+
22
+ - Anchored `dispute` on `held_payment` to `release_deadline` like `cancel`, so a dispute after the release deadline refuses instead of freezing money the clock already released.
23
+ - Declared the safe-integer maximum on `share_offering.totalShares` and `share_allocation.shares` so the lowered schema round-trips byte for byte.
24
+
12
25
  ## [2.0.0] - 2026-09-10
13
26
 
14
27
  ### Added
package/dist/src/cli.d.ts CHANGED
@@ -18,6 +18,6 @@ export interface Io {
18
18
  readonly stdin?: NodeJS.ReadableStream;
19
19
  readonly stdout?: NodeJS.WritableStream;
20
20
  }
21
- export declare const USAGE_TEXT = "hsx 2.0.0, the HSX compiler\n\nUsage:\n hsx check <file.hsx> [--strict]\n hsx build <file.hsx> [--out <file.json>] [--strict]\n hsx cost <file.hsx> [--json] [--out <file.json>] [--strict]\n hsx explain <HSX####>\n hsx format <file.hsx>\n hsx lsp\n hsx --version\n hsx --help\n\nCommands:\n check Compile and report diagnostics. Prints nothing when the program is clean.\n build Compile and write canonical UDL as JSON.\n cost Compile and print the version-pinned cost manifest as a table or JSON.\n explain Print one diagnostic title, fix, and source example.\n format Print the source in the one canonical HSX style.\n lsp Run the language server over stdin and stdout.\n\nOptions:\n --json Print the cost manifest as JSON instead of a table.\n --out <file> Write build or cost JSON to this path instead of stdout.\n --strict Treat warning-severity diagnostics as failures.\n\nExit codes:\n 0 the program compiled (verdict valid, or warning without --strict)\n 1 the program was refused (verdict invalid, or warning with --strict)\n 2 the command line or the input file could not be used";
21
+ export declare const USAGE_TEXT = "hsx 2.0.1, the HSX compiler\n\nUsage:\n hsx check <file.hsx> [--strict]\n hsx build <file.hsx> [--out <file.json>] [--strict]\n hsx cost <file.hsx> [--json] [--out <file.json>] [--strict]\n hsx explain <HSX####>\n hsx format <file.hsx>\n hsx lsp\n hsx --version\n hsx --help\n\nCommands:\n check Compile and report diagnostics. Prints nothing when the program is clean.\n build Compile and write canonical UDL as JSON.\n cost Compile and print the version-pinned cost manifest as a table or JSON.\n explain Print one diagnostic title, fix, and source example.\n format Print the source in the one canonical HSX style.\n lsp Run the language server over stdin and stdout.\n\nOptions:\n --json Print the cost manifest as JSON instead of a table.\n --out <file> Write build or cost JSON to this path instead of stdout.\n --strict Treat warning-severity diagnostics as failures.\n\nExit codes:\n 0 the program compiled (verdict valid, or warning without --strict)\n 1 the program was refused (verdict invalid, or warning with --strict)\n 2 the command line or the input file could not be used";
22
22
  export declare function runCli(argv: readonly string[], io: Io): Promise<number>;
23
23
  //# sourceMappingURL=cli.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/diagnostics.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,MAAM,EAAE,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,CAAC;IACzD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAiBD,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,SAAS,yBAAyB,EAqfrD,CAAC"}
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/diagnostics.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,MAAM,EAAE,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,CAAC;IACzD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAiBD,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,SAAS,yBAAyB,EA+frD,CAAC"}
@@ -338,6 +338,13 @@ action pay { computes remainder rest { amount_ref: total; on_zero: refuse; total
338
338
  fix: "Move all money in one currency; a program bills in one ledger currency.",
339
339
  example: instrument("", "amount: money<SAR>; fee: money<USD>;"),
340
340
  },
341
+ {
342
+ code: "HSX1306",
343
+ stage: "typecheck",
344
+ title: "Fixed-currency amount moved in another currency",
345
+ fix: "Bind the currency of a money<CUR> move or account step as the constant CUR; the compiler pins a binding that reads the instrument's currency field.",
346
+ example: instrument(`action pay { agent_description: "Pay the amount."; moves: [{ "bind": { "amount": { "from": "instance"; "path": "fields.amount"; }; "currency": { "from": "const"; "value": "USD"; }; "destinationAccountId": { "from": "instance"; "path": "fields.payeeAccountId"; }; "sourceAccountId": { "from": "instance"; "path": "fields.payerAccountId"; }; }; "key": "transfer"; "operation": "internal_transfer.create"; }]; steps: []; }`, "amount: money<SAR>; payeeAccountId: account<SAR>; payerAccountId: account<SAR>;"),
347
+ },
341
348
  {
342
349
  code: "HSX1401",
343
350
  stage: "typecheck",
@@ -1 +1 @@
1
- {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/diagnostics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/diagnostics.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,GAAG,CACjB,IAAY,EACZ,MAAM,GAAG,EAAE,EACH,EAAE,CAAC;;;aAGA,MAAM;;;;;;IAMf,IAAI;EACN,CAAC;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,cAAc,GAAyC;IAClE;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,0BAA0B;QACjC,GAAG,EAAE,+CAA+C;QACpD,OAAO,EAAE,EAAE;KACZ;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,cAAc;QACrB,GAAG,EAAE,6CAA6C;QAClD,OAAO,EACL,qEAAqE;KACxE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,+BAA+B;QACtC,GAAG,EAAE,uCAAuC;QAC5C,OAAO,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,2BAA2B;KACtD;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,0BAA0B;QACjC,GAAG,EAAE,4DAA4D;QACjE,OAAO,EAAE,kCAAkC;KAC5C;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,uBAAuB;QAC9B,GAAG,EAAE,gEAAgE;QACrE,OAAO,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,iHAAiH;KAC5I;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,oBAAoB;QAC3B,GAAG,EAAE,sCAAsC;QAC3C,iFAAiF;QACjF,OAAO,EAAE,IAAI;QACb,MAAM,EACJ,0EAA0E;KAC7E;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,uBAAuB;QAC9B,GAAG,EAAE,kEAAkE;QACvE,sEAAsE;QACtE,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,+DAA+D;KACxE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,oCAAoC;QAC3C,GAAG,EAAE,qDAAqD;QAC1D,OAAO,EAAE;;;;;EAKX;KACC;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,kCAAkC;QACzC,GAAG,EAAE,mEAAmE;QACxE,OAAO,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,yCAAyC;KACpE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,gCAAgC;QACvC,GAAG,EAAE,wEAAwE;QAC7E,8EAA8E;QAC9E,OAAO,EAAE,IAAI;QACb,MAAM,EACJ,iFAAiF;KACpF;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,2BAA2B;QAClC,GAAG,EAAE,wEAAwE;QAC7E,OAAO,EAAE;;wCAE2B;KACrC;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,2BAA2B;QAClC,GAAG,EAAE,mDAAmD;QACxD,OAAO,EAAE;;8BAEiB;KAC3B;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,wBAAwB;QAC/B,GAAG,EAAE,6EAA6E;QAClF,OAAO,EAAE;;wCAE2B;KACrC;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,0BAA0B;QACjC,GAAG,EAAE,gCAAgC;QACrC,OAAO,EAAE;;wDAE2C;KACrD;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,sBAAsB;QAC7B,GAAG,EAAE,gDAAgD;QACrD,OAAO,EAAE,cAAc;KACxB;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,mCAAmC;QAC1C,GAAG,EAAE,2DAA2D;QAChE,8DAA8D;QAC9D,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,0DAA0D;KACnE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,6BAA6B;QACpC,GAAG,EAAE,oDAAoD;QACzD,8DAA8D;QAC9D,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,0DAA0D;KACnE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,gCAAgC;QACvC,GAAG,EAAE,yDAAyD;QAC9D,8DAA8D;QAC9D,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,0DAA0D;KACnE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,kCAAkC;QACzC,GAAG,EAAE,2DAA2D;QAChE,OAAO,EAAE,oDAAoD;KAC9D;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,4BAA4B;QACnC,GAAG,EAAE,gEAAgE;QACrE,8DAA8D;QAC9D,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,0DAA0D;KACnE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,wBAAwB;QAC/B,GAAG,EAAE,8DAA8D;QACnE,8DAA8D;QAC9D,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,0DAA0D;KACnE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,qDAAqD;QAC5D,GAAG,EAAE,uFAAuF;QAC5F,8DAA8D;QAC9D,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,0DAA0D;KACnE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,6BAA6B;QACpC,GAAG,EAAE,oDAAoD;QACzD,OAAO,EAAE,UAAU,CAAC,oBAAoB,CAAC;KAC1C;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,gDAAgD;QACvD,GAAG,EAAE,yFAAyF;QAC9F,OAAO,EAAE;;;;;;;;;;;gDAWmC;KAC7C;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,kCAAkC;QACzC,GAAG,EAAE,4IAA4I;QACjJ,OAAO,EAAE;;;;;;;;;;;;;gFAamE;KAC7E;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,mBAAmB;QAC1B,GAAG,EAAE,8DAA8D;QACnE,OAAO,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,oCAAoC;KAC/D;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,qCAAqC;QAC5C,GAAG,EAAE,2DAA2D;QAChE,OAAO,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,qCAAqC;KAChE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,uBAAuB;QAC9B,GAAG,EAAE,6DAA6D;QAClE,OAAO,EAAE,UAAU,CAAC,eAAe,CAAC;KACrC;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,0BAA0B;QACjC,GAAG,EAAE,sDAAsD;QAC3D,OAAO,EAAE,UAAU,CAAC,4BAA4B,CAAC;KAClD;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,mCAAmC;QAC1C,GAAG,EAAE,wDAAwD;QAC7D,OAAO,EAAE;;;;;;;8BAOiB;KAC3B;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,sCAAsC;QAC7C,GAAG,EAAE,uDAAuD;QAC5D,OAAO,EAAE,UAAU,CAAC;0JACkI,CAAC;KACxJ;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,4BAA4B;QACnC,GAAG,EAAE,uDAAuD;QAC5D,OAAO,EAAE,UAAU,CAAC;2GACmF,CAAC;KACzG;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,0BAA0B;QACjC,GAAG,EAAE,oEAAoE;QACzE,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC;KACxB;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,wBAAwB;QAC/B,GAAG,EAAE,oEAAoE;QACzE,wEAAwE;QACxE,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,6DAA6D;KACtE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,6BAA6B;QACpC,GAAG,EAAE,kDAAkD;QACvD,yEAAyE;QACzE,OAAO,EAAE,IAAI;QACb,MAAM,EACJ,qEAAqE;KACxE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,0BAA0B;QACjC,GAAG,EAAE,yDAAyD;QAC9D,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,qBAAqB,CAAC;KAC/C;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,+BAA+B;QACtC,GAAG,EAAE,yEAAyE;QAC9E,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,sCAAsC,CAAC;KAChE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,iDAAiD;QACxD,GAAG,EAAE,qJAAqJ;QAC1J,OAAO,EAAE,UAAU,CACjB,qaAAqa,EACra,iFAAiF,CAClF;KACF;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,kBAAkB;QACzB,GAAG,EAAE,sEAAsE;QAC3E,OAAO,EAAE,UAAU,CAAC,4CAA4C,CAAC;KAClE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,mBAAmB;QAC1B,GAAG,EAAE,gDAAgD;QACrD,OAAO,EACL,sGAAsG;KACzG;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,6BAA6B;QACpC,GAAG,EAAE,6DAA6D;QAClE,OAAO,EAAE;;;;;;;0DAO6C;KACvD;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,+BAA+B;QACtC,GAAG,EAAE,mDAAmD;QACxD,OAAO,EAAE,UAAU,CAAC,sDAAsD,CAAC;KAC5E;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,gCAAgC;QACvC,GAAG,EAAE,qEAAqE;QAC1E,OAAO,EAAE;;8BAEiB;KAC3B;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,8BAA8B;QACrC,GAAG,EAAE,kDAAkD;QACvD,OAAO,EAAE;;;;;;;8BAOiB;KAC3B;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,oBAAoB;QAC3B,GAAG,EAAE,uDAAuD;QAC5D,OAAO,EAAE,UAAU,CAAC,uBAAuB,CAAC;KAC7C;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,8BAA8B;QACrC,GAAG,EAAE,iDAAiD;QACtD,OAAO,EAAE,uCAAuC;KACjD;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,sBAAsB;QAC7B,GAAG,EAAE,4CAA4C;QACjD,OAAO,EACL,2IAA2I;KAC9I;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,uBAAuB;QAC9B,GAAG,EAAE,6BAA6B;QAClC,OAAO,EACL,wHAAwH;KAC3H;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,+BAA+B;QACtC,GAAG,EAAE,oCAAoC;QACzC,OAAO,EAAE,UAAU,CAAC,kCAAkC,CAAC;KACxD;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,oCAAoC;QAC3C,GAAG,EAAE,mDAAmD;QACxD,OAAO,EAAE,UAAU,CACjB,wEAAwE,CACzE;KACF;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,8BAA8B;QACrC,GAAG,EAAE,0DAA0D;QAC/D,OAAO,EAAE;;8CAEiC;KAC3C;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,kCAAkC;QACzC,GAAG,EAAE,6GAA6G;QAClH,OAAO,EAAE;;;;;;;;;EASX;KACC;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,8CAA8C;QACrD,GAAG,EAAE,yIAAyI;QAC9I,OAAO,EAAE;;;;;EAKX;KACC;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,mBAAmB;QAC1B,GAAG,EAAE,qEAAqE;QAC1E,+EAA+E;QAC/E,OAAO,EAAE,IAAI;QACb,MAAM,EACJ,sEAAsE;KACzE;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,uBAAuB;QAC9B,GAAG,EAAE,gEAAgE;QACrE,gFAAgF;QAChF,OAAO,EAAE,IAAI;QACb,MAAM,EACJ,uEAAuE;KAC1E;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,4BAA4B;QACnC,GAAG,EAAE,wDAAwD;QAC7D,OAAO,EAAE,UAAU,CAAC,wBAAwB,CAAC;KAC9C;CACO,CAAC"}
@@ -26,7 +26,7 @@ export const BUNDLED_STD_FILES = new Map([
26
26
  ],
27
27
  [
28
28
  "money_flows/held_payment.hsx",
29
- 'module std.money_flows.held_payment\n\nexport instrument held_payment<C>(payer: party, payee: party, amount: money<C>, release: condition, fees: optional<block>, on_cancel: optional<block>, derived_amount: optional<block>, release_to: optional<party>, whole_amount: optional<block>, release_action: optional<text>, whole_fee: optional<money<C>>, reference: optional<text>, upstream: optional<ref>, id_prefix_override: optional<text>) {\n let(release_name): release;\n let(release_actor_text): if_eq(len(release_allowed), 1, words(at(release_allowed, 1)), concat("a party allowed by ", release));\n let(payer_account_field): camel(concat(payer, "_account_id"));\n let(payee_account_field): camel(concat(payee, "_account_id"));\n let(release_to_account_field): camel(concat(release_to, "_account_id"));\n let(payer_fee): get(fees, payer);\n let(payee_fee): get(fees, payee);\n let(payer_fee_kind): kind(payer_fee);\n let(payee_fee_kind): kind(payee_fee);\n when_eq(payee_fee_kind, binding) {\n when(on_cancel) {\n unsupported {\n code: HSX1110;\n message: "exact payee fees cannot combine with on_cancel yet";\n fix: "remove on_cancel or use a percentage payee fee";\n }\n }\n }\n let(payer_bps): basis_points(payer_fee);\n let(payee_bps): basis_points(payee_fee);\n let(net_bps): sub(10000, payee_fee);\n let(net_percent): percent_text(net_bps);\n let(cancel_payer): get(on_cancel, payer);\n let(cancel_payee): get(on_cancel, payee);\n let(cancel_payer_bps): basis_points(cancel_payer);\n let(cancel_payee_bps): basis_points(cancel_payee);\n let(cancel_splits): lt(1, len(on_cancel));\n let(piece1_bps): min(net_bps, cancel_payer_bps);\n let(piece3_bps): min(payee_bps, cancel_payee_bps);\n let(piece2_bps): sub(sub(10000, piece1_bps), piece3_bps);\n let(piece1_percent): percent_text(piece1_bps);\n let(piece2_percent): percent_text(piece2_bps);\n let(piece3_percent): percent_text(piece3_bps);\n let(carved_spans): lt(cancel_payee_bps, payee_bps);\n let(derived_field): get(derived_amount, "field");\n let(derived_source): get(derived_amount, "source");\n let(derived_rule): get(derived_amount, "rule");\n let(derived_bearer): get(derived_amount, "bearer");\n agent_description: concat("Reach for ", words(instrument), " when the ", words(payer), " must commit money up front and nobody is paid until ", release, " fires. Funding moves ", amount, " into this settlement\'s own escrow account, where it stays until a release or an unwind pays it out. A straight-through payment with no custody step is a different shape.");\n when_not(whole_amount) {\n summary: concat("Escrow-held payment from ", words(payer), " to ", words(payee));\n title: sentence(instrument);\n when_not(release_to) { description: concat("Held payment: the ", words(payer), " funds ", amount, " into this settlement\'s own escrow; ", release_actor_text, " confirms through ", release, " to release"); }\n when(release_to) { description: concat("Held payment: the ", words(payer), " funds ", amount, " into this settlement\'s own escrow; ", release_actor_text, " confirms through ", release, " to release to the ", words(release_to), ", whose advance the ", words(payee), " repays out of it"); }\n fields {\n let(fee_collection_key): "x-hyperscale-fee-collection-port";\n let(reference_filter_key): "x-hyperscale-reference-filter";\n when(release_to) {\n [release_to_account_field] { type: account<C>; description: concat("The ", words(release_to), " account"); [reference_filter_key]: { column: role; values: [customer_balance]; }; }\n }\n platformAccountId {\n type: account<C>;\n description: "The product fee collection account";\n [fee_collection_key]: true;\n [reference_filter_key]: { column: role; values: [customer_balance, product_revenue]; };\n }\n when_not(payee_fee) {\n when_not(cancel_splits) { amount { type: money<C>; description: "The held amount in {C} minor units, funded and paid out whole"; } }\n when(cancel_splits) {\n amount { type: money<C>; description: "The gross held amount in {C} minor units; the piece fields below partition it exactly"; }\n piece1Amount { type: money<C>; description: concat(cancel_payer, " of ", amount, " (carries the integer-division remainder): released to the ", payee, "; on cancellation to the ", payer, ". Computed as floor(", amount, " * ", cancel_payer_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n piece2Amount { type: money<C>; description: concat(cancel_payee, " of ", amount, ": released to the ", payee, "; on cancellation to the ", payee, ". Computed as floor(", amount, " * ", cancel_payee_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n }\n }\n when(payee_fee) {\n amount { type: money<C>; description: "The gross held amount in {C} minor units; the piece fields below partition it exactly"; }\n when_not(on_cancel) {\n when_eq(payee_fee_kind, percent) {\n piece1Amount { type: money<C>; description: concat(net_percent, " of ", amount, " (carries the integer-division remainder): released to the ", payee, ". Computed as floor(", amount, " * ", net_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n piece2Amount { type: money<C>; description: concat(payee_fee, " of ", amount, ": released to the platform. Computed as floor(", amount, " * ", payee_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; optional: true; }\n }\n when_eq(payee_fee_kind, binding) {\n piece1Amount { type: money<C>; description: concat("The remainder of ", amount, " after the exact ", payee_fee, " fee; released to the ", payee); pattern: "^[1-9][0-9]{0,17}$"; }\n [payee_fee] { type: payee_fee; description: concat("Immutable exact ", payee, " fee in ", C, " minor units; released to the platform"); pattern: "^[1-9][0-9]{0,17}$"; }\n }\n }\n when(on_cancel) {\n piece1Amount { type: money<C>; description: concat(piece1_percent, " of ", amount, " (carries the integer-division remainder): released to the ", payee, "; on cancellation to the ", payer, ". Computed as floor(", amount, " * ", piece1_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n when(carved_spans) {\n piece2Amount { type: money<C>; description: concat(piece2_percent, " of ", amount, ": released to the platform; on cancellation to the ", payer, ". Computed as floor(", amount, " * ", piece2_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n piece3Amount { type: money<C>; description: concat(piece3_percent, " of ", amount, ": released to the platform; on cancellation to the ", payee, ". Computed as floor(", amount, " * ", piece3_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n carvedFeeAmount { type: money<C>; description: "Machine-owned total of the 2 carved platform fee pieces"; pattern: "^[1-9][0-9]{0,17}$"; optional: true; }\n }\n when_not(carved_spans) {\n piece2Amount { type: money<C>; description: concat(piece2_percent, " of ", amount, ": released to the ", payee, "; on cancellation to the ", payee, ". Computed as floor(", amount, " * ", piece2_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n piece3Amount { type: money<C>; description: concat(piece3_percent, " of ", amount, ": released to the platform; on cancellation to the ", payee, ". Computed as floor(", amount, " * ", piece3_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; optional: true; }\n }\n }\n }\n when_eq(payer_fee_kind, percent) { serviceFeeAmount { type: money<C>; description: concat("Machine-owned ", payer_fee, " service fee computed from ", amount, "; charged on top at funding"); pattern: "^[1-9][0-9]{0,17}$"; optional: true; } }\n when_eq(payer_fee_kind, binding) { [payer_fee] { type: payer_fee; description: concat("Immutable exact ", payer, " fee in ", C, " minor units; charged on top at funding"); pattern: "^[1-9][0-9]{0,17}$"; } }\n when(release_deadline) {\n when_not(release_to) { [release_deadline] { type: date; description: concat("The date an undecided hold releases to the ", words(payee), " on; ", release, " and cancellation decide only before it"); } }\n when(release_to) { [release_deadline] { type: date; description: concat("The date an undecided hold releases to the ", words(release_to), " on; ", release, " and cancellation decide only before it"); } }\n }\n when(derived_amount) { [derived_field] { type: money<C>; description: "Machine-computed {derived_rule} of {derived_source}; callers never supply it"; pattern: "^[1-9][0-9]{0,17}$"; optional: true; } }\n }\n lifecycle {\n when_not(payee_fee) {\n when_not(cancel_splits) {\n states created funded disputed released;\n when(on_cancel) { states cancelled; }\n states abandoned;\n }\n when(cancel_splits) { states created funding_1 funded disputed releasing_1 released cancelling_1 cancelled abandoned; }\n }\n when(payee_fee) {\n when_not(on_cancel) { states created funding_1 funded disputed releasing_1 released abandoned; }\n when(on_cancel) {\n when_eq(payer_fee_kind, percent) { states created funding_1 funding_2 funding_3 funded disputed releasing_1 releasing_2 released cancelling_1 cancelling_2 cancelled abandoning_1 abandoned abandoning_2; }\n when_eq(payer_fee_kind, none) { states created funding_1 funding_2 funded disputed releasing_1 releasing_2 released cancelling_1 cancelling_2 cancelled abandoning_1 abandoned; }\n when_eq(payer_fee_kind, binding) { states created funding_1 funding_2 funded disputed releasing_1 releasing_2 released cancelling_1 cancelling_2 cancelled abandoning_1 abandoned; }\n }\n }\n initial created;\n when_not(payee_fee) {\n when_not(cancel_splits) {\n on fund_piece_1: created -> funded;\n on [release_name]: funded -> released;\n when(release_deadline) { on release_on_deadline: funded -> released; }\n when(on_cancel) { on cancel: funded -> cancelled; }\n }\n when(cancel_splits) {\n on fund_piece_1: created -> funding_1;\n on fund_piece_2: funding_1 -> funded;\n on [release_name]: funded -> releasing_1;\n on release_piece_2: releasing_1 -> released;\n on cancel: funded -> cancelling_1;\n on refund_piece_2: cancelling_1 -> cancelled;\n on unfund_piece_1: funding_1 -> abandoned;\n }\n }\n when(payee_fee) {\n when_not(on_cancel) {\n on fund_piece_1: created -> funding_1;\n on fund_piece_2: funding_1 -> funded;\n on [release_name]: funded -> releasing_1;\n when(release_deadline) { on release_on_deadline: funded -> releasing_1; }\n on release_piece_2: releasing_1 -> released;\n on unfund_piece_1: funding_1 -> abandoned;\n }\n when(on_cancel) {\n on fund_piece_1: created -> funding_1;\n on fund_piece_2: funding_1 -> funding_2;\n when_eq(payer_fee_kind, percent) {\n on fund_piece_3: funding_2 -> funding_3;\n on collect_service_fee: funding_3 -> funded;\n }\n when_eq(payer_fee_kind, none) { on fund_piece_3: funding_2 -> funded; }\n when_eq(payer_fee_kind, binding) { on fund_piece_3: funding_2 -> funded; }\n on [release_name]: funded -> releasing_1;\n on release_piece_2: releasing_1 -> releasing_2;\n on release_piece_3: releasing_2 -> released;\n on cancel: funded -> cancelling_1;\n on refund_piece_2: cancelling_1 -> cancelling_2;\n on refund_piece_3: cancelling_2 -> cancelled;\n when_eq(payer_fee_kind, percent) {\n on unfund_piece_3: funding_3 -> abandoning_2;\n on unfund_piece_2: funding_2 | abandoning_2 -> abandoning_1;\n }\n when_eq(payer_fee_kind, none) { on unfund_piece_2: funding_2 -> abandoning_1; }\n when_eq(payer_fee_kind, binding) { on unfund_piece_2: funding_2 -> abandoning_1; }\n on unfund_piece_1: funding_1 | abandoning_1 -> abandoned;\n }\n }\n on dispute: funded -> disputed;\n on resume: disputed -> funded;\n on abandon: created -> abandoned;\n }\n parties {\n payer: payer;\n beneficiary: payee;\n }\n when_eq(payer_fee_kind, percent) {\n computes fees: { amount_field: serviceFeeAmount; base_field: amount; bearer_field: payer_account_field; position: on_top; rule: { kind: bps; bps: payer_bps; }; };\n }\n when_eq(payer_fee_kind, binding) {\n computes fees: { amount_field: camel(payer_fee); base_field: amount; bearer_field: payer_account_field; position: on_top; rule: { kind: exact; field: camel(payer_fee); currency_field: currency; }; };\n }\n when(payee_fee) {\n when(on_cancel) {\n action fund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move piece 2 of the split amount from the ", words(payer), " into escrow. Piece 1 must be in escrow first. It debits the ", words(payer), " for real, and the hold is still short of funded until piece 3 lands.");\n summary: "Fund piece 2 of the held amount into escrow";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece2TransferTransferId: transferId; }; }];\n sandbox_failure_point: funding;\n steps: [];\n }\n action fund_piece_3 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move piece 3 of the split amount from the ", words(payer), " into escrow. Pieces 1 and 2 must be in escrow first. It debits the ", words(payer), " for real. Where the product charges a percentage payer fee, one more call collects that fee before the hold counts as funded.");\n summary: "Fund piece 3 of the held amount into escrow";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece3Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_3; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece3TransferTransferId: transferId; }; }];\n sandbox_failure_point: funding;\n steps: [];\n }\n when_eq(payer_fee_kind, percent) {\n action collect_service_fee {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Charge the ", words(payer), " the percentage service fee on top of the held amount and pay it to the platform account. All three funding pieces must be in escrow first. It debits the ", words(payer), " for real and it is the last step of funding.");\n summary: "Collect the payer-side service fee";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.serviceFeeAmount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: collect_service_fee; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { collectServiceFeeTransferTransferId: transferId; }; }];\n steps: [];\n }\n }\n action release_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Pay piece 2 out of escrow once the release decision has run. Its destination follows the product fee split, either the platform account or the ", words(payee), ". Money leaves escrow on this call and does not come back.");\n summary: "Release piece 2 of the held amount";\n when(carved_spans) { let(release_piece_2_destination): "fields.platformAccountId"; }\n when_not(carved_spans) { let(release_piece_2_destination): concat("fields.", payee_account_field); }\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: release_piece_2_destination; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n action release_piece_3 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Pay piece 3 out of escrow to the platform account, which closes the release. Piece 2 must be released first. Money leaves escrow on this call and does not come back.");\n summary: "Release piece 3 of the held amount";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece3Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_3; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece3TransferTransferId: transferId; }; }];\n steps: [];\n }\n action refund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 2 out of escrow once cancel has run. Its destination follows the product fee split, either the ", words(payer), " or the ", words(payee), ". Money leaves escrow on this call and does not come back.");\n summary: "Return piece 2 on cancellation";\n when(carved_spans) { let(refund_piece_2_destination): concat("fields.", payer_account_field); }\n when_not(carved_spans) { let(refund_piece_2_destination): concat("fields.", payee_account_field); }\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refund_piece_2_destination; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: refund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { refundPiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n action refund_piece_3 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 3 out of escrow to the ", words(payee), ", which closes the cancellation. Piece 2 must be returned first. Money leaves escrow on this call and does not come back.");\n summary: "Return piece 3 on cancellation";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece3Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: refund_piece_3; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { refundPiece3TransferTransferId: transferId; }; }];\n steps: [];\n }\n action unfund_piece_1 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 1 from escrow to the ", words(payer), " and abandon the ", words(instrument), ". It runs when only piece 1 was ever funded, or after the later pieces have already gone back. The settlement ends abandoned.");\n summary: "Return piece 1 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece1TransferTransferId: transferId; }; }];\n steps: [];\n }\n action unfund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 2 from escrow to the ", words(payer), " while abandoning a part-funded ", words(instrument), ". Funding must have stopped at piece 2, or piece 3 must already be back. Piece 1 still has to be returned after this.");\n summary: "Return piece 2 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n when_eq(payer_fee_kind, percent) {\n action unfund_piece_3 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 3 from escrow to the ", words(payer), " while abandoning a ", words(instrument), " funded as far as piece 3. Pieces 2 and 1 still have to be returned after this, in that order.");\n summary: "Return piece 3 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece3Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_3; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece3TransferTransferId: transferId; }; }];\n steps: [];\n }\n }\n }\n when_not(on_cancel) {\n when_eq(payee_fee_kind, percent) {\n computes fees: { amount_field: piece2Amount; base_field: amount; bearer_field: payee_account_field; position: carved; rule: { kind: bps; bps: payee_bps; }; };\n partitions: { total_field: amount; piece_fields: [piece1Amount, piece2Amount]; };\n }\n when_eq(payee_fee_kind, binding) {\n computes fees: { amount_field: camel(payee_fee); base_field: amount; bearer_field: payee_account_field; position: carved; rule: { kind: exact; field: camel(payee_fee); currency_field: currency; }; };\n partitions: { total_field: amount; piece_fields: [piece1Amount, camel(payee_fee)]; };\n }\n }\n when(on_cancel) {\n when_eq(payee_fee_kind, percent) {\n when(carved_spans) {\n computes fees: { amount_field: carvedFeeAmount; base_field: amount; bearer_field: payee_account_field; position: carved; rule: { kind: bps; bps: payee_bps; }; };\n }\n when_not(carved_spans) {\n computes fees: { amount_field: piece3Amount; base_field: amount; bearer_field: payee_account_field; position: carved; rule: { kind: bps; bps: payee_bps; }; };\n }\n }\n partitions: { total_field: amount; piece_fields: [piece1Amount, piece2Amount, piece3Amount]; };\n when(carved_spans) { partitions: { total_field: carvedFeeAmount; piece_fields: [piece2Amount, piece3Amount]; }; }\n }\n }\n when_not(payee_fee) {\n when(cancel_splits) { partitions: { total_field: amount; piece_fields: [piece1Amount, piece2Amount]; }; }\n }\n when(derived_amount) {\n computes derived: { field: derived_field; source_field: derived_source; rounding: floor; rule: { kind: percentage_of; bps: derived_rule; }; };\n }\n action create {\n let(owner_id): "owner.id";\n let(owner_type): "owner.type";\n agent_description: concat("Open the ", words(instrument), " and provision the escrow account that holds the funds. This is the first call, and every funding and release action moves money through that account. It does not move the held amount itself.");\n summary: concat("Create a ", words(instrument), " settlement");\n when_not(derived_amount) { moves: []; }\n when(derived_amount) {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n moves: [{ key: "derived_amount"; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", derived_field); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: create; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", camel(derived_bearer), "AccountId"); }; }; capture: { createDerivedAmountTransferId: transferId; }; }];\n }\n steps: [{ operation: "account.escrow.provision"; bind: { currency: { from: instance; path: fields.currency; }; [owner_id]: { from: instance; path: productId; }; [owner_type]: { from: const; value: product; }; productId: { from: instance; path: productId; }; role: { from: const; value: product_escrow; }; }; capture: { escrowAccountId: accountId; }; }];\n }\n action fund_piece_1 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move the ", words(payer), "\'s money into this settlement\'s escrow. Call it after create and before any release. It debits the ", words(payer), " for real, and where the product charges a payer-side fee that fee is taken on top in the same call. Only a later release or unwind moves the money again.");\n summary: "Fund piece 1 of the held amount into escrow";\n when_not(payee_fee) {\n when_not(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1TransferTransferId: transferId; }; }]; }\n when(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1TransferTransferId: transferId; }; }]; }\n }\n when(payee_fee) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1TransferTransferId: transferId; }; }]; }\n when_eq(payer_fee_kind, percent) {\n when_not(payee_fee) { moves: [{ key: service_fee; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.serviceFeeAmount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1ServiceFeeTransferId: transferId; }; }]; }\n when(payee_fee) {\n when_not(on_cancel) { moves: [{ key: service_fee; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.serviceFeeAmount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1ServiceFeeTransferId: transferId; }; }]; }\n }\n }\n when_eq(payer_fee_kind, binding) { moves: [{ key: service_fee; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", payer_fee); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1ServiceFeeTransferId: transferId; }; }]; }\n sandbox_failure_point: funding;\n steps: [];\n }\n action [release_name] {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n let(release_capture): camel(concat(release_name, "_transfer_transfer_id"));\n agent_description: concat("Confirm ", release, " and start paying the held money out of escrow. The ", words(instrument), " must be funded first, and the caller must be ", release_actor_text, ". Where the product requires a decision reference, supply it here. Money leaves escrow on this call and does not come back.");\n summary: concat("Confirm through ", release, " and start the release payout");\n when(release_deadline) { deadline { field: release_deadline; }; }\n when(release_fields) {\n input {\n type: object;\n additional_properties: false;\n properties {\n for input_name in keys(release_fields) {\n [input_name]: get(release_fields, input_name);\n }\n }\n required: keys(release_fields);\n }\n }\n port { allowed_parties: release_allowed; };\n when_not(payee_fee) {\n when_not(cancel_splits) {\n when_not(release_to) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { [release_capture]: transferId; }; }]; }\n when(release_to) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", release_to_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { [release_capture]: transferId; }; }]; }\n }\n when(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { [release_capture]: transferId; }; }]; }\n }\n when(payee_fee) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { [release_capture]: transferId; }; }]; }\n sandbox_failure_point: "release";\n steps: [];\n }\n when(release_deadline) {\n action release_on_deadline {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n when_not(release_to) { summary: "Release to the {payee} when {release_deadline} arrives undecided"; }\n when(release_to) { summary: "Release to the {release_to} when {release_deadline} arrives undecided"; }\n due { field: release_deadline; };\n when_not(payee_fee) {\n when_not(release_to) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_on_deadline; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releaseOnDeadlineTransferTransferId: transferId; }; }]; }\n when(release_to) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", release_to_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_on_deadline; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releaseOnDeadlineTransferTransferId: transferId; }; }]; }\n }\n when(payee_fee) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_on_deadline; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releaseOnDeadlineTransferTransferId: transferId; }; }]; }\n steps: [];\n }\n }\n when(on_cancel) {\n action cancel {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Cancel the ", words(instrument), " and start returning the held money to the ", words(payer), ". It must be funded and not yet released. Cancellation is final, and a cancelled settlement never releases. Where the product sets a release deadline, this call is refused once that date passes.");\n summary: "Cancel the settlement and start the unwind";\n when(release_deadline) { deadline { field: release_deadline; }; }\n when_not(payee_fee) {\n when_not(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: cancel; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { cancelTransferTransferId: transferId; }; }]; }\n when(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: cancel; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { cancelTransferTransferId: transferId; }; }]; }\n }\n when(payee_fee) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: cancel; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { cancelTransferTransferId: transferId; }; }]; }\n steps: [];\n }\n }\n when(payee_fee) {\n when_not(on_cancel) {\n action fund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move the carved platform fee piece from the ", words(payer), " into escrow, which completes funding. Piece 1 must be in escrow first. It debits the ", words(payer), " for real, and the whole held amount then sits in escrow.");\n summary: "Fund piece 2 of the held amount into escrow";\n when_eq(payee_fee_kind, percent) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece2TransferTransferId: transferId; }; }]; }\n when_eq(payee_fee_kind, binding) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", payee_fee); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece2TransferTransferId: transferId; }; }]; }\n sandbox_failure_point: funding;\n steps: [];\n }\n action release_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Pay the carved platform fee out of escrow to the platform account, which closes the release. The release decision must have run first. Money leaves escrow on this call and does not come back.");\n summary: "Release piece 2 of the held amount";\n when_eq(payee_fee_kind, percent) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece2TransferTransferId: transferId; }; }]; }\n when_eq(payee_fee_kind, binding) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", payee_fee); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece2TransferTransferId: transferId; }; }]; }\n steps: [];\n }\n action unfund_piece_1 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 1 from escrow to the ", words(payer), " and abandon the ", words(instrument), ". It runs only while funding stopped after piece 1, before the release. The settlement ends abandoned.");\n summary: "Return piece 1 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece1TransferTransferId: transferId; }; }];\n steps: [];\n }\n }\n }\n when_not(payee_fee) {\n when(cancel_splits) {\n action fund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move piece 2 of the split amount from the ", words(payer), " into escrow, which completes funding. Piece 1 must be in escrow first. It debits the ", words(payer), " for real, and the whole held amount then sits in escrow.");\n summary: "Fund piece 2 of the held amount into escrow";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece2TransferTransferId: transferId; }; }];\n sandbox_failure_point: funding;\n steps: [];\n }\n action release_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Pay piece 2 out of escrow to the ", words(payee), ", which closes the release. The release decision must have run first. Money leaves escrow on this call and does not come back.");\n summary: "Release piece 2 of the held amount";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n action refund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 2 out of escrow to the ", words(payee), ", which closes the cancellation. Cancel must have run first. Money leaves escrow on this call and does not come back.");\n summary: "Return piece 2 on cancellation";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: refund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { refundPiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n action unfund_piece_1 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 1 from escrow to the ", words(payer), " and abandon the ", words(instrument), ". It runs only while funding stopped after piece 1, before the release. The settlement ends abandoned.");\n summary: "Return piece 1 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece1TransferTransferId: transferId; }; }];\n steps: [];\n }\n }\n }\n action abandon {\n agent_description: concat("Close a ", words(instrument), " that was never funded. The escrow account must be empty, so this refuses once any piece is in it. It moves no money and the settlement ends here with no way back.");\n summary: "Abandon the settlement before any money is held";\n requires drained: { path: refs.escrowAccountId; };\n moves: [];\n steps: [];\n }\n action dispute {\n agent_description: concat("Freeze a funded ", words(instrument), " so neither release nor refund can run until the parties settle the disagreement. No money moves and the whole balance stays put. Only a funded ", words(instrument), " disputes.");\n description: concat("Freezes funded ", words(instrument), ", preserving the entire balance while the parties decide what happens next.");\n summary: concat("Dispute a ", words(instrument), " settlement");\n moves: [];\n steps: [];\n }\n action resume {\n agent_description: concat("Lift the dispute hold and put the ", words(instrument), " back where it was, funded and ready to release. No money moves and the balance was never touched. Only a disputed ", words(instrument), " resumes. Use this when the parties settled without a refund.");\n description: concat("Ends the dispute hold without moving money and returns the fully funded ", words(instrument), " to its first milestone.");\n summary: concat("Resume a ", words(instrument), " settlement");\n moves: [];\n steps: [];\n }\n }\n when(whole_amount) {\n let(fee_collection_key): "x-hyperscale-fee-collection-port";\n let(reference_filter_key): "x-hyperscale-reference-filter";\n let(whole_fee_field): camel(whole_fee);\n title: sentence(instrument);\n id_prefix: if_eq(id_prefix_override, false, prefix(instrument), id_prefix_override);\n summary: concat("Escrow-held payment from ", words(payer), " to ", words(payee));\n description: concat("Held payment: the ", words(payer), " funds ", amount, " into this settlement\'s own escrow; ", release_actor_text, " confirms through ", release, " to release");\n distinct_parties: true;\n caller_parked_states: {\n created: "The tenant either funds the hold or abandons it before any money moves.";\n disputed: "Dispute resolution is a human judgment; the parties resume the hold to continue.";\n };\n fields {\n currency { type: text; description: "One currency for the hold and its fee"; const: C; }\n amount { type: money<C>; description: "Amount held in custody, in {C} minor units"; }\n [payee]AccountId { type: account<C>; description: "Party the hold protects and pays on release"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }\n [payer]AccountId { type: account<C>; description: "Party whose money is held until the hold resolves"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }\n platformAccountId { type: account<C>; description: "Product revenue or customer balance account collecting the custody fee"; [fee_collection_key]: true; [reference_filter_key]: { column: role; values: [customer_balance, product_revenue]; }; }\n when(reference) { reference { type: text; description: "The tenant\'s own identifier for what is held: invoice number, project code, contract reference"; optional: true; max_length: 180; min_length: 1; } }\n [release_deadline] { type: date; description: "Date the hold releases to the payee on its own; fixed at creation and the cutoff for both the release port and cancellation"; }\n whole_fee { type: money<C>; description: "Custody fee charged on top at funding and never placed in escrow"; }\n when(upstream) { upstream { type: ref<instrument>; description: "Hold this one is carved out of, when a chain of holds passes the same money down"; optional: true; pattern: concat("^", id_prefix_override, "_(sandbox|live)_[a-z0-9]{8,64}$"); } }\n }\n lifecycle {\n states created funded disputed released cancelled abandoned;\n initial created;\n on abandon: created -> abandoned;\n on cancel: funded -> cancelled;\n on dispute: funded -> disputed;\n on fund: created -> funded;\n on [release_action]: funded -> released;\n on release_on_deadline: funded -> released;\n on resume: disputed -> funded;\n }\n parties { beneficiary: payee_account_field; payer: payer_account_field; }\n required: [payer_account_field, payee_account_field, platformAccountId, amount, whole_fee_field, currency, release_deadline];\n action create {\n let(owner_id): "owner.id";\n let(owner_type): "owner.type";\n agent_description: concat("Open the ", words(instrument), " and provision the escrow account that holds the money. No money moves on this call. ", release_deadline, " is fixed here and never moves again, so one date governs the early release, the cancellation, and the automatic payout.");\n summary: concat("Create a ", words(instrument), " settlement");\n moves: [];\n steps: [{ operation: "account.escrow.provision"; bind: { currency: { from: instance; path: fields.currency; }; [owner_id]: { from: instance; path: productId; }; [owner_type]: { from: const; value: product; }; productId: { from: instance; path: productId; }; role: { from: const; value: product_escrow; }; }; capture: { escrowAccountId: accountId; }; }];\n }\n action fund {\n agent_description: concat("Move ", amount, " from the ", words(payer), " into escrow and charge ", whole_fee_field, " on top to the platform account, as one linked batch. This moves money and the ", words(payer), " pays both. Only a created hold funds. The fee never enters escrow, so it is non-refundable however the hold ends.");\n summary: "Fund the hold and collect the custody fee";\n moves: [\n { key: principal; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: fund; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundingTransferId: transferId; }; },\n { key: service_fee; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", whole_fee_field); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: service_fee; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { serviceFeeTransferId: transferId; }; }\n ];\n sandbox_failure_point: funding;\n steps: [];\n }\n action [release_action] {\n agent_description: concat("Pay the ", words(payee), " the whole ", amount, " out of escrow ahead of ", release_deadline, ". This moves money and does not reverse. Only a funded hold releases, the caller must act as ", words(at(release_allowed, 1)), ", and the call is refused once ", release_deadline, " passes. The custody fee stays posted.");\n summary: concat("Release the hold to the ", words(payee), " early");\n deadline: { field: release_deadline; };\n port: { allowed_parties: [at(release_allowed, 1)]; };\n moves: [{ key: release_action; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: release_action; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releaseTransferId: transferId; }; }];\n sandbox_failure_point: "release";\n steps: [];\n }\n action release_on_deadline {\n summary: concat("Release the hold to the ", words(payee), " on its release date");\n due: { field: release_deadline; };\n event_name: concat(instrument, ".released_on_deadline");\n moves: [{ key: release_action; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: deadline_release; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { deadlineReleaseTransferId: transferId; }; }];\n steps: [];\n }\n action cancel {\n agent_description: concat("Return the whole ", amount, " from escrow to the ", words(payer), " and end the hold. This moves money and does not reverse. Only a funded hold cancels, and only before ", release_deadline, " passes. The custody fee stays posted because the custody it paid for was already provided.");\n summary: "Cancel the hold and return the held amount";\n deadline: { field: release_deadline; };\n event_name: concat(instrument, ".cancelled");\n moves: [{ key: refund; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: cancel_refund; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { cancelRefundTransferId: transferId; }; }];\n steps: [];\n }\n action abandon {\n agent_description: concat("Close a ", words(instrument), " that was opened and never funded. No money has moved and the escrow must be empty, so this is a lifecycle transition only. A funded hold refuses. Release it to the ", words(payee), " or cancel it back to the ", words(payer), " instead.");\n summary: "Abandon the hold before it is funded";\n moves: [];\n requires_drained: { path: refs.escrowAccountId; };\n steps: [];\n }\n action dispute {\n agent_description: concat("Freeze a funded ", words(instrument), " so neither release nor refund can run until the parties settle the disagreement. No money moves and the whole balance stays put. Only a funded ", words(instrument), " disputes.");\n description: concat("Freezes funded ", words(instrument), ", preserving the entire balance while the parties decide what happens next.");\n summary: concat("Dispute a ", words(instrument), " settlement");\n moves: [];\n steps: [];\n }\n action resume {\n agent_description: concat("Lift the dispute hold and put the ", words(instrument), " back where it was, funded and ready to release. No money moves and the balance was never touched. Only a disputed ", words(instrument), " resumes. Use this when the parties settled without a refund.");\n description: concat("Ends the dispute hold without moving money and returns the fully funded ", words(instrument), " to its first milestone.");\n summary: concat("Resume a ", words(instrument), " settlement");\n moves: [];\n steps: [];\n }\n }\n}\n',
29
+ 'module std.money_flows.held_payment\n\nexport instrument held_payment<C>(payer: party, payee: party, amount: money<C>, release: condition, fees: optional<block>, on_cancel: optional<block>, derived_amount: optional<block>, release_to: optional<party>, whole_amount: optional<block>, release_action: optional<text>, whole_fee: optional<money<C>>, reference: optional<text>, upstream: optional<ref>, id_prefix_override: optional<text>) {\n let(release_name): release;\n let(release_actor_text): if_eq(len(release_allowed), 1, words(at(release_allowed, 1)), concat("a party allowed by ", release));\n let(payer_account_field): camel(concat(payer, "_account_id"));\n let(payee_account_field): camel(concat(payee, "_account_id"));\n let(release_to_account_field): camel(concat(release_to, "_account_id"));\n let(payer_fee): get(fees, payer);\n let(payee_fee): get(fees, payee);\n let(payer_fee_kind): kind(payer_fee);\n let(payee_fee_kind): kind(payee_fee);\n when_eq(payee_fee_kind, binding) {\n when(on_cancel) {\n unsupported {\n code: HSX1110;\n message: "exact payee fees cannot combine with on_cancel yet";\n fix: "remove on_cancel or use a percentage payee fee";\n }\n }\n }\n let(payer_bps): basis_points(payer_fee);\n let(payee_bps): basis_points(payee_fee);\n let(net_bps): sub(10000, payee_fee);\n let(net_percent): percent_text(net_bps);\n let(cancel_payer): get(on_cancel, payer);\n let(cancel_payee): get(on_cancel, payee);\n let(cancel_payer_bps): basis_points(cancel_payer);\n let(cancel_payee_bps): basis_points(cancel_payee);\n let(cancel_splits): lt(1, len(on_cancel));\n let(piece1_bps): min(net_bps, cancel_payer_bps);\n let(piece3_bps): min(payee_bps, cancel_payee_bps);\n let(piece2_bps): sub(sub(10000, piece1_bps), piece3_bps);\n let(piece1_percent): percent_text(piece1_bps);\n let(piece2_percent): percent_text(piece2_bps);\n let(piece3_percent): percent_text(piece3_bps);\n let(carved_spans): lt(cancel_payee_bps, payee_bps);\n let(derived_field): get(derived_amount, "field");\n let(derived_source): get(derived_amount, "source");\n let(derived_rule): get(derived_amount, "rule");\n let(derived_bearer): get(derived_amount, "bearer");\n agent_description: concat("Reach for ", words(instrument), " when the ", words(payer), " must commit money up front and nobody is paid until ", release, " fires. Funding moves ", amount, " into this settlement\'s own escrow account, where it stays until a release or an unwind pays it out. A straight-through payment with no custody step is a different shape.");\n when_not(whole_amount) {\n summary: concat("Escrow-held payment from ", words(payer), " to ", words(payee));\n title: sentence(instrument);\n when_not(release_to) { description: concat("Held payment: the ", words(payer), " funds ", amount, " into this settlement\'s own escrow; ", release_actor_text, " confirms through ", release, " to release"); }\n when(release_to) { description: concat("Held payment: the ", words(payer), " funds ", amount, " into this settlement\'s own escrow; ", release_actor_text, " confirms through ", release, " to release to the ", words(release_to), ", whose advance the ", words(payee), " repays out of it"); }\n fields {\n let(fee_collection_key): "x-hyperscale-fee-collection-port";\n let(reference_filter_key): "x-hyperscale-reference-filter";\n when(release_to) {\n [release_to_account_field] { type: account<C>; description: concat("The ", words(release_to), " account"); [reference_filter_key]: { column: role; values: [customer_balance]; }; }\n }\n platformAccountId {\n type: account<C>;\n description: "The product fee collection account";\n [fee_collection_key]: true;\n [reference_filter_key]: { column: role; values: [customer_balance, product_revenue]; };\n }\n when_not(payee_fee) {\n when_not(cancel_splits) { amount { type: money<C>; description: "The held amount in {C} minor units, funded and paid out whole"; } }\n when(cancel_splits) {\n amount { type: money<C>; description: "The gross held amount in {C} minor units; the piece fields below partition it exactly"; }\n piece1Amount { type: money<C>; description: concat(cancel_payer, " of ", amount, " (carries the integer-division remainder): released to the ", payee, "; on cancellation to the ", payer, ". Computed as floor(", amount, " * ", cancel_payer_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n piece2Amount { type: money<C>; description: concat(cancel_payee, " of ", amount, ": released to the ", payee, "; on cancellation to the ", payee, ". Computed as floor(", amount, " * ", cancel_payee_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n }\n }\n when(payee_fee) {\n amount { type: money<C>; description: "The gross held amount in {C} minor units; the piece fields below partition it exactly"; }\n when_not(on_cancel) {\n when_eq(payee_fee_kind, percent) {\n piece1Amount { type: money<C>; description: concat(net_percent, " of ", amount, " (carries the integer-division remainder): released to the ", payee, ". Computed as floor(", amount, " * ", net_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n piece2Amount { type: money<C>; description: concat(payee_fee, " of ", amount, ": released to the platform. Computed as floor(", amount, " * ", payee_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; optional: true; }\n }\n when_eq(payee_fee_kind, binding) {\n piece1Amount { type: money<C>; description: concat("The remainder of ", amount, " after the exact ", payee_fee, " fee; released to the ", payee); pattern: "^[1-9][0-9]{0,17}$"; }\n [payee_fee] { type: payee_fee; description: concat("Immutable exact ", payee, " fee in ", C, " minor units; released to the platform"); pattern: "^[1-9][0-9]{0,17}$"; }\n }\n }\n when(on_cancel) {\n piece1Amount { type: money<C>; description: concat(piece1_percent, " of ", amount, " (carries the integer-division remainder): released to the ", payee, "; on cancellation to the ", payer, ". Computed as floor(", amount, " * ", piece1_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n when(carved_spans) {\n piece2Amount { type: money<C>; description: concat(piece2_percent, " of ", amount, ": released to the platform; on cancellation to the ", payer, ". Computed as floor(", amount, " * ", piece2_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n piece3Amount { type: money<C>; description: concat(piece3_percent, " of ", amount, ": released to the platform; on cancellation to the ", payee, ". Computed as floor(", amount, " * ", piece3_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n carvedFeeAmount { type: money<C>; description: "Machine-owned total of the 2 carved platform fee pieces"; pattern: "^[1-9][0-9]{0,17}$"; optional: true; }\n }\n when_not(carved_spans) {\n piece2Amount { type: money<C>; description: concat(piece2_percent, " of ", amount, ": released to the ", payee, "; on cancellation to the ", payee, ". Computed as floor(", amount, " * ", piece2_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; }\n piece3Amount { type: money<C>; description: concat(piece3_percent, " of ", amount, ": released to the platform; on cancellation to the ", payee, ". Computed as floor(", amount, " * ", piece3_bps, " / 10000) in ", C, " minor units"); pattern: "^[1-9][0-9]{0,17}$"; optional: true; }\n }\n }\n }\n when_eq(payer_fee_kind, percent) { serviceFeeAmount { type: money<C>; description: concat("Machine-owned ", payer_fee, " service fee computed from ", amount, "; charged on top at funding"); pattern: "^[1-9][0-9]{0,17}$"; optional: true; } }\n when_eq(payer_fee_kind, binding) { [payer_fee] { type: payer_fee; description: concat("Immutable exact ", payer, " fee in ", C, " minor units; charged on top at funding"); pattern: "^[1-9][0-9]{0,17}$"; } }\n when(release_deadline) {\n when_not(release_to) { [release_deadline] { type: date; description: concat("The date an undecided hold releases to the ", words(payee), " on; ", release, " and cancellation decide only before it"); } }\n when(release_to) { [release_deadline] { type: date; description: concat("The date an undecided hold releases to the ", words(release_to), " on; ", release, " and cancellation decide only before it"); } }\n }\n when(derived_amount) { [derived_field] { type: money<C>; description: "Machine-computed {derived_rule} of {derived_source}; callers never supply it"; pattern: "^[1-9][0-9]{0,17}$"; optional: true; } }\n }\n lifecycle {\n when_not(payee_fee) {\n when_not(cancel_splits) {\n states created funded disputed released;\n when(on_cancel) { states cancelled; }\n states abandoned;\n }\n when(cancel_splits) { states created funding_1 funded disputed releasing_1 released cancelling_1 cancelled abandoned; }\n }\n when(payee_fee) {\n when_not(on_cancel) { states created funding_1 funded disputed releasing_1 released abandoned; }\n when(on_cancel) {\n when_eq(payer_fee_kind, percent) { states created funding_1 funding_2 funding_3 funded disputed releasing_1 releasing_2 released cancelling_1 cancelling_2 cancelled abandoning_1 abandoned abandoning_2; }\n when_eq(payer_fee_kind, none) { states created funding_1 funding_2 funded disputed releasing_1 releasing_2 released cancelling_1 cancelling_2 cancelled abandoning_1 abandoned; }\n when_eq(payer_fee_kind, binding) { states created funding_1 funding_2 funded disputed releasing_1 releasing_2 released cancelling_1 cancelling_2 cancelled abandoning_1 abandoned; }\n }\n }\n initial created;\n when_not(payee_fee) {\n when_not(cancel_splits) {\n on fund_piece_1: created -> funded;\n on [release_name]: funded -> released;\n when(release_deadline) { on release_on_deadline: funded -> released; }\n when(on_cancel) { on cancel: funded -> cancelled; }\n }\n when(cancel_splits) {\n on fund_piece_1: created -> funding_1;\n on fund_piece_2: funding_1 -> funded;\n on [release_name]: funded -> releasing_1;\n on release_piece_2: releasing_1 -> released;\n on cancel: funded -> cancelling_1;\n on refund_piece_2: cancelling_1 -> cancelled;\n on unfund_piece_1: funding_1 -> abandoned;\n }\n }\n when(payee_fee) {\n when_not(on_cancel) {\n on fund_piece_1: created -> funding_1;\n on fund_piece_2: funding_1 -> funded;\n on [release_name]: funded -> releasing_1;\n when(release_deadline) { on release_on_deadline: funded -> releasing_1; }\n on release_piece_2: releasing_1 -> released;\n on unfund_piece_1: funding_1 -> abandoned;\n }\n when(on_cancel) {\n on fund_piece_1: created -> funding_1;\n on fund_piece_2: funding_1 -> funding_2;\n when_eq(payer_fee_kind, percent) {\n on fund_piece_3: funding_2 -> funding_3;\n on collect_service_fee: funding_3 -> funded;\n }\n when_eq(payer_fee_kind, none) { on fund_piece_3: funding_2 -> funded; }\n when_eq(payer_fee_kind, binding) { on fund_piece_3: funding_2 -> funded; }\n on [release_name]: funded -> releasing_1;\n on release_piece_2: releasing_1 -> releasing_2;\n on release_piece_3: releasing_2 -> released;\n on cancel: funded -> cancelling_1;\n on refund_piece_2: cancelling_1 -> cancelling_2;\n on refund_piece_3: cancelling_2 -> cancelled;\n when_eq(payer_fee_kind, percent) {\n on unfund_piece_3: funding_3 -> abandoning_2;\n on unfund_piece_2: funding_2 | abandoning_2 -> abandoning_1;\n }\n when_eq(payer_fee_kind, none) { on unfund_piece_2: funding_2 -> abandoning_1; }\n when_eq(payer_fee_kind, binding) { on unfund_piece_2: funding_2 -> abandoning_1; }\n on unfund_piece_1: funding_1 | abandoning_1 -> abandoned;\n }\n }\n on dispute: funded -> disputed;\n on resume: disputed -> funded;\n on abandon: created -> abandoned;\n }\n parties {\n payer: payer;\n beneficiary: payee;\n }\n when_eq(payer_fee_kind, percent) {\n computes fees: { amount_field: serviceFeeAmount; base_field: amount; bearer_field: payer_account_field; position: on_top; rule: { kind: bps; bps: payer_bps; }; };\n }\n when_eq(payer_fee_kind, binding) {\n computes fees: { amount_field: camel(payer_fee); base_field: amount; bearer_field: payer_account_field; position: on_top; rule: { kind: exact; field: camel(payer_fee); currency_field: currency; }; };\n }\n when(payee_fee) {\n when(on_cancel) {\n action fund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move piece 2 of the split amount from the ", words(payer), " into escrow. Piece 1 must be in escrow first. It debits the ", words(payer), " for real, and the hold is still short of funded until piece 3 lands.");\n summary: "Fund piece 2 of the held amount into escrow";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece2TransferTransferId: transferId; }; }];\n sandbox_failure_point: funding;\n steps: [];\n }\n action fund_piece_3 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move piece 3 of the split amount from the ", words(payer), " into escrow. Pieces 1 and 2 must be in escrow first. It debits the ", words(payer), " for real. Where the product charges a percentage payer fee, one more call collects that fee before the hold counts as funded.");\n summary: "Fund piece 3 of the held amount into escrow";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece3Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_3; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece3TransferTransferId: transferId; }; }];\n sandbox_failure_point: funding;\n steps: [];\n }\n when_eq(payer_fee_kind, percent) {\n action collect_service_fee {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Charge the ", words(payer), " the percentage service fee on top of the held amount and pay it to the platform account. All three funding pieces must be in escrow first. It debits the ", words(payer), " for real and it is the last step of funding.");\n summary: "Collect the payer-side service fee";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.serviceFeeAmount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: collect_service_fee; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { collectServiceFeeTransferTransferId: transferId; }; }];\n steps: [];\n }\n }\n action release_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Pay piece 2 out of escrow once the release decision has run. Its destination follows the product fee split, either the platform account or the ", words(payee), ". Money leaves escrow on this call and does not come back.");\n summary: "Release piece 2 of the held amount";\n when(carved_spans) { let(release_piece_2_destination): "fields.platformAccountId"; }\n when_not(carved_spans) { let(release_piece_2_destination): concat("fields.", payee_account_field); }\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: release_piece_2_destination; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n action release_piece_3 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Pay piece 3 out of escrow to the platform account, which closes the release. Piece 2 must be released first. Money leaves escrow on this call and does not come back.");\n summary: "Release piece 3 of the held amount";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece3Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_3; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece3TransferTransferId: transferId; }; }];\n steps: [];\n }\n action refund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 2 out of escrow once cancel has run. Its destination follows the product fee split, either the ", words(payer), " or the ", words(payee), ". Money leaves escrow on this call and does not come back.");\n summary: "Return piece 2 on cancellation";\n when(carved_spans) { let(refund_piece_2_destination): concat("fields.", payer_account_field); }\n when_not(carved_spans) { let(refund_piece_2_destination): concat("fields.", payee_account_field); }\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refund_piece_2_destination; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: refund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { refundPiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n action refund_piece_3 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 3 out of escrow to the ", words(payee), ", which closes the cancellation. Piece 2 must be returned first. Money leaves escrow on this call and does not come back.");\n summary: "Return piece 3 on cancellation";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece3Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: refund_piece_3; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { refundPiece3TransferTransferId: transferId; }; }];\n steps: [];\n }\n action unfund_piece_1 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 1 from escrow to the ", words(payer), " and abandon the ", words(instrument), ". It runs when only piece 1 was ever funded, or after the later pieces have already gone back. The settlement ends abandoned.");\n summary: "Return piece 1 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece1TransferTransferId: transferId; }; }];\n steps: [];\n }\n action unfund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 2 from escrow to the ", words(payer), " while abandoning a part-funded ", words(instrument), ". Funding must have stopped at piece 2, or piece 3 must already be back. Piece 1 still has to be returned after this.");\n summary: "Return piece 2 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n when_eq(payer_fee_kind, percent) {\n action unfund_piece_3 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 3 from escrow to the ", words(payer), " while abandoning a ", words(instrument), " funded as far as piece 3. Pieces 2 and 1 still have to be returned after this, in that order.");\n summary: "Return piece 3 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece3Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_3; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece3TransferTransferId: transferId; }; }];\n steps: [];\n }\n }\n }\n when_not(on_cancel) {\n when_eq(payee_fee_kind, percent) {\n computes fees: { amount_field: piece2Amount; base_field: amount; bearer_field: payee_account_field; position: carved; rule: { kind: bps; bps: payee_bps; }; };\n partitions: { total_field: amount; piece_fields: [piece1Amount, piece2Amount]; };\n }\n when_eq(payee_fee_kind, binding) {\n computes fees: { amount_field: camel(payee_fee); base_field: amount; bearer_field: payee_account_field; position: carved; rule: { kind: exact; field: camel(payee_fee); currency_field: currency; }; };\n partitions: { total_field: amount; piece_fields: [piece1Amount, camel(payee_fee)]; };\n }\n }\n when(on_cancel) {\n when_eq(payee_fee_kind, percent) {\n when(carved_spans) {\n computes fees: { amount_field: carvedFeeAmount; base_field: amount; bearer_field: payee_account_field; position: carved; rule: { kind: bps; bps: payee_bps; }; };\n }\n when_not(carved_spans) {\n computes fees: { amount_field: piece3Amount; base_field: amount; bearer_field: payee_account_field; position: carved; rule: { kind: bps; bps: payee_bps; }; };\n }\n }\n partitions: { total_field: amount; piece_fields: [piece1Amount, piece2Amount, piece3Amount]; };\n when(carved_spans) { partitions: { total_field: carvedFeeAmount; piece_fields: [piece2Amount, piece3Amount]; }; }\n }\n }\n when_not(payee_fee) {\n when(cancel_splits) { partitions: { total_field: amount; piece_fields: [piece1Amount, piece2Amount]; }; }\n }\n when(derived_amount) {\n computes derived: { field: derived_field; source_field: derived_source; rounding: floor; rule: { kind: percentage_of; bps: derived_rule; }; };\n }\n action create {\n let(owner_id): "owner.id";\n let(owner_type): "owner.type";\n agent_description: concat("Open the ", words(instrument), " and provision the escrow account that holds the funds. This is the first call, and every funding and release action moves money through that account. It does not move the held amount itself.");\n summary: concat("Create a ", words(instrument), " settlement");\n when_not(derived_amount) { moves: []; }\n when(derived_amount) {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n moves: [{ key: "derived_amount"; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", derived_field); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: create; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", camel(derived_bearer), "AccountId"); }; }; capture: { createDerivedAmountTransferId: transferId; }; }];\n }\n steps: [{ operation: "account.escrow.provision"; bind: { currency: { from: instance; path: fields.currency; }; [owner_id]: { from: instance; path: productId; }; [owner_type]: { from: const; value: product; }; productId: { from: instance; path: productId; }; role: { from: const; value: product_escrow; }; }; capture: { escrowAccountId: accountId; }; }];\n }\n action fund_piece_1 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move the ", words(payer), "\'s money into this settlement\'s escrow. Call it after create and before any release. It debits the ", words(payer), " for real, and where the product charges a payer-side fee that fee is taken on top in the same call. Only a later release or unwind moves the money again.");\n summary: "Fund piece 1 of the held amount into escrow";\n when_not(payee_fee) {\n when_not(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1TransferTransferId: transferId; }; }]; }\n when(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1TransferTransferId: transferId; }; }]; }\n }\n when(payee_fee) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1TransferTransferId: transferId; }; }]; }\n when_eq(payer_fee_kind, percent) {\n when_not(payee_fee) { moves: [{ key: service_fee; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.serviceFeeAmount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1ServiceFeeTransferId: transferId; }; }]; }\n when(payee_fee) {\n when_not(on_cancel) { moves: [{ key: service_fee; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.serviceFeeAmount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1ServiceFeeTransferId: transferId; }; }]; }\n }\n }\n when_eq(payer_fee_kind, binding) { moves: [{ key: service_fee; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", payer_fee); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece1ServiceFeeTransferId: transferId; }; }]; }\n sandbox_failure_point: funding;\n steps: [];\n }\n action [release_name] {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n let(release_capture): camel(concat(release_name, "_transfer_transfer_id"));\n agent_description: concat("Confirm ", release, " and start paying the held money out of escrow. The ", words(instrument), " must be funded first, and the caller must be ", release_actor_text, ". Where the product requires a decision reference, supply it here. Money leaves escrow on this call and does not come back.");\n summary: concat("Confirm through ", release, " and start the release payout");\n when(release_deadline) { deadline { field: release_deadline; }; }\n when(release_fields) {\n input {\n type: object;\n additional_properties: false;\n properties {\n for input_name in keys(release_fields) {\n [input_name]: get(release_fields, input_name);\n }\n }\n required: keys(release_fields);\n }\n }\n port { allowed_parties: release_allowed; };\n when_not(payee_fee) {\n when_not(cancel_splits) {\n when_not(release_to) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { [release_capture]: transferId; }; }]; }\n when(release_to) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", release_to_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { [release_capture]: transferId; }; }]; }\n }\n when(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { [release_capture]: transferId; }; }]; }\n }\n when(payee_fee) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_name; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { [release_capture]: transferId; }; }]; }\n sandbox_failure_point: "release";\n steps: [];\n }\n when(release_deadline) {\n action release_on_deadline {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n when_not(release_to) { summary: "Release to the {payee} when {release_deadline} arrives undecided"; }\n when(release_to) { summary: "Release to the {release_to} when {release_deadline} arrives undecided"; }\n due { field: release_deadline; };\n when_not(payee_fee) {\n when_not(release_to) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_on_deadline; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releaseOnDeadlineTransferTransferId: transferId; }; }]; }\n when(release_to) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", release_to_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_on_deadline; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releaseOnDeadlineTransferTransferId: transferId; }; }]; }\n }\n when(payee_fee) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_on_deadline; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releaseOnDeadlineTransferTransferId: transferId; }; }]; }\n steps: [];\n }\n }\n when(on_cancel) {\n action cancel {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Cancel the ", words(instrument), " and start returning the held money to the ", words(payer), ". It must be funded and not yet released. Cancellation is final, and a cancelled settlement never releases. Where the product sets a release deadline, this call is refused once that date passes.");\n summary: "Cancel the settlement and start the unwind";\n when(release_deadline) { deadline { field: release_deadline; }; }\n when_not(payee_fee) {\n when_not(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: cancel; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { cancelTransferTransferId: transferId; }; }]; }\n when(cancel_splits) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: cancel; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { cancelTransferTransferId: transferId; }; }]; }\n }\n when(payee_fee) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: cancel; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { cancelTransferTransferId: transferId; }; }]; }\n steps: [];\n }\n }\n when(payee_fee) {\n when_not(on_cancel) {\n action fund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move the carved platform fee piece from the ", words(payer), " into escrow, which completes funding. Piece 1 must be in escrow first. It debits the ", words(payer), " for real, and the whole held amount then sits in escrow.");\n summary: "Fund piece 2 of the held amount into escrow";\n when_eq(payee_fee_kind, percent) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece2TransferTransferId: transferId; }; }]; }\n when_eq(payee_fee_kind, binding) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", payee_fee); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece2TransferTransferId: transferId; }; }]; }\n sandbox_failure_point: funding;\n steps: [];\n }\n action release_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Pay the carved platform fee out of escrow to the platform account, which closes the release. The release decision must have run first. Money leaves escrow on this call and does not come back.");\n summary: "Release piece 2 of the held amount";\n when_eq(payee_fee_kind, percent) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece2TransferTransferId: transferId; }; }]; }\n when_eq(payee_fee_kind, binding) { moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", payee_fee); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece2TransferTransferId: transferId; }; }]; }\n steps: [];\n }\n action unfund_piece_1 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 1 from escrow to the ", words(payer), " and abandon the ", words(instrument), ". It runs only while funding stopped after piece 1, before the release. The settlement ends abandoned.");\n summary: "Return piece 1 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece1TransferTransferId: transferId; }; }];\n steps: [];\n }\n }\n }\n when_not(payee_fee) {\n when(cancel_splits) {\n action fund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Move piece 2 of the split amount from the ", words(payer), " into escrow, which completes funding. Piece 1 must be in escrow first. It debits the ", words(payer), " for real, and the whole held amount then sits in escrow.");\n summary: "Fund piece 2 of the held amount into escrow";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: fund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundPiece2TransferTransferId: transferId; }; }];\n sandbox_failure_point: funding;\n steps: [];\n }\n action release_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Pay piece 2 out of escrow to the ", words(payee), ", which closes the release. The release decision must have run first. Money leaves escrow on this call and does not come back.");\n summary: "Release piece 2 of the held amount";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: release_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releasePiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n action refund_piece_2 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 2 out of escrow to the ", words(payee), ", which closes the cancellation. Cancel must have run first. Money leaves escrow on this call and does not come back.");\n summary: "Return piece 2 on cancellation";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece2Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: refund_piece_2; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { refundPiece2TransferTransferId: transferId; }; }];\n steps: [];\n }\n action unfund_piece_1 {\n let(metadata_instrument): "metadata.instrumentId";\n let(metadata_instance): "metadata.instrumentInstanceId";\n let(metadata_phase): "metadata.phase";\n agent_description: concat("Return piece 1 from escrow to the ", words(payer), " and abandon the ", words(instrument), ". It runs only while funding stopped after piece 1, before the release. The settlement ends abandoned.");\n summary: "Return piece 1 to the {payer} on abandonment";\n moves: [{ key: transfer; operation: internal_transfer.create; bind: { amount: { from: instance; path: fields.piece1Amount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: unfund_piece_1; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { unfundPiece1TransferTransferId: transferId; }; }];\n steps: [];\n }\n }\n }\n action abandon {\n agent_description: concat("Close a ", words(instrument), " that was never funded. The escrow account must be empty, so this refuses once any piece is in it. It moves no money and the settlement ends here with no way back.");\n summary: "Abandon the settlement before any money is held";\n requires drained: { path: refs.escrowAccountId; };\n moves: [];\n steps: [];\n }\n action dispute {\n agent_description: concat("Freeze a funded ", words(instrument), " so neither release nor refund can run until the parties settle the disagreement. No money moves and the whole balance stays put. Only a funded ", words(instrument), " disputes.");\n description: concat("Freezes funded ", words(instrument), ", preserving the entire balance while the parties decide what happens next.");\n summary: concat("Dispute a ", words(instrument), " settlement");\n when(release_deadline) { deadline { field: release_deadline; }; }\n moves: [];\n steps: [];\n }\n action resume {\n agent_description: concat("Lift the dispute hold and put the ", words(instrument), " back where it was, funded and ready to release. No money moves and the balance was never touched. Only a disputed ", words(instrument), " resumes. Use this when the parties settled without a refund.");\n description: concat("Ends the dispute hold without moving money and returns the fully funded ", words(instrument), " to its first milestone.");\n summary: concat("Resume a ", words(instrument), " settlement");\n moves: [];\n steps: [];\n }\n }\n when(whole_amount) {\n let(fee_collection_key): "x-hyperscale-fee-collection-port";\n let(reference_filter_key): "x-hyperscale-reference-filter";\n let(whole_fee_field): camel(whole_fee);\n title: sentence(instrument);\n id_prefix: if_eq(id_prefix_override, false, prefix(instrument), id_prefix_override);\n summary: concat("Escrow-held payment from ", words(payer), " to ", words(payee));\n description: concat("Held payment: the ", words(payer), " funds ", amount, " into this settlement\'s own escrow; ", release_actor_text, " confirms through ", release, " to release");\n distinct_parties: true;\n caller_parked_states: {\n created: "The tenant either funds the hold or abandons it before any money moves.";\n disputed: "Dispute resolution is a human judgment; the parties resume the hold to continue.";\n };\n fields {\n currency { type: text; description: "One currency for the hold and its fee"; const: C; }\n amount { type: money<C>; description: "Amount held in custody, in {C} minor units"; }\n [payee]AccountId { type: account<C>; description: "Party the hold protects and pays on release"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }\n [payer]AccountId { type: account<C>; description: "Party whose money is held until the hold resolves"; [reference_filter_key]: { column: role; values: [customer_balance]; }; }\n platformAccountId { type: account<C>; description: "Product revenue or customer balance account collecting the custody fee"; [fee_collection_key]: true; [reference_filter_key]: { column: role; values: [customer_balance, product_revenue]; }; }\n when(reference) { reference { type: text; description: "The tenant\'s own identifier for what is held: invoice number, project code, contract reference"; optional: true; max_length: 180; min_length: 1; } }\n [release_deadline] { type: date; description: "Date the hold releases to the payee on its own; fixed at creation and the cutoff for both the release port and cancellation"; }\n whole_fee { type: money<C>; description: "Custody fee charged on top at funding and never placed in escrow"; }\n when(upstream) { upstream { type: ref<instrument>; description: "Hold this one is carved out of, when a chain of holds passes the same money down"; optional: true; pattern: concat("^", id_prefix_override, "_(sandbox|live)_[a-z0-9]{8,64}$"); } }\n }\n lifecycle {\n states created funded disputed released cancelled abandoned;\n initial created;\n on abandon: created -> abandoned;\n on cancel: funded -> cancelled;\n on dispute: funded -> disputed;\n on fund: created -> funded;\n on [release_action]: funded -> released;\n on release_on_deadline: funded -> released;\n on resume: disputed -> funded;\n }\n parties { beneficiary: payee_account_field; payer: payer_account_field; }\n required: [payer_account_field, payee_account_field, platformAccountId, amount, whole_fee_field, currency, release_deadline];\n action create {\n let(owner_id): "owner.id";\n let(owner_type): "owner.type";\n agent_description: concat("Open the ", words(instrument), " and provision the escrow account that holds the money. No money moves on this call. ", release_deadline, " is fixed here and never moves again, so one date governs the early release, the cancellation, and the automatic payout.");\n summary: concat("Create a ", words(instrument), " settlement");\n moves: [];\n steps: [{ operation: "account.escrow.provision"; bind: { currency: { from: instance; path: fields.currency; }; [owner_id]: { from: instance; path: productId; }; [owner_type]: { from: const; value: product; }; productId: { from: instance; path: productId; }; role: { from: const; value: product_escrow; }; }; capture: { escrowAccountId: accountId; }; }];\n }\n action fund {\n agent_description: concat("Move ", amount, " from the ", words(payer), " into escrow and charge ", whole_fee_field, " on top to the platform account, as one linked batch. This moves money and the ", words(payer), " pays both. Only a created hold funds. The fee never enters escrow, so it is non-refundable however the hold ends.");\n summary: "Fund the hold and collect the custody fee";\n moves: [\n { key: principal; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: refs.escrowAccountId; }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: fund; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { fundingTransferId: transferId; }; },\n { key: service_fee; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", whole_fee_field); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: fields.platformAccountId; }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: service_fee; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: concat("fields.", payer_account_field); }; }; capture: { serviceFeeTransferId: transferId; }; }\n ];\n sandbox_failure_point: funding;\n steps: [];\n }\n action [release_action] {\n agent_description: concat("Pay the ", words(payee), " the whole ", amount, " out of escrow ahead of ", release_deadline, ". This moves money and does not reverse. Only a funded hold releases, the caller must act as ", words(at(release_allowed, 1)), ", and the call is refused once ", release_deadline, " passes. The custody fee stays posted.");\n summary: concat("Release the hold to the ", words(payee), " early");\n deadline: { field: release_deadline; };\n port: { allowed_parties: [at(release_allowed, 1)]; };\n moves: [{ key: release_action; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: release_action; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { releaseTransferId: transferId; }; }];\n sandbox_failure_point: "release";\n steps: [];\n }\n action release_on_deadline {\n summary: concat("Release the hold to the ", words(payee), " on its release date");\n due: { field: release_deadline; };\n event_name: concat(instrument, ".released_on_deadline");\n moves: [{ key: release_action; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: deadline_release; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { deadlineReleaseTransferId: transferId; }; }];\n steps: [];\n }\n action cancel {\n agent_description: concat("Return the whole ", amount, " from escrow to the ", words(payer), " and end the hold. This moves money and does not reverse. Only a funded hold cancels, and only before ", release_deadline, " passes. The custody fee stays posted because the custody it paid for was already provided.");\n summary: "Cancel the hold and return the held amount";\n deadline: { field: release_deadline; };\n event_name: concat(instrument, ".cancelled");\n moves: [{ key: refund; operation: internal_transfer.create; bind: { amount: { from: instance; path: concat("fields.", amount); }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; "metadata.instrumentId": { from: const; value: instrument; }; "metadata.instrumentInstanceId": { from: instance; path: instrumentInstanceId; }; "metadata.phase": { from: const; value: cancel_refund; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { cancelRefundTransferId: transferId; }; }];\n steps: [];\n }\n action abandon {\n agent_description: concat("Close a ", words(instrument), " that was opened and never funded. No money has moved and the escrow must be empty, so this is a lifecycle transition only. A funded hold refuses. Release it to the ", words(payee), " or cancel it back to the ", words(payer), " instead.");\n summary: "Abandon the hold before it is funded";\n moves: [];\n requires_drained: { path: refs.escrowAccountId; };\n steps: [];\n }\n action dispute {\n agent_description: concat("Freeze a funded ", words(instrument), " so neither release nor refund can run until the parties settle the disagreement. No money moves and the whole balance stays put. Only a funded ", words(instrument), " disputes.");\n description: concat("Freezes funded ", words(instrument), ", preserving the entire balance while the parties decide what happens next.");\n summary: concat("Dispute a ", words(instrument), " settlement");\n deadline: { field: release_deadline; };\n moves: [];\n steps: [];\n }\n action resume {\n agent_description: concat("Lift the dispute hold and put the ", words(instrument), " back where it was, funded and ready to release. No money moves and the balance was never touched. Only a disputed ", words(instrument), " resumes. Use this when the parties settled without a refund.");\n description: concat("Ends the dispute hold without moving money and returns the fully funded ", words(instrument), " to its first milestone.");\n summary: concat("Resume a ", words(instrument), " settlement");\n moves: [];\n steps: [];\n }\n }\n}\n',
30
30
  ],
31
31
  [
32
32
  "money_flows/index.hsx",
@@ -1 +1 @@
1
- {"version":3,"file":"std-bundle.js","sourceRoot":"","sources":["../../src/std-bundle.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,MAAM,CAAC,MAAM,iBAAiB,GAAgC,IAAI,GAAG,CAGnE;IACA;QACE,cAAc;QACd,s/RAAs/R;KACv/R;IACD;QACE,yBAAyB;QACzB,w8OAAw8O;KACz8O;IACD;QACE,qCAAqC;QACrC,q5OAAq5O;KACt5O;IACD;QACE,kCAAkC;QAClC,urYAAurY;KACxrY;IACD;QACE,0CAA0C;QAC1C,u/NAAu/N;KACx/N;IACD;QACE,iCAAiC;QACjC,6mMAA6mM;KAC9mM;IACD;QACE,8BAA8B;QAC9B,om/DAAom/D;KACrm/D;IACD;QACE,uBAAuB;QACvB,oGAAoG;KACrG;IACD;QACE,kCAAkC;QAClC,qvbAAqvb;KACtvb;IACD;QACE,yBAAyB;QACzB,2/EAA2/E;KAC5/E;IACD;QACE,8BAA8B;QAC9B,ghKAAghK;KACjhK;IACD;QACE,iCAAiC;QACjC,0kXAA0kX;KAC3kX;IACD;QACE,mCAAmC;QACnC,gnNAAgnN;KACjnN;IACD;QACE,sCAAsC;QACtC,s0CAAs0C;KACv0C;IACD;QACE,+BAA+B;QAC/B,ygqBAAygqB;KAC1gqB;IACD;QACE,2BAA2B;QAC3B,g4+BAAg4+B;KACj4+B;IACD;QACE,kCAAkC;QAClC,u0YAAu0Y;KACx0Y;IACD;QACE,kCAAkC;QAClC,+1XAA+1X;KACh2X;IACD;QACE,sBAAsB;QACtB,ykoCAAykoC;KAC1koC;IACD;QACE,gCAAgC;QAChC,27dAA27d;KAC57d;IACD;QACE,uCAAuC;QACvC,spVAAspV;KACvpV;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"std-bundle.js","sourceRoot":"","sources":["../../src/std-bundle.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,MAAM,CAAC,MAAM,iBAAiB,GAAgC,IAAI,GAAG,CAGnE;IACA;QACE,cAAc;QACd,s/RAAs/R;KACv/R;IACD;QACE,yBAAyB;QACzB,w8OAAw8O;KACz8O;IACD;QACE,qCAAqC;QACrC,q5OAAq5O;KACt5O;IACD;QACE,kCAAkC;QAClC,urYAAurY;KACxrY;IACD;QACE,0CAA0C;QAC1C,u/NAAu/N;KACx/N;IACD;QACE,iCAAiC;QACjC,6mMAA6mM;KAC9mM;IACD;QACE,8BAA8B;QAC9B,0t/DAA0t/D;KAC3t/D;IACD;QACE,uBAAuB;QACvB,oGAAoG;KACrG;IACD;QACE,kCAAkC;QAClC,qvbAAqvb;KACtvb;IACD;QACE,yBAAyB;QACzB,2/EAA2/E;KAC5/E;IACD;QACE,8BAA8B;QAC9B,ghKAAghK;KACjhK;IACD;QACE,iCAAiC;QACjC,0kXAA0kX;KAC3kX;IACD;QACE,mCAAmC;QACnC,gnNAAgnN;KACjnN;IACD;QACE,sCAAsC;QACtC,s0CAAs0C;KACv0C;IACD;QACE,+BAA+B;QAC/B,ygqBAAygqB;KAC1gqB;IACD;QACE,2BAA2B;QAC3B,g4+BAAg4+B;KACj4+B;IACD;QACE,kCAAkC;QAClC,u0YAAu0Y;KACx0Y;IACD;QACE,kCAAkC;QAClC,+1XAA+1X;KACh2X;IACD;QACE,sBAAsB;QACtB,ykoCAAykoC;KAC1koC;IACD;QACE,gCAAgC;QAChC,27dAA27d;KAC57d;IACD;QACE,uCAAuC;QACvC,spVAAspV;KACvpV;CACF,CAAC,CAAC"}
@@ -2421,7 +2421,8 @@ function checkInstrument(name, body, parties, ports, aliases, diagnostics) {
2421
2421
  },
2422
2422
  },
2423
2423
  };
2424
- });
2424
+ })
2425
+ .map((action) => pinFixedCurrencyBindings(action, fields, diagnostics));
2425
2426
  for (const action of actions) {
2426
2427
  for (const declared of ports.get(action.name) ?? []) {
2427
2428
  const allowed = entry(declared.body, "allowed")?.value;
@@ -2999,6 +3000,93 @@ function friendlyMoveRows(body) {
2999
3000
  function isJsonObject(value) {
3000
3001
  return value !== null && typeof value === "object" && !Array.isArray(value);
3001
3002
  }
3003
+ /**
3004
+ * A money<SAR> field moves SAR, whatever the caller wrote in the instance
3005
+ * currency field. Every move of a fixed-currency amount, and every account
3006
+ * step of an instrument whose money is fixed, binds that currency as a
3007
+ * constant: a binding that reads one of the instrument's own text fields is
3008
+ * pinned here, and one the compiler cannot pin (an input, a ref, or a
3009
+ * constant naming another currency) is refused as HSX1306.
3010
+ */
3011
+ function pinFixedCurrencyBindings(action, fields, diagnostics) {
3012
+ const fieldByName = new Map(fields.map((field) => [field.name, field]));
3013
+ const fixedCurrencyOf = (field) => field?.type.kind === "money" &&
3014
+ field.type.currency &&
3015
+ CURRENCY.test(field.type.currency)
3016
+ ? field.type.currency
3017
+ : undefined;
3018
+ const fixed = new Set(fields.flatMap((field) => fixedCurrencyOf(field) ?? []));
3019
+ // Two fixed currencies is HSX1305's refusal; one decides here, none skips.
3020
+ const ledger = fixed.size === 1 ? [...fixed][0] : undefined;
3021
+ if (!ledger)
3022
+ return action;
3023
+ const instanceField = (binding) => binding !== undefined &&
3024
+ isJsonObject(binding) &&
3025
+ binding.from === "instance" &&
3026
+ typeof binding.path === "string" &&
3027
+ binding.path.startsWith("fields.")
3028
+ ? fieldByName.get(binding.path.slice("fields.".length))
3029
+ : undefined;
3030
+ const pin = (entry, currency, subject) => {
3031
+ if (!isJsonObject(entry))
3032
+ return entry;
3033
+ const bind = entry.bind;
3034
+ if (bind === undefined || !isJsonObject(bind))
3035
+ return entry;
3036
+ const binding = bind.currency;
3037
+ if (binding === undefined)
3038
+ return entry;
3039
+ const bound = isJsonObject(binding) && binding.from === "const"
3040
+ ? String(binding.value)
3041
+ : undefined;
3042
+ if (bound === currency)
3043
+ return entry;
3044
+ if (bound === undefined && instanceField(binding)?.type.kind === "text") {
3045
+ return {
3046
+ ...entry,
3047
+ bind: { ...bind, currency: { from: "const", value: currency } },
3048
+ };
3049
+ }
3050
+ diagnostics.push({
3051
+ code: "HSX1306",
3052
+ fix: `bind currency as { from: const; value: ${currency}; }`,
3053
+ message: `action ${action.name} binds the currency of ${subject} to ${bound ?? "a caller-supplied value"}; a money<${currency}> amount moves in ${currency}`,
3054
+ severity: "error",
3055
+ span: action.origin,
3056
+ });
3057
+ return entry;
3058
+ };
3059
+ const moves = action.slots.moves ?? [];
3060
+ const steps = action.slots.steps ?? [];
3061
+ return {
3062
+ ...action,
3063
+ slots: {
3064
+ ...action.slots,
3065
+ moves: Array.isArray(moves)
3066
+ ? moves.map((move) => {
3067
+ if (!isJsonObject(move))
3068
+ return move;
3069
+ // A post settles a reservation; the ledger refuses a post whose
3070
+ // currency differs from the reserve, which is pinned here.
3071
+ if (move.operation === "internal_transfer.post")
3072
+ return move;
3073
+ const bind = move.bind;
3074
+ const amount = bind !== undefined && isJsonObject(bind)
3075
+ ? instanceField(bind.amount)
3076
+ : undefined;
3077
+ return pin(move, fixedCurrencyOf(amount) ?? ledger, amount ? `fields.${amount.name}` : "the moved amount");
3078
+ })
3079
+ : moves,
3080
+ steps: Array.isArray(steps)
3081
+ ? steps.map((step) => isJsonObject(step) &&
3082
+ typeof step.operation === "string" &&
3083
+ step.operation.startsWith("account.")
3084
+ ? pin(step, ledger, `the ${step.operation} account`)
3085
+ : step)
3086
+ : steps,
3087
+ },
3088
+ };
3089
+ }
3002
3090
  function bindFieldReferences(slots, fields, action, diagnostics) {
3003
3091
  const externalFieldSlot = (path) => {
3004
3092
  const key = path.at(-1);