Skip to content

Payment Split Fractional Rounding Auditor #590

Description

@Kingsman-99

Description

When invoice amounts are divided among recipients using non-integer ratios, floating-point rounding can produce per-recipient amounts that do not sum exactly to the invoice total. Even a one-stroop discrepancy causes settlement failures or unintentional overpayment, and the error is currently silent. A rounding auditor would verify that computed per-recipient amounts sum exactly to the total, apply a deterministic largest-remainder correction when needed, and record each adjustment for downstream audit logging.

Technical Context

New module src/invoice/rounding.ts exposing auditSplitRounding(total: bigint, splits: SplitLine[]): AuditedSplitResult. All amounts represented as bigint stroops throughout to avoid floating-point drift. SplitLine, AuditedSplitResult, and RoundingOverflowError types in src/types.ts. Integrates with src/invoice/calculator.ts where per-recipient amounts are first derived. Edge cases include ratios that do not sum to exactly 1.0 and invoice amounts as small as 1 stroop.

Acceptance Criteria

  • auditSplitRounding returns adjusted amounts that sum exactly to total as a bigint
  • The largest-remainder method is used for correction: fractional remainders are ranked descending and whole stroops distributed to recipients with the largest remainders first
  • Adjustments whose total absolute value exceeds BigInt(Math.ceil(splits.length / 2)) stroops throw a RoundingOverflowError to surface unexpectedly large deviations
  • Each applied adjustment is recorded in AuditedSplitResult.adjustments as { recipientId: string; delta: bigint } for use by the per-split audit log
  • Tests cover exact-division splits requiring no correction, a 3-way uneven split requiring +1 stroop correction, and a 1-stroop invoice split across 3 recipients
  • All CI checks (npm test, npm run build, ESLint/TypeScript) pass and the branch has no merge conflicts

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions