mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-04 20:17:09 +00:00
fix(folio): the bound carries no unconfirmed-submit guard
deleting confirmedApplied here broke 0 of 355 tests: under a bound a submit that may not have landed moves the balance by 0, which the bound already permits, so the guard could only ever drop the double commit it exists to catch. the relaunch guard stays for a reason the bound does not cover, and both tests now assert a verdict that changes when their guard does.
This commit is contained in:
1 parent
5b6816956f
commit
40c39e93b9
2 files changed
+32
-22
No files matched your search
@@ -736,13 +736,19 @@ export function submitChangesBalanceByAtMostTypedAmount(args: {
|
|||||||
|
|
||||||
if (route !== "home") return true;
|
if (route !== "home") return true;
|
||||||
if (!isTxnSubmitTap(lastAction)) return true;
|
if (!isTxnSubmitTap(lastAction)) return true;
|
||||||
// The whole rule is that the delta belongs to THIS submit. A submit the
|
// The two totals were read from two different processes. SqlLedgerStore
|
||||||
// runner could not confirm may have committed nothing, and a balance that
|
// starts each one on stateIn(Eagerly, emptyList()) and HomeScreen composes
|
||||||
// did not move is then exactly what a healthy app looks like.
|
// formatCents(total) off whatever the flow holds, so a restarted app draws
|
||||||
if (!confirmedApplied(lastAction)) return true;
|
// $0.00 into TotalBalance until sqlite answers, and that number is as far
|
||||||
// The runner restarted the app after this tap, so the process may have died
|
// from the last one as the accounts are rich. There is no submit anywhere
|
||||||
// between the commit and the sqlite write. A balance that did not move is
|
// that explains it.
|
||||||
// then a healthy app, exactly as it is for a submit that may not have landed.
|
//
|
||||||
|
// A submit the runner could not confirm needs no guard of its own: it may
|
||||||
|
// have committed nothing, and a balance that did not move is under any bound.
|
||||||
|
// countSubmitsInWindow counts it exactly like a confirmed one, so a total
|
||||||
|
// that moved by more than one typed amount is the same double commit either
|
||||||
|
// way. Under the equality this used to be, that case had to be excused; a
|
||||||
|
// guard for it here now only drops the convictions it exists to make.
|
||||||
if (acrossRelaunch(lastAction)) return true;
|
if (acrossRelaunch(lastAction)) return true;
|
||||||
if (submitsInWindow !== 1) return true;
|
if (submitsInWindow !== 1) return true;
|
||||||
if (typedAmount === 0) return true;
|
if (typedAmount === 0) return true;
|
||||||
|
|||||||
@@ -504,20 +504,23 @@ test("freshness boundary: a window with no submit in it is vacuous", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// applied: null is the runner saying it dispatched the tap and never learned
|
// applied: null is the runner saying it dispatched the tap and never learned
|
||||||
// whether it landed. A submit that committed nothing leaves the balance where
|
// whether it landed. Under the bound that buys the app nothing it did not
|
||||||
// it was, so demanding the typed amount of movement for it convicts an app that
|
// already have: a submit that committed nothing leaves the balance where it
|
||||||
// did exactly what it should have.
|
// was, and a balance that has not moved is under any bound. What the window
|
||||||
test("a submit the runner could not confirm demands no balance move", () => {
|
// still promises is that no OTHER submit action could have moved it, because
|
||||||
|
// countSubmitsInWindow counts an unconfirmed tap exactly like a confirmed one.
|
||||||
|
// So a move of twice the typed amount is the same double commit either way.
|
||||||
|
test("a submit the runner could not confirm is still held to the bound", () => {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
submitChangesBalanceByAtMostTypedAmount({
|
submitChangesBalanceByAtMostTypedAmount({
|
||||||
route: "home",
|
route: "home",
|
||||||
lastAction: { kind: "Tap", on: submitOn, applied: null },
|
lastAction: { kind: "DoubleTap", on: submitOn, applied: null },
|
||||||
submitsInWindow: 1,
|
submitsInWindow: 1,
|
||||||
typedAmount: 500,
|
typedAmount: 500,
|
||||||
prevTotalBalance: 1000,
|
prevTotalBalance: 1000,
|
||||||
currTotalBalance: 1000,
|
currTotalBalance: 2000,
|
||||||
}),
|
}),
|
||||||
true,
|
false,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -583,20 +586,21 @@ test("the measured double submit still fires under the bound", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// relaunched: true is the runner saying its foreground guard restarted the app
|
// relaunched: true is the runner saying its foreground guard restarted the app
|
||||||
// after this action. The tap landed, so the window still counts it, but nobody
|
// after this action, so the two totals being compared were read from two
|
||||||
// can promise the process lived long enough for the write to reach sqlite. A
|
// different processes. SqlLedgerStore starts every one of them on
|
||||||
// balance still sitting where it was is exactly what a healthy app looks like
|
// stateIn(Eagerly, emptyList()) and HomeScreen composes formatCents(total) off
|
||||||
// across a relaunch, and demanding the typed amount of movement convicts it for
|
// whatever the flow holds, so the restarted app draws $0.00 into TotalBalance
|
||||||
// the runner's own restart.
|
// until sqlite answers. That reading is not a total this tap moved, and it is
|
||||||
test("a submit the runner relaunched across demands no balance move", () => {
|
// as far from the last one as the account is rich.
|
||||||
|
test("a total drawn by a restarted process is not compared with the old one", () => {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
submitChangesBalanceByAtMostTypedAmount({
|
submitChangesBalanceByAtMostTypedAmount({
|
||||||
route: "home",
|
route: "home",
|
||||||
lastAction: { kind: "Tap", on: submitOn, applied: true, relaunched: true },
|
lastAction: { kind: "Tap", on: submitOn, applied: true, relaunched: true },
|
||||||
submitsInWindow: 1,
|
submitsInWindow: 1,
|
||||||
typedAmount: 500,
|
typedAmount: 500,
|
||||||
prevTotalBalance: 1000,
|
prevTotalBalance: 455800,
|
||||||
currTotalBalance: 1000,
|
currTotalBalance: 0,
|
||||||
}),
|
}),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user