mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
Merge branch 'folio-spec-attribution' into trial-merge
This commit is contained in:
commit
6a7764eac7
5 files changed
+169
-12
No files matched your search
@@ -106,6 +106,21 @@ export function readHomeTotalBalance(args: {
|
||||
//
|
||||
// Callers pass null for a reading they could not take, so an empty list and an
|
||||
// empty map are one case here rather than two.
|
||||
//
|
||||
// A non-empty list is trusted as current, and that rests on the app's shape
|
||||
// rather than on anything in the frame. `fresh` also resets the submit window,
|
||||
// so a card list drawn before the store caught up with a commit would bank
|
||||
// stale counts, start the next window empty, and leave the rise arriving with
|
||||
// no budget to cover it: a healthy app convicted of a double submit. Folio
|
||||
// cannot serve that frame. AddTransactionViewModel.submit pops ONE entry, so a
|
||||
// commit lands back on the ledger it came from and the first Home reading is a
|
||||
// whole action and settle later. Two pops do reach Home, but two pops means two
|
||||
// Submit events, which is the double submit itself, and a verdict there is
|
||||
// late rather than wrong. Measured over four recorded android runs: 51
|
||||
// commit-capable single taps landed on the ledger or the transaction screen and
|
||||
// none on Home, 49 of 49 commits already showed their new balance in the frame
|
||||
// read at the same step, and no rise ever arrived against an empty budget in
|
||||
// 1303 steps. A submit that navigated straight to Home would reopen this.
|
||||
export interface HomeCardReading<T> {
|
||||
value: T | null;
|
||||
carrier: T | null;
|
||||
@@ -678,12 +693,27 @@ 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. The route gate skips steps
|
||||
// whose landing screen is not Home: totalBalance is only freshly read from
|
||||
// Home's own TOTAL BALANCE node, so off-Home comparisons would read a stale
|
||||
// carrier value and false-fire.
|
||||
// button, the absolute change in total balance cannot EXCEED the amount the
|
||||
// user typed. A double-submit lands two transactions and shifts the balance by
|
||||
// 2x the typed amount, tripping this check. The route gate skips steps whose
|
||||
// landing screen is not Home: totalBalance is only freshly read from Home's own
|
||||
// TOTAL BALANCE node, so off-Home comparisons would read a stale carrier value
|
||||
// and false-fire.
|
||||
//
|
||||
// A bound rather than the equality this used to be, and the same bound
|
||||
// committedAmountExceedsOneSubmit applies to the account's own balance. The
|
||||
// write finishes before AddTransactionViewModel navigates, but nothing
|
||||
// establishes that Home's total has re-rendered before the frame is read: the
|
||||
// store's flow re-emits on its own schedule. A total that has not caught up has
|
||||
// not moved at all, and an equality convicts a healthy app for it.
|
||||
//
|
||||
// The cost is real and is not covered anywhere else in this spec: a balance
|
||||
// that moves by LESS than the amount typed, a transaction silently dropped or
|
||||
// committed for the wrong amount, is a bug this no longer judges. It cannot be
|
||||
// told apart from a total one frame behind, and a check that fires on both is
|
||||
// evidence about neither. What it keeps is the bug it exists for: every one of
|
||||
// the four recorded android convictions is a 6400 move against 3200 typed, and
|
||||
// 2x still exceeds x.
|
||||
//
|
||||
// submitsInWindow is what keeps the comparison honest. prevTotalBalance is the
|
||||
// last total we READ, not the total as of the previous transaction, so the two
|
||||
@@ -724,7 +754,7 @@ export function submitChangesBalanceByTypedAmount(args: {
|
||||
// transaction at whatever fits a Kotlin Long, so a balance of ~1e18 cents is
|
||||
// one accepted amount away, and up there the gap between representable
|
||||
// values is 128 cents: a real 1600-cent move reads back as something else
|
||||
// entirely. The equality below is then false for a healthy single submit
|
||||
// entirely. The comparison below is then false for a healthy single submit
|
||||
// exactly as readily as for a double one, and a check that cannot pass is not
|
||||
// a check that failed.
|
||||
//
|
||||
@@ -739,5 +769,5 @@ export function submitChangesBalanceByTypedAmount(args: {
|
||||
if (!Number.isSafeInteger(prevTotalBalance)) return true;
|
||||
if (!Number.isSafeInteger(currTotalBalance)) return true;
|
||||
if (!Number.isSafeInteger(typedAmount)) return true;
|
||||
return Math.abs(currTotalBalance - prevTotalBalance) === typedAmount;
|
||||
return Math.abs(currTotalBalance - prevTotalBalance) <= typedAmount;
|
||||
}
|
||||
@@ -258,10 +258,15 @@ 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. The route gate inside the
|
||||
// Property 2: a tap on TxnSubmit cannot move the total balance by more than the
|
||||
// typed amount. A double-submit lands two transactions, so the balance shifts 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.
|
||||
//
|
||||
// The name is the property's, and the gate keys on it, so it stays; what it
|
||||
// demands is the bound, for the reason submitChangesBalanceByTypedAmount gives:
|
||||
// a total that has not re-rendered yet has not moved, and an equality convicts a
|
||||
// healthy app for a frame that has not caught up.
|
||||
const submitMovesBalanceByTypedAmount = always(
|
||||
next(() =>
|
||||
submitChangesBalanceByTypedAmount({
|
||||
|
||||
Reference in new issue
Block a user