refactor(folio): name the balance property for the bound it asserts

it stopped being an equality and became |delta| <= typed, so the old name
demanded more than the property does. renamed with the ci gate's
GATED_PROPERTIES in the same commit so the gate never sees a name it does
not know.
This commit is contained in:
pj committed 2026-08-15 23:04:15 +05:30
1 parent 6a7764eac7
commit 112d347432
8 files changed
+57 -57

No files matched your search

@@ -3,14 +3,14 @@ import { test } from "node:test";
import {
parseTypedAmount,
submitChangesBalanceByTypedAmount,
submitChangesBalanceByAtMostTypedAmount,
} from "../../../examples/folio/sanderling/predicates.ts";
const submitOn = "testTag:LedgerScreen > testTag:TxnSubmit";
test("single submit: delta matches typed amount", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -24,7 +24,7 @@ test("single submit: delta matches typed amount", () => {
test("double submit: delta is twice the typed amount, fires", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -38,7 +38,7 @@ test("double submit: delta is twice the typed amount, fires", () => {
test("DoubleTap kind also caught when delta exceeds typed amount", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "DoubleTap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -52,7 +52,7 @@ test("DoubleTap kind also caught when delta exceeds typed amount", () => {
test("wrong action kind: vacuous true even with mismatch", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "InputText", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -66,7 +66,7 @@ test("wrong action kind: vacuous true even with mismatch", () => {
test("wrong target: vacuous true even with mismatch", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: "testTag:LoginScreen > testTag:LoginSubmit", applied: true },
submitsInWindow: 1,
@@ -80,7 +80,7 @@ test("wrong target: vacuous true even with mismatch", () => {
test("null lastAction: vacuous true", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: null,
submitsInWindow: 1,
@@ -94,7 +94,7 @@ test("null lastAction: vacuous true", () => {
test("zero typedAmount: vacuous true", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -108,7 +108,7 @@ test("zero typedAmount: vacuous true", () => {
test("selector as object: coerced safely and TxnSubmit detected", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: { testTag: "TxnSubmit" }, applied: true },
submitsInWindow: 1,
@@ -122,7 +122,7 @@ test("selector as object: coerced safely and TxnSubmit detected", () => {
test("selector as object without TxnSubmit: vacuous true", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: { testTag: "LoginSubmit" }, applied: true },
submitsInWindow: 1,
@@ -136,7 +136,7 @@ test("selector as object without TxnSubmit: vacuous true", () => {
test("raw whole-dollar input: single submit clears", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -150,7 +150,7 @@ test("raw whole-dollar input: single submit clears", () => {
test("raw whole-dollar input: double submit fires", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -164,7 +164,7 @@ test("raw whole-dollar input: double submit fires", () => {
test("decimal input from empty prior balance clears", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -178,7 +178,7 @@ test("decimal input from empty prior balance clears", () => {
test("DoubleTap kind with raw whole-dollar input fires", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "DoubleTap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -192,7 +192,7 @@ test("DoubleTap kind with raw whole-dollar input fires", () => {
test("route gate: ledger landing with stale carrier is skipped", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "ledger",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -206,7 +206,7 @@ test("route gate: ledger landing with stale carrier is skipped", () => {
test("route gate: add-transaction landing with double-submit delta is skipped", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "add-transaction",
lastAction: { kind: "DoubleTap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -220,7 +220,7 @@ test("route gate: add-transaction landing with double-submit delta is skipped",
test("route gate: null route is skipped", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: null,
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -234,7 +234,7 @@ test("route gate: null route is skipped", () => {
test("route gate: home landing with matching delta passes", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -248,7 +248,7 @@ test("route gate: home landing with matching delta passes", () => {
test("route gate: home landing with double-insert delta fires", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -273,7 +273,7 @@ test("above 2^53 the arithmetic itself is wrong, which is why the guard exists",
test("above 2^53 a healthy single submit is not reported", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -287,7 +287,7 @@ test("above 2^53 a healthy single submit is not reported", () => {
test("above 2^53 a double-submit delta is not reported either", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -301,7 +301,7 @@ test("above 2^53 a double-submit delta is not reported either", () => {
test("an unreadable previous balance above 2^53 is not evidence", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -318,7 +318,7 @@ test("an unreadable previous balance above 2^53 is not evidence", () => {
// and must not convict on one it cannot hold.
test("typed amount above 2^53 is not evidence", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -334,7 +334,7 @@ test("typed amount above 2^53 is not evidence", () => {
// more is where counting stops being exact.
test("boundary: a double submit landing exactly on MAX_SAFE_INTEGER still fires", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -348,7 +348,7 @@ test("boundary: a double submit landing exactly on MAX_SAFE_INTEGER still fires"
test("boundary: a single submit landing exactly on MAX_SAFE_INTEGER passes", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -362,7 +362,7 @@ test("boundary: a single submit landing exactly on MAX_SAFE_INTEGER passes", ()
test("boundary: one cent past MAX_SAFE_INTEGER stops being evidence", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -379,7 +379,7 @@ test("boundary: one cent past MAX_SAFE_INTEGER stops being evidence", () => {
// typed amount, so a mismatch here is real and must still be reported.
test("a large but exact difference between safe balances still fires", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -395,7 +395,7 @@ test("a large but exact difference between safe balances still fires", () => {
// and the property must stay quiet rather than demand a 1e23-cent move.
test("21-digit typed amount with an unmoved balance is not a violation", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -415,7 +415,7 @@ test("21-digit typed amount with an unmoved balance is not a violation", () => {
// and an unrelated 26200 credit.
test("freshness: two submits in the window is vacuous, not a conviction", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "DoubleTap", on: submitOn, applied: true },
submitsInWindow: 2,
@@ -429,7 +429,7 @@ test("freshness: two submits in the window is vacuous, not a conviction", () =>
test("freshness: two submits cannot convict even on a clean 2x delta", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 2,
@@ -446,7 +446,7 @@ test("freshness: two submits cannot convict even on a clean 2x delta", () => {
// (nothing to attribute the move to), and two or more means the move is shared.
test("freshness boundary: exactly one submit is the window that convicts", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "DoubleTap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -460,7 +460,7 @@ test("freshness boundary: exactly one submit is the window that convicts", () =>
test("freshness boundary: one submit with a healthy 1x delta still passes", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -474,7 +474,7 @@ test("freshness boundary: one submit with a healthy 1x delta still passes", () =
test("freshness boundary: three submits is vacuous", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 3,
@@ -491,7 +491,7 @@ test("freshness boundary: three submits is vacuous", () => {
// submit in it explains no balance move.
test("freshness boundary: a window with no submit in it is vacuous", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 0,
@@ -509,7 +509,7 @@ test("freshness boundary: a window with no submit in it is vacuous", () => {
// did exactly what it should have.
test("a submit the runner could not confirm demands no balance move", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: null },
submitsInWindow: 1,
@@ -528,7 +528,7 @@ test("a submit the runner could not confirm demands no balance move", () => {
// and an equality reads that as the app having ignored the amount.
test("a commit the Home total has not caught up with is not a violation", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -546,7 +546,7 @@ test("a commit the Home total has not caught up with is not a violation", () =>
// that fires on both is not evidence about either.
test("an under-move is no longer judged, which is the trade", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -568,7 +568,7 @@ test("the measured double submit still fires under the bound", () => {
[200000032904800, 200000032911200],
]) {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "DoubleTap", on: submitOn, applied: true },
submitsInWindow: 1,
@@ -590,7 +590,7 @@ test("the measured double submit still fires under the bound", () => {
// the runner's own restart.
test("a submit the runner relaunched across demands no balance move", () => {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "Tap", on: submitOn, applied: true, relaunched: true },
submitsInWindow: 1,
@@ -607,7 +607,7 @@ test("a submit the runner relaunched across demands no balance move", () => {
test("no relaunch reported still convicts a double submit", () => {
for (const relaunched of [null, undefined]) {
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { kind: "DoubleTap", on: submitOn, applied: true, relaunched },
submitsInWindow: 1,
+4 -4
View File
@@ -6,7 +6,7 @@ import {
readHomeCards,
readHomeTotalBalance,
routeOfFrame,
submitChangesBalanceByTypedAmount,
submitChangesBalanceByAtMostTypedAmount,
} from "../../../examples/folio/sanderling/predicates.ts";
// The spec's own screen table. A frame is the set of markers its accessibility
@@ -119,7 +119,7 @@ test("the measured android transition chain no longer convicts at delta 0", () =
const landing = step(["HomeScreen"], "$86,911.00", phantomSubmit);
assert.equal(landing.submits, 6);
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: landing.route,
lastAction: phantomSubmit,
submitsInWindow: landing.submits,
@@ -137,7 +137,7 @@ test("the measured android transition chain no longer convicts at delta 0", () =
// than an equality. A balance that did not move is under any typed amount,
// whether nothing was submitted or the total has not caught up yet.
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: phantomSubmit,
submitsInWindow: 1,
@@ -151,7 +151,7 @@ test("the measured android transition chain no longer convicts at delta 0", () =
// The double tap it was always meant to catch is untouched by that: two
// 33900 debits against one action still exceed the amount typed for it.
assert.equal(
submitChangesBalanceByTypedAmount({
submitChangesBalanceByAtMostTypedAmount({
route: "home",
lastAction: { ...phantomSubmit, kind: "DoubleTap" },
submitsInWindow: 1,
+1 -1
View File
@@ -338,7 +338,7 @@ test("an extractor that returned undefined keeps its index through JSON", () =>
// state.lastAction is the one piece of state the page cannot observe for
// itself: only the runner knows which action it actually applied. While the web
// runtime hardcoded null there, a spec property gated on the last action (e.g.
// folio's submitMovesBalanceByTypedAmount, which only looks at taps on
// folio's submitMovesBalanceByAtMostTypedAmount, which only looks at taps on
// TxnSubmit) was vacuously true on web forever, and the run went green having
// checked nothing.
function lastActionSeenByASpec(pushed: unknown): unknown {