Sign in

    ledgerweave

    Deterministic multi-source business ledger reconciliation and exception attribution.

    ledger
    reconciliation
    data-quality
    csv
    Download zip
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    25 days ago
    Downloads
    19

    #LedgerWeave

    LedgerWeave is a MoonBit reconciliation engine for multi-source business ledgers. It compares orders, captured payments, refunds, and adjustments under an explicit policy, then produces per-order balances and actionable exception findings.

    It is designed for offline, deterministic review before a team acts on a monthly or daily settlement file. Amounts use integer minor units: 12000 represents CNY 120.00.

    #What it checks

    • duplicate identifiers within each source;
    • positive amounts and allowed currencies;
    • unknown order references and cross-record currency mismatches;
    • payment timing windows and payments against cancelled orders;
    • refund total not exceeding captured payment;
    • underpayment, over-collection, and overdue open balances.

    #Scope and boundaries

    LedgerWeave does not connect to bank accounts, move money, calculate tax, or claim accounting compliance. It evaluates only supplied records under a versioned, explicit policy. A passing result means no blocking inconsistency was found in that input; it is not an audit opinion.

    #Requirements

    • MoonBit >= 0.10.14 (developed with moon 0.1.20260920)

    #Run the included example

    moon check moon test moon run cmd/main

    The demo intentionally contains an unknown payment and a payment for a cancelled order. Its report therefore ends in REVIEW REQUIRED and explains each exception.

    #Library usage

    let policy = @ledgerweave.default_policy()
    let input : @ledgerweave.LedgerInput = {
    orders: [{ id: "ORD-1", account_id: "team", currency: "CNY", amount_minor: 1000, created_day: 1, status: Paid }],
    payments: [{ id: "PAY-1", order_id: "ORD-1", currency: "CNY", amount_minor: 1000, received_day: 1, status: Captured }],
    refunds: [],
    adjustments: [],
    }
    let result = @ledgerweave.reconcile(input, policy, 1)
    assert_true(result.valid)

    #Architecture

    LedgerInput is immutable input. validate performs source-level checks. reconcile computes captured, refunded and adjusted balances for every known order, then derives balance findings. report converts only the structured result into terminal-safe text. No report function changes ledger state.

    #Development

    moon fmt moon check moon test moon build --target native moon publish --dry-run

    #License

    Apache-2.0. See LICENSE. The first release has no third-party runtime dependencies; details are recorded in THIRD_PARTY_NOTICES.md.

    #CSV command-line workflow

    The native CLI accepts four CSV files plus the current business day:

    moon run --target native cmd/main -- \ examples/csv/orders.csv examples/csv/payments.csv \ examples/csv/refunds.csv examples/csv/adjustments.csv 40

    The headers are fixed and intentional: orders requires id,account_id,currency,amount_minor,created_day,status; payments use id,order_id,currency,amount_minor,received_day,status; refunds use id,order_id,currency,amount_minor,refunded_day,reason; and adjustments use id,order_id,currency,amount_minor,day,direction,reason.

    CSV values may be quoted and use doubled quotes for literal quotes. Unreadable files terminate the native CLI through its explicit filesystem error boundary. Missing columns or malformed numeric values are converted to empty/zero fields and are subsequently surfaced by LedgerWeave validation instead of being silently accepted.

    AdjustmentDirection

    pub(all) enum AdjustmentDirection {
    Credit
    Debit
    } derive(Eq,
    Debug
    )

    AdjustmentRecord

    pub(all) struct AdjustmentRecord {
    id : String
    order_id : String
    currency : String
    amount_minor : Int
    day : Int
    direction : AdjustmentDirection
    reason : String
    } derive(Eq,
    Debug
    )

    Finding

    pub(all) struct Finding {
    code : FindingCode
    severity : Severity
    record_kind : RecordKind
    record_id : String
    order_id : String
    message : String
    } derive(Eq,
    Debug
    )

    FindingCode

    pub(all) enum FindingCode {
    DuplicateOrderId
    DuplicatePaymentId
    DuplicateRefundId
    DuplicateAdjustmentId
    InvalidAmount
    InvalidCurrency
    UnknownOrder
    CurrencyMismatch
    PaymentAfterDeadline
    PaymentForCancelledOrder
    RefundExceedsPayment
    Overpaid
    Underpaid
    OpenPastDue
    PaymentVoided
    MissingReference
    } derive(Eq,
    Debug
    )

    LedgerInput

    pub(all) struct LedgerInput {
    orders : Array[OrderRecord]
    payments : Array[PaymentRecord]
    refunds : Array[RefundRecord]
    adjustments : Array[AdjustmentRecord]
    } derive(Eq,
    Debug
    )

    OrderBalance

    pub(all) struct OrderBalance {
    order_id : String
    expected_minor : Int
    captured_minor : Int
    refunded_minor : Int
    adjustments_minor : Int
    outstanding_minor : Int
    resolution : Resolution
    } derive(Eq,
    Debug
    )

    OrderRecord

    pub(all) struct OrderRecord {
    id : String
    account_id : String
    currency : String
    amount_minor : Int
    created_day : Int
    status : OrderStatus
    } derive(Eq,
    Debug
    )

    OrderStatus

    pub(all) enum OrderStatus {
    Pending
    Paid
    Cancelled
    Refunded
    } derive(Eq,
    Debug
    )

    PaymentRecord

    pub(all) struct PaymentRecord {
    id : String
    order_id : String
    currency : String
    amount_minor : Int
    received_day : Int
    status : PaymentStatus
    } derive(Eq,
    Debug
    )

    PaymentStatus

    pub(all) enum PaymentStatus {
    Captured
    Voided
    Failed
    } derive(Eq,
    Debug
    )

    Policy

    pub(all) struct Policy {
    allowed_currencies : Array[String]
    amount_tolerance_minor : Int
    max_payment_lag_days : Int
    max_open_age_days : Int
    permit_cancelled_payment : Bool
    } derive(Eq,
    Debug
    )

    ReconciliationResult

    pub(all) struct ReconciliationResult {
    balances : Array[OrderBalance]
    findings : Array[Finding]
    valid : Bool
    } derive(Eq,
    Debug
    )

    RecordKind

    pub(all) enum RecordKind {
    Order
    Payment
    Refund
    Adjustment
    } derive(Eq,
    Debug
    )

    LedgerWeave's stable domain vocabulary. Amounts are always integer minor units.

    RefundRecord

    pub(all) struct RefundRecord {
    id : String
    order_id : String
    currency : String
    amount_minor : Int
    refunded_day : Int
    reason : String
    } derive(Eq,
    Debug
    )

    Resolution

    pub(all) enum Resolution {
    Settled
    AwaitingPayment
    OverCollected
    RefundRisk
    NeedsReview
    } derive(Eq,
    Debug
    )

    Severity

    pub(all) enum Severity {
    Info
    Warning
    Error
    } derive(Eq,
    Debug
    )

    abs_int

    fn abs_int(value : Int) -> Int

    clean_input

    fn clean_input() -> LedgerInput

    contains_string

    fn contains_string(items : Array[String], wanted : String) -> Bool

    count_string

    fn count_string(items : Array[String], wanted : String) -> Int

    default_policy

    fn default_policy() -> Policy

    demo_input

    fn demo_input() -> LedgerInput

    A deliberately mixed fixture used by the executable demo and integration tests.

    empty_input

    fn empty_input() -> LedgerInput

    find_order

    fn find_order(input : LedgerInput, order_id : String) -> OrderRecord?

    finding_code_label

    fn finding_code_label(value : FindingCode) -> String

    is_blank

    fn is_blank(value : String) -> Bool

    make_finding

    fn make_finding(code : FindingCode, severity : Severity, record_kind : RecordKind, record_id : String, order_id : String, message : String) -> Finding

    parse_adjustments_csv

    fn parse_adjustments_csv(text : String) -> Array[AdjustmentRecord]

    parse_csv

    fn parse_csv(text : String) -> Array[Array[String]]

    that the normal validation stage reports rather than causing partial mutation.

    parse_day

    fn parse_day(text : String) -> Int

    Parses a non-negative day number for command adapters. Invalid input becomes zero.

    parse_ledger_csv

    fn parse_ledger_csv(orders : String, payments : String, refunds : String, adjustments : String) -> LedgerInput

    parse_orders_csv

    fn parse_orders_csv(text : String) -> Array[OrderRecord]

    parse_payments_csv

    fn parse_payments_csv(text : String) -> Array[PaymentRecord]

    parse_refunds_csv

    fn parse_refunds_csv(text : String) -> Array[RefundRecord]

    reconcile

    fn reconcile(input : LedgerInput, policy : Policy, current_day : Int) -> ReconciliationResult

    render_balances

    fn render_balances(result : ReconciliationResult) -> String

    render_findings

    fn render_findings(result : ReconciliationResult) -> String

    render_summary

    fn render_summary(result : ReconciliationResult) -> String

    resolution_label

    fn resolution_label(value : Resolution) -> String

    severity_label

    fn severity_label(value : Severity) -> String

    sum_adjustments

    fn sum_adjustments(input : LedgerInput, order_id : String) -> Int

    sum_captured

    fn sum_captured(input : LedgerInput, order_id : String) -> Int

    sum_refunded

    fn sum_refunded(input : LedgerInput, order_id : String) -> Int

    validate

    fn validate(input : LedgerInput, policy : Policy) -> Array[Finding]

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io