Feat/expr number overload#66
Conversation
…(), raw number and tag still work directly
Greptile SummaryThis PR introduces a new
Confidence Score: 3/5Safe to review further, but the number overload introduces a client-side validation gap that allows negative cent amounts to silently reach the backend. The number overload in
Important Files Changed
|
| if (typeof value === "number") { | ||
| return toExprValue({ kind: "amount", value } as PriceExpr<TTags>); | ||
| } |
There was a problem hiding this comment.
Negative amounts bypass the nonnegative debit guard
biller.expr(-100) produces { kind: "amount", value: -100 }, an ExprValue that passes isValidExpr() because validateAmount() only rejects non-finite and non-integer values — negative numbers are explicitly left to "the backend". Meanwhile, passing -100 directly as debit: -100 is rejected immediately by the Zod union's z.number().nonnegative() branch. The two paths that reach the same semantic result are validated inconsistently, so a negative raw-amount expression silently escapes the client-side guard that exists for the direct-number case.
No description provided.