Files
transcription/docs/ver4.8/feature_backlog_v4_8.md
T
Jim Lancaster 30fcef3892
Quality Gate / gate (push) Successful in 34s
gpt-5.3-codex review Phase 3
2026-08-19 20:50:21 -05:00

7.1 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.

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 into ui/components/media_urls.py as resolve_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.

Practicality: high. Effort: S. Recommended first feature.

The storage layer is already built:

  • ui/homepage_store.py:82 list_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?
  • Architecture & Code Review Report
  • .github/instructions/ui.instructions.md
  • src/transcription/ui/homepage_store.py - existing multi-image storage
  • src/transcription/ui/components/media_urls.py - canonical URL resolution