Summary
Split-check creation validates source state outside the transaction and uses proportional rounding that can produce an invalid negative remainder for small totals.
Current behavior
main/routes/bills.ts:263-339 reads and validates the source bill before withTxn.
- Concurrent split requests can both pass validation and create multiple split groups.
- The final check receives
totalMinor - used; rounded allocations can make this negative.
void_adjustment rows are not excluded from item allocation.
Expected behavior
A split operation should be atomic, repeat-safe, and allocate non-negative integer minor-unit amounts whose sums reconcile exactly.
Acceptance criteria
- Move source-state validation and allocation reads into the transaction.
- Allow only one split group per source order/bill.
- Use a largest-remainder or equivalent integer-minor-unit allocation algorithm.
- Reject or exclude invalid/void-adjustment rows.
- Add concurrent split, one-cent total, and voided-item regression tests.
Relevant files
main/routes/bills.ts, split-check integration tests
Summary
Split-check creation validates source state outside the transaction and uses proportional rounding that can produce an invalid negative remainder for small totals.
Current behavior
main/routes/bills.ts:263-339reads and validates the source bill beforewithTxn.totalMinor - used; rounded allocations can make this negative.void_adjustmentrows are not excluded from item allocation.Expected behavior
A split operation should be atomic, repeat-safe, and allocate non-negative integer minor-unit amounts whose sums reconcile exactly.
Acceptance criteria
Relevant files
main/routes/bills.ts, split-check integration tests