You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The monthly PDF now renders in PRESS — the warm-paper editorial brand shared across the author's other tools. Flat cream paper edge to edge, ink rules for structure, and a single accent colour. Owned by report/brand.py and overridable via BUDGET_BRAND_FILE.
Bars are ink; over-budget is a mark, not a hue. The accent is spent on the overspend segment past the budget tick, so the colour is a measure of how far over a category went rather than a label saying it was.
Savings-type categories no longer set the bar scale. A large transfer into a floor category used to compress every ordinary spending row to a few pixels.
The report opens with a generated one-line summary instead of a bare grid of figures.
Amazon connector (new)
Pulls order and item detail for an account and reconciles it against the ledger, so an otherwise opaque marketplace charge can be explained line by line.
Matching goes through the retailer's own transaction list, not order totals — one order can ship in several boxes and settle as several charges days apart.
Ambiguity is never guessed. Two same-amount charges in the same window are recorded unmatched and surfaced for confirmation; a wrong match would attribute the wrong basket to a charge.
Coverage is reported in dollars, not transaction count — nine small matches and one large miss is not "90% covered".
Authentication captures a browser session rather than storing a password, so passkey-only accounts work and no reusable credential lands on disk.
A sync that returns nothing while the ledger shows charges in the window aborts and writes nothing, rather than reporting an empty month.
Transaction splits (new)
One charge can be apportioned across several categories, so a mixed order stops counting entirely against whichever category its merchant rule assigned.
Aggregates read an effective_txns view; an unsplit row yields itself, a split row yields one line per split.
A transaction's splits must sum to its amount exactly — enforced on write and auditable at any time via budget verify-splits. A violation would invent or destroy money in every total downstream, silently.
Item prices are scaled proportionally to what was actually charged, so every cent lands on a real line and no synthetic adjustment row appears.
Categories are never inferred in code; allocation is proposed and confirmed, never assumed.
Security and privacy
Sync error messages are read-denied to the agent layer, matching the existing treatment of import errors — a stored exception can embed the values it was binding.
Connector data is written as immutable imported fact; the agent can read it and never write it.
Example data, comments and documentation were scrubbed of real values throughout.
Automation
Adopted a dev → main promotion model with auto-merge on green, branch cleanup on merge, and a manual gate before any release is tagged.
main now requires a passing check and forbids force-pushes and deletion; dev stays push-open but deletion-locked.