7.4 KiB
V4.8 Feature Backlog
Status: not scoped. This is a parking document, not a frozen boundary. It records feature work deferred out of V4.6 and V4.7 together with the evidence gathered so far, so that scoping V4.8 does not start from a blank page.
V4.8 is the first release since V4.5 to add new user-facing behavior. V4.6 was pure remediation and V4.7 is architectural cleanup; both were held to "no new features." That constraint ends here, which means V4.8 needs a different verification gate: V4.6 and V4.7 could be validated by "the suite still passes unchanged," and V4.8 cannot.
Dependency on V4.7
The model-performance rollup below must not begin until V4.7 Phase 4 lands. duration_ms currently measures provider call plus image normalization, artifact persistence, and a DB commit, while the timeout governs only the provider call. A rollup built on it would chart preprocessing time mixed with provider latency and look authoritative while quietly misleading. V4.7 Phase 1 removes normalization and artifact persistence from that window, but the commit remains inside it until Phase 4. See archived V4.7 scope boundary at docs-v4x-archive:docs/ver4.7/scope_boundary_v4_7.md.
Candidate Features
1. Pan and Zoom on Source Detail
Practicality: high. Effort: S.
ui/components/document_panzoom.py existed and was deleted in V4.6 Phase 5 (6a3ee26) because it was exported but wired to no page. It is 136 lines and recoverable:
git show 6a3ee26^:src/transcription/ui/components/document_panzoom.py
It already handled both images and PDFs (the latter via an iframe).
Two things must change on reintroduction - this is not a straight revert:
- It loaded Panzoom from the unpkg CDN. For an archival application the library should be vendored locally, otherwise the viewer breaks offline and depends on a third party staying available.
- It carried its own
_document_url()helper. V4.6 Phase 5 extracted exactly that logic intoui/components/media_urls.pyasresolve_media_url. Reintroducing the old helper would recreate the duplication Phase 5 removed.
Scope note: apply it to Source Detail only. dark_room_viewer (ui/components/viewers.py) is shared by four pages - sources_page.py:268, home_page.py:25 and :88, people_page.py:453, documents_page.py:524 - so a flag on it would leak pan-zoom into the homepage and document detail, which is not wanted. Add a separate component and use it only at sources_page.py:268.
Numbering note: the Phase 5 commit message states pan-zoom would return "in V4.7 alongside the other photo/image work." Moving it to V4.8 preserves that intent - it stays grouped with the photo work - and changes only the release number.
2. Homepage Image Gallery
Practicality: high. Effort: S. Recommended first feature.
The storage layer is already built:
ui/homepage_store.py:82list_homepage_images()already returns every stored image, sorted by modification time.store_homepage_image()already accumulates files rather than overwriting.- Today the UI calls only
latest_homepage_image()and displays one image.list_homepage_images()is currently exercised only by tests.
So multi-image upload is effectively done; what is missing is presentation. NiceGUI 3.13.0 provides ui.carousel for left/right navigation and ui.timer for rotation.
Sub-items:
- Multi-image display with left/right navigation - small, mostly wiring.
- Optional slideshow rotating every ~10 minutes.
Performance caveat: list_homepage_images() performs a directory scan with a stat() per file on every call, and home_page.py already performs blocking I/O in the page handler (V4.6 review log [25], which was deliberately left alone). A rotating timer that re-enumerates on every tick would repeat that scan indefinitely. Enumerate once at page load and cache the list.
3. Multiple Person Portraits
Practicality: medium. Effort: M/L. Defer behind item 2.
Person.portrait_path is a single string column. Supporting multiple portraits requires a new table, a data migration, and upload UI - a materially larger job than item 2, and a different one.
4. Image Descriptions
Practicality: medium, conditional. Effort: M.
Homepage images are filesystem-only with no metadata store, so a caption has nowhere to live today. This needs either a sidecar JSON file or a real table.
This is cheap only if item 3 is being done at the same time, since both need the same metadata layer. Designing that layer twice would be wasteful; design it once or not at all.
5. Model-Performance Rollup (V4.6 review log [54])
Practicality: high, but blocked. Effort: M.
Run-time telemetry is already captured and is per page: execution_attempt.duration_ms is a required non-null field written on all three paths in workflows.py (success 278, TimeoutError 295, general failure 330), with failures using a monotonic clock. Verified against the live database: 80 rows across 80 distinct (job, source, attempt) combinations, one row per page - the largest job has 60 attempts across 60 distinct pages - and zero nulls. Token counts live on the same row in normalized_metadata.usage, so tokens-per-second is already derivable without a join.
What is missing is aggregation. The figure is visible only for the latest attempt of one source at a time (sources_page.py:400), rendered raw as "27612 ms". There is no rollup by model, prompt, or document.
The gap is concrete: calibrating the provider timeout on 2026-08-18 required hand-written SQL against the database, because the application could not answer "which model is slow."
Proposed shape: median / p95 / max duration, tokens per second, and a timeout rate, grouped by model. Blocked on V4.7 Phase 4.
6. Desaturated Background Wallpaper
Practicality: low. Recommendation: do not build, or gate behind a setting defaulted off.
Trivial to implement (ui.add_css with a CSS filter), but this is a dense archival data application - transcripts, JSON evidence panels, data tables. A background image behind all of that costs contrast and legibility on every page, for aesthetic gain only.
Suggested Grouping
If V4.8 is scoped as one release, the natural split is:
Track A - image experience: items 1 and 2. Both are small, both are self-contained UI work, and item 2's storage layer already exists. This is the highest value for the least risk.
Track B - metadata layer: items 3 and 4 together, since they share a table. Only worth starting if both are wanted.
Track C - telemetry: item 5, gated on V4.7 Phase 4.
Item 6 is not recommended.
Open Questions for Scoping
- Should Track B happen at all, or is one portrait per person sufficient?
- Should the slideshow interval be configurable, or fixed?
- Should the model-performance rollup be its own page, or a panel on an existing one?
- Should vendored Panzoom be committed to the repository, or fetched at build time?
Related Local References
- Archived V4.7 scope boundary:
docs-v4x-archive:docs/ver4.7/scope_boundary_v4_7.md(blocking dependency for item 5) - Archived V4.6 scope boundary:
docs-v4x-archive:docs/ver4.6/scope_boundary_v4_6.md - Architecture & Code Review Report
.github/instructions/ui.instructions.mdsrc/transcription/ui/homepage_store.py- existing multi-image storagesrc/transcription/ui/components/media_urls.py- canonical URL resolution