mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
fix(folio): use sum-of-added-rows in balanceMatchesAddedTxn
The old predicate (every row's signed amount equals delta) silently passed the double-submit bug because two same-amount rows each match the delta in isolation. Switching to the sum check (addedSum === delta) catches both the double-submit case and any future multi-row append whose total drifts from the balance change.
This commit is contained in:
1 parent
35fce05b65
commit
b88b6c239d
1 file changed
+14
-19
@@ -12,17 +12,13 @@ import {
|
||||
whenRoute,
|
||||
} from "@sanderling/spec";
|
||||
import { defaultActions } from "@sanderling/spec/defaults";
|
||||
import { balanceMatchesAddedSum, type LedgerRow } from "./predicates";
|
||||
|
||||
interface Account {
|
||||
name: string;
|
||||
balance: number;
|
||||
}
|
||||
|
||||
interface LedgerRow {
|
||||
key: string;
|
||||
signed: number;
|
||||
}
|
||||
|
||||
// Parses formatCents output like "$5.00", "-$1,234.56", "+$0.50" back to integer cents.
|
||||
function parseDollarCents(text: string | undefined): number {
|
||||
if (!text) return 0;
|
||||
@@ -93,22 +89,21 @@ const newAccountBalanceIsZero = always(
|
||||
})
|
||||
);
|
||||
|
||||
// Property 2: when new ledger rows appear, the ledger balance delta equals
|
||||
// the sum of the new rows' signed amounts. A double-submit lands two rows
|
||||
// whose individual amounts cannot both equal the aggregate delta, so each
|
||||
// such row fires the property.
|
||||
// Property 2: when new ledger rows appear, the balance delta equals the SUM
|
||||
// of the new rows' signed amounts. Single-row and multi-row sums both must
|
||||
// match; a double-submit lands two rows whose total is twice the balance
|
||||
// change and trips the sum check.
|
||||
const balanceMatchesAddedTxn = always(
|
||||
now(() => route.current === "ledger").implies(
|
||||
next(() => {
|
||||
const prev = ledgerRows.previous ?? [];
|
||||
const curr = ledgerRows.current;
|
||||
const prevKeys = new Set(prev.map(r => r.key));
|
||||
const added = curr.filter(r => !prevKeys.has(r.key));
|
||||
if (added.length === 0) return true;
|
||||
const delta = ledgerBalance.current - (ledgerBalance.previous ?? 0);
|
||||
return added.every(r => r.signed === delta);
|
||||
})
|
||||
)
|
||||
next(() =>
|
||||
balanceMatchesAddedSum(
|
||||
ledgerRows.previous ?? [],
|
||||
ledgerRows.current,
|
||||
ledgerBalance.previous ?? 0,
|
||||
ledgerBalance.current,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const DEMO_EMAIL = "[email protected]";
|
||||
|
||||
Reference in new issue
Block a user