A participant who has overpaid a trip showed as "$-816.16" under a column
headed "Outstanding on this trip". A negative outstanding reads as a bug
rather than as "they are ahead", so the sign is now spelled out: magnitude
plus one of all square / owes you / ahead — you owe them, coloured the same
way Shared colours the same three states.
Also corrects the footer, which had gone stale and was now simply false. It
said settlement could not be computed per trip because payments carried no
trip attribution. Migration 0022 added split_payments.trip_id and the figures
above it have been net of trip-scoped payments since. What a reader needs to
know is the opposite of what it said: household-tab payments are the ones NOT
counted here.
Total Spend is every payer's trip-tagged spending; the split figures directly
below it are scoped to the owner. Two lenses on one screen read as one unless
the card says which it is. The number is unchanged and deliberate -- a trip
cost what the group put into it -- so this is a label, not a fix.
a4ab543 landed six hours ago and this branch rewrote one of the queries it
had just fixed, quietly dropping both of its guarantees.
That commit made EXCLUDE_RECONCILED_SOURCE "one fragment both sides import"
because an inlined copy is how the reconciled-row exclusion drifted out of
the analytics routes and double-counted 48 rows / $4,474.79. The trip owed
query here had hand-inlined its own copy — the fragment assumes the alias
`t` and this query used `tx`, so the path of least resistance was to
re-create exactly the divergence that was being removed. Aliased to `t` so
the fragments apply directly.
The same commit made balances count rows whose AUD value is unknown rather
than netting a foreign figure against AUD ones. The trip figure had no
equivalent — on the query where it matters most, because a trip is where
foreign rows actually live. A Europe total silently mixing EUR into AUD is
the whole failure that fix was written to prevent.
The column header still read "Share of this trip" while the number is now
net of payments, which is the same class of drift a4ab543 set out to fix.
It reads "Outstanding on this trip", carries the approx/unconverted caveat
the Shared cards use, and greys a settled zero.
The trip view showed Total Owed / Settled / Unsettled per participant, with the
last two derived from transaction_splits.settled. Nothing sets that flag - its
only writer was /api/splits/settle, which no UI calls - so it is false on all 673
splits and every trip reported 100% unsettled, including trips already paid in
full. Molina has paid $20,782.79 against $19,556.07 of splits and the Europe trip
still showed her entire share outstanding.
A correct per-trip figure is not computable either: split_payments records only
from, to, amount and date, so a payment cannot be attributed to a trip. The trip
view now shows each participant's share and points at Shared for what is actually
owed, which is where settlement genuinely lives.
Also removes /api/splits/settle. It was unreachable from the UI but live on its
URL, and a single call with participant_id would mark every one of that person's
splits settled - writing a flag nothing reads. Settlement will be reintroduced
against settlement contexts (docs/shared-expenses-design.md).
getParticipantBalances is deliberately untouched: it computes splits minus
payments, which is coherent. Excluding settled splits there while still
subtracting the payments that settled them would double-count.
App-wide retheme done at the token layer: Tailwind's zinc scale is remapped
to warm ink/paper neutrals and indigo to copper in globals.css, so every
page inherits the palette. Fraunces (serif display) added for page titles
and hero figures; all figures now render in mono with tabular numerals.
Analytics page redesigned around a month spine — twelve clickable columns
scaled to each month's spend that act as hero, context, and period
navigation. Adds a 'What changed' top-movers panel vs the previous month,
replaces the 8-line category trend chart with per-category sparkline small
multiples, heat-tints the six-month ledger table, and restyles the Pareto,
pace chart, and cashflow strip. Kept: Pareto, cumulative-vs-typical pace,
drill-downs, regular/occasional split.
Insights and Merchants restyled to the same kit; chart tokens centralised
in category-colors.ts (CHART). Cleared the pre-existing lint errors in
insights (typed tooltip, removed any-casts).
Adds trips table usage across API and UI: trip CRUD, per-trip analytics
(category/daily/merchant/tag/participant breakdowns), tag-to-trip
conversion, trip assignment via transaction overrides, and trip filter
in the transactions view. Recovered from working tree after local git
corruption; feature was already live via host-context Docker builds.