Skip to content

0.4.0: spending insights, safety net follow-through, payment method, stale-rate transparency, tests#14

Merged
kenrinzero merged 3 commits into
mainfrom
claude/roadmap-0.4.0
May 30, 2026
Merged

0.4.0: spending insights, safety net follow-through, payment method, stale-rate transparency, tests#14
kenrinzero merged 3 commits into
mainfrom
claude/roadmap-0.4.0

Conversation

@kenrinzero

Copy link
Copy Markdown
Owner

0.4.0 — finishing the post-audit roadmap

Implements every kept item from the improvement audit, landed as one release. Branches off main after PR #13 (safety net) was merged; bumps 0.3.0 → 0.4.0.

Data insight (mining the renewal_log + categories)

  • by_category totals mode (t) — per-category monthly-equivalent subtotals in base, largest first (top-5 + "+N").
  • forecast totals mode (t) — concrete, non-amortized 30/60/90-day cash-out (walks each active sub's real billing cycles; cumulative and horizon-inclusive), so clustered annual renewals stop hiding behind the amortized average.
  • Month-grouped history (h) — per-month subtotal headers; the current month's header also shows your amortized estimate, so actual-so-far reads against what you committed to.

Features

  • Duplicate a subscription (D / Shift+D) — clones the highlighted sub into a prefilled modal (lowercase d stays Delete).
  • payment_method field — optional funding source ("which card is this on?"): additive column + migration, full CRUD/CSV/JSON round-trip, a modal field, shown on the row, and matched by the / filter.
  • Budget warning — when a monthly income is set and amortized commitment exceeds it, the notice board shows a calm ▲ BASE x over budget (n%) line under the banner, regardless of the active totals mode.

Robustness

  • Stale-rate transparencycurrency.get_rate_status returns (rate, fresh|stale|missing). A failed fetch now reuses the last-known rate of any age (db.get_last_rate) instead of a fake 1:1, and the title bar distinguishes ⌛ stale (old-but-real) from ⚠ rate (never cached). A genuine 1.0 fetched today reads as fresh, not flagged.

Code health & tests

  • gakkari/totals.py — the money/sort math lifted out of the MainScreen god-object into pure, explicitly-parameterized functions; MainScreen delegates.
  • GAKKARI_DB env seam in get_conn() (read at call time) so tests/tooling can point at a temp DB.
  • First test suitetests/ with 57 pytest tests (models date/tax/factor math, totals incl. forecast/by-category, io validation + round-trip, db round-trips + backup rotation, EN/JA i18n key-parity) + .github/workflows/ci.yml running them plus a non-UTF-8-locale CLI smoke (which guards the --help/--notice em-dash fix) on Python 3.12 / 3.13.
  • Polish — UTF-8 stream guard moved to the top of __main__.main() (fixes --help/argparse mojibake under a legacy codepage); dead SCREENS dict + redundant CSS_PATH removed from app.py.

Docs

CLAUDE.md (data model, totals cycle, rate-freshness, project layout, a 0.4.0 deltas section) and README (features + credits) refreshed.

Verification

  • 57 tests pass; py_compile + import smoke clean; --help and --notice exit 0 under LC_ALL=C.
  • An adversarial multi-agent review of the full diff (UI wiring, history/notice signature changes, data layer + SQL placeholder counts, totals parity) returned zero correctness findings — the one low-severity note (export default path ignoring the new env seam) is fixed in this branch.

🤖 Generated with Claude Code

kenrinzero and others added 3 commits May 30, 2026 14:42
…sparency, tests

Finishes the post-audit roadmap (everything kept). Bumps 0.3.0 -> 0.4.0.

Data insight
- by_category and forecast (30/60/90-day cash-out) totals-cycle modes
- history screen grouped by month with per-month subtotals + the current
  month's actual-vs-estimate line

Features
- duplicate a subscription (Shift+D) into a prefilled modal
- payment_method field on Subscription (column + migration, CRUD/io round-trip,
  modal field, filterable, shown on the row)
- budget over-commitment warning in the notice board (when income is set)

Robustness
- stale-rate transparency: get_rate_status -> (rate, fresh|stale|missing); a
  failed fetch reuses the last-known rate (db.get_last_rate) instead of a fake
  1:1, and the title bar shows stale vs missing distinctly

Code health / tests
- lifted totals + sort math into pure gakkari/totals.py (MainScreen delegates)
- GAKKARI_DB env seam in get_conn() so tests use a temp DB
- tests/ pytest suite (54 tests: models, totals, io, db) + .github/workflows/ci.yml
- moved the UTF-8 stream guard to the top of __main__.main() (fixes --help /
  --notice em-dash mojibake under a legacy codepage); removed the dead SCREENS
  dict + redundant CSS_PATH from app.py

Docs: CLAUDE.md + README refreshed; version bumped in all three spots.
Verified: 54 tests pass; py_compile + import smoke clean; --help/--notice exit 0
under LC_ALL=C.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…I_DB

- tests/test_strings.py: assert EN and JA string tables have identical keys
  (a missing JA key silently falls back to EN), plus t() fallback behavior.
- export_modal._default_path now resolves through db._db_path() so the
  suggested export directory tracks the DB actually in use (addresses the
  one low-severity finding from the 0.4.0 review).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- docs/index.html: features list updated for 0.4.0 (undo, month-grouped
  history, by-category + forecast totals, duplicate + payment-method,
  budget watch, safe-by-default) and the Opus 4.8 credit line; the site is
  a standalone file, so it does not track the README automatically.
- notice_panel tutorial (N off-state): add the global ? Help and Esc Back
  rows (the new D/u keys were already present), + bind_back string EN/JA.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kenrinzero kenrinzero merged commit 236e57d into main May 30, 2026
4 checks passed
@kenrinzero kenrinzero deleted the claude/roadmap-0.4.0 branch May 30, 2026 13:03
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.

1 participant