Skip to content

feat(money): integer micro-dollar storage (#38)#44

Merged
tcconnally merged 1 commit into
mainfrom
fix/micro-dollars-38
Jun 24, 2026
Merged

feat(money): integer micro-dollar storage (#38)#44
tcconnally merged 1 commit into
mainfrom
fix/micro-dollars-38

Conversation

@tcconnally

Copy link
Copy Markdown
Contributor

Summary

Closes #38. Money was stored as REAL USD, which accumulates float drift when summing many sub-cent ledger rows. This switches storage to integer micro-dollars (1 USD = 1,000,000 micros) so balances and spend totals are exact, while keeping the entire public API and templates in float USD.

Changes

  • db.py: SCHEMA_VERSION = 4; usd_to_micros/micros_to_usd helpers + MICROS_PER_USD; money columns now INTEGER (cost_micros, delta_micros, balance_after_micros, monthly_budget_micros); idempotent v3->v4 migration (_migrate_money_to_micros) that ALTERs, backfills round(usd*1e6), and drops legacy columns; row accessors expose float-USD aliases so callers, views, reports, and Stripe code are unchanged.
  • metering.py / reports.py: all SUM(cost_usd)/SUM(delta_usd) aggregate on the *_micros integer columns and convert to USD once at the boundary.

Tests

tests/test_micros.py (9 new): conversion round-trip & rounding, exact summation over 10,000 sub-cent debits (no drift), integer-column assertions, and v3->v4 migration + idempotency. Full suite: 102 passed (93 existing + 9 new). Python 3.9-safe, stdlib only.

Closes #38. Money was stored as REAL USD, which drifts when summing many
sub-cent rows. Switch storage to integer micro-dollars (1 USD = 1_000_000
micros) so ledger balances and spend totals are exact, while keeping the
public API in float USD.

- db.py: SCHEMA_VERSION=4; usd_to_micros/micros_to_usd helpers; money cols
  -> INTEGER (cost_micros, delta_micros, balance_after_micros,
  monthly_budget_micros); idempotent v3->v4 migration with exact backfill;
  row accessors expose float-USD aliases at the boundary.
- metering.py / reports.py: aggregate on *_micros, convert to USD at edges.
- tests/test_micros.py: conversion round-trip, exact summation over 10k
  sub-cent debits, integer-column assertions, v3->v4 migration + idempotency.
@tcconnally tcconnally merged commit 4c51d3e into main Jun 24, 2026
4 checks passed
@tcconnally tcconnally deleted the fix/micro-dollars-38 branch June 24, 2026 02:16
tcconnally added a commit that referenced this pull request Jun 24, 2026
…ELOG

Both 1.0 launch-gate milestones are merged in code but the version was stuck
at 0.5.1 with no changelog entries for either:

- v0.6 money & concurrency correctness (#26#30, #38) — merged via #41/#44.
- v0.7 security hardening (#31#37) — merged via #42.

Bump version (pyproject + __init__) to 0.7.0 and add [0.6.0] and [0.7.0]
CHANGELOG sections so the version reflects reality. No behavior change; no
launch switches flipped — the roadmap's v0.7 exit (external security review)
remains a separate human gate before public launch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tcconnally added a commit that referenced this pull request Jun 24, 2026
…ELOG (#45)

Both 1.0 launch-gate milestones are merged in code but the version was stuck
at 0.5.1 with no changelog entries for either:

- v0.6 money & concurrency correctness (#26#30, #38) — merged via #41/#44.
- v0.7 security hardening (#31#37) — merged via #42.

Bump version (pyproject + __init__) to 0.7.0 and add [0.6.0] and [0.7.0]
CHANGELOG sections so the version reflects reality. No behavior change; no
launch switches flipped — the roadmap's v0.7 exit (external security review)
remains a separate human gate before public launch.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] Store money as integer micro-dollars instead of float REAL

1 participant