Evidence (all reproduced by executing the real functions)
src/lib/statement-format/usd-compact.ts:
formatUsdCompact(999_999) → "$1000K" (and 999_950 → "$1000K") — should roll over to "$1M".
formatUsdCompact(-50_000) → "$-50K", -1_500_000 → "$-1.5M", -2_143 → "$-2,143" — ASCII hyphen inside the dollar amount, inconsistent with formatSignedUsd's typographic −$ convention (src/lib/statement-format/signed-usd.ts).
src/lib/statement-format/bucketed-usd.ts:
- Half-bucket rounding is asymmetric:
formatBucketedUsd(250, 500) → "~+$500" but formatBucketedUsd(-250, 500) → "<$500" (because Math.round(-0.5) rounds toward +∞). Positive and negative PnL of equal magnitude disclose differently — for a disclosure-sensitive surface this should be sign-symmetric (round half away from zero).
"<$500" for a negative near-zero value reads as "small positive". The live site currently shows <$25 for wallets that lost money (e.g. wallet_254c at −1.60, wallet_e68b at −6.25 on /statements/2026-05-31-weekly). Consider ±<$25 or ≈$0 wording.
bucketUsdToNearest(-1.6, 25) returns -0 (negative zero) — harmless today (-0 === 0), worth normalizing while in there.
TDD plan (failing tests first)
Extend the existing test files (usd-compact.test.ts, bucketed-usd.test.ts):
formatUsdCompact: 999_999 → "$1M", 999_950 → "$1M", -999_999 → "−$1M", -50_000 → "−$50K", -2_143 → "−$2,143", -12_500 → "−$12.5K" (decide sign-then-dollar order to match formatSignedUsd).
bucketUsdToNearest: (-250, 500) → -500 (half away from zero); (250, 500) → 500; Object.is(bucketUsdToNearest(-1.6, 25), 0) (no -0).
formatBucketedUsd: symmetric output for ±250; chosen wording for negative sub-bucket values.
Note: current tests only cover positive values ≥ 0 and miss the 999_999 boundary entirely — that's the gap that let these ship.
Acceptance criteria
| AC |
Test |
| K→M rollover at the formatting boundary |
unit |
| Single minus-sign convention across all USD formatters |
unit (assert the exact glyph) |
| Sign-symmetric bucketing |
unit |
Evidence (all reproduced by executing the real functions)
src/lib/statement-format/usd-compact.ts:formatUsdCompact(999_999)→"$1000K"(and999_950→"$1000K") — should roll over to"$1M".formatUsdCompact(-50_000)→"$-50K",-1_500_000→"$-1.5M",-2_143→"$-2,143"— ASCII hyphen inside the dollar amount, inconsistent withformatSignedUsd's typographic−$convention (src/lib/statement-format/signed-usd.ts).src/lib/statement-format/bucketed-usd.ts:formatBucketedUsd(250, 500)→"~+$500"butformatBucketedUsd(-250, 500)→"<$500"(becauseMath.round(-0.5)rounds toward +∞). Positive and negative PnL of equal magnitude disclose differently — for a disclosure-sensitive surface this should be sign-symmetric (round half away from zero)."<$500"for a negative near-zero value reads as "small positive". The live site currently shows<$25for wallets that lost money (e.g. wallet_254c at −1.60, wallet_e68b at −6.25 on /statements/2026-05-31-weekly). Consider±<$25or≈$0wording.bucketUsdToNearest(-1.6, 25)returns-0(negative zero) — harmless today (-0 === 0), worth normalizing while in there.TDD plan (failing tests first)
Extend the existing test files (
usd-compact.test.ts,bucketed-usd.test.ts):formatUsdCompact:999_999 → "$1M",999_950 → "$1M",-999_999 → "−$1M",-50_000 → "−$50K",-2_143 → "−$2,143",-12_500 → "−$12.5K"(decide sign-then-dollar order to matchformatSignedUsd).bucketUsdToNearest:(-250, 500) → -500(half away from zero);(250, 500) → 500;Object.is(bucketUsdToNearest(-1.6, 25), 0)(no-0).formatBucketedUsd: symmetric output for ±250; chosen wording for negative sub-bucket values.Note: current tests only cover positive values ≥ 0 and miss the 999_999 boundary entirely — that's the gap that let these ship.
Acceptance criteria