From 4c7c22ced658d761a54ecc473baf89ba92af6d0f Mon Sep 17 00:00:00 2001 From: PJ Date: Sun, 31 May 2026 22:14:38 +0530 Subject: [PATCH] fix(folio): gate submit-balance property on Home route landing totalBalance is only freshly computed when AccountCards are visible on Home; off-Home landings return the carrier and would false-fire the property, latching always(next(F)) to false and masking the real double-submit bug. Skip vacuously when route is not "home". --- examples/folio/sanderling/predicates.ts | 9 +++++++-- examples/folio/sanderling/spec.ts | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/folio/sanderling/predicates.ts b/examples/folio/sanderling/predicates.ts index ec48f93..13149b5 100644 --- a/examples/folio/sanderling/predicates.ts +++ b/examples/folio/sanderling/predicates.ts @@ -39,14 +39,19 @@ export function parseTypedAmount(text: string | undefined | null): number { // When the last action is a tap (or double-tap) on the transaction Submit // button, the absolute change in total balance must equal the amount the // user typed. A double-submit lands two transactions and shifts the balance -// by 2x the typed amount, tripping this check. +// by 2x the typed amount, tripping this check. The route gate skips steps +// whose landing screen is not Home: totalBalance is only freshly computed +// from visible AccountCards on Home, so off-Home comparisons would read a +// stale carrier value and false-fire. export function submitChangesBalanceByTypedAmount(args: { + route: string | null; lastAction: { kind?: string; on?: string | object } | null; typedAmount: number; prevTotalBalance: number; currTotalBalance: number; }): boolean { - const { lastAction, typedAmount, prevTotalBalance, currTotalBalance } = args; + const { route, lastAction, typedAmount, prevTotalBalance, currTotalBalance } = args; + if (route !== "home") return true; if (lastAction == null) return true; if (lastAction.kind !== "Tap" && lastAction.kind !== "DoubleTap") return true; const on = lastAction.on; diff --git a/examples/folio/sanderling/spec.ts b/examples/folio/sanderling/spec.ts index ee21cd3..a323b6c 100644 --- a/examples/folio/sanderling/spec.ts +++ b/examples/folio/sanderling/spec.ts @@ -98,10 +98,12 @@ const newAccountBalanceIsZero = always( // Property 2: a tap on TxnSubmit must move the total balance by exactly the // typed amount. A double-submit lands two transactions, so the balance shifts -// by twice the typed amount and the check fires. +// by twice the typed amount and the check fires. The route gate inside the +// predicate skips off-Home landings where totalBalance.current is the carrier. const submitMovesBalanceByTypedAmount = always( next(() => submitChangesBalanceByTypedAmount({ + route: route.current, lastAction: lastAction.current, typedAmount: parseTypedAmount(txnAmountField.previous?.text), prevTotalBalance: totalBalance.previous ?? 0,