Theme C — High-interaction workspaces (Components v2)¶
Status: 1.0 named workspaces landed (Speaker ID Phase 9, Studio review, viewer click-drag)
Last updated: 2026-10-07
Roadmap home: docs/ROADMAP.md §C
Product constraint: Streamlit shell + Python domain; specialised CCv2 workspaces only. Theme D full-file reader shares the package but is owned by ROADMAP §D / karaoke-playback.md.
Goal¶
Escape Streamlit’s rerun model for workstation pages (Speaker ID, Corrections review, per-segment word selection) without abandoning Streamlit for the analysis workbench. Manuscript-style rich edit stays out of this theme. Theme D full-file reader is a separate CCv2 component (reader_workspace); see karaoke-playback.md.
Locked decisions¶
Shared
SpeakerIdActionServiceowns Speaker ID mutations (Phase −1). After Phase 9 the naming/playback surface is CCv2-only.Three state tiers: browser-local ephemeral · sparse Streamlit
setStateValue· revisioned domain triggers. Never streamcurrent_time_msviasetStateValue.Every domain trigger is a revisioned command envelope; acks carry authoritative revisions.
Optimistic reconciliation: one mutating speaker action in flight; nav may be optimistic; ignore stale/out-of-order acks by
action_seq; duplicateaction_idnever writes twice; protocol/build mismatch fails closed.Python CCv2
key=is transcript-scoped (speaker_id_ws:{transcript_id}), not global.ClipTransport T0 = measured base64 in JSON
data. Binary only via a separate tested conduit (T1); no undocumented Streamlit media URLs.CCv2 bridge uses only non-blocking ClipService APIs (
cached_clip_status/get_cached_clip_bytes/enqueue_clip). Never coldget_clip_path/get_clip_bytes.Packaged CCv2 from Streamlit
component-templatev2 layout: component-level[[tool.streamlit.component.components]], assets in wheel/sdist.Dist policy: commit built
frontend/buildassets into the workspaces package (reproducible installs without Node at runtime). CI rebuilds and fails on drift. Lockfile + Node engines pinned.Shadow DOM = style isolation only. Render text via
textContent.asset_diris public.Feature flag for Corrections default on. Rollback with
TX_CORRECTIONS_WORKSPACE_COMPONENT=0. Speaker ID CCv2 is required (Phase 9); missingtranscriptx-workspacesis an install error, not a classic-UI fallback.
Protocol¶
See transcriptx.app.speaker_id.protocol and transcriptx_workspaces protocol modules.
Field |
Role |
|---|---|
|
Fail closed on mismatch ( |
|
Fail closed → reload/fallback |
|
Idempotency |
|
Monotonic; ignore out-of-order acks |
|
Workspace identity |
|
Stale reject |
|
When clip-relevant |
Prefetch / memory budgets¶
Budget |
Default |
|---|---|
Max clips per warm request |
8 |
Max bytes per clip into browser |
1_500_000 |
Max total Blob memory / workspace |
8_000_000 |
Max concurrent miss retries |
2 |
Retry count |
4 |
Backoff |
200ms × 2^n (cap 3s) |
Global ClipService inflight |
existing |
Revoke Blob URLs on replacement, transcript switch, and unmount.
Quantitative gates¶
Phase 0¶
Zero
<audio>element replacement on metadata-onlydatarefresh (element identity)Cleanup revokes Blob URLs / clears timers
Dist policy locked (this doc § Locked #9)
Phase 2¶
Zero audio replacement on mapping/metadata refresh for same transcript key
Bridge handlers return pending without joining cold ffmpeg (no multi-second block)
Prefetch budgets held; multi-session backpressure respected
Record p50/p95 trigger→ack for nav/warm in CI artefacts when measured
Phase 5 (default-on, historical)¶
Browser harness green (audio identity, transcript switch, keyboard suppression)
Docker/web images install
transcriptx-workspaceswheelCorrections flag defaults on; env rollback retained for one release after 1.0
Speaker ID missing-package fallback to classic widgets removed in Phase 9 (install error instead)
Zero duplicate mutations under replayed
action_id
Feature flags¶
Flag |
Default |
Meaning |
|---|---|---|
|
|
CCv2 Corrections review pane |
Env rollback: TX_CORRECTIONS_WORKSPACE_COMPONENT=0. Theme D reader flag (TX_READER_WORKSPACE_COMPONENT) is documented in karaoke-playback.md, not Theme C.
Frontend toolchain¶
Node
>=20 <23(CI uses 22.x)npm lockfile committed
@streamlit/component-v2-libpinned in workspaces packageVite,
base: "./", hashedspeaker_id-*.js/corrections-*.js/viewer_edit-*.js/reader-*.js(Theme D) plus named CSS
Keyboard map (Phase 3)¶
Active only when workspace focused; suppressed in inputs/contenteditable.
Key |
Action |
|---|---|
|
Next speaker |
|
Prev speaker |
|
Play/pause |
|
Save name |
|
Ignore toggle |
|
Help |
Avoid browser/AT reserved chords.
ClipTransport¶
T0: base64 (or data-URL string) inside JSON metadata
dataT1: only if measured need — dedicated binary conduit component whose entire
data=is bytes, correlated byclip_id+ revision in the metadata component; tested on min + current StreamlitT2: browser
Map<clipId, BlobURL>under budgetsT3: documented local route — Theme D
reader_workspaceuses loopback Range media (src/transcriptx/web/media_route.py); Speaker ID stays on T0
Invest / narrow / defer (after Phase 3)¶
Corrections CCv2 review and viewer click-drag landed for 1.0. SPA rewrite still needs written remount/bytes/focus evidence. Escalate to a custom local frontend only with evidence that CCv2 remount/bytes/focus limits block product goals.
First escalation (if the gate fires): loopback application API over existing app.controllers / workflows, with Streamlit remaining the only client until that API is stable — then grow workspaces off Streamlit hosting. Do not jump to Gradio/NiceGUI or an OS-native workbench rewrite. Full Streamlit retirement is a late 1.x / 2.0 programme (theme I), not a Theme C deliverable. Roadmap: ROADMAP.md §C (shell review) and §I.
Phase 9 legacy retirement¶
Done for 1.0 (2026-10-06). Soak evidence: CI workspaces-theme-c, GUI E2E, and Docker wheel install since default-on (2026-08-11). Native [web] now installs the package. Classic Speaker ID naming/playback widgets are removed. Missing package → install error.
Previous criteria (all true):
Shared
SpeakerIdActionServicemeans both paths have identical domain semantics (enforced by tests) — doneRollback / flag-off path survived the stated release window after default-on — waived in favour of CI/E2E/Docker soak; native extra now required
Browser acceptance suite remains green in CI (Streamlit min + current)
Explicit changelog + known-limitations update