Shared costs, split to the penny - #15
Merged
Merged
Conversation
The last big gap from the research. Flatastic wins flatshares by bundling chores with groceries and money, and Splitastic exists purely because people wanted a self-hosted version of the money half. Everything is integer minor units. Money in floating point is a well-known way to end up a penny out and unable to explain why, and being unable to explain why is fatal for a feature whose entire job is settling an argument about money. splitEvenly hands out the remainder one unit at a time rather than dropping it, so shares always sum to exactly the amount. A ledger that loses a penny per split loses trust far faster than one that is a penny uneven. There is a property test across a range of amounts and household sizes confirming it. settleUp is greedy - repeatedly settle the largest creditor against the largest debtor. Not provably minimal, since that is NP-hard, but within one transfer of optimal at household sizes and, more importantly, stable and explainable. 'You pay Ben twelve pounds' is a sentence people act on; a clever three-way cycle is one they argue with. Shares are stored per expense rather than recomputed from the current member list, for the same reason effort is snapshotted onto a completed chore: somebody joining or leaving next month must not silently rewrite what was owed last month. One correction on the way. My epsilon test asserted no single-penny transfers, but the default epsilon of 1 only drops zero-value ones. The code was right and the test was wrong: for money, silently discarding a penny is worse than mentioning one. Fixed the misleading comment, kept the exact-clearing default, and added a test for the rounding option showing precisely what it leaves unsettled. 25 new tests, 222 total. All six routes verified against the running server with no errors.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The last big gap from the research. Flatastic wins flatshares by bundling chores with groceries and money, and Splitastic exists purely because people wanted a self-hosted version of the money half.
Everything is integer pence
Money in floating point is a well-known way to end up a penny out and unable to explain why — and being unable to explain why is fatal for a feature whose entire job is settling an argument about money.
splitEvenlyhands out the remainder one unit at a time rather than dropping it, so shares always sum to exactly the amount. £10 between three is 334/333/333, not three lots of 333 and a penny quietly gone. There's a property test across a range of amounts and household sizes confirming it holds.Settling up
Greedy: repeatedly settle the largest creditor against the largest debtor.
Not provably minimal — that's NP-hard — but it lands within one transfer of optimal at household sizes, and it has a property that matters more here than optimality: it's stable and explainable. "You pay Ben £12" is a sentence people act on. A clever three-way cycle is one they argue with, which defeats the point.
Guaranteed to need at most n−1 payments for n people, with a test asserting it.
Shares are stored, not recomputed
Per expense, explicitly — for the same reason effort is snapshotted onto a completed chore. Somebody joining or leaving next month must not silently rewrite what was owed last month.
Settled expenses stay in the ledger as history rather than being deleted; "what did we spend last month" is a question people ask.
A correction worth recording
My epsilon test asserted that no single-penny transfers are emitted — but the default epsilon of 1 only drops zero-value transfers.
The code was right and the test was wrong. For money, silently discarding a penny is worse than mentioning one, so the exact-clearing default stays. I fixed the misleading doc comment that had implied otherwise, and added a separate test for the rounding option that states precisely how much it leaves unsettled.
Verified
25 new tests (222 total), including household isolation: one household can neither read, settle, nor delete another's ledger. All six routes confirmed against the running server with zero errors.