Skip to content

fix(stats): stop showing 0 MiB for tiny media and scan media once per stats run - #476

Merged
GeiserX merged 1 commit into
mainfrom
ai/stats-nits
Sep 24, 2026
Merged

GeiserX merged 1 commit into
mainfrom
ai/stats-nits

Conversation

@GeiserX

@GeiserX GeiserX commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Problem

The statistics popup showed "0 MiB" of storage next to a non-zero file count whenever the downloaded media added up to less than half a MiB. The daily statistics job also scanned the downloaded media three times: a count, a size sum, and the per-(account, chat) grouping, although the grouping already carries both figures. And no test covered a cached blob that holds the per-chat media counts map but not the bytes map, the case where a restricted viewer must get neither media figure.

Fix

  • formatSize in index.html returns <1 MiB when the size is above 0 and below 0.5 MiB. Zero still reads 0 MiB and every other value renders as before. A node test runs the real function: 0, 0.29, 0.5 and 12.3 give 0 MiB, <1 MiB, 1 MiB and 12 MiB. The last two were pinned from the output before this change.
  • calculate_and_store_statistics adds up media_files and the DB size total from the grouped rows, including rows with a NULL chat_id, which appear in neither map. The two standalone queries are gone. The stored keys and values stay the same. The mocked test now expects 4 execute calls. A new test on a real SQLite adapter seeds one NULL-chat row and one row that was never downloaded, then checks that the totals equal the map sums plus the NULL-chat row.
  • A new route test in test_stats_account_scoped.py writes a blob with the counts map and no bytes map. A restricted principal gets neither media_files nor total_size_mb; an unrestricted one still gets the archive-wide figures. The route code did not change. The test pins the existing and guard: switching it to or fails only this test.

What it deletes / overwrites / forgets

  • Deletes: nothing.
  • Overwrites: nothing new. The cached_stats blob is rewritten the same way it was before, with the same keys and values.
  • Forgets: nothing.

For review

  • On PostgreSQL, SUM(file_size) used to come back as a Decimal. Now the total is the sum of Python ints, the same way the per-chat bytes map was already built. total_size_mb could differ in the last rounded digit only in a rare tie, and SQLite behaves exactly as before. The Postgres-parametrised tests skip locally and run in CI.
  • <1 MiB also shows in the per-chat badge, but the badge only renders when the size is above 0, so a chat with no media still shows no badge.

Summary by CodeRabbit

  • Bug Fixes
    • File sizes greater than zero but smaller than 0.5 MiB now display as “<1 MiB” instead of rounding down to “0 MiB.” Zero-size files and larger sizes retain their existing display formats.
    • Archive-wide media counts and storage totals continue to include downloaded media associated with chats and media not linked to a chat.

formatSize rendered 0 < size < 0.5 MiB as "0 MiB" next to a non-zero file count; it now reads "<1 MiB". calculate_and_store_statistics derives the archive-wide media count and DB size total from the grouped per-(account, chat) rows, NULL-chat rows included, instead of two extra scans over media. Adds a route test for a cached blob that carries the media counts map but no bytes map.
@coderabbitai

coderabbitai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: GeiserX/Telegram-Archive/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: b7fd294c-17a0-47a5-8399-ac763559d768

📥 Commits

Reviewing files that changed from the base of the PR and between ae0fbc0 and 95d7924.

📒 Files selected for processing (5)
  • src/db/adapter.py
  • src/web/templates/index.html
  • tests/test_db_adapter.py
  • tests/test_frontend_bootstrap.py
  • tests/test_stats_account_scoped.py

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

Archive media totals now come from grouped per-chat rows, including NULL-chat rows. The viewer displays positive sizes below 0.5 MiB as <1 MiB. Tests cover archive totals, account-scoped cached statistics, and size formatting.

Changes

Archive statistics

Layer / File(s) Summary
Grouped archive totals and cached statistics
src/db/adapter.py, tests/test_db_adapter.py, tests/test_stats_account_scoped.py
The statistics calculation derives archive totals from grouped media rows, including NULL-chat rows, and reduces the number of database queries. Tests check the totals, query count, and account-scoped response when cached media bytes are absent.

Media size formatting

Layer / File(s) Summary
Sub-MiB display formatting
src/web/templates/index.html, tests/test_frontend_bootstrap.py
The formatter displays positive sizes below 0.5 MiB as <1 MiB. The regression test checks zero, values below the threshold, the threshold, and a larger value.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Low

Merge Risk: ⚪ Minimal · up to 95d79

The statistics and display changes are ready to merge after normal checks.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the problem, implementation, tests, database aggregation changes, and compatibility considerations, but it does not follow the required template. It omits the Type of Change, … Add all required template sections. Mark the applicable checkboxes, complete the database consistency checklist, state database and deployment impact, and confirm testing, security, and manual validation status.
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 4 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes both primary changes: the tiny-media display fix and the statistics scan reduction.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the problem, implementation, tests, database aggregation changes, and compatibility considerations, but it does not follow the required template. It omits the Type of Change, Database Changes, Data Consistency Checklist, Testing checklist, Security Checklist, and Deployment Notes sections.

Full details: Docstring Coverage

Explanation

Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 4 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@github-actions

Copy link
Copy Markdown

🐳 Dev images published!

  • drumsergio/telegram-archive:dev
  • drumsergio/telegram-archive-viewer:dev

The dev/test instance will pick up these changes automatically (Portainer GitOps).

To test locally:

docker pull drumsergio/telegram-archive:dev
docker pull drumsergio/telegram-archive-viewer:dev

@codecov

codecov Bot commented Sep 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.96%. Comparing base (ae0fbc0) to head (95d7924).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #476   +/-   ##
=======================================
  Coverage   94.96%   94.96%           
=======================================
  Files          29       29           
  Lines       12318    12319    +1     
=======================================
+ Hits        11698    11699    +1     
  Misses        620      620           
Files with missing lines Coverage Δ
src/db/adapter.py 96.22% <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 385eb65 into main Sep 24, 2026
11 checks passed
@GeiserX
GeiserX deleted the ai/stats-nits branch September 24, 2026 09:46
@GeiserX GeiserX mentioned this pull request Sep 24, 2026
PhenixStar pushed a commit to PhenixStar/Telegram-Archive that referenced this pull request Sep 25, 2026
…per-chat maps

Semantic port of upstream GeiserX#473 and GeiserX#476 for our one-account-per-archive
layout (maps keyed by chat id, not account:chat).

/api/stats returned the cached blob as is, so every login - including
share tokens and viewer accounts restricted to a few chats - received the
archive-wide totals and per_chat_message_counts, the id and message count
of every archived chat.

- The per-chat maps (messages, and now downloaded media count and bytes)
  are scoping input only: stripped from /api/stats and /api/stats/refresh.
- A restricted viewer's chats, messages, media and storage are summed over
  its visible chats (fail closed). A blob written before the media maps
  existed omits the two media figures, and the popup hides those rows
  rather than showing 0 or archive-wide numbers.
- The stats job reads downloaded media in one grouped scan instead of
  three; totals still count rows without a chat id.
- formatSize shows "<1 MiB" instead of "0 MiB" for tiny totals.

Co-Authored-By: Claude Opus 5.5 (1M context) <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.

1 participant