Skip to content

fix: the dashboard asserted $0.00 before anything had ever looked - #202

Merged
GeiserX merged 1 commit into
mainfrom
fix/beads-batch-19
Aug 4, 2026
Merged

fix: the dashboard asserted $0.00 before anything had ever looked#202
GeiserX merged 1 commit into
mainfrom
fix/beads-batch-19

Conversation

@GeiserX

@GeiserX GeiserX commented Aug 4, 2026

Copy link
Copy Markdown
Owner

The defect

A brand-new user's first view of CashPilot:

Total Balance $0.00 — Today $0.00 — This Month $0.00

Stated as measurements, in the same typeface those cards will later carry real money in. Worse, the same three cards render identically when collection has silently stopped — an expired cookie, deleted credentials, a wedged scheduler.

Verified live on an empty install: /api/earnings/summary returns {"total":0,"today":0.0,"month":0,...} with no field separating "no earnings rows exist" from "balances summed to zero". And dashboard.html shipped the zeroes hardcoded, so they were on screen before any request was made.

The fix

/api/earnings/summary now reports has_readings, computed from the earnings rows it was already fetching — no extra query. The cards render an em dash plus "Nothing collected yet" until something has actually been read. The topbar total gets the same treatment, since one of them saying $0.00 would undo the other.

A service read at exactly 0.00 still counts as read. Folding a genuine measured zero back into "nothing yet" would replace one wrong answer with another, and a control pins it.

This is the rule the codebase already applies to balances, running costs and payout minimums — absent is not zero — applied to the first screen a new user ever sees.

Evidence

ruff check + ruff format --check clean, node --check clean, 95.12% coverage, 2644 passed.

Negative control:

reverted tests that fail
endpoint stops reporting has_readings 3
derive it from the total instead of the rows 2
cards render currency unconditionally 1
one hardcoded $0.00 restored to the template 2

One note worth recording: the third control initially passed. My renderer assertion matched data.has_readings === false anywhere in the file, and the note-toggling line satisfies it on its own — so it proved nothing about the three cards it named. Strengthened to pin the money path, and each card is now separately asserted to go through it.

Closes CashPilot-93t

A brand-new user's first view of CashPilot was "Total Balance $0.00 / Today
$0.00 / This Month $0.00" — stated as measurements, in the same typeface those
cards will later carry real money in. The three cards rendered identically when
collection had silently STOPPED: an expired cookie, deleted credentials, a
wedged scheduler. Nothing in the payload let the page tell "nothing measured
yet" from "measured, and it was zero", and the template shipped the zeroes
hardcoded, so they were on screen before any request was even made.

/api/earnings/summary now reports has_readings, computed from the earnings rows
it was already fetching. The cards render an em dash and "Nothing collected yet"
until something has actually been read; the topbar total gets the same
treatment, since one of them saying $0.00 would undo the other.

A service read at exactly 0.00 still counts as read. Folding a genuine measured
zero back into "nothing yet" would replace one wrong answer with another, and a
control pins it.

This is the rule the codebase already follows for balances, costs and payout
minimums — absent is not zero — applied to the first screen a new user sees.

Negative control: dropping has_readings fails 3 tests; deriving it from the
total instead of the rows fails 2; rendering currency unconditionally fails 1;
restoring one hardcoded $0.00 fails 2. The renderer assertion was strengthened
after the third control initially PASSED — it matched a string that also occurs
on the note-toggling line, so it was proving nothing about the cards it named.

Closes CashPilot-93t
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@GeiserX, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c804132-30e7-4d20-940e-7288806c1cec

📥 Commits

Reviewing files that changed from the base of the PR and between 52b6ad6 and d1fcbf8.

📒 Files selected for processing (4)
  • app/main.py
  • app/static/js/app.js
  • app/templates/dashboard.html
  • tests/test_beads_batch_19.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.07%. Comparing base (52b6ad6) to head (d1fcbf8).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #202   +/-   ##
=======================================
  Coverage   95.07%   95.07%           
=======================================
  Files          46       46           
  Lines        5912     5913    +1     
=======================================
+ Hits         5621     5622    +1     
  Misses        291      291           
Files with missing lines Coverage Δ
app/main.py 97.35% <100.00%> (+<0.01%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@GeiserX
GeiserX merged commit 6a8569f into main Aug 4, 2026
8 checks passed
@GeiserX
GeiserX deleted the fix/beads-batch-19 branch August 4, 2026 15:06
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