Skip to content

feat(dashboard): wire reading-pace forecasts into a Time to finish section (EXP-04)#46

Merged
ChelseaKR merged 1 commit into
mainfrom
claude/project-code-review-merge-jz4qwg
Jul 14, 2026
Merged

feat(dashboard): wire reading-pace forecasts into a Time to finish section (EXP-04)#46
ChelseaKR merged 1 commit into
mainfrom
claude/project-code-review-merge-jz4qwg

Conversation

@ChelseaKR

Copy link
Copy Markdown
Owner

What & why

app.forecast shipped as a pure, tested module (EXP-04) but nothing rendered it — the feature was invisible to users. This wires it into the dashboard: build_view computes a per-book BookForecast for every currently-reading title, and the renderer shows an accessible "Time to finish" section.

  • Remaining pages come from the book's reading stat (total_pages − pages_read); a book with no stat yields the module's honest Forecast.unknown() rather than a guess.
  • The section is a <table> mirroring the existing sections: a range, never a single number, with the window basis disclosed ("from your last N reading days"), and unestimable books shown as such ("not enough recent reading to estimate"). No color-only meaning.
  • BookForecast lives in app.view; app.render imports it under TYPE_CHECKING (annotations are already lazy via from __future__ import annotations), so no import cycle is introduced.

Definition of Done

  • Tests added: an estimable book renders an hours range with its basis and passes the a11y structural check (check_html); a book with no page stat renders the honest "not enough recent reading to estimate" text; the demo render includes the "Time to finish" heading.
  • Docs updated: CHANGELOG.md (Unreleased → Added) and the EXP-04 note in docs/ideation/03-expansions.md (dashboard wiring now done).
  • No secrets, tokens, or real library data in the diff — tests use constructed fixtures.
  • Four hard guardrails intact: this is read-only view/render plumbing over already-ingested data; no reading data leaves the instance; no catalog access touched; no author identity inferred.
  • Commit signed off and Conventional Commits.

Verification note (please confirm on CI): this repo targets Python 3.14, which this build sandbox can't provide (interpreter downloads are blocked here), so I could not run the full make verify against 3.14 locally. What I did verify: the full suite (389 tests, including the two new forecast tests) passes when run on Python 3.12 with a temporary 3.12-compat shim that I did not commit — the shipped diff contains only the EXP-04 changes; and ruff check + ruff format --check are clean under the repo's target-version = "py314" config on the changed files. The 3.14 mypy/pytest gate runs in CI; I'll watch it and fix any fallout.

If this touches a workflow or a dependency

N/A — no workflow, uses:, or dependency change; uv.lock untouched.


Generated by Claude Code

…ction (EXP-04)

app.forecast shipped as a pure, tested module but nothing rendered it. Build a
per-book BookForecast for every currently-reading title (remaining pages from
the reading stat; no stat -> honest Forecast.unknown()), thread a forecasts
field through DashboardView, and render an accessible 'Time to finish' table
mirroring the existing sections: a range never a single number, the window
basis disclosed, and unestimable books shown as such rather than guessed.

BookForecast lives in app.view and is imported into app.render under
TYPE_CHECKING (annotations are already lazy) so no import cycle is introduced.

Tests: an estimable book renders an hours range with its basis and passes the
a11y structural check; a book with no page stat renders the honest
'not enough recent reading to estimate' text.

Signed-off-by: ChelseaKR <3114598+ChelseaKR@users.noreply.github.com>
@ChelseaKR
ChelseaKR merged commit c4a973b into main Jul 14, 2026
5 checks passed
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