@hyperscale0/hsx 5.5.0 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/src/compile.d.ts +5 -0
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +25 -4
- package/dist/src/compile.js.map +1 -1
- package/dist/src/std-bundle.js +1 -1
- package/dist/src/std-bundle.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +3 -3
- package/src/compile.ts +32 -0
- package/src/std-bundle.ts +1 -1
- package/src/version.ts +1 -1
- package/std/travel.hsx +3 -3
package/dist/src/std-bundle.js
CHANGED
|
@@ -10,7 +10,7 @@ export const BUNDLED_STD_FILES = new Map([
|
|
|
10
10
|
["money.hsx", "header money\n\n// Economics: Held funding and returns are principal. Release to the company realizes\n// earnings; release to another participant is a payout. Generic transfers, splits,\n// schedules, swaps, boundary payouts and metered fees retain no assumed purpose.\n\n// Expose each attachment's create and caller actions explicitly. A transfer or\n// split pays once; a hold exposes fund, release and refund separately. Release\n// pays payee and refund returns payer. A hold has no dispute or damage decision.\n// A schedule needs count unique occurrence records before activation; each due\n// occurrence pays only while the schedule is active. A due time promises no retry.\n// A pool accepts whole contributions only up to its remaining target and at most\n// 366 paid records. Expose pay to release the exact target. Clock failure refunds\n// original contributors; excess acceptance and partial contribution are absent.\n// A swap reserves both legs before exchange or voids reservations on expiry.\n// Payout instruct reserves across the selected adapter; confirm/reject require\n// matching terminal instruction evidence. An acknowledgement cannot settle it.\n// Metered bill charges a unique usage identity at the fixed unit price.\n\n// Cost: transfer.pay declares one transfer. Hold.create declares one owned account;\n// fund, release and refund each declare one transfer. Schedules and pools add bounded\n// child invocations. Run hsx cost on the composed program for counts, not SAR prices.\n\ninstrument transfer(payer: party, payee: party, amount: money = runtime) {\n summary: \"One transfer between the bound parties.\"\n fields { amount: money = amount }\n lifecycle { states: [pending, paid, cancelled], initial: pending }\n action create { actor: { party: payer }, requires self.amount > \"0\" }\n action pay {\n from: pending, to: paid, actor: { party: payer }\n moves self.amount from payer to payee\n }\n action cancel { from: pending, to: cancelled, actor: { party: payer } }\n}\n\ninstrument hold(payer: party, payee: party, amount: money = runtime) {\n summary: \"Hold the declared amount until release or refund.\"\n fields { payer: account of payer, payee: account of payee, amount: money = amount, price: money = self.amount, held: account of self }\n lifecycle { states: [pending, funded, released, refunded, cancelled], initial: pending }\n action create { }\n action fund {\n from: pending, to: funded, actor: { party: payer }\n moves self.amount from payer to self.held economics { purpose: principal, sourceParty: payer }\n }\n action confirm {\n from: pending, to: funded\n requires self.held.balance == self.amount\n }\n action release {\n from: funded, to: released, actor: { party: payer }\n moves self.amount from self.held to payee economics { recipient: payee, company: { purpose: earning, sourceParty: payer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action refund {\n from: funded, to: refunded, actor: { party: payee }\n moves self.amount from self.held to payer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel { from: pending, to: cancelled }\n}\n\ninstrument split(payer: party, amount: money = runtime, shares: split = { programOperator: 100% }) {\n summary: \"Split one amount; the last declared recipient receives the rounding remainder.\"\n fields { amount: money = amount }\n lifecycle { states: [pending, paid, cancelled], initial: pending }\n action create {}\n action pay { allowZero: true, requires self.amount > \"0\"; from: pending, to: paid, actor: { party: payer }, moves self.amount from payer shares shares }\n action cancel { from: pending, to: cancelled }\n}\n\ninstrument schedule(payer: party, payee: party, amount: money = runtime, count: integer(1, 366) = 12) {\n summary: \"A finite schedule whose dated pieces sum exactly to the declared total.\"\n fields { amount: money = amount, count: integer = count, dates: list(date, count) }\n lifecycle { states: [draft, active, complete, cancelled], initial: draft }\n action create {}\n action activate {\n from: draft, to: active\n requires count of { instrument: occurrence, reference: \"schedule\", anchor: self.id, states: [pending], limit: 366 } == self.count\n }\n action complete {\n from: active, to: complete\n requires count of { instrument: occurrence, reference: \"schedule\", anchor: self.id, states: [pending], limit: 366 } == 0\n }\n action cancel { from: [draft, active], to: cancelled }\n records {\n occurrence: {\n fields {\n schedule: ref<parent>, position: integer(1, count), dueAt: date = at(self.schedule.dates, self.position)\n base: money = divide(self.schedule.amount, count)\n allocated: money = multiply(self.base, count)\n remainder: money = subtract(self.schedule.amount, self.allocated)\n first: integer = divide(1, self.position)\n adjustment: money = multiply(self.remainder, self.first)\n amount: money = sum(self.base, self.adjustment)\n }\n lifecycle { states: [pending, paid, cancelled], initial: pending }\n action create { requires self.schedule in [draft]; requires unique \"scheduled_position\" on [self.schedule, self.position] }\n action pay { allowZero: true, from: pending, to: paid, actor: clock, due: { at: self.dueAt }, requires self.schedule in [active], moves self.amount from payer to payee }\n action cancel { from: pending, to: cancelled, requires self.schedule in [cancelled] }\n }\n }\n}\n\ninstrument pool(payer: party, payee: party, target: money, closes: date) {\n summary: \"Contributions fund one threshold or return to their original contributor.\"\n fields { target: money = target, closesAt: date = closes, held: account of self }\n lifecycle { states: [open, paid, failed], initial: open }\n action create { }\n action pay {\n from: open, to: paid, actor: { party: payee }\n requires self.held.balance == self.target\n moves self.target from self.held to payee economics { recipient: payee, company: { purpose: earning, sourceParty: payer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action fail {\n from: open, to: failed, actor: clock, due: { at: self.closesAt }\n requires self.held.balance < self.target\n invoke: [{ selection: { instrument: contribution, reference: \"pool\", anchor: self.id, states: [paid], limit: 366 }, action: refund, input: {} }]\n }\n records {\n contribution: {\n fields { pool: ref<parent>, payer: account of payer, amount: money, remaining: money? }\n lifecycle { states: [pending, paid, refunded], initial: pending }\n invariants count of { instrument: current(), reference: \"pool\", anchor: self.pool, states: [paid], limit: 366 } <= 366\n action create { requires self.pool in [open] }\n action pay { from: pending, to: paid, actor: { party: payer }, deadline: { at: self.pool.closesAt }, requires self.pool in [open], calculate: [{ target: remaining, op: subtract, base: { field: self.pool.target }, subtract: [{ field: self.pool.held.balance }] }], requires self.amount <= self.remaining, moves self.amount from self.payer to self.pool.held economics { purpose: principal, sourceParty: payer } }\n action refund { from: paid, to: refunded, actor: { parent: parent }, moves self.amount from self.pool.held to self.payer economics { purpose: principal, sourceParty: programOperator } }\n }\n }\n}\n\ninstrument swap(first: party, second: party, first_amount: money, second_amount: money, expires: date) {\n summary: \"Two reservations settle together or both return.\"\n fields { firstAmount: money = first_amount, secondAmount: money = second_amount, expiresAt: date = expires, firstReceipt: text?, secondReceipt: text? }\n lifecycle { states: [pending, first_ready, second_ready, both_ready, exchanged, cancelled], initial: pending }\n action create {}\n action fund_first { from: pending, to: first_ready, actor: { party: first }, deadline: { at: self.expiresAt }, moves reserve self.firstAmount from first to second capture \"firstReceipt\" }\n action fund_second { from: first_ready, to: both_ready, actor: { party: second }, deadline: { at: self.expiresAt }, moves reserve self.secondAmount from second to first capture \"secondReceipt\" }\n action start_second { from: pending, to: second_ready, actor: { party: second }, deadline: { at: self.expiresAt }, moves reserve self.secondAmount from second to first capture \"secondReceipt\" }\n action finish_first { from: second_ready, to: both_ready, actor: { party: first }, deadline: { at: self.expiresAt }, moves reserve self.firstAmount from first to second capture \"firstReceipt\" }\n action expire_second { from: second_ready, to: cancelled, actor: clock, due: { at: self.expiresAt }, moves void self.secondReceipt }\n action exchange { from: both_ready, to: exchanged, actor: { party: first }, moves post self.firstReceipt; moves post self.secondReceipt }\n action cancel { from: pending, to: cancelled }\n action expire_first { from: first_ready, to: cancelled, actor: clock, due: { at: self.expiresAt }, moves void self.firstReceipt }\n action expire_both { from: both_ready, to: cancelled, actor: clock, due: { at: self.expiresAt }, moves void self.firstReceipt; moves void self.secondReceipt }\n}\n\ninstrument payout(payer: party, payee: party, adapter: text, max_age: duration, amount: money = runtime) {\n summary: \"Reserve funds until matching terminal boundary evidence permits posting.\"\n fields { amount: money = amount, receipt: text? }\n lifecycle { states: [pending, instructed, settled, rejected], initial: pending }\n action create {}\n action instruct {\n from: pending, to: instructed, actor: { party: payer }\n moves reserve self.amount from payer to payee capture \"receipt\" boundary adapter\n }\n action confirm {\n from: instructed, to: settled\n requires evidence self.id family boundary check outcome result confirmed maxAge max_age instruction self.receipt\n moves post self.receipt\n }\n action reject {\n from: instructed, to: rejected\n requires evidence self.id family boundary check outcome result rejected maxAge max_age instruction self.receipt\n moves void self.receipt\n }\n}\n\ninstrument metered(payer: party, payee: party, unit_price: money, units: integer = 1, fee: fee = { seller: 0% }) {\n summary: \"A unique usage event priced once at the fixed unit price.\"\n fields { usageIdentity: text, unitPrice: money = unit_price, units: integer = units, amount: money = multiply(self.unitPrice, self.units) }\n lifecycle { states: [recorded, billed, cancelled], initial: recorded }\n action create { requires unique \"usage_event\" on [self.usageIdentity] }\n action bill { allowZero: true, requires self.amount > \"0\"; from: recorded, to: billed, actor: { party: payee }, moves self.amount from payer to payee fee fee }\n action cancel { from: recorded, to: cancelled }\n}\n"],
|
|
11
11
|
["reporting.hsx", "header reporting\n\n// Attach portfolio to one or more financing plans. Its only lifecycle action is\n// create; reports use the declared report request/read roles, not a money action.\n// Aging selects active facilities and includes earned profit when deciding arrears.\n// The default-rate report measures period-end stock, not new default incidence.\n// Paid facilities are excluded and write-offs counted separately. Amounts are SAR\n// minor units; declared scale and rounding govern ratios. Missing identity joins\n// or unreconciled schedule counts refuse. Origination cohorts and bureau output\n// explicitly refuse until their unavailable governed facts exist. No bureau\n// submission, provider layout, external transport or restructuring proof is supplied.\n\n// Cost: portfolio.create declares no transfers, owned accounts or invocations.\n// That zero instruction count does not price report capture, rendering, storage or\n// release. The host owns those charges and their execution.\n\ninstrument portfolio(on: ref<financing.installments>[], default_days: integer(1, 3650) = 90, retention_years: integer(1, 100) = 10, aging_first_days: integer(1, 3650) = 30, aging_second_days: integer(1, 3650) = 60, aging_third_days: integer(1, 3650) = 90, ratio_scale: integer(1, 1000000) = 10000, ratio_rounding: enum(floor, halfUp) = floor, lock_wait_ms: integer(1, 2000) = 2000, capture_ms: integer(1, 10000) = 10000, max_rows: integer(1, 100000) = 10000, max_join_rows: integer(1, 1000000) = 100000, max_bytes: integer(1024, 16777216) = 8388608) {\n summary: \"Declared financing reports evaluated over frozen Product facts.\"\n fields {}\n lifecycle { states: [declared], initial: declared }\n action create {}\n constraints { aging_first_days: less_than(aging_second_days), aging_second_days: less_than(aging_third_days) }\n reports: [\n {\n identity: { id: \"portfolio_aging\", version: 1, description: \"Period-end outstanding principal by oldest unpaid installment. Remaining scheduled profit is distinct from accrued profit. Restructuring evidence is unavailable.\" },\n scope: { kind: \"product\", classification: \"internal\", currency: \"SAR\" },\n datasets: [\n {\n id: \"facilities\",\n source: \"instrument\",\n instruments: on,\n rowKey: \"facilityId\",\n columns: [\n {\n name: \"facilityId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"borrowerAccount\",\n field: \"borrower\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"state\",\n field: \"status\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"originalPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduleCount\",\n field: \"months\",\n type: { kind: \"integer\" },\n required: true\n },\n {\n name: \"recordedCreation\",\n field: \"createdAt\",\n type: { kind: \"date\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"activeState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"active\"\n },\n {\n id: \"paidState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"paid\"\n },\n {\n id: \"writtenState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"written_off\"\n },\n { id: \"active\", op: \"equal\", left: \"state\", right: \"activeState\" },\n { id: \"paid\", op: \"equal\", left: \"state\", right: \"paidState\" },\n { id: \"writtenOff\", op: \"equal\", left: \"state\", right: \"writtenState\" },\n { id: \"activeOrPaid\", op: \"or\", left: \"active\", right: \"paid\" },\n { id: \"financed\", op: \"or\", left: \"active\", right: \"writtenOff\" }\n ],\n selection: \"active\"\n },\n {\n id: \"schedule\",\n source: \"instrument\",\n instruments: child(on, slice),\n rowKey: \"sliceId\",\n columns: [\n {\n name: \"sliceId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"planId\",\n field: \"plan\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"due\",\n field: \"dueAt\",\n type: { kind: \"date\" },\n required: true\n },\n {\n name: \"principal\",\n field: \"principalReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"profit\",\n field: \"profitReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"earnedProfit\",\n field: \"profitEarned.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduledPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n {\n id: \"zeroDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n { id: \"observed\", op: \"parameter\", name: \"observationAt\" },\n { id: \"scheduledOutstanding\", op: \"sum\", left: \"principal\", right: \"profit\" },\n { id: \"totalOutstanding\", op: \"sum\", left: \"scheduledOutstanding\", right: \"earnedProfit\" },\n { id: \"unpaid\", op: \"less\", left: \"zeroMoney\", right: \"totalOutstanding\" },\n { id: \"elapsed\", op: \"daysBetween\", left: \"due\", right: \"observed\" },\n { id: \"nonnegativeDays\", op: \"maximum\", left: \"elapsed\", right: \"zeroDays\" },\n { id: \"daysPastDue\", op: \"choose\", condition: \"unpaid\", yes: \"nonnegativeDays\", no: \"zeroDays\" }\n ]\n },\n {\n id: \"borrowerAccounts\",\n source: \"account\",\n instruments: [ ],\n rowKey: \"accountId\",\n columns: [\n {\n name: \"accountId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participant\",\n field: \"ownerParticipantId\",\n type: { kind: \"text\" },\n required: false\n }\n ],\n expressions: [ ]\n },\n {\n id: \"borrowers\",\n source: \"identity\",\n instruments: [ ],\n rowKey: \"customerId\",\n columns: [\n {\n name: \"customerId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participantId\",\n field: \"participantId\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"entityId\",\n field: \"entityId\",\n type: { kind: \"text\" },\n required: true\n }\n ],\n expressions: [ ]\n }\n ],\n time: { timezone: \"Asia/Riyadh\", boundary: \"startInclusiveEndExclusive\", observation: \"periodEnd\", history: \"retainedOnly\" },\n selection: { dataset: \"facilities\" },\n calculation: {\n joins: [\n {\n dataset: \"schedule\",\n local: \"facilityId\",\n foreign: \"planId\",\n cardinality: \"many\",\n missing: \"refuse\",\n aggregates: [\n { name: \"outstandingPrincipal\", op: \"sum\", value: \"principal\" },\n { name: \"remainingScheduledProfit\", op: \"sum\", value: \"profit\" },\n { name: \"scheduledPrincipalTotal\", op: \"sum\", value: \"scheduledPrincipal\" },\n { name: \"capturedScheduleCount\", op: \"count\" },\n { name: \"oldestUnpaidDays\", op: \"maximum\", value: \"daysPastDue\" }\n ]\n },\n {\n dataset: \"borrowerAccounts\",\n local: \"borrowerAccount\",\n foreign: \"accountId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerParticipant\", op: \"minimum\", value: \"participant\" }\n ]\n },\n {\n dataset: \"borrowers\",\n local: \"borrowerParticipant\",\n foreign: \"participantId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerEntity\", op: \"minimum\", value: \"entityId\" }\n ]\n }\n ],\n expressions: [\n {\n id: \"day0\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n {\n id: \"day30\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: aging_first_days\n },\n {\n id: \"day60\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: aging_second_days\n },\n {\n id: \"day90\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: aging_third_days\n },\n {\n id: \"band0\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"current\"\n },\n {\n id: \"band30\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"first\"\n },\n {\n id: \"band60\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"second\"\n },\n {\n id: \"band90\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"third\"\n },\n {\n id: \"bandLate\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"later\"\n },\n { id: \"current\", op: \"atMost\", left: \"oldestUnpaidDays\", right: \"day0\" },\n { id: \"first\", op: \"atMost\", left: \"oldestUnpaidDays\", right: \"day30\" },\n { id: \"second\", op: \"atMost\", left: \"oldestUnpaidDays\", right: \"day60\" },\n { id: \"third\", op: \"atMost\", left: \"oldestUnpaidDays\", right: \"day90\" },\n { id: \"lateBand\", op: \"choose\", condition: \"third\", yes: \"band90\", no: \"bandLate\" },\n { id: \"secondBand\", op: \"choose\", condition: \"second\", yes: \"band60\", no: \"lateBand\" },\n { id: \"firstBand\", op: \"choose\", condition: \"first\", yes: \"band30\", no: \"secondBand\" },\n { id: \"agingBand\", op: \"choose\", condition: \"current\", yes: \"band0\", no: \"firstBand\" }\n ],\n groupBy: [ \"agingBand\" ],\n aggregates: [\n { name: \"facilities\", op: \"count\" },\n { name: \"principalMinor\", op: \"sum\", value: \"outstandingPrincipal\" },\n { name: \"scheduledProfitMinor\", op: \"sum\", value: \"remainingScheduledProfit\" }\n ],\n resultExpressions: [ ]\n },\n validation: {\n empty: \"noEligibleFacilities\",\n required: [ \"borrowerEntity\" ],\n reconcile: [ ],\n rowReconcile: [\n { left: \"originalPrincipal\", right: \"scheduledPrincipalTotal\" },\n { left: \"scheduleCount\", right: \"capturedScheduleCount\" }\n ],\n unavailableFacts: [ ],\n lockTimeoutMs: lock_wait_ms,\n captureTimeoutMs: capture_ms,\n maxRows: max_rows,\n maxJoinRows: max_join_rows,\n maxBytes: max_bytes\n },\n output: {\n profile: \"internal.v1\",\n formats: [ \"json\", \"csv\" ],\n columns: [\n {\n name: \"agingBand\",\n label: \"agingBand\",\n type: { kind: \"text\" }\n },\n {\n name: \"facilities\",\n label: \"facilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"principalMinor\",\n label: \"principalMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n },\n {\n name: \"scheduledProfitMinor\",\n label: \"scheduledProfitMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n }\n ],\n sort: [ \"agingBand\" ]\n },\n authority: {\n request: [ \"owner\", \"finance\" ],\n read: [ \"owner\", \"admin\", \"operations\", \"finance\", \"viewer\" ],\n release: [ ],\n retention: { policy: \"report_replay\", years: retention_years }\n }\n },\n {\n identity: { id: \"origination_cohorts\", version: 1, description: \"Origination cohort performance. Refuses until business-effective origination dates and dated repayment allocation are retained; record creation time is not origination.\" },\n scope: { kind: \"product\", classification: \"internal\", currency: \"SAR\" },\n datasets: [\n {\n id: \"facilities\",\n source: \"instrument\",\n instruments: on,\n rowKey: \"facilityId\",\n columns: [\n {\n name: \"facilityId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"borrowerAccount\",\n field: \"borrower\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"state\",\n field: \"status\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"originalPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduleCount\",\n field: \"months\",\n type: { kind: \"integer\" },\n required: true\n },\n {\n name: \"recordedCreation\",\n field: \"createdAt\",\n type: { kind: \"date\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"activeState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"active\"\n },\n {\n id: \"paidState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"paid\"\n },\n {\n id: \"writtenState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"written_off\"\n },\n { id: \"active\", op: \"equal\", left: \"state\", right: \"activeState\" },\n { id: \"paid\", op: \"equal\", left: \"state\", right: \"paidState\" },\n { id: \"writtenOff\", op: \"equal\", left: \"state\", right: \"writtenState\" },\n { id: \"activeOrPaid\", op: \"or\", left: \"active\", right: \"paid\" },\n { id: \"financed\", op: \"or\", left: \"active\", right: \"writtenOff\" }\n ],\n selection: \"financed\"\n },\n {\n id: \"schedule\",\n source: \"instrument\",\n instruments: child(on, slice),\n rowKey: \"sliceId\",\n columns: [\n {\n name: \"sliceId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"planId\",\n field: \"plan\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"due\",\n field: \"dueAt\",\n type: { kind: \"date\" },\n required: true\n },\n {\n name: \"principal\",\n field: \"principalReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"profit\",\n field: \"profitReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"earnedProfit\",\n field: \"profitEarned.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduledPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n {\n id: \"zeroDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n { id: \"observed\", op: \"parameter\", name: \"observationAt\" },\n { id: \"scheduledOutstanding\", op: \"sum\", left: \"principal\", right: \"profit\" },\n { id: \"totalOutstanding\", op: \"sum\", left: \"scheduledOutstanding\", right: \"earnedProfit\" },\n { id: \"unpaid\", op: \"less\", left: \"zeroMoney\", right: \"totalOutstanding\" },\n { id: \"elapsed\", op: \"daysBetween\", left: \"due\", right: \"observed\" },\n { id: \"nonnegativeDays\", op: \"maximum\", left: \"elapsed\", right: \"zeroDays\" },\n { id: \"daysPastDue\", op: \"choose\", condition: \"unpaid\", yes: \"nonnegativeDays\", no: \"zeroDays\" }\n ]\n },\n {\n id: \"borrowerAccounts\",\n source: \"account\",\n instruments: [ ],\n rowKey: \"accountId\",\n columns: [\n {\n name: \"accountId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participant\",\n field: \"ownerParticipantId\",\n type: { kind: \"text\" },\n required: false\n }\n ],\n expressions: [ ]\n },\n {\n id: \"borrowers\",\n source: \"identity\",\n instruments: [ ],\n rowKey: \"customerId\",\n columns: [\n {\n name: \"customerId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participantId\",\n field: \"participantId\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"entityId\",\n field: \"entityId\",\n type: { kind: \"text\" },\n required: true\n }\n ],\n expressions: [ ]\n }\n ],\n time: { timezone: \"Asia/Riyadh\", boundary: \"startInclusiveEndExclusive\", observation: \"periodEnd\", history: \"retainedOnly\" },\n selection: { dataset: \"facilities\" },\n calculation: {\n joins: [\n {\n dataset: \"schedule\",\n local: \"facilityId\",\n foreign: \"planId\",\n cardinality: \"many\",\n missing: \"refuse\",\n aggregates: [\n { name: \"outstandingPrincipal\", op: \"sum\", value: \"principal\" },\n { name: \"remainingScheduledProfit\", op: \"sum\", value: \"profit\" },\n { name: \"scheduledPrincipalTotal\", op: \"sum\", value: \"scheduledPrincipal\" },\n { name: \"capturedScheduleCount\", op: \"count\" },\n { name: \"oldestUnpaidDays\", op: \"maximum\", value: \"daysPastDue\" }\n ]\n },\n {\n dataset: \"borrowerAccounts\",\n local: \"borrowerAccount\",\n foreign: \"accountId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerParticipant\", op: \"minimum\", value: \"participant\" }\n ]\n },\n {\n dataset: \"borrowers\",\n local: \"borrowerParticipant\",\n foreign: \"participantId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerEntity\", op: \"minimum\", value: \"entityId\" }\n ]\n }\n ],\n expressions: [\n { id: \"recordedMonth\", op: \"bucket\", value: \"recordedCreation\", unit: \"month\" }\n ],\n groupBy: [ \"recordedMonth\" ],\n aggregates: [\n { name: \"facilities\", op: \"count\" },\n { name: \"principalMinor\", op: \"sum\", value: \"outstandingPrincipal\" }\n ],\n resultExpressions: [ ]\n },\n validation: {\n empty: \"noEligibleFacilities\",\n required: [ \"borrowerEntity\" ],\n reconcile: [ ],\n rowReconcile: [\n { left: \"originalPrincipal\", right: \"scheduledPrincipalTotal\" },\n { left: \"scheduleCount\", right: \"capturedScheduleCount\" }\n ],\n unavailableFacts: [ \"business-effective origination timestamp\", \"dated repayment allocation and recovery history\" ],\n lockTimeoutMs: lock_wait_ms,\n captureTimeoutMs: capture_ms,\n maxRows: max_rows,\n maxJoinRows: max_join_rows,\n maxBytes: max_bytes\n },\n output: {\n profile: \"internal.v1\",\n formats: [ \"json\", \"csv\" ],\n columns: [\n {\n name: \"recordedMonth\",\n label: \"recordedMonth\",\n type: { kind: \"text\" }\n },\n {\n name: \"facilities\",\n label: \"facilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"principalMinor\",\n label: \"principalMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n }\n ],\n sort: [ \"recordedMonth\" ]\n },\n authority: {\n request: [ \"owner\", \"finance\" ],\n read: [ \"owner\", \"admin\", \"operations\", \"finance\", \"viewer\" ],\n release: [ ],\n retention: { policy: \"report_replay\", years: retention_years }\n }\n },\n {\n identity: { id: \"period_end_outstanding_principal_default_rate\", version: 1, description: \"Current active facilities with any unpaid installment at least the declared default days past due, observed at period end. Cure when arrears clear. Count and outstanding-principal weighted rates in the declared scale exclude paid and written-off facilities; write-offs are counted separately. This is a stock measure, not a new-default incidence or origination cohort rate.\" },\n scope: { kind: \"product\", classification: \"internal\", currency: \"SAR\" },\n datasets: [\n {\n id: \"facilities\",\n source: \"instrument\",\n instruments: on,\n rowKey: \"facilityId\",\n columns: [\n {\n name: \"facilityId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"borrowerAccount\",\n field: \"borrower\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"state\",\n field: \"status\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"originalPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduleCount\",\n field: \"months\",\n type: { kind: \"integer\" },\n required: true\n },\n {\n name: \"recordedCreation\",\n field: \"createdAt\",\n type: { kind: \"date\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"activeState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"active\"\n },\n {\n id: \"paidState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"paid\"\n },\n {\n id: \"writtenState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"written_off\"\n },\n { id: \"active\", op: \"equal\", left: \"state\", right: \"activeState\" },\n { id: \"paid\", op: \"equal\", left: \"state\", right: \"paidState\" },\n { id: \"writtenOff\", op: \"equal\", left: \"state\", right: \"writtenState\" },\n { id: \"activeOrPaid\", op: \"or\", left: \"active\", right: \"paid\" },\n { id: \"financed\", op: \"or\", left: \"active\", right: \"writtenOff\" }\n ],\n selection: \"financed\"\n },\n {\n id: \"schedule\",\n source: \"instrument\",\n instruments: child(on, slice),\n rowKey: \"sliceId\",\n columns: [\n {\n name: \"sliceId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"planId\",\n field: \"plan\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"due\",\n field: \"dueAt\",\n type: { kind: \"date\" },\n required: true\n },\n {\n name: \"principal\",\n field: \"principalReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"profit\",\n field: \"profitReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"earnedProfit\",\n field: \"profitEarned.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduledPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n {\n id: \"zeroDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n { id: \"observed\", op: \"parameter\", name: \"observationAt\" },\n { id: \"scheduledOutstanding\", op: \"sum\", left: \"principal\", right: \"profit\" },\n { id: \"totalOutstanding\", op: \"sum\", left: \"scheduledOutstanding\", right: \"earnedProfit\" },\n { id: \"unpaid\", op: \"less\", left: \"zeroMoney\", right: \"totalOutstanding\" },\n { id: \"elapsed\", op: \"daysBetween\", left: \"due\", right: \"observed\" },\n { id: \"nonnegativeDays\", op: \"maximum\", left: \"elapsed\", right: \"zeroDays\" },\n { id: \"daysPastDue\", op: \"choose\", condition: \"unpaid\", yes: \"nonnegativeDays\", no: \"zeroDays\" }\n ]\n },\n {\n id: \"borrowerAccounts\",\n source: \"account\",\n instruments: [ ],\n rowKey: \"accountId\",\n columns: [\n {\n name: \"accountId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participant\",\n field: \"ownerParticipantId\",\n type: { kind: \"text\" },\n required: false\n }\n ],\n expressions: [ ]\n },\n {\n id: \"borrowers\",\n source: \"identity\",\n instruments: [ ],\n rowKey: \"customerId\",\n columns: [\n {\n name: \"customerId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participantId\",\n field: \"participantId\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"entityId\",\n field: \"entityId\",\n type: { kind: \"text\" },\n required: true\n }\n ],\n expressions: [ ]\n }\n ],\n time: { timezone: \"Asia/Riyadh\", boundary: \"startInclusiveEndExclusive\", observation: \"periodEnd\", history: \"retainedOnly\" },\n selection: { dataset: \"facilities\" },\n calculation: {\n joins: [\n {\n dataset: \"schedule\",\n local: \"facilityId\",\n foreign: \"planId\",\n cardinality: \"many\",\n missing: \"refuse\",\n aggregates: [\n { name: \"outstandingPrincipal\", op: \"sum\", value: \"principal\" },\n { name: \"remainingScheduledProfit\", op: \"sum\", value: \"profit\" },\n { name: \"scheduledPrincipalTotal\", op: \"sum\", value: \"scheduledPrincipal\" },\n { name: \"capturedScheduleCount\", op: \"count\" },\n { name: \"oldestUnpaidDays\", op: \"maximum\", value: \"daysPastDue\" }\n ]\n },\n {\n dataset: \"borrowerAccounts\",\n local: \"borrowerAccount\",\n foreign: \"accountId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerParticipant\", op: \"minimum\", value: \"participant\" }\n ]\n },\n {\n dataset: \"borrowers\",\n local: \"borrowerParticipant\",\n foreign: \"participantId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerEntity\", op: \"minimum\", value: \"entityId\" }\n ]\n }\n ],\n expressions: [\n {\n id: \"threshold\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: default_days\n },\n {\n id: \"zero\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n {\n id: \"one\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 1\n },\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n { id: \"pastThreshold\", op: \"atMost\", left: \"threshold\", right: \"oldestUnpaidDays\" },\n { id: \"isDefault\", op: \"and\", left: \"active\", right: \"pastThreshold\" },\n { id: \"activeCount\", op: \"choose\", condition: \"active\", yes: \"one\", no: \"zero\" },\n { id: \"defaultCount\", op: \"choose\", condition: \"isDefault\", yes: \"one\", no: \"zero\" },\n { id: \"writeOffCount\", op: \"choose\", condition: \"writtenOff\", yes: \"one\", no: \"zero\" },\n { id: \"activePrincipal\", op: \"choose\", condition: \"active\", yes: \"outstandingPrincipal\", no: \"zeroMoney\" },\n { id: \"defaultPrincipal\", op: \"choose\", condition: \"isDefault\", yes: \"outstandingPrincipal\", no: \"zeroMoney\" }\n ],\n groupBy: [ ],\n aggregates: [\n { name: \"activeFacilities\", op: \"sum\", value: \"activeCount\" },\n { name: \"defaultFacilities\", op: \"sum\", value: \"defaultCount\" },\n { name: \"writtenOffFacilities\", op: \"sum\", value: \"writeOffCount\" },\n { name: \"activePrincipalMinor\", op: \"sum\", value: \"activePrincipal\" },\n { name: \"defaultPrincipalMinor\", op: \"sum\", value: \"defaultPrincipal\" }\n ],\n resultExpressions: [\n { id: \"countRate\", op: \"ratio\", numerator: \"defaultFacilities\", denominator: \"activeFacilities\", scale: ratio_scale, rounding: ratio_rounding, zero: \"null\" },\n { id: \"principalRate\", op: \"ratio\", numerator: \"defaultPrincipalMinor\", denominator: \"activePrincipalMinor\", scale: ratio_scale, rounding: ratio_rounding, zero: \"null\" },\n {\n id: \"restructuringEvidence\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"unavailable\"\n },\n {\n id: \"defaultDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: default_days\n },\n {\n id: \"rateScale\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: ratio_scale\n }\n ]\n },\n validation: {\n empty: \"refuse\",\n required: [ \"borrowerEntity\" ],\n reconcile: [ ],\n rowReconcile: [\n { left: \"originalPrincipal\", right: \"scheduledPrincipalTotal\" },\n { left: \"scheduleCount\", right: \"capturedScheduleCount\" }\n ],\n unavailableFacts: [ ],\n lockTimeoutMs: lock_wait_ms,\n captureTimeoutMs: capture_ms,\n maxRows: max_rows,\n maxJoinRows: max_join_rows,\n maxBytes: max_bytes\n },\n output: {\n profile: \"internal.v1\",\n formats: [ \"json\", \"csv\" ],\n columns: [\n {\n name: \"activeFacilities\",\n label: \"activeFacilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"defaultFacilities\",\n label: \"defaultFacilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"writtenOffFacilities\",\n label: \"writtenOffFacilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"activePrincipalMinor\",\n label: \"activePrincipalMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n },\n {\n name: \"defaultPrincipalMinor\",\n label: \"defaultPrincipalMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n },\n {\n name: \"countRate\",\n label: \"countRate\",\n type: { kind: \"integer\" }\n },\n {\n name: \"principalRate\",\n label: \"principalRate\",\n type: { kind: \"integer\" }\n },\n {\n name: \"restructuringEvidence\",\n label: \"restructuringEvidence\",\n type: { kind: \"text\" }\n },\n {\n name: \"defaultDays\",\n label: \"defaultDays\",\n type: { kind: \"integer\" }\n },\n {\n name: \"rateScale\",\n label: \"rateScale\",\n type: { kind: \"integer\" }\n }\n ],\n sort: [ \"activeFacilities\" ]\n },\n authority: {\n request: [ \"owner\", \"finance\" ],\n read: [ \"owner\", \"admin\", \"operations\", \"finance\", \"viewer\" ],\n release: [ ],\n retention: { policy: \"report_replay\", years: retention_years }\n }\n },\n {\n identity: { id: \"bureau_facility\", version: 1, description: \"Bureau facility definition only. No submission, provider layout or transport is admitted until the member specification and required governed facts exist.\" },\n scope: { kind: \"product\", classification: \"internal\", currency: \"SAR\" },\n datasets: [\n {\n id: \"facilities\",\n source: \"instrument\",\n instruments: on,\n rowKey: \"facilityId\",\n columns: [\n {\n name: \"facilityId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"borrowerAccount\",\n field: \"borrower\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"state\",\n field: \"status\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"originalPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduleCount\",\n field: \"months\",\n type: { kind: \"integer\" },\n required: true\n },\n {\n name: \"recordedCreation\",\n field: \"createdAt\",\n type: { kind: \"date\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"activeState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"active\"\n },\n {\n id: \"paidState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"paid\"\n },\n {\n id: \"writtenState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"written_off\"\n },\n { id: \"active\", op: \"equal\", left: \"state\", right: \"activeState\" },\n { id: \"paid\", op: \"equal\", left: \"state\", right: \"paidState\" },\n { id: \"writtenOff\", op: \"equal\", left: \"state\", right: \"writtenState\" },\n { id: \"activeOrPaid\", op: \"or\", left: \"active\", right: \"paid\" },\n { id: \"financed\", op: \"or\", left: \"active\", right: \"writtenOff\" }\n ],\n selection: \"financed\"\n },\n {\n id: \"schedule\",\n source: \"instrument\",\n instruments: child(on, slice),\n rowKey: \"sliceId\",\n columns: [\n {\n name: \"sliceId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"planId\",\n field: \"plan\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"due\",\n field: \"dueAt\",\n type: { kind: \"date\" },\n required: true\n },\n {\n name: \"principal\",\n field: \"principalReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"profit\",\n field: \"profitReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"earnedProfit\",\n field: \"profitEarned.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduledPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n {\n id: \"zeroDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n { id: \"observed\", op: \"parameter\", name: \"observationAt\" },\n { id: \"scheduledOutstanding\", op: \"sum\", left: \"principal\", right: \"profit\" },\n { id: \"totalOutstanding\", op: \"sum\", left: \"scheduledOutstanding\", right: \"earnedProfit\" },\n { id: \"unpaid\", op: \"less\", left: \"zeroMoney\", right: \"totalOutstanding\" },\n { id: \"elapsed\", op: \"daysBetween\", left: \"due\", right: \"observed\" },\n { id: \"nonnegativeDays\", op: \"maximum\", left: \"elapsed\", right: \"zeroDays\" },\n { id: \"daysPastDue\", op: \"choose\", condition: \"unpaid\", yes: \"nonnegativeDays\", no: \"zeroDays\" }\n ]\n },\n {\n id: \"borrowerAccounts\",\n source: \"account\",\n instruments: [ ],\n rowKey: \"accountId\",\n columns: [\n {\n name: \"accountId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participant\",\n field: \"ownerParticipantId\",\n type: { kind: \"text\" },\n required: false\n }\n ],\n expressions: [ ]\n },\n {\n id: \"borrowers\",\n source: \"identity\",\n instruments: [ ],\n rowKey: \"customerId\",\n columns: [\n {\n name: \"customerId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participantId\",\n field: \"participantId\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"entityId\",\n field: \"entityId\",\n type: { kind: \"text\" },\n required: true\n }\n ],\n expressions: [ ]\n }\n ],\n time: { timezone: \"Asia/Riyadh\", boundary: \"startInclusiveEndExclusive\", observation: \"periodEnd\", history: \"retainedOnly\" },\n selection: { dataset: \"facilities\" },\n calculation: {\n joins: [\n {\n dataset: \"schedule\",\n local: \"facilityId\",\n foreign: \"planId\",\n cardinality: \"many\",\n missing: \"refuse\",\n aggregates: [\n { name: \"outstandingPrincipal\", op: \"sum\", value: \"principal\" },\n { name: \"remainingScheduledProfit\", op: \"sum\", value: \"profit\" },\n { name: \"scheduledPrincipalTotal\", op: \"sum\", value: \"scheduledPrincipal\" },\n { name: \"capturedScheduleCount\", op: \"count\" },\n { name: \"oldestUnpaidDays\", op: \"maximum\", value: \"daysPastDue\" }\n ]\n },\n {\n dataset: \"borrowerAccounts\",\n local: \"borrowerAccount\",\n foreign: \"accountId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerParticipant\", op: \"minimum\", value: \"participant\" }\n ]\n },\n {\n dataset: \"borrowers\",\n local: \"borrowerParticipant\",\n foreign: \"participantId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerEntity\", op: \"minimum\", value: \"entityId\" }\n ]\n }\n ],\n expressions: [ ],\n groupBy: [ ],\n aggregates: [ ],\n resultExpressions: [ ]\n },\n validation: {\n empty: \"refuse\",\n required: [ \"borrowerEntity\" ],\n reconcile: [ ],\n rowReconcile: [\n { left: \"originalPrincipal\", right: \"scheduledPrincipalTotal\" },\n { left: \"scheduleCount\", right: \"capturedScheduleCount\" }\n ],\n unavailableFacts: [ \"approved member format contract\", \"versioned borrower identity and dispute facts\", \"business-effective origination and repayment allocation history\" ],\n lockTimeoutMs: lock_wait_ms,\n captureTimeoutMs: capture_ms,\n maxRows: max_rows,\n maxJoinRows: max_join_rows,\n maxBytes: max_bytes\n },\n output: {\n profile: \"internal.v1\",\n formats: [ \"json\", \"csv\" ],\n columns: [\n {\n name: \"facilityId\",\n label: \"facilityId\",\n type: { kind: \"text\" }\n },\n {\n name: \"borrowerEntity\",\n label: \"borrowerEntity\",\n type: { kind: \"text\" }\n },\n {\n name: \"outstandingPrincipal\",\n label: \"outstandingPrincipal\",\n type: { kind: \"money\", currency: \"SAR\" }\n }\n ],\n sort: [ \"facilityId\" ]\n },\n authority: {\n request: [ \"owner\", \"finance\" ],\n read: [ \"owner\", \"admin\", \"operations\", \"finance\", \"viewer\" ],\n release: [ ],\n retention: { policy: \"report_replay\", years: retention_years }\n }\n }\n ]\n}\n"],
|
|
12
12
|
["savings.hsx", "header savings\n\n// Economics: Contributions and returned pots are principal, not company earnings.\n\n// Expose circle.create and membership.create; create one pending contribution\n// record per member per circle date before membership.activate. Circle activation\n// is clock-owned and needs exactly members joined memberships at or after startsAt.\n// Membership.activate needs the active circle and its full pending schedule.\n// Membership.received means the member received the pot. Contribution.paid means\n// one contribution was collected. Neither record's state proves the other's state.\n// A member can have received the pot with future unpaid contributions, or paid\n// a contribution while their membership still waits for its payout seat.\n// Receive counts preceding received memberships, never paid contributions.\n// Eight members at 300 SAR require 2400 SAR per payout; seven payments supply 2100,\n// so a full payout lacks 300 unless other cash exists. There is no reduced payout.\n// Contribution.pay has a due time and no deadline or prior-payment requirement.\n// Late and out-of-order collection is admitted while membership is active or\n// received and circle is active. Clock admission does not promise scheduler retry.\n// Circle.close needs every membership received and an empty held account.\n// Circle creation collects circleDates, one date per member for contributions and payouts.\n\n// Cost: circle.create declares one owned account. Each contribution payment\n// and each pot payout declares one transfer. Multiply by the actual member and\n// period counts for a completed circle; hsx cost reports per-action bounds.\n\ninstrument circle(contribution: money, members: integer(1, 60), starts: date, memberships: ref<savings.membership> = object(savings.membership)) {\n summary: \"A fixed group contributes on its explicit calendar and takes the pot in order.\"\n fields { contribution: money = contribution, members: integer = members, startsAt: date = starts, circleDates: list(date, members), pot: money = multiply(self.contribution, self.members), held: account of self }\n lifecycle { states: [forming, active, closed, disbanded], initial: forming }\n action create { }\n action activate {\n from: forming, to: active, actor: clock, due: { at: self.startsAt }\n requires count of { instrument: memberships, reference: \"circle\", anchor: self.id, states: [joined], limit: 60 } == self.members\n }\n action close {\n from: active, to: closed\n requires count of { instrument: memberships, reference: \"circle\", anchor: self.id, states: [received], limit: 60 } == self.members\n requires self.held.balance == \"0\"\n }\n action disband { from: forming, to: disbanded }\n}\n\ninstrument membership(circle: ref<savings.circle>, member: party) {\n summary: \"A member contributes on the circle calendar and receives the pot in the assigned seat.\"\n fields { circle: ref<circle>, member: account of member, seat: integer(1, 60), preceding: integer = subtract(self.seat, 1), receivesAt: date = at(self.circle.circleDates, self.seat), contribution: money = self.circle.contribution, total: money = self.circle.pot }\n lifecycle { states: [joined, active, received, withdrawn], initial: joined }\n action create { requires self.seat <= self.circle.members; requires self.circle in [forming]; requires unique \"circle_seat\" on [self.circle, self.seat]; requires unique \"circle_member\" on [self.circle, self.member] }\n action activate {\n from: joined, to: active\n requires self.circle in [active]\n requires count of { instrument: contribution, reference: \"membership\", anchor: self.id, states: [pending], limit: 60 } == self.circle.members\n }\n action receive {\n from: active, to: received, actor: clock, due: { at: self.receivesAt }\n requires self.circle in [active]\n requires count of { instrument: all(savings.membership), reference: \"circle\", anchor: self.circle, states: [received], limit: 60 } == self.preceding\n moves self.total from self.circle.held to self.member economics { purpose: principal, sourceParty: programOperator }\n }\n action withdraw { from: joined, to: withdrawn, requires self.circle in [disbanded] }\n records {\n contribution: {\n fields { membership: ref<parent>, period: integer(1, 60), dueAt: date = at(self.membership.circle.circleDates, self.period), amount: money = self.membership.contribution }\n lifecycle { states: [pending, paid], initial: pending }\n action create { requires self.period <= self.membership.circle.members; requires self.membership in [joined]; requires unique \"seat_period\" on [self.membership, self.period] }\n action pay { from: pending, to: paid, actor: clock, due: { at: self.dueAt }, requires self.membership in [active, received]; requires self.membership.circle in [active], moves self.amount from self.membership.member to self.membership.circle.held economics { purpose: principal, sourceParty: member } }\n }\n }\n}\n"],
|
|
13
|
-
["travel.hsx", "header travel\n\n// Economics: Booking funds and refunds are principal. Supplier payments are payouts,\n// tax is pass-through, and the company margin is earning. An outside operator\n// receives a participant payout instead of company earnings.\n\n// Publish a package before booking.create. Expose deposit, balance and confirm\n// separately. Deposit needs pending premium slices whose cover is active, and\n// collects those premiums in addition to booking cash. Balance is due by balanceAt.\n// Expose cancel_early, cancel_middle and cancel_late for the desired booking paths.\n// Early returns all held booking cash, whether deposit-only or fully paid. Middle\n// returns held minus the original deposit; a deposit-only booking gets zero.\n// Supplier penalty is based on supplierCost; tax applies to retained margin,\n// and the bound operator receives the remainder. Late returns no buyer cash.\n// Middle opens at earlyAt and ends at lateAt, which is middleAt plus 1ms; late\n// starts there. Default_balance can already cancel a deposit_paid booking at\n// balanceAt, after which no booking cancellation is reachable. Clock order matters.\n// Booking refunds exclude insurance premiums, broker commission and all balances\n// outside booking.held. Expose cover.cancel independently to refund eligible paid\n// premium periods before startsAt; slice.refund is parent-owned. Active/expired\n// premium periods remain excluded. Confirmation timeout returns the full booking\n// price from paid only. A penalty above held cash or retained deposit refuses;\n// this header does not subsidize a shortfall or reduce the configured penalty.\n\n// Cost: booking.create declares one owned account. Deposit also invokes premium\n// collections; cancellation declares the selected refund, penalty, tax and retained\n// moves. Run hsx cost for bounded counts. Supplier penalties are business terms,\n// not compiler or executor fees.\n\ninstrument package(price: money, supplier_cost: money, departure: date) {\n constraints { supplier_cost: at_most(price) }\n summary: \"Immutable package price, supplier cost and departure.\"\n fields { price: money = price, supplierCost: money = supplier_cost, departure: date = departure }\n lifecycle { states: [draft, published, closed], initial: draft }\n action create { requires self.supplierCost <= self.price }\n action publish { from: draft, to: published }\n action close { from: published, to: closed, actor: clock, due: { at: self.departure } }\n}\n\ninstrument booking(package: ref<travel.package>, buyer: party, supplier: party, operator: party = programOperator, cover: ref<insurance.cover>, deposit: percent = 30%, balance_before: duration = 14d, confirm_within: duration = 24h, tax: percent = 15%, early_before: duration = 30d, middle_before: duration = 15d, middle_penalty: percent = 10%, late_penalty: percent = 30%) {\n constraints { early_before: greater_than(middle_before) }\n summary: \"A deposited booking with three cancellation bands and confirmation.\"\n fields {\n package: ref<package>, buyer: account of buyer, supplier: account of supplier\n price: money = self.package.price, supplierCost: money = self.package.supplierCost\n deposit: money = rate(self.price, deposit), balance: money = subtract(self.price, self.deposit)\n margin: money = subtract(self.price, self.supplierCost)\n tax: money = rate(self.margin, tax), operatorNet: money = subtract(self.margin, self.tax)\n middlePenalty: money = rate(self.supplierCost, middle_penalty)\n latePenalty: money = rate(self.supplierCost, late_penalty)\n balanceAt: date = before(self.package.departure, balance_before)\n earlyAt: date = before(self.package.departure, early_before)\n middleAt: date = before(self.package.departure, middle_before)\n lateAt: date = after(self.middleAt, 1ms)\n confirmBy: date = after(self.package.departure, confirm_within)\n held: account of self\n refund: money?, retainedMargin: money?, retainedTax: money?, retainedNet: money?\n }\n lifecycle { states: [created, deposit_paid, paid, completed, cancelled, refunded], initial: created }\n action create {\n requires self.package in [published]\n }\n action deposit { allowZero: true, requires self.price > \"0\";\n from: created, to: deposit_paid, actor: { party: buyer }, deadline: { at: self.balanceAt }\n requires count of { instrument: child(cover, slice), reference: \"covers\", anchor: self.id, states: [pending], limit: 366 } >= 1\n moves self.deposit from buyer to self.held economics { purpose: principal, sourceParty: buyer }\n invoke: [{ selection: { instrument: child(cover, slice), reference: \"covers\", anchor: self.id, states: [pending], limit: 366 }, action: collect, input: {} }]\n }\n action balance { allowZero: true, requires self.price > \"0\";\n from: deposit_paid, to: paid, actor: { party: buyer }, deadline: { at: self.balanceAt }\n moves self.balance from buyer to self.held economics { purpose: principal, sourceParty: buyer }\n }\n action confirm { allowZero: true, requires self.price > \"0\";\n from: paid, to: completed, actor: { party: operator }\n due: { at: self.package.departure }, deadline: { at: self.confirmBy }\n moves self.supplierCost from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.tax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.operatorNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action timeout {\n from: paid, to: refunded, actor: clock, due: { at: self.confirmBy }\n moves self.price from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel_early { allowZero: true, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, deadline: { at: self.earlyAt }\n moves self.held.balance from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel_middle { allowZero: true, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.earlyAt }, deadline: { at: self.lateAt }\n calculate: [\n { target: refund, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.deposit }] }\n { target: retainedMargin, op: \"subtract\", base: { field: self.deposit }, subtract: [{ field: self.middlePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.refund from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n moves self.middlePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action cancel_late { allowZero: true, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.lateAt }\n calculate: [\n { target: retainedMargin, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.latePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action default_balance { allowZero: true, requires self.price > \"0\";\n from: deposit_paid, to: cancelled, actor: clock, due: { at: self.balanceAt }\n calculate: [\n { target: retainedMargin, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.latePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n}\n"],
|
|
13
|
+
["travel.hsx", "header travel\n\n// Economics: Booking funds and refunds are principal. Supplier payments are payouts,\n// tax is pass-through, and the company margin is earning. An outside operator\n// receives a participant payout instead of company earnings.\n\n// Publish a package before booking.create. Expose deposit, balance and confirm\n// separately. Deposit needs pending premium slices whose cover is active, and\n// collects those premiums in addition to booking cash. Balance is due by balanceAt.\n// Expose cancel_early, cancel_middle and cancel_late for the desired booking paths.\n// Early returns all held booking cash, whether deposit-only or fully paid. Middle\n// returns held minus the original deposit; a deposit-only booking gets zero.\n// Supplier penalty is based on supplierCost; tax applies to retained margin,\n// and the bound operator receives the remainder. Late returns no buyer cash.\n// Middle opens at earlyAt and ends at lateAt, which is middleAt plus 1ms; late\n// starts there. Default_balance can already cancel a deposit_paid booking at\n// balanceAt, after which no booking cancellation is reachable. Clock order matters.\n// Booking refunds exclude insurance premiums, broker commission and all balances\n// outside booking.held. Expose cover.cancel independently to refund eligible paid\n// premium periods before startsAt; slice.refund is parent-owned. Active/expired\n// premium periods remain excluded. Confirmation timeout returns the full booking\n// price from paid only. A penalty above held cash or retained deposit refuses;\n// this header does not subsidize a shortfall or reduce the configured penalty.\n\n// Cost: booking.create declares one owned account. Deposit also invokes premium\n// collections; cancellation declares the selected refund, penalty, tax and retained\n// moves. Run hsx cost for bounded counts. Supplier penalties are business terms,\n// not compiler or executor fees.\n\ninstrument package(price: money, supplier_cost: money, departure: date) {\n constraints { supplier_cost: at_most(price) }\n summary: \"Immutable package price, supplier cost and departure.\"\n fields { price: money = price, supplierCost: money = supplier_cost, departure: date = departure }\n lifecycle { states: [draft, published, closed], initial: draft }\n action create { requires self.supplierCost <= self.price }\n action publish { from: draft, to: published }\n action close { from: published, to: closed, actor: clock, due: { at: self.departure } }\n}\n\ninstrument booking(package: ref<travel.package>, buyer: party, supplier: party, operator: party = programOperator, cover: ref<insurance.cover>, deposit: percent = 30%, balance_before: duration = 14d, confirm_within: duration = 24h, tax: percent = 15%, early_before: duration = 30d, middle_before: duration = 15d, middle_penalty: percent = 10%, late_penalty: percent = 30%) {\n constraints { early_before: greater_than(middle_before) }\n summary: \"A deposited booking with three cancellation bands and confirmation.\"\n fields {\n package: ref<package>, buyer: account of buyer, supplier: account of supplier\n price: money = self.package.price, supplierCost: money = self.package.supplierCost\n deposit: money = rate(self.price, deposit), balance: money = subtract(self.price, self.deposit)\n margin: money = subtract(self.price, self.supplierCost)\n tax: money = rate(self.margin, tax), operatorNet: money = subtract(self.margin, self.tax)\n middlePenalty: money = rate(self.supplierCost, middle_penalty)\n latePenalty: money = rate(self.supplierCost, late_penalty)\n balanceAt: date = before(self.package.departure, balance_before)\n earlyAt: date = before(self.package.departure, early_before)\n middleAt: date = before(self.package.departure, middle_before)\n lateAt: date = after(self.middleAt, 1ms)\n confirmBy: date = after(self.package.departure, confirm_within)\n held: account of self\n refund: money?, retainedMargin: money?, retainedTax: money?, retainedNet: money?\n }\n lifecycle { states: [created, deposit_paid, paid, completed, cancelled, refunded], initial: created }\n action create {\n requires self.package in [published]\n }\n action deposit { allowZero: true, requires self.price > \"0\";\n from: created, to: deposit_paid, actor: { party: buyer }, deadline: { at: self.balanceAt }\n requires count of { instrument: child(cover, slice), reference: \"covers\", anchor: self.id, states: [pending], limit: 366 } >= 1\n moves self.deposit from buyer to self.held economics { purpose: principal, sourceParty: buyer }\n invoke: [{ selection: { instrument: child(cover, slice), reference: \"covers\", anchor: self.id, states: [pending], limit: 366 }, action: collect, input: {} }]\n }\n action balance { allowZero: true, requires self.price > \"0\";\n from: deposit_paid, to: paid, actor: { party: buyer }, deadline: { at: self.balanceAt }\n moves self.balance from buyer to self.held economics { purpose: principal, sourceParty: buyer }\n }\n action confirm { allowZero: true, requires self.price > \"0\";\n from: paid, to: completed, actor: { party: operator }\n due: { at: self.package.departure }, deadline: { at: self.confirmBy }\n moves self.supplierCost from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.tax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.operatorNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action timeout {\n from: paid, to: refunded, actor: clock, due: { at: self.confirmBy }\n moves self.price from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel_early { allowZero: true, purpose: option, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, deadline: { at: self.earlyAt }\n moves self.held.balance from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel_middle { allowZero: true, purpose: option, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.earlyAt }, deadline: { at: self.lateAt }\n calculate: [\n { target: refund, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.deposit }] }\n { target: retainedMargin, op: \"subtract\", base: { field: self.deposit }, subtract: [{ field: self.middlePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.refund from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n moves self.middlePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action cancel_late { allowZero: true, purpose: option, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.lateAt }\n calculate: [\n { target: retainedMargin, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.latePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action default_balance { allowZero: true, requires self.price > \"0\";\n from: deposit_paid, to: cancelled, actor: clock, due: { at: self.balanceAt }\n calculate: [\n { target: retainedMargin, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.latePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n}\n"],
|
|
14
14
|
["wallet.hsx", "header wallet\n\n// Economics: Topups and withdrawals are excluded prepaid credit. Spending remains\n// unclassified because the bound payee alone does not state the purchase purpose.\n\n// Expose balance.create, activate, topup and withdraw as needed. Holder moves\n// cash only while active. Freeze blocks new topups, withdrawals and spend reserves;\n// close requires no held cash. Freeze/unfreeze use caller operation authority.\n// A separate spend record checks its amount against spendLimit at creation.\n// Expose reserve, pay and cancel for the bound payee. Reserve requires an active\n// wallet before expiresAt; pay posts the whole reservation, cancel/expiry void it.\n// Existing reservations may still post after the wallet freezes. There is no\n// daily aggregate limit, partial spend or card-network settlement in this header.\n\n// Cost: balance.create declares one owned account; topup and withdraw each\n// declare one transfer. Spend reserve, pay and cancel each declare one transfer\n// instruction. These are counts, not the executor tariff.\n\ninstrument balance(holder: party, spend_limit: money = 100000 SAR) {\n summary: \"A holder's reusable balance with an immutable per-spend ceiling.\"\n fields { holder: account of holder, held: account of self, spendLimit: money = spend_limit }\n lifecycle { states: [pending, active, frozen, closed], initial: pending }\n action create { }\n action activate { from: pending, to: active, actor: { party: holder } }\n action topup {\n from: active, to: active, actor: { party: holder }\n input { amount: money }\n moves input.amount from holder to self.held economics { purpose: prepaid_credit, sourceParty: holder }\n }\n action withdraw {\n from: active, to: active, actor: { party: holder }\n input { amount: money }\n moves input.amount from self.held to holder economics { purpose: prepaid_credit, sourceParty: programOperator }\n }\n action freeze { from: active, to: frozen, }\n action unfreeze { from: frozen, to: active, }\n action close { from: [pending, active], to: closed, requires self.held.balance == \"0\" }\n}\n\ninstrument spend(wallet: ref<wallet.balance>, payee: party) {\n summary: \"Reserve one wallet spend, then post or void the same reservation.\"\n fields { wallet: ref<wallet>, amount: money, expiresAt: date, reservation: text? }\n lifecycle { states: [pending, reserved, paid, cancelled, expired], initial: pending }\n action create {\n requires self.wallet in [active]\n requires self.amount <= self.wallet.spendLimit\n }\n action reserve {\n from: pending, to: reserved, actor: { party: payee }\n requires self.wallet in [active]\n deadline: { at: self.expiresAt }\n moves reserve self.amount from self.wallet.held to payee capture \"reservation\"\n }\n action pay { from: reserved, to: paid, actor: { party: payee }, moves post self.reservation }\n action cancel { from: reserved, to: cancelled, actor: { party: payee }, moves void self.reservation }\n action expire { from: reserved, to: expired, actor: clock, due: { at: self.expiresAt }, moves void self.reservation }\n}\n"],
|
|
15
15
|
]);
|
|
16
16
|
//# sourceMappingURL=std-bundle.js.map
|
|
@@ -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,CAAiB;IACpF,CAAC,WAAW,EAAE,2oKAA2oK,CAAC;IAC1pK,CAAC,iBAAiB,EAAE,2sNAA2sN,CAAC;IAChuN,CAAC,YAAY,EAAE,+qHAA+qH,CAAC;IAC/rH,CAAC,eAAe,EAAE,gq9DAAgq9D,CAAC;IACnr9D,CAAC,eAAe,EAAE,01KAA01K,CAAC;IAC72K,CAAC,aAAa,EAAE,qwTAAqwT,CAAC;IACtxT,CAAC,iBAAiB,EAAE,s+TAAs+T,CAAC;IAC3/T,CAAC,WAAW,EAAE,u1VAAu1V,CAAC;IACt2V,CAAC,eAAe,EAAE,649CAA649C,CAAC;IACh69C,CAAC,aAAa,EAAE,85JAA85J,CAAC;IAC/6J,CAAC,YAAY,EAAE,
|
|
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,CAAiB;IACpF,CAAC,WAAW,EAAE,2oKAA2oK,CAAC;IAC1pK,CAAC,iBAAiB,EAAE,2sNAA2sN,CAAC;IAChuN,CAAC,YAAY,EAAE,+qHAA+qH,CAAC;IAC/rH,CAAC,eAAe,EAAE,gq9DAAgq9D,CAAC;IACnr9D,CAAC,eAAe,EAAE,01KAA01K,CAAC;IAC72K,CAAC,aAAa,EAAE,qwTAAqwT,CAAC;IACtxT,CAAC,iBAAiB,EAAE,s+TAAs+T,CAAC;IAC3/T,CAAC,WAAW,EAAE,u1VAAu1V,CAAC;IACt2V,CAAC,eAAe,EAAE,649CAA649C,CAAC;IACh69C,CAAC,aAAa,EAAE,85JAA85J,CAAC;IAC/6J,CAAC,YAAY,EAAE,o7SAAo7S,CAAC;IACp8S,CAAC,YAAY,EAAE,2jGAA2jG,CAAC;CAC5kG,CAAC,CAAC"}
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const HSX_VERSION = "5.
|
|
1
|
+
export declare const HSX_VERSION = "5.6.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const HSX_VERSION = "5.
|
|
1
|
+
export const HSX_VERSION = "5.6.0";
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperscale0/hsx",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.6.0",
|
|
4
4
|
"description": "The strictly typed HSX language: compile total financial programs into canonical UDL.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hsx",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
88
|
"@hyperscale0/adl": "1.0.0-beta.10",
|
|
89
|
-
"@hyperscale0/udl": "4.
|
|
89
|
+
"@hyperscale0/udl": "4.8.0",
|
|
90
90
|
"fast-sha256": "1.3.0"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
@@ -98,5 +98,5 @@
|
|
|
98
98
|
"Amir Ayub",
|
|
99
99
|
"Sara AlBakaawi"
|
|
100
100
|
],
|
|
101
|
-
"gitHead": "
|
|
101
|
+
"gitHead": "be567dd18eb45ea3e02adc1f33b8491aa05df135"
|
|
102
102
|
}
|
package/src/compile.ts
CHANGED
|
@@ -56,6 +56,7 @@ export interface CompileDiagnostic extends Diagnostic {
|
|
|
56
56
|
export interface CompileOriginMapEntry {
|
|
57
57
|
path: string;
|
|
58
58
|
span: Span & { line: number; column: number };
|
|
59
|
+
standardBlock?: { key: string; recordPath: string; headerDigest: string };
|
|
59
60
|
}
|
|
60
61
|
export interface AdapterBindingTarget {
|
|
61
62
|
adapter: ProviderAdapter;
|
|
@@ -428,6 +429,10 @@ export function compile(
|
|
|
428
429
|
);
|
|
429
430
|
const templates = new Map<string, InstrumentDecl>();
|
|
430
431
|
const declarationSources = new Map<InstrumentDecl, string>();
|
|
432
|
+
const standardOrigins = new Map<
|
|
433
|
+
InstrumentDecl,
|
|
434
|
+
NonNullable<CompileOriginMapEntry["standardBlock"]>
|
|
435
|
+
>();
|
|
431
436
|
const requirementOrigins = new Map<
|
|
432
437
|
UdlSubjectRequirement,
|
|
433
438
|
{ source: string; span: Span; message: string }
|
|
@@ -447,6 +452,13 @@ export function compile(
|
|
|
447
452
|
if (!content)
|
|
448
453
|
fail(use, `unknown header ${use.name}`, "choose a published header");
|
|
449
454
|
sources.set(use.name, content);
|
|
455
|
+
const bundled = bundledStandardLibrary.source(use.name);
|
|
456
|
+
const headerDigest =
|
|
457
|
+
bundled === content
|
|
458
|
+
? Array.from(sha256(new TextEncoder().encode(content)), (byte) =>
|
|
459
|
+
byte.toString(16).padStart(2, "0"),
|
|
460
|
+
).join("")
|
|
461
|
+
: undefined;
|
|
450
462
|
let header;
|
|
451
463
|
try {
|
|
452
464
|
header = parseHeader(content, use.name);
|
|
@@ -475,6 +487,14 @@ export function compile(
|
|
|
475
487
|
);
|
|
476
488
|
templates.set(prefix, parentDecl);
|
|
477
489
|
declarationSources.set(parentDecl, use.name);
|
|
490
|
+
if (headerDigest) {
|
|
491
|
+
const [, root, ...record] = prefix.split(".");
|
|
492
|
+
standardOrigins.set(parentDecl, {
|
|
493
|
+
key: `${use.name}.${root}`,
|
|
494
|
+
recordPath: record.join("."),
|
|
495
|
+
headerDigest,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
478
498
|
const recs = entries(asBlock(entries(parentDecl.body).get("records")));
|
|
479
499
|
for (const [recName, recBlock] of recs) {
|
|
480
500
|
const recDecl: InstrumentDecl = {
|
|
@@ -663,6 +683,7 @@ export function compile(
|
|
|
663
683
|
exportPath: string;
|
|
664
684
|
revision?: number | undefined;
|
|
665
685
|
},
|
|
686
|
+
standardOrigin?: NonNullable<CompileOriginMapEntry["standardBlock"]>,
|
|
666
687
|
) => {
|
|
667
688
|
const resolveFamilyInstruments = (
|
|
668
689
|
family: UdlFamily,
|
|
@@ -2847,6 +2868,7 @@ export function compile(
|
|
|
2847
2868
|
origins.push({
|
|
2848
2869
|
path: `$.instruments[${document.instruments.length}]`,
|
|
2849
2870
|
span: { ...origin, ...lineColAt(source, origin.start) },
|
|
2871
|
+
...(standardOrigin ? { standardBlock: standardOrigin } : {}),
|
|
2850
2872
|
});
|
|
2851
2873
|
if (familyDeclaration && familyDeclaration.revision !== undefined) {
|
|
2852
2874
|
inst.family = {
|
|
@@ -2904,6 +2926,14 @@ export function compile(
|
|
|
2904
2926
|
enums,
|
|
2905
2927
|
childAttachment,
|
|
2906
2928
|
childFamily,
|
|
2929
|
+
standardOrigin
|
|
2930
|
+
? {
|
|
2931
|
+
...standardOrigin,
|
|
2932
|
+
recordPath: [standardOrigin.recordPath, key]
|
|
2933
|
+
.filter(Boolean)
|
|
2934
|
+
.join("."),
|
|
2935
|
+
}
|
|
2936
|
+
: undefined,
|
|
2907
2937
|
);
|
|
2908
2938
|
}
|
|
2909
2939
|
};
|
|
@@ -3035,6 +3065,7 @@ export function compile(
|
|
|
3035
3065
|
attachments,
|
|
3036
3066
|
},
|
|
3037
3067
|
templateFamily ? { ...templateFamily } : undefined,
|
|
3068
|
+
standardOrigins.get(template),
|
|
3038
3069
|
);
|
|
3039
3070
|
} catch (error) {
|
|
3040
3071
|
if (!(error instanceof CompileFailure)) throw error;
|
|
@@ -3180,6 +3211,7 @@ export function compile(
|
|
|
3180
3211
|
new Map(),
|
|
3181
3212
|
undefined,
|
|
3182
3213
|
templateFamily ? { ...templateFamily } : undefined,
|
|
3214
|
+
standardOrigins.get(template),
|
|
3183
3215
|
);
|
|
3184
3216
|
}
|
|
3185
3217
|
if (decl.kind === "object") {
|
package/src/std-bundle.ts
CHANGED
|
@@ -11,6 +11,6 @@ export const BUNDLED_STD_FILES: ReadonlyMap<string, string> = new Map<string, st
|
|
|
11
11
|
["money.hsx", "header money\n\n// Economics: Held funding and returns are principal. Release to the company realizes\n// earnings; release to another participant is a payout. Generic transfers, splits,\n// schedules, swaps, boundary payouts and metered fees retain no assumed purpose.\n\n// Expose each attachment's create and caller actions explicitly. A transfer or\n// split pays once; a hold exposes fund, release and refund separately. Release\n// pays payee and refund returns payer. A hold has no dispute or damage decision.\n// A schedule needs count unique occurrence records before activation; each due\n// occurrence pays only while the schedule is active. A due time promises no retry.\n// A pool accepts whole contributions only up to its remaining target and at most\n// 366 paid records. Expose pay to release the exact target. Clock failure refunds\n// original contributors; excess acceptance and partial contribution are absent.\n// A swap reserves both legs before exchange or voids reservations on expiry.\n// Payout instruct reserves across the selected adapter; confirm/reject require\n// matching terminal instruction evidence. An acknowledgement cannot settle it.\n// Metered bill charges a unique usage identity at the fixed unit price.\n\n// Cost: transfer.pay declares one transfer. Hold.create declares one owned account;\n// fund, release and refund each declare one transfer. Schedules and pools add bounded\n// child invocations. Run hsx cost on the composed program for counts, not SAR prices.\n\ninstrument transfer(payer: party, payee: party, amount: money = runtime) {\n summary: \"One transfer between the bound parties.\"\n fields { amount: money = amount }\n lifecycle { states: [pending, paid, cancelled], initial: pending }\n action create { actor: { party: payer }, requires self.amount > \"0\" }\n action pay {\n from: pending, to: paid, actor: { party: payer }\n moves self.amount from payer to payee\n }\n action cancel { from: pending, to: cancelled, actor: { party: payer } }\n}\n\ninstrument hold(payer: party, payee: party, amount: money = runtime) {\n summary: \"Hold the declared amount until release or refund.\"\n fields { payer: account of payer, payee: account of payee, amount: money = amount, price: money = self.amount, held: account of self }\n lifecycle { states: [pending, funded, released, refunded, cancelled], initial: pending }\n action create { }\n action fund {\n from: pending, to: funded, actor: { party: payer }\n moves self.amount from payer to self.held economics { purpose: principal, sourceParty: payer }\n }\n action confirm {\n from: pending, to: funded\n requires self.held.balance == self.amount\n }\n action release {\n from: funded, to: released, actor: { party: payer }\n moves self.amount from self.held to payee economics { recipient: payee, company: { purpose: earning, sourceParty: payer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action refund {\n from: funded, to: refunded, actor: { party: payee }\n moves self.amount from self.held to payer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel { from: pending, to: cancelled }\n}\n\ninstrument split(payer: party, amount: money = runtime, shares: split = { programOperator: 100% }) {\n summary: \"Split one amount; the last declared recipient receives the rounding remainder.\"\n fields { amount: money = amount }\n lifecycle { states: [pending, paid, cancelled], initial: pending }\n action create {}\n action pay { allowZero: true, requires self.amount > \"0\"; from: pending, to: paid, actor: { party: payer }, moves self.amount from payer shares shares }\n action cancel { from: pending, to: cancelled }\n}\n\ninstrument schedule(payer: party, payee: party, amount: money = runtime, count: integer(1, 366) = 12) {\n summary: \"A finite schedule whose dated pieces sum exactly to the declared total.\"\n fields { amount: money = amount, count: integer = count, dates: list(date, count) }\n lifecycle { states: [draft, active, complete, cancelled], initial: draft }\n action create {}\n action activate {\n from: draft, to: active\n requires count of { instrument: occurrence, reference: \"schedule\", anchor: self.id, states: [pending], limit: 366 } == self.count\n }\n action complete {\n from: active, to: complete\n requires count of { instrument: occurrence, reference: \"schedule\", anchor: self.id, states: [pending], limit: 366 } == 0\n }\n action cancel { from: [draft, active], to: cancelled }\n records {\n occurrence: {\n fields {\n schedule: ref<parent>, position: integer(1, count), dueAt: date = at(self.schedule.dates, self.position)\n base: money = divide(self.schedule.amount, count)\n allocated: money = multiply(self.base, count)\n remainder: money = subtract(self.schedule.amount, self.allocated)\n first: integer = divide(1, self.position)\n adjustment: money = multiply(self.remainder, self.first)\n amount: money = sum(self.base, self.adjustment)\n }\n lifecycle { states: [pending, paid, cancelled], initial: pending }\n action create { requires self.schedule in [draft]; requires unique \"scheduled_position\" on [self.schedule, self.position] }\n action pay { allowZero: true, from: pending, to: paid, actor: clock, due: { at: self.dueAt }, requires self.schedule in [active], moves self.amount from payer to payee }\n action cancel { from: pending, to: cancelled, requires self.schedule in [cancelled] }\n }\n }\n}\n\ninstrument pool(payer: party, payee: party, target: money, closes: date) {\n summary: \"Contributions fund one threshold or return to their original contributor.\"\n fields { target: money = target, closesAt: date = closes, held: account of self }\n lifecycle { states: [open, paid, failed], initial: open }\n action create { }\n action pay {\n from: open, to: paid, actor: { party: payee }\n requires self.held.balance == self.target\n moves self.target from self.held to payee economics { recipient: payee, company: { purpose: earning, sourceParty: payer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action fail {\n from: open, to: failed, actor: clock, due: { at: self.closesAt }\n requires self.held.balance < self.target\n invoke: [{ selection: { instrument: contribution, reference: \"pool\", anchor: self.id, states: [paid], limit: 366 }, action: refund, input: {} }]\n }\n records {\n contribution: {\n fields { pool: ref<parent>, payer: account of payer, amount: money, remaining: money? }\n lifecycle { states: [pending, paid, refunded], initial: pending }\n invariants count of { instrument: current(), reference: \"pool\", anchor: self.pool, states: [paid], limit: 366 } <= 366\n action create { requires self.pool in [open] }\n action pay { from: pending, to: paid, actor: { party: payer }, deadline: { at: self.pool.closesAt }, requires self.pool in [open], calculate: [{ target: remaining, op: subtract, base: { field: self.pool.target }, subtract: [{ field: self.pool.held.balance }] }], requires self.amount <= self.remaining, moves self.amount from self.payer to self.pool.held economics { purpose: principal, sourceParty: payer } }\n action refund { from: paid, to: refunded, actor: { parent: parent }, moves self.amount from self.pool.held to self.payer economics { purpose: principal, sourceParty: programOperator } }\n }\n }\n}\n\ninstrument swap(first: party, second: party, first_amount: money, second_amount: money, expires: date) {\n summary: \"Two reservations settle together or both return.\"\n fields { firstAmount: money = first_amount, secondAmount: money = second_amount, expiresAt: date = expires, firstReceipt: text?, secondReceipt: text? }\n lifecycle { states: [pending, first_ready, second_ready, both_ready, exchanged, cancelled], initial: pending }\n action create {}\n action fund_first { from: pending, to: first_ready, actor: { party: first }, deadline: { at: self.expiresAt }, moves reserve self.firstAmount from first to second capture \"firstReceipt\" }\n action fund_second { from: first_ready, to: both_ready, actor: { party: second }, deadline: { at: self.expiresAt }, moves reserve self.secondAmount from second to first capture \"secondReceipt\" }\n action start_second { from: pending, to: second_ready, actor: { party: second }, deadline: { at: self.expiresAt }, moves reserve self.secondAmount from second to first capture \"secondReceipt\" }\n action finish_first { from: second_ready, to: both_ready, actor: { party: first }, deadline: { at: self.expiresAt }, moves reserve self.firstAmount from first to second capture \"firstReceipt\" }\n action expire_second { from: second_ready, to: cancelled, actor: clock, due: { at: self.expiresAt }, moves void self.secondReceipt }\n action exchange { from: both_ready, to: exchanged, actor: { party: first }, moves post self.firstReceipt; moves post self.secondReceipt }\n action cancel { from: pending, to: cancelled }\n action expire_first { from: first_ready, to: cancelled, actor: clock, due: { at: self.expiresAt }, moves void self.firstReceipt }\n action expire_both { from: both_ready, to: cancelled, actor: clock, due: { at: self.expiresAt }, moves void self.firstReceipt; moves void self.secondReceipt }\n}\n\ninstrument payout(payer: party, payee: party, adapter: text, max_age: duration, amount: money = runtime) {\n summary: \"Reserve funds until matching terminal boundary evidence permits posting.\"\n fields { amount: money = amount, receipt: text? }\n lifecycle { states: [pending, instructed, settled, rejected], initial: pending }\n action create {}\n action instruct {\n from: pending, to: instructed, actor: { party: payer }\n moves reserve self.amount from payer to payee capture \"receipt\" boundary adapter\n }\n action confirm {\n from: instructed, to: settled\n requires evidence self.id family boundary check outcome result confirmed maxAge max_age instruction self.receipt\n moves post self.receipt\n }\n action reject {\n from: instructed, to: rejected\n requires evidence self.id family boundary check outcome result rejected maxAge max_age instruction self.receipt\n moves void self.receipt\n }\n}\n\ninstrument metered(payer: party, payee: party, unit_price: money, units: integer = 1, fee: fee = { seller: 0% }) {\n summary: \"A unique usage event priced once at the fixed unit price.\"\n fields { usageIdentity: text, unitPrice: money = unit_price, units: integer = units, amount: money = multiply(self.unitPrice, self.units) }\n lifecycle { states: [recorded, billed, cancelled], initial: recorded }\n action create { requires unique \"usage_event\" on [self.usageIdentity] }\n action bill { allowZero: true, requires self.amount > \"0\"; from: recorded, to: billed, actor: { party: payee }, moves self.amount from payer to payee fee fee }\n action cancel { from: recorded, to: cancelled }\n}\n"],
|
|
12
12
|
["reporting.hsx", "header reporting\n\n// Attach portfolio to one or more financing plans. Its only lifecycle action is\n// create; reports use the declared report request/read roles, not a money action.\n// Aging selects active facilities and includes earned profit when deciding arrears.\n// The default-rate report measures period-end stock, not new default incidence.\n// Paid facilities are excluded and write-offs counted separately. Amounts are SAR\n// minor units; declared scale and rounding govern ratios. Missing identity joins\n// or unreconciled schedule counts refuse. Origination cohorts and bureau output\n// explicitly refuse until their unavailable governed facts exist. No bureau\n// submission, provider layout, external transport or restructuring proof is supplied.\n\n// Cost: portfolio.create declares no transfers, owned accounts or invocations.\n// That zero instruction count does not price report capture, rendering, storage or\n// release. The host owns those charges and their execution.\n\ninstrument portfolio(on: ref<financing.installments>[], default_days: integer(1, 3650) = 90, retention_years: integer(1, 100) = 10, aging_first_days: integer(1, 3650) = 30, aging_second_days: integer(1, 3650) = 60, aging_third_days: integer(1, 3650) = 90, ratio_scale: integer(1, 1000000) = 10000, ratio_rounding: enum(floor, halfUp) = floor, lock_wait_ms: integer(1, 2000) = 2000, capture_ms: integer(1, 10000) = 10000, max_rows: integer(1, 100000) = 10000, max_join_rows: integer(1, 1000000) = 100000, max_bytes: integer(1024, 16777216) = 8388608) {\n summary: \"Declared financing reports evaluated over frozen Product facts.\"\n fields {}\n lifecycle { states: [declared], initial: declared }\n action create {}\n constraints { aging_first_days: less_than(aging_second_days), aging_second_days: less_than(aging_third_days) }\n reports: [\n {\n identity: { id: \"portfolio_aging\", version: 1, description: \"Period-end outstanding principal by oldest unpaid installment. Remaining scheduled profit is distinct from accrued profit. Restructuring evidence is unavailable.\" },\n scope: { kind: \"product\", classification: \"internal\", currency: \"SAR\" },\n datasets: [\n {\n id: \"facilities\",\n source: \"instrument\",\n instruments: on,\n rowKey: \"facilityId\",\n columns: [\n {\n name: \"facilityId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"borrowerAccount\",\n field: \"borrower\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"state\",\n field: \"status\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"originalPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduleCount\",\n field: \"months\",\n type: { kind: \"integer\" },\n required: true\n },\n {\n name: \"recordedCreation\",\n field: \"createdAt\",\n type: { kind: \"date\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"activeState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"active\"\n },\n {\n id: \"paidState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"paid\"\n },\n {\n id: \"writtenState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"written_off\"\n },\n { id: \"active\", op: \"equal\", left: \"state\", right: \"activeState\" },\n { id: \"paid\", op: \"equal\", left: \"state\", right: \"paidState\" },\n { id: \"writtenOff\", op: \"equal\", left: \"state\", right: \"writtenState\" },\n { id: \"activeOrPaid\", op: \"or\", left: \"active\", right: \"paid\" },\n { id: \"financed\", op: \"or\", left: \"active\", right: \"writtenOff\" }\n ],\n selection: \"active\"\n },\n {\n id: \"schedule\",\n source: \"instrument\",\n instruments: child(on, slice),\n rowKey: \"sliceId\",\n columns: [\n {\n name: \"sliceId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"planId\",\n field: \"plan\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"due\",\n field: \"dueAt\",\n type: { kind: \"date\" },\n required: true\n },\n {\n name: \"principal\",\n field: \"principalReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"profit\",\n field: \"profitReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"earnedProfit\",\n field: \"profitEarned.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduledPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n {\n id: \"zeroDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n { id: \"observed\", op: \"parameter\", name: \"observationAt\" },\n { id: \"scheduledOutstanding\", op: \"sum\", left: \"principal\", right: \"profit\" },\n { id: \"totalOutstanding\", op: \"sum\", left: \"scheduledOutstanding\", right: \"earnedProfit\" },\n { id: \"unpaid\", op: \"less\", left: \"zeroMoney\", right: \"totalOutstanding\" },\n { id: \"elapsed\", op: \"daysBetween\", left: \"due\", right: \"observed\" },\n { id: \"nonnegativeDays\", op: \"maximum\", left: \"elapsed\", right: \"zeroDays\" },\n { id: \"daysPastDue\", op: \"choose\", condition: \"unpaid\", yes: \"nonnegativeDays\", no: \"zeroDays\" }\n ]\n },\n {\n id: \"borrowerAccounts\",\n source: \"account\",\n instruments: [ ],\n rowKey: \"accountId\",\n columns: [\n {\n name: \"accountId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participant\",\n field: \"ownerParticipantId\",\n type: { kind: \"text\" },\n required: false\n }\n ],\n expressions: [ ]\n },\n {\n id: \"borrowers\",\n source: \"identity\",\n instruments: [ ],\n rowKey: \"customerId\",\n columns: [\n {\n name: \"customerId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participantId\",\n field: \"participantId\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"entityId\",\n field: \"entityId\",\n type: { kind: \"text\" },\n required: true\n }\n ],\n expressions: [ ]\n }\n ],\n time: { timezone: \"Asia/Riyadh\", boundary: \"startInclusiveEndExclusive\", observation: \"periodEnd\", history: \"retainedOnly\" },\n selection: { dataset: \"facilities\" },\n calculation: {\n joins: [\n {\n dataset: \"schedule\",\n local: \"facilityId\",\n foreign: \"planId\",\n cardinality: \"many\",\n missing: \"refuse\",\n aggregates: [\n { name: \"outstandingPrincipal\", op: \"sum\", value: \"principal\" },\n { name: \"remainingScheduledProfit\", op: \"sum\", value: \"profit\" },\n { name: \"scheduledPrincipalTotal\", op: \"sum\", value: \"scheduledPrincipal\" },\n { name: \"capturedScheduleCount\", op: \"count\" },\n { name: \"oldestUnpaidDays\", op: \"maximum\", value: \"daysPastDue\" }\n ]\n },\n {\n dataset: \"borrowerAccounts\",\n local: \"borrowerAccount\",\n foreign: \"accountId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerParticipant\", op: \"minimum\", value: \"participant\" }\n ]\n },\n {\n dataset: \"borrowers\",\n local: \"borrowerParticipant\",\n foreign: \"participantId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerEntity\", op: \"minimum\", value: \"entityId\" }\n ]\n }\n ],\n expressions: [\n {\n id: \"day0\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n {\n id: \"day30\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: aging_first_days\n },\n {\n id: \"day60\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: aging_second_days\n },\n {\n id: \"day90\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: aging_third_days\n },\n {\n id: \"band0\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"current\"\n },\n {\n id: \"band30\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"first\"\n },\n {\n id: \"band60\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"second\"\n },\n {\n id: \"band90\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"third\"\n },\n {\n id: \"bandLate\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"later\"\n },\n { id: \"current\", op: \"atMost\", left: \"oldestUnpaidDays\", right: \"day0\" },\n { id: \"first\", op: \"atMost\", left: \"oldestUnpaidDays\", right: \"day30\" },\n { id: \"second\", op: \"atMost\", left: \"oldestUnpaidDays\", right: \"day60\" },\n { id: \"third\", op: \"atMost\", left: \"oldestUnpaidDays\", right: \"day90\" },\n { id: \"lateBand\", op: \"choose\", condition: \"third\", yes: \"band90\", no: \"bandLate\" },\n { id: \"secondBand\", op: \"choose\", condition: \"second\", yes: \"band60\", no: \"lateBand\" },\n { id: \"firstBand\", op: \"choose\", condition: \"first\", yes: \"band30\", no: \"secondBand\" },\n { id: \"agingBand\", op: \"choose\", condition: \"current\", yes: \"band0\", no: \"firstBand\" }\n ],\n groupBy: [ \"agingBand\" ],\n aggregates: [\n { name: \"facilities\", op: \"count\" },\n { name: \"principalMinor\", op: \"sum\", value: \"outstandingPrincipal\" },\n { name: \"scheduledProfitMinor\", op: \"sum\", value: \"remainingScheduledProfit\" }\n ],\n resultExpressions: [ ]\n },\n validation: {\n empty: \"noEligibleFacilities\",\n required: [ \"borrowerEntity\" ],\n reconcile: [ ],\n rowReconcile: [\n { left: \"originalPrincipal\", right: \"scheduledPrincipalTotal\" },\n { left: \"scheduleCount\", right: \"capturedScheduleCount\" }\n ],\n unavailableFacts: [ ],\n lockTimeoutMs: lock_wait_ms,\n captureTimeoutMs: capture_ms,\n maxRows: max_rows,\n maxJoinRows: max_join_rows,\n maxBytes: max_bytes\n },\n output: {\n profile: \"internal.v1\",\n formats: [ \"json\", \"csv\" ],\n columns: [\n {\n name: \"agingBand\",\n label: \"agingBand\",\n type: { kind: \"text\" }\n },\n {\n name: \"facilities\",\n label: \"facilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"principalMinor\",\n label: \"principalMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n },\n {\n name: \"scheduledProfitMinor\",\n label: \"scheduledProfitMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n }\n ],\n sort: [ \"agingBand\" ]\n },\n authority: {\n request: [ \"owner\", \"finance\" ],\n read: [ \"owner\", \"admin\", \"operations\", \"finance\", \"viewer\" ],\n release: [ ],\n retention: { policy: \"report_replay\", years: retention_years }\n }\n },\n {\n identity: { id: \"origination_cohorts\", version: 1, description: \"Origination cohort performance. Refuses until business-effective origination dates and dated repayment allocation are retained; record creation time is not origination.\" },\n scope: { kind: \"product\", classification: \"internal\", currency: \"SAR\" },\n datasets: [\n {\n id: \"facilities\",\n source: \"instrument\",\n instruments: on,\n rowKey: \"facilityId\",\n columns: [\n {\n name: \"facilityId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"borrowerAccount\",\n field: \"borrower\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"state\",\n field: \"status\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"originalPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduleCount\",\n field: \"months\",\n type: { kind: \"integer\" },\n required: true\n },\n {\n name: \"recordedCreation\",\n field: \"createdAt\",\n type: { kind: \"date\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"activeState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"active\"\n },\n {\n id: \"paidState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"paid\"\n },\n {\n id: \"writtenState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"written_off\"\n },\n { id: \"active\", op: \"equal\", left: \"state\", right: \"activeState\" },\n { id: \"paid\", op: \"equal\", left: \"state\", right: \"paidState\" },\n { id: \"writtenOff\", op: \"equal\", left: \"state\", right: \"writtenState\" },\n { id: \"activeOrPaid\", op: \"or\", left: \"active\", right: \"paid\" },\n { id: \"financed\", op: \"or\", left: \"active\", right: \"writtenOff\" }\n ],\n selection: \"financed\"\n },\n {\n id: \"schedule\",\n source: \"instrument\",\n instruments: child(on, slice),\n rowKey: \"sliceId\",\n columns: [\n {\n name: \"sliceId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"planId\",\n field: \"plan\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"due\",\n field: \"dueAt\",\n type: { kind: \"date\" },\n required: true\n },\n {\n name: \"principal\",\n field: \"principalReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"profit\",\n field: \"profitReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"earnedProfit\",\n field: \"profitEarned.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduledPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n {\n id: \"zeroDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n { id: \"observed\", op: \"parameter\", name: \"observationAt\" },\n { id: \"scheduledOutstanding\", op: \"sum\", left: \"principal\", right: \"profit\" },\n { id: \"totalOutstanding\", op: \"sum\", left: \"scheduledOutstanding\", right: \"earnedProfit\" },\n { id: \"unpaid\", op: \"less\", left: \"zeroMoney\", right: \"totalOutstanding\" },\n { id: \"elapsed\", op: \"daysBetween\", left: \"due\", right: \"observed\" },\n { id: \"nonnegativeDays\", op: \"maximum\", left: \"elapsed\", right: \"zeroDays\" },\n { id: \"daysPastDue\", op: \"choose\", condition: \"unpaid\", yes: \"nonnegativeDays\", no: \"zeroDays\" }\n ]\n },\n {\n id: \"borrowerAccounts\",\n source: \"account\",\n instruments: [ ],\n rowKey: \"accountId\",\n columns: [\n {\n name: \"accountId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participant\",\n field: \"ownerParticipantId\",\n type: { kind: \"text\" },\n required: false\n }\n ],\n expressions: [ ]\n },\n {\n id: \"borrowers\",\n source: \"identity\",\n instruments: [ ],\n rowKey: \"customerId\",\n columns: [\n {\n name: \"customerId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participantId\",\n field: \"participantId\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"entityId\",\n field: \"entityId\",\n type: { kind: \"text\" },\n required: true\n }\n ],\n expressions: [ ]\n }\n ],\n time: { timezone: \"Asia/Riyadh\", boundary: \"startInclusiveEndExclusive\", observation: \"periodEnd\", history: \"retainedOnly\" },\n selection: { dataset: \"facilities\" },\n calculation: {\n joins: [\n {\n dataset: \"schedule\",\n local: \"facilityId\",\n foreign: \"planId\",\n cardinality: \"many\",\n missing: \"refuse\",\n aggregates: [\n { name: \"outstandingPrincipal\", op: \"sum\", value: \"principal\" },\n { name: \"remainingScheduledProfit\", op: \"sum\", value: \"profit\" },\n { name: \"scheduledPrincipalTotal\", op: \"sum\", value: \"scheduledPrincipal\" },\n { name: \"capturedScheduleCount\", op: \"count\" },\n { name: \"oldestUnpaidDays\", op: \"maximum\", value: \"daysPastDue\" }\n ]\n },\n {\n dataset: \"borrowerAccounts\",\n local: \"borrowerAccount\",\n foreign: \"accountId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerParticipant\", op: \"minimum\", value: \"participant\" }\n ]\n },\n {\n dataset: \"borrowers\",\n local: \"borrowerParticipant\",\n foreign: \"participantId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerEntity\", op: \"minimum\", value: \"entityId\" }\n ]\n }\n ],\n expressions: [\n { id: \"recordedMonth\", op: \"bucket\", value: \"recordedCreation\", unit: \"month\" }\n ],\n groupBy: [ \"recordedMonth\" ],\n aggregates: [\n { name: \"facilities\", op: \"count\" },\n { name: \"principalMinor\", op: \"sum\", value: \"outstandingPrincipal\" }\n ],\n resultExpressions: [ ]\n },\n validation: {\n empty: \"noEligibleFacilities\",\n required: [ \"borrowerEntity\" ],\n reconcile: [ ],\n rowReconcile: [\n { left: \"originalPrincipal\", right: \"scheduledPrincipalTotal\" },\n { left: \"scheduleCount\", right: \"capturedScheduleCount\" }\n ],\n unavailableFacts: [ \"business-effective origination timestamp\", \"dated repayment allocation and recovery history\" ],\n lockTimeoutMs: lock_wait_ms,\n captureTimeoutMs: capture_ms,\n maxRows: max_rows,\n maxJoinRows: max_join_rows,\n maxBytes: max_bytes\n },\n output: {\n profile: \"internal.v1\",\n formats: [ \"json\", \"csv\" ],\n columns: [\n {\n name: \"recordedMonth\",\n label: \"recordedMonth\",\n type: { kind: \"text\" }\n },\n {\n name: \"facilities\",\n label: \"facilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"principalMinor\",\n label: \"principalMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n }\n ],\n sort: [ \"recordedMonth\" ]\n },\n authority: {\n request: [ \"owner\", \"finance\" ],\n read: [ \"owner\", \"admin\", \"operations\", \"finance\", \"viewer\" ],\n release: [ ],\n retention: { policy: \"report_replay\", years: retention_years }\n }\n },\n {\n identity: { id: \"period_end_outstanding_principal_default_rate\", version: 1, description: \"Current active facilities with any unpaid installment at least the declared default days past due, observed at period end. Cure when arrears clear. Count and outstanding-principal weighted rates in the declared scale exclude paid and written-off facilities; write-offs are counted separately. This is a stock measure, not a new-default incidence or origination cohort rate.\" },\n scope: { kind: \"product\", classification: \"internal\", currency: \"SAR\" },\n datasets: [\n {\n id: \"facilities\",\n source: \"instrument\",\n instruments: on,\n rowKey: \"facilityId\",\n columns: [\n {\n name: \"facilityId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"borrowerAccount\",\n field: \"borrower\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"state\",\n field: \"status\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"originalPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduleCount\",\n field: \"months\",\n type: { kind: \"integer\" },\n required: true\n },\n {\n name: \"recordedCreation\",\n field: \"createdAt\",\n type: { kind: \"date\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"activeState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"active\"\n },\n {\n id: \"paidState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"paid\"\n },\n {\n id: \"writtenState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"written_off\"\n },\n { id: \"active\", op: \"equal\", left: \"state\", right: \"activeState\" },\n { id: \"paid\", op: \"equal\", left: \"state\", right: \"paidState\" },\n { id: \"writtenOff\", op: \"equal\", left: \"state\", right: \"writtenState\" },\n { id: \"activeOrPaid\", op: \"or\", left: \"active\", right: \"paid\" },\n { id: \"financed\", op: \"or\", left: \"active\", right: \"writtenOff\" }\n ],\n selection: \"financed\"\n },\n {\n id: \"schedule\",\n source: \"instrument\",\n instruments: child(on, slice),\n rowKey: \"sliceId\",\n columns: [\n {\n name: \"sliceId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"planId\",\n field: \"plan\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"due\",\n field: \"dueAt\",\n type: { kind: \"date\" },\n required: true\n },\n {\n name: \"principal\",\n field: \"principalReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"profit\",\n field: \"profitReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"earnedProfit\",\n field: \"profitEarned.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduledPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n {\n id: \"zeroDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n { id: \"observed\", op: \"parameter\", name: \"observationAt\" },\n { id: \"scheduledOutstanding\", op: \"sum\", left: \"principal\", right: \"profit\" },\n { id: \"totalOutstanding\", op: \"sum\", left: \"scheduledOutstanding\", right: \"earnedProfit\" },\n { id: \"unpaid\", op: \"less\", left: \"zeroMoney\", right: \"totalOutstanding\" },\n { id: \"elapsed\", op: \"daysBetween\", left: \"due\", right: \"observed\" },\n { id: \"nonnegativeDays\", op: \"maximum\", left: \"elapsed\", right: \"zeroDays\" },\n { id: \"daysPastDue\", op: \"choose\", condition: \"unpaid\", yes: \"nonnegativeDays\", no: \"zeroDays\" }\n ]\n },\n {\n id: \"borrowerAccounts\",\n source: \"account\",\n instruments: [ ],\n rowKey: \"accountId\",\n columns: [\n {\n name: \"accountId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participant\",\n field: \"ownerParticipantId\",\n type: { kind: \"text\" },\n required: false\n }\n ],\n expressions: [ ]\n },\n {\n id: \"borrowers\",\n source: \"identity\",\n instruments: [ ],\n rowKey: \"customerId\",\n columns: [\n {\n name: \"customerId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participantId\",\n field: \"participantId\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"entityId\",\n field: \"entityId\",\n type: { kind: \"text\" },\n required: true\n }\n ],\n expressions: [ ]\n }\n ],\n time: { timezone: \"Asia/Riyadh\", boundary: \"startInclusiveEndExclusive\", observation: \"periodEnd\", history: \"retainedOnly\" },\n selection: { dataset: \"facilities\" },\n calculation: {\n joins: [\n {\n dataset: \"schedule\",\n local: \"facilityId\",\n foreign: \"planId\",\n cardinality: \"many\",\n missing: \"refuse\",\n aggregates: [\n { name: \"outstandingPrincipal\", op: \"sum\", value: \"principal\" },\n { name: \"remainingScheduledProfit\", op: \"sum\", value: \"profit\" },\n { name: \"scheduledPrincipalTotal\", op: \"sum\", value: \"scheduledPrincipal\" },\n { name: \"capturedScheduleCount\", op: \"count\" },\n { name: \"oldestUnpaidDays\", op: \"maximum\", value: \"daysPastDue\" }\n ]\n },\n {\n dataset: \"borrowerAccounts\",\n local: \"borrowerAccount\",\n foreign: \"accountId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerParticipant\", op: \"minimum\", value: \"participant\" }\n ]\n },\n {\n dataset: \"borrowers\",\n local: \"borrowerParticipant\",\n foreign: \"participantId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerEntity\", op: \"minimum\", value: \"entityId\" }\n ]\n }\n ],\n expressions: [\n {\n id: \"threshold\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: default_days\n },\n {\n id: \"zero\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n {\n id: \"one\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 1\n },\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n { id: \"pastThreshold\", op: \"atMost\", left: \"threshold\", right: \"oldestUnpaidDays\" },\n { id: \"isDefault\", op: \"and\", left: \"active\", right: \"pastThreshold\" },\n { id: \"activeCount\", op: \"choose\", condition: \"active\", yes: \"one\", no: \"zero\" },\n { id: \"defaultCount\", op: \"choose\", condition: \"isDefault\", yes: \"one\", no: \"zero\" },\n { id: \"writeOffCount\", op: \"choose\", condition: \"writtenOff\", yes: \"one\", no: \"zero\" },\n { id: \"activePrincipal\", op: \"choose\", condition: \"active\", yes: \"outstandingPrincipal\", no: \"zeroMoney\" },\n { id: \"defaultPrincipal\", op: \"choose\", condition: \"isDefault\", yes: \"outstandingPrincipal\", no: \"zeroMoney\" }\n ],\n groupBy: [ ],\n aggregates: [\n { name: \"activeFacilities\", op: \"sum\", value: \"activeCount\" },\n { name: \"defaultFacilities\", op: \"sum\", value: \"defaultCount\" },\n { name: \"writtenOffFacilities\", op: \"sum\", value: \"writeOffCount\" },\n { name: \"activePrincipalMinor\", op: \"sum\", value: \"activePrincipal\" },\n { name: \"defaultPrincipalMinor\", op: \"sum\", value: \"defaultPrincipal\" }\n ],\n resultExpressions: [\n { id: \"countRate\", op: \"ratio\", numerator: \"defaultFacilities\", denominator: \"activeFacilities\", scale: ratio_scale, rounding: ratio_rounding, zero: \"null\" },\n { id: \"principalRate\", op: \"ratio\", numerator: \"defaultPrincipalMinor\", denominator: \"activePrincipalMinor\", scale: ratio_scale, rounding: ratio_rounding, zero: \"null\" },\n {\n id: \"restructuringEvidence\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"unavailable\"\n },\n {\n id: \"defaultDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: default_days\n },\n {\n id: \"rateScale\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: ratio_scale\n }\n ]\n },\n validation: {\n empty: \"refuse\",\n required: [ \"borrowerEntity\" ],\n reconcile: [ ],\n rowReconcile: [\n { left: \"originalPrincipal\", right: \"scheduledPrincipalTotal\" },\n { left: \"scheduleCount\", right: \"capturedScheduleCount\" }\n ],\n unavailableFacts: [ ],\n lockTimeoutMs: lock_wait_ms,\n captureTimeoutMs: capture_ms,\n maxRows: max_rows,\n maxJoinRows: max_join_rows,\n maxBytes: max_bytes\n },\n output: {\n profile: \"internal.v1\",\n formats: [ \"json\", \"csv\" ],\n columns: [\n {\n name: \"activeFacilities\",\n label: \"activeFacilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"defaultFacilities\",\n label: \"defaultFacilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"writtenOffFacilities\",\n label: \"writtenOffFacilities\",\n type: { kind: \"integer\" }\n },\n {\n name: \"activePrincipalMinor\",\n label: \"activePrincipalMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n },\n {\n name: \"defaultPrincipalMinor\",\n label: \"defaultPrincipalMinor\",\n type: { kind: \"money\", currency: \"SAR\" }\n },\n {\n name: \"countRate\",\n label: \"countRate\",\n type: { kind: \"integer\" }\n },\n {\n name: \"principalRate\",\n label: \"principalRate\",\n type: { kind: \"integer\" }\n },\n {\n name: \"restructuringEvidence\",\n label: \"restructuringEvidence\",\n type: { kind: \"text\" }\n },\n {\n name: \"defaultDays\",\n label: \"defaultDays\",\n type: { kind: \"integer\" }\n },\n {\n name: \"rateScale\",\n label: \"rateScale\",\n type: { kind: \"integer\" }\n }\n ],\n sort: [ \"activeFacilities\" ]\n },\n authority: {\n request: [ \"owner\", \"finance\" ],\n read: [ \"owner\", \"admin\", \"operations\", \"finance\", \"viewer\" ],\n release: [ ],\n retention: { policy: \"report_replay\", years: retention_years }\n }\n },\n {\n identity: { id: \"bureau_facility\", version: 1, description: \"Bureau facility definition only. No submission, provider layout or transport is admitted until the member specification and required governed facts exist.\" },\n scope: { kind: \"product\", classification: \"internal\", currency: \"SAR\" },\n datasets: [\n {\n id: \"facilities\",\n source: \"instrument\",\n instruments: on,\n rowKey: \"facilityId\",\n columns: [\n {\n name: \"facilityId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"borrowerAccount\",\n field: \"borrower\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"state\",\n field: \"status\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"originalPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduleCount\",\n field: \"months\",\n type: { kind: \"integer\" },\n required: true\n },\n {\n name: \"recordedCreation\",\n field: \"createdAt\",\n type: { kind: \"date\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"activeState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"active\"\n },\n {\n id: \"paidState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"paid\"\n },\n {\n id: \"writtenState\",\n op: \"literal\",\n type: { kind: \"text\" },\n value: \"written_off\"\n },\n { id: \"active\", op: \"equal\", left: \"state\", right: \"activeState\" },\n { id: \"paid\", op: \"equal\", left: \"state\", right: \"paidState\" },\n { id: \"writtenOff\", op: \"equal\", left: \"state\", right: \"writtenState\" },\n { id: \"activeOrPaid\", op: \"or\", left: \"active\", right: \"paid\" },\n { id: \"financed\", op: \"or\", left: \"active\", right: \"writtenOff\" }\n ],\n selection: \"financed\"\n },\n {\n id: \"schedule\",\n source: \"instrument\",\n instruments: child(on, slice),\n rowKey: \"sliceId\",\n columns: [\n {\n name: \"sliceId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"planId\",\n field: \"plan\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"due\",\n field: \"dueAt\",\n type: { kind: \"date\" },\n required: true\n },\n {\n name: \"principal\",\n field: \"principalReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"profit\",\n field: \"profitReceivable.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"earnedProfit\",\n field: \"profitEarned.balance\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n },\n {\n name: \"scheduledPrincipal\",\n field: \"principal\",\n type: { kind: \"money\", currency: \"SAR\" },\n required: true\n }\n ],\n expressions: [\n {\n id: \"zeroMoney\",\n op: \"literal\",\n type: { kind: \"money\", currency: \"SAR\" },\n value: \"0\"\n },\n {\n id: \"zeroDays\",\n op: \"literal\",\n type: { kind: \"integer\" },\n value: 0\n },\n { id: \"observed\", op: \"parameter\", name: \"observationAt\" },\n { id: \"scheduledOutstanding\", op: \"sum\", left: \"principal\", right: \"profit\" },\n { id: \"totalOutstanding\", op: \"sum\", left: \"scheduledOutstanding\", right: \"earnedProfit\" },\n { id: \"unpaid\", op: \"less\", left: \"zeroMoney\", right: \"totalOutstanding\" },\n { id: \"elapsed\", op: \"daysBetween\", left: \"due\", right: \"observed\" },\n { id: \"nonnegativeDays\", op: \"maximum\", left: \"elapsed\", right: \"zeroDays\" },\n { id: \"daysPastDue\", op: \"choose\", condition: \"unpaid\", yes: \"nonnegativeDays\", no: \"zeroDays\" }\n ]\n },\n {\n id: \"borrowerAccounts\",\n source: \"account\",\n instruments: [ ],\n rowKey: \"accountId\",\n columns: [\n {\n name: \"accountId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participant\",\n field: \"ownerParticipantId\",\n type: { kind: \"text\" },\n required: false\n }\n ],\n expressions: [ ]\n },\n {\n id: \"borrowers\",\n source: \"identity\",\n instruments: [ ],\n rowKey: \"customerId\",\n columns: [\n {\n name: \"customerId\",\n field: \"id\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"participantId\",\n field: \"participantId\",\n type: { kind: \"text\" },\n required: true\n },\n {\n name: \"entityId\",\n field: \"entityId\",\n type: { kind: \"text\" },\n required: true\n }\n ],\n expressions: [ ]\n }\n ],\n time: { timezone: \"Asia/Riyadh\", boundary: \"startInclusiveEndExclusive\", observation: \"periodEnd\", history: \"retainedOnly\" },\n selection: { dataset: \"facilities\" },\n calculation: {\n joins: [\n {\n dataset: \"schedule\",\n local: \"facilityId\",\n foreign: \"planId\",\n cardinality: \"many\",\n missing: \"refuse\",\n aggregates: [\n { name: \"outstandingPrincipal\", op: \"sum\", value: \"principal\" },\n { name: \"remainingScheduledProfit\", op: \"sum\", value: \"profit\" },\n { name: \"scheduledPrincipalTotal\", op: \"sum\", value: \"scheduledPrincipal\" },\n { name: \"capturedScheduleCount\", op: \"count\" },\n { name: \"oldestUnpaidDays\", op: \"maximum\", value: \"daysPastDue\" }\n ]\n },\n {\n dataset: \"borrowerAccounts\",\n local: \"borrowerAccount\",\n foreign: \"accountId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerParticipant\", op: \"minimum\", value: \"participant\" }\n ]\n },\n {\n dataset: \"borrowers\",\n local: \"borrowerParticipant\",\n foreign: \"participantId\",\n cardinality: \"one\",\n missing: \"refuse\",\n aggregates: [\n { name: \"borrowerEntity\", op: \"minimum\", value: \"entityId\" }\n ]\n }\n ],\n expressions: [ ],\n groupBy: [ ],\n aggregates: [ ],\n resultExpressions: [ ]\n },\n validation: {\n empty: \"refuse\",\n required: [ \"borrowerEntity\" ],\n reconcile: [ ],\n rowReconcile: [\n { left: \"originalPrincipal\", right: \"scheduledPrincipalTotal\" },\n { left: \"scheduleCount\", right: \"capturedScheduleCount\" }\n ],\n unavailableFacts: [ \"approved member format contract\", \"versioned borrower identity and dispute facts\", \"business-effective origination and repayment allocation history\" ],\n lockTimeoutMs: lock_wait_ms,\n captureTimeoutMs: capture_ms,\n maxRows: max_rows,\n maxJoinRows: max_join_rows,\n maxBytes: max_bytes\n },\n output: {\n profile: \"internal.v1\",\n formats: [ \"json\", \"csv\" ],\n columns: [\n {\n name: \"facilityId\",\n label: \"facilityId\",\n type: { kind: \"text\" }\n },\n {\n name: \"borrowerEntity\",\n label: \"borrowerEntity\",\n type: { kind: \"text\" }\n },\n {\n name: \"outstandingPrincipal\",\n label: \"outstandingPrincipal\",\n type: { kind: \"money\", currency: \"SAR\" }\n }\n ],\n sort: [ \"facilityId\" ]\n },\n authority: {\n request: [ \"owner\", \"finance\" ],\n read: [ \"owner\", \"admin\", \"operations\", \"finance\", \"viewer\" ],\n release: [ ],\n retention: { policy: \"report_replay\", years: retention_years }\n }\n }\n ]\n}\n"],
|
|
13
13
|
["savings.hsx", "header savings\n\n// Economics: Contributions and returned pots are principal, not company earnings.\n\n// Expose circle.create and membership.create; create one pending contribution\n// record per member per circle date before membership.activate. Circle activation\n// is clock-owned and needs exactly members joined memberships at or after startsAt.\n// Membership.activate needs the active circle and its full pending schedule.\n// Membership.received means the member received the pot. Contribution.paid means\n// one contribution was collected. Neither record's state proves the other's state.\n// A member can have received the pot with future unpaid contributions, or paid\n// a contribution while their membership still waits for its payout seat.\n// Receive counts preceding received memberships, never paid contributions.\n// Eight members at 300 SAR require 2400 SAR per payout; seven payments supply 2100,\n// so a full payout lacks 300 unless other cash exists. There is no reduced payout.\n// Contribution.pay has a due time and no deadline or prior-payment requirement.\n// Late and out-of-order collection is admitted while membership is active or\n// received and circle is active. Clock admission does not promise scheduler retry.\n// Circle.close needs every membership received and an empty held account.\n// Circle creation collects circleDates, one date per member for contributions and payouts.\n\n// Cost: circle.create declares one owned account. Each contribution payment\n// and each pot payout declares one transfer. Multiply by the actual member and\n// period counts for a completed circle; hsx cost reports per-action bounds.\n\ninstrument circle(contribution: money, members: integer(1, 60), starts: date, memberships: ref<savings.membership> = object(savings.membership)) {\n summary: \"A fixed group contributes on its explicit calendar and takes the pot in order.\"\n fields { contribution: money = contribution, members: integer = members, startsAt: date = starts, circleDates: list(date, members), pot: money = multiply(self.contribution, self.members), held: account of self }\n lifecycle { states: [forming, active, closed, disbanded], initial: forming }\n action create { }\n action activate {\n from: forming, to: active, actor: clock, due: { at: self.startsAt }\n requires count of { instrument: memberships, reference: \"circle\", anchor: self.id, states: [joined], limit: 60 } == self.members\n }\n action close {\n from: active, to: closed\n requires count of { instrument: memberships, reference: \"circle\", anchor: self.id, states: [received], limit: 60 } == self.members\n requires self.held.balance == \"0\"\n }\n action disband { from: forming, to: disbanded }\n}\n\ninstrument membership(circle: ref<savings.circle>, member: party) {\n summary: \"A member contributes on the circle calendar and receives the pot in the assigned seat.\"\n fields { circle: ref<circle>, member: account of member, seat: integer(1, 60), preceding: integer = subtract(self.seat, 1), receivesAt: date = at(self.circle.circleDates, self.seat), contribution: money = self.circle.contribution, total: money = self.circle.pot }\n lifecycle { states: [joined, active, received, withdrawn], initial: joined }\n action create { requires self.seat <= self.circle.members; requires self.circle in [forming]; requires unique \"circle_seat\" on [self.circle, self.seat]; requires unique \"circle_member\" on [self.circle, self.member] }\n action activate {\n from: joined, to: active\n requires self.circle in [active]\n requires count of { instrument: contribution, reference: \"membership\", anchor: self.id, states: [pending], limit: 60 } == self.circle.members\n }\n action receive {\n from: active, to: received, actor: clock, due: { at: self.receivesAt }\n requires self.circle in [active]\n requires count of { instrument: all(savings.membership), reference: \"circle\", anchor: self.circle, states: [received], limit: 60 } == self.preceding\n moves self.total from self.circle.held to self.member economics { purpose: principal, sourceParty: programOperator }\n }\n action withdraw { from: joined, to: withdrawn, requires self.circle in [disbanded] }\n records {\n contribution: {\n fields { membership: ref<parent>, period: integer(1, 60), dueAt: date = at(self.membership.circle.circleDates, self.period), amount: money = self.membership.contribution }\n lifecycle { states: [pending, paid], initial: pending }\n action create { requires self.period <= self.membership.circle.members; requires self.membership in [joined]; requires unique \"seat_period\" on [self.membership, self.period] }\n action pay { from: pending, to: paid, actor: clock, due: { at: self.dueAt }, requires self.membership in [active, received]; requires self.membership.circle in [active], moves self.amount from self.membership.member to self.membership.circle.held economics { purpose: principal, sourceParty: member } }\n }\n }\n}\n"],
|
|
14
|
-
["travel.hsx", "header travel\n\n// Economics: Booking funds and refunds are principal. Supplier payments are payouts,\n// tax is pass-through, and the company margin is earning. An outside operator\n// receives a participant payout instead of company earnings.\n\n// Publish a package before booking.create. Expose deposit, balance and confirm\n// separately. Deposit needs pending premium slices whose cover is active, and\n// collects those premiums in addition to booking cash. Balance is due by balanceAt.\n// Expose cancel_early, cancel_middle and cancel_late for the desired booking paths.\n// Early returns all held booking cash, whether deposit-only or fully paid. Middle\n// returns held minus the original deposit; a deposit-only booking gets zero.\n// Supplier penalty is based on supplierCost; tax applies to retained margin,\n// and the bound operator receives the remainder. Late returns no buyer cash.\n// Middle opens at earlyAt and ends at lateAt, which is middleAt plus 1ms; late\n// starts there. Default_balance can already cancel a deposit_paid booking at\n// balanceAt, after which no booking cancellation is reachable. Clock order matters.\n// Booking refunds exclude insurance premiums, broker commission and all balances\n// outside booking.held. Expose cover.cancel independently to refund eligible paid\n// premium periods before startsAt; slice.refund is parent-owned. Active/expired\n// premium periods remain excluded. Confirmation timeout returns the full booking\n// price from paid only. A penalty above held cash or retained deposit refuses;\n// this header does not subsidize a shortfall or reduce the configured penalty.\n\n// Cost: booking.create declares one owned account. Deposit also invokes premium\n// collections; cancellation declares the selected refund, penalty, tax and retained\n// moves. Run hsx cost for bounded counts. Supplier penalties are business terms,\n// not compiler or executor fees.\n\ninstrument package(price: money, supplier_cost: money, departure: date) {\n constraints { supplier_cost: at_most(price) }\n summary: \"Immutable package price, supplier cost and departure.\"\n fields { price: money = price, supplierCost: money = supplier_cost, departure: date = departure }\n lifecycle { states: [draft, published, closed], initial: draft }\n action create { requires self.supplierCost <= self.price }\n action publish { from: draft, to: published }\n action close { from: published, to: closed, actor: clock, due: { at: self.departure } }\n}\n\ninstrument booking(package: ref<travel.package>, buyer: party, supplier: party, operator: party = programOperator, cover: ref<insurance.cover>, deposit: percent = 30%, balance_before: duration = 14d, confirm_within: duration = 24h, tax: percent = 15%, early_before: duration = 30d, middle_before: duration = 15d, middle_penalty: percent = 10%, late_penalty: percent = 30%) {\n constraints { early_before: greater_than(middle_before) }\n summary: \"A deposited booking with three cancellation bands and confirmation.\"\n fields {\n package: ref<package>, buyer: account of buyer, supplier: account of supplier\n price: money = self.package.price, supplierCost: money = self.package.supplierCost\n deposit: money = rate(self.price, deposit), balance: money = subtract(self.price, self.deposit)\n margin: money = subtract(self.price, self.supplierCost)\n tax: money = rate(self.margin, tax), operatorNet: money = subtract(self.margin, self.tax)\n middlePenalty: money = rate(self.supplierCost, middle_penalty)\n latePenalty: money = rate(self.supplierCost, late_penalty)\n balanceAt: date = before(self.package.departure, balance_before)\n earlyAt: date = before(self.package.departure, early_before)\n middleAt: date = before(self.package.departure, middle_before)\n lateAt: date = after(self.middleAt, 1ms)\n confirmBy: date = after(self.package.departure, confirm_within)\n held: account of self\n refund: money?, retainedMargin: money?, retainedTax: money?, retainedNet: money?\n }\n lifecycle { states: [created, deposit_paid, paid, completed, cancelled, refunded], initial: created }\n action create {\n requires self.package in [published]\n }\n action deposit { allowZero: true, requires self.price > \"0\";\n from: created, to: deposit_paid, actor: { party: buyer }, deadline: { at: self.balanceAt }\n requires count of { instrument: child(cover, slice), reference: \"covers\", anchor: self.id, states: [pending], limit: 366 } >= 1\n moves self.deposit from buyer to self.held economics { purpose: principal, sourceParty: buyer }\n invoke: [{ selection: { instrument: child(cover, slice), reference: \"covers\", anchor: self.id, states: [pending], limit: 366 }, action: collect, input: {} }]\n }\n action balance { allowZero: true, requires self.price > \"0\";\n from: deposit_paid, to: paid, actor: { party: buyer }, deadline: { at: self.balanceAt }\n moves self.balance from buyer to self.held economics { purpose: principal, sourceParty: buyer }\n }\n action confirm { allowZero: true, requires self.price > \"0\";\n from: paid, to: completed, actor: { party: operator }\n due: { at: self.package.departure }, deadline: { at: self.confirmBy }\n moves self.supplierCost from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.tax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.operatorNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action timeout {\n from: paid, to: refunded, actor: clock, due: { at: self.confirmBy }\n moves self.price from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel_early { allowZero: true, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, deadline: { at: self.earlyAt }\n moves self.held.balance from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel_middle { allowZero: true, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.earlyAt }, deadline: { at: self.lateAt }\n calculate: [\n { target: refund, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.deposit }] }\n { target: retainedMargin, op: \"subtract\", base: { field: self.deposit }, subtract: [{ field: self.middlePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.refund from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n moves self.middlePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action cancel_late { allowZero: true, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.lateAt }\n calculate: [\n { target: retainedMargin, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.latePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action default_balance { allowZero: true, requires self.price > \"0\";\n from: deposit_paid, to: cancelled, actor: clock, due: { at: self.balanceAt }\n calculate: [\n { target: retainedMargin, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.latePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n}\n"],
|
|
14
|
+
["travel.hsx", "header travel\n\n// Economics: Booking funds and refunds are principal. Supplier payments are payouts,\n// tax is pass-through, and the company margin is earning. An outside operator\n// receives a participant payout instead of company earnings.\n\n// Publish a package before booking.create. Expose deposit, balance and confirm\n// separately. Deposit needs pending premium slices whose cover is active, and\n// collects those premiums in addition to booking cash. Balance is due by balanceAt.\n// Expose cancel_early, cancel_middle and cancel_late for the desired booking paths.\n// Early returns all held booking cash, whether deposit-only or fully paid. Middle\n// returns held minus the original deposit; a deposit-only booking gets zero.\n// Supplier penalty is based on supplierCost; tax applies to retained margin,\n// and the bound operator receives the remainder. Late returns no buyer cash.\n// Middle opens at earlyAt and ends at lateAt, which is middleAt plus 1ms; late\n// starts there. Default_balance can already cancel a deposit_paid booking at\n// balanceAt, after which no booking cancellation is reachable. Clock order matters.\n// Booking refunds exclude insurance premiums, broker commission and all balances\n// outside booking.held. Expose cover.cancel independently to refund eligible paid\n// premium periods before startsAt; slice.refund is parent-owned. Active/expired\n// premium periods remain excluded. Confirmation timeout returns the full booking\n// price from paid only. A penalty above held cash or retained deposit refuses;\n// this header does not subsidize a shortfall or reduce the configured penalty.\n\n// Cost: booking.create declares one owned account. Deposit also invokes premium\n// collections; cancellation declares the selected refund, penalty, tax and retained\n// moves. Run hsx cost for bounded counts. Supplier penalties are business terms,\n// not compiler or executor fees.\n\ninstrument package(price: money, supplier_cost: money, departure: date) {\n constraints { supplier_cost: at_most(price) }\n summary: \"Immutable package price, supplier cost and departure.\"\n fields { price: money = price, supplierCost: money = supplier_cost, departure: date = departure }\n lifecycle { states: [draft, published, closed], initial: draft }\n action create { requires self.supplierCost <= self.price }\n action publish { from: draft, to: published }\n action close { from: published, to: closed, actor: clock, due: { at: self.departure } }\n}\n\ninstrument booking(package: ref<travel.package>, buyer: party, supplier: party, operator: party = programOperator, cover: ref<insurance.cover>, deposit: percent = 30%, balance_before: duration = 14d, confirm_within: duration = 24h, tax: percent = 15%, early_before: duration = 30d, middle_before: duration = 15d, middle_penalty: percent = 10%, late_penalty: percent = 30%) {\n constraints { early_before: greater_than(middle_before) }\n summary: \"A deposited booking with three cancellation bands and confirmation.\"\n fields {\n package: ref<package>, buyer: account of buyer, supplier: account of supplier\n price: money = self.package.price, supplierCost: money = self.package.supplierCost\n deposit: money = rate(self.price, deposit), balance: money = subtract(self.price, self.deposit)\n margin: money = subtract(self.price, self.supplierCost)\n tax: money = rate(self.margin, tax), operatorNet: money = subtract(self.margin, self.tax)\n middlePenalty: money = rate(self.supplierCost, middle_penalty)\n latePenalty: money = rate(self.supplierCost, late_penalty)\n balanceAt: date = before(self.package.departure, balance_before)\n earlyAt: date = before(self.package.departure, early_before)\n middleAt: date = before(self.package.departure, middle_before)\n lateAt: date = after(self.middleAt, 1ms)\n confirmBy: date = after(self.package.departure, confirm_within)\n held: account of self\n refund: money?, retainedMargin: money?, retainedTax: money?, retainedNet: money?\n }\n lifecycle { states: [created, deposit_paid, paid, completed, cancelled, refunded], initial: created }\n action create {\n requires self.package in [published]\n }\n action deposit { allowZero: true, requires self.price > \"0\";\n from: created, to: deposit_paid, actor: { party: buyer }, deadline: { at: self.balanceAt }\n requires count of { instrument: child(cover, slice), reference: \"covers\", anchor: self.id, states: [pending], limit: 366 } >= 1\n moves self.deposit from buyer to self.held economics { purpose: principal, sourceParty: buyer }\n invoke: [{ selection: { instrument: child(cover, slice), reference: \"covers\", anchor: self.id, states: [pending], limit: 366 }, action: collect, input: {} }]\n }\n action balance { allowZero: true, requires self.price > \"0\";\n from: deposit_paid, to: paid, actor: { party: buyer }, deadline: { at: self.balanceAt }\n moves self.balance from buyer to self.held economics { purpose: principal, sourceParty: buyer }\n }\n action confirm { allowZero: true, requires self.price > \"0\";\n from: paid, to: completed, actor: { party: operator }\n due: { at: self.package.departure }, deadline: { at: self.confirmBy }\n moves self.supplierCost from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.tax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.operatorNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action timeout {\n from: paid, to: refunded, actor: clock, due: { at: self.confirmBy }\n moves self.price from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel_early { allowZero: true, purpose: option, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, deadline: { at: self.earlyAt }\n moves self.held.balance from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel_middle { allowZero: true, purpose: option, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.earlyAt }, deadline: { at: self.lateAt }\n calculate: [\n { target: refund, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.deposit }] }\n { target: retainedMargin, op: \"subtract\", base: { field: self.deposit }, subtract: [{ field: self.middlePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.refund from self.held to buyer economics { purpose: principal, sourceParty: programOperator }\n moves self.middlePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action cancel_late { allowZero: true, purpose: option, requires self.price > \"0\";\n from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.lateAt }\n calculate: [\n { target: retainedMargin, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.latePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action default_balance { allowZero: true, requires self.price > \"0\";\n from: deposit_paid, to: cancelled, actor: clock, due: { at: self.balanceAt }\n calculate: [\n { target: retainedMargin, op: \"subtract\", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }\n { target: retainedTax, op: \"rate\", base: { field: self.retainedMargin }, bps: { literal: tax }, rounding: \"floor\" }\n { target: retainedNet, op: \"subtract\", base: { field: self.retainedMargin }, subtract: [{ field: self.retainedTax }] }\n ]\n moves self.latePenalty from self.held to supplier economics { purpose: participant_payout, sourceParty: programOperator }\n moves self.retainedTax from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n moves self.retainedNet from self.held to operator economics { recipient: operator, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n}\n"],
|
|
15
15
|
["wallet.hsx", "header wallet\n\n// Economics: Topups and withdrawals are excluded prepaid credit. Spending remains\n// unclassified because the bound payee alone does not state the purchase purpose.\n\n// Expose balance.create, activate, topup and withdraw as needed. Holder moves\n// cash only while active. Freeze blocks new topups, withdrawals and spend reserves;\n// close requires no held cash. Freeze/unfreeze use caller operation authority.\n// A separate spend record checks its amount against spendLimit at creation.\n// Expose reserve, pay and cancel for the bound payee. Reserve requires an active\n// wallet before expiresAt; pay posts the whole reservation, cancel/expiry void it.\n// Existing reservations may still post after the wallet freezes. There is no\n// daily aggregate limit, partial spend or card-network settlement in this header.\n\n// Cost: balance.create declares one owned account; topup and withdraw each\n// declare one transfer. Spend reserve, pay and cancel each declare one transfer\n// instruction. These are counts, not the executor tariff.\n\ninstrument balance(holder: party, spend_limit: money = 100000 SAR) {\n summary: \"A holder's reusable balance with an immutable per-spend ceiling.\"\n fields { holder: account of holder, held: account of self, spendLimit: money = spend_limit }\n lifecycle { states: [pending, active, frozen, closed], initial: pending }\n action create { }\n action activate { from: pending, to: active, actor: { party: holder } }\n action topup {\n from: active, to: active, actor: { party: holder }\n input { amount: money }\n moves input.amount from holder to self.held economics { purpose: prepaid_credit, sourceParty: holder }\n }\n action withdraw {\n from: active, to: active, actor: { party: holder }\n input { amount: money }\n moves input.amount from self.held to holder economics { purpose: prepaid_credit, sourceParty: programOperator }\n }\n action freeze { from: active, to: frozen, }\n action unfreeze { from: frozen, to: active, }\n action close { from: [pending, active], to: closed, requires self.held.balance == \"0\" }\n}\n\ninstrument spend(wallet: ref<wallet.balance>, payee: party) {\n summary: \"Reserve one wallet spend, then post or void the same reservation.\"\n fields { wallet: ref<wallet>, amount: money, expiresAt: date, reservation: text? }\n lifecycle { states: [pending, reserved, paid, cancelled, expired], initial: pending }\n action create {\n requires self.wallet in [active]\n requires self.amount <= self.wallet.spendLimit\n }\n action reserve {\n from: pending, to: reserved, actor: { party: payee }\n requires self.wallet in [active]\n deadline: { at: self.expiresAt }\n moves reserve self.amount from self.wallet.held to payee capture \"reservation\"\n }\n action pay { from: reserved, to: paid, actor: { party: payee }, moves post self.reservation }\n action cancel { from: reserved, to: cancelled, actor: { party: payee }, moves void self.reservation }\n action expire { from: reserved, to: expired, actor: clock, due: { at: self.expiresAt }, moves void self.reservation }\n}\n"],
|
|
16
16
|
]);
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const HSX_VERSION = "5.
|
|
1
|
+
export const HSX_VERSION = "5.6.0";
|