Repository navigation
Date, read and split money the same way everywhere (app review batch 3) - #26
Merged
Merged
Conversation
… shares Finding 33 from the app review. Activity, statements, the expenses download and "This month" cut each timestamp to its UTC date, so in a British summer anything entered between midnight and 1am, and in New York anything after 8pm, was dated the wrong day. They now share one helper, timestampDay, which gives the day where the member is, and the existing timestamp formatter is built on it. A statement could also list a repayment before the share it pays: when the money arrived before the bill was entered, or when the share's UTC date was the next day. A repayment now always follows its share, and a reversal its repayment, and each keeps its own date. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
Finding 52 from the app review. When an amount did not split evenly, allocateExpense gave the spare penny to whoever came first in the list it was given. Add expense previewed the split in the order people were ticked but saved it in member order, so after unticking and ticking someone again the preview showed the penny on one person and the save charged it to another. Ties for a spare penny now go by user id inside allocateExpense, so the same people always get the same amounts whatever order they are listed in, and every preview matches what is saved. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
Every money field, and every exact split amount, now reads what was typed through one parser in packages/core. "1,200" and "1,200.50" work in every commune; "12,50" works in a euro commune, and elsewhere the field says to use a full stop for pence. The Add expense window had its own parser with no upper limit, so it could send amounts the database refuses; every field now stops at the database's 10,000,000,000.00 and says so, and every money field is long enough to type it. Exact split templates are stored as plain figures however they were typed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
The settings screen counted only live expenses and funds, so with every expense voided it offered a currency change the database then refused. Neither counted recurring bills or exact split templates, so a commune with only those could switch from pounds to dollars and relabel their amounts. Migration 0035 puts the rule in one place: the currency is fixed once the commune has an expense, fund, recurring bill or exact split template, voided or archived ones included. update_commune_details enforces it, and the snapshot reports what fixes it, so the settings screen follows the same rule and says why the currency is locked. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
The statement picker listed only current members, so there was no way to see the record with someone who had left. People who have left and share anything with you are now listed under their own Former members heading, with the same statement, balance and CSV download. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
When an attempt to record a repayment, or to tell the payer about one, got no reply, a later refusal still said "Nothing was recorded" or "Nothing was reported", although the first attempt may have gone through. Both dialogs now say an earlier attempt may already have been saved and where to check, as the other money forms do. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
…ure attempt Once a correction or void may have been saved by an attempt whose reply was lost, a later refusal now says the earlier attempt may already have saved it and where to check, as the repayment and payment report dialogs do, instead of "Nothing was changed." Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
The local list and the Neon release order now run to 0035, and the handoff summarises the money accuracy fixes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
A first group of thousands starting with 0 was read as thousands, so "0,500", meant as 0.50, became 500.00 without a word, in every currency. A group of thousands now starts with 1 to 9, so it is refused with the field's example. Add expense previewed the split between everyone ticked, including someone who had left since the form opened, but saved it between the current members only: three people at 9.00 showed 3.00 each and saved 4.50 each. The preview now uses the same people as the save. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Owner
Author
|
The Vercel preview for Generated by Claude Code |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This branch had an error being deployed
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.
Before: activity, "This month", statements and exports dated entries by their UTC day, so an expense entered at 9pm in New York showed the next day, and one entered just after midnight in London's summer time showed the day before. Amount fields refused "1,200", and a euro commune could not type "12,50". Add expense could show the spare penny on one person and save it on another. A commune whose only records were recurring bills or exact split templates could switch from pounds to dollars, turning a £90 bill into $90, and the settings screen and the database disagreed about when the currency was fixed. Statements could not be opened for someone who had left. After an attempt whose reply was lost, a later refusal in the money dialogs said nothing had been saved, which might not be true.
After: entries are dated by the member's own day, every money field reads amounts one way, the preview and the save agree on every penny, one rule fixes the currency and the screen says why, statements with former members open from the breakdown, and those dialogs say an earlier attempt may already have been saved and where to check. Each fix has a test that fails on the old code.
This is batch 3 of the app review fixes and is built on #25 (batch 2), so review that first; the diff here shows only this batch.
What changed, by finding
packages/core/src/money.ts, used by every money field and exact split value. "1,200" and "1,200.50" work everywhere; "12,50" and "1.200,50" work in euro communes; elsewhere a decimal comma gets "Use a full stop for pence, like 12.50." A group of thousands never starts with 0, so "0,500" is refused rather than read as 500. The limit is the database's, 10,000,000,000.00, everywhere.update_commune_detailsenforces it and the snapshot reports what fixes it, which the settings screen explains.Releasing
Nothing hosted was touched. Migration 0035 is local only and follows 0034; it does not change the release order. A client from before 0035 keeps working: its settings screen may still offer a currency change that the database now refuses with a clear message.
How it was checked
On the final branch: 21 SQL test files on fresh databases plus the lock order test, 15 local API suites on a disposable database and port, 414 web tests in 39 files (date tests run in New York and London time zones), the reminder worker's tests, typechecks for the web app, local API and worker, and a production build.
In a browser: "1,200" read as £1,200.00 and saved with an even split, "12,50" refused in a pound commune with the full stop message, "12,50" and "1.200,50" read in a euro commune, a commune whose only record is a recurring bill showing the currency locked and why, and a statement with someone who left after repaying their share.
How
The database stays the authority:
commune_private.currency_locked_bydecides the currency rule, the snapshot reports it, and the screen only displays it (with the same rule worked out from loaded records against a database without 0035). The commune row is locked while the details change, and adding any of those records waits for that lock, so the database rule cannot be raced. One gap remains: a form left open while an admin changes the currency of a commune with no money records yet saves its amount in the new currency, where it then shows with the new symbol. The patch toupdate_commune_detailsand the snapshot usespg_get_functiondefandreplace()and stops if the definition no longer matches.🤖 Generated with Claude Code
https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
Generated by Claude Code