Skip to content

Commit 6cd3eb8

Browse files
authored
Merge pull request #5 from managedcode/codex/fix-validation-regressions
Fix reader and Go Live validation regressions
2 parents 65e862a + b64753f commit 6cd3eb8

File tree

130 files changed

+4915
-1953
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+4915
-1953
lines changed

AGENTS.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ Local `AGENTS.md` files may tighten these values, but they must not loosen them
278278
- String literals are forbidden in implementation code. Declare them once as named constants, enums, configuration entries, or dedicated value objects, then reuse those symbols.
279279
- Avoid magic literals. Extract shared values into constants, enums, configuration, or dedicated types.
280280
- URLs, storage keys, JS interop identifiers, route fragments, and user-visible fallback strings are implementation literals too. They MUST live behind named constants or localized catalogs.
281+
- JS bridges must not invent repo-owned CSS custom-property names, DOM selectors, or feature data-attribute names inside `.js` files when Blazor/C# can own and pass those contract strings explicitly.
282+
- Fallback device names, fallback device labels, and other invented media-device placeholders are forbidden in runtime and tests; use real device metadata when it exists, otherwise keep the field empty or assert on explicit no-device state instead of fabricating names.
281283
- Design boundaries so real behaviour can be tested through public interfaces.
282284
- The repo-root `.editorconfig` is the source of truth for formatting, naming, style, and analyzer severity. Use nested `.editorconfig` files only when they clearly serve a subtree-specific purpose.
283285

@@ -304,10 +306,27 @@ Repo-specific design rules:
304306
- Repo-owned manifests, scripts, workflows, and project files that track third-party runtime JavaScript SDKs MUST point to concrete GitHub release versions and asset URLs, never floating references.
305307
- Any vendored runtime JavaScript SDK that tracks an upstream GitHub repo MUST have an automated watcher job that checks new GitHub releases and opens a repo issue describing the required update when a newer release appears.
306308
- Teleprompter TPS speed modifiers MUST affect both playback timing and subtle word- or phrase-level letter spacing, so slower spans open up slightly and faster spans tighten slightly without hurting readability.
309+
- Teleprompter default reader width MUST start at the maximum readable width from the design unless the user explicitly narrows it; shipping a visibly narrower default is a regression.
310+
- Teleprompter speed styling MUST produce a visible but tasteful letter-spacing or kerning change: slower text opens up slightly and faster text tightens slightly, not a no-op.
307311
- Teleprompter reader word styling MUST mirror TPS/editor inline semantics: explicit inline TPS tags control per-word emphasis and color, while section or block emotion sets card context and must not recolor every reader word.
312+
- Teleprompter underline or highlight treatments that span a phrase or block MUST render as one continuous block-level treatment; separate per-word underlines inside the same phrase are forbidden.
313+
- Teleprompter read-state styling MUST mute phrase-level underline or highlight accents once the emphasized text has been read; bright lingering underline accents on already-read text are forbidden.
314+
- Teleprompter reader text MUST appear on the focal guide immediately when a word or block becomes active; visible post-appearance drift or settling onto the guide is forbidden.
315+
- Teleprompter route styles MUST be present on the first paint; a flash of unstyled or late-styled reader UI during route entry is a regression.
308316
- Teleprompter block transitions MUST stay visually consistent: outgoing cards move upward and incoming cards rise from below in the same direction every time; alternating up/down travel is forbidden, and extra settling, bounce, or intermediate card states are forbidden.
317+
- Teleprompter focus treatment MUST stay visually calm: the active focus word may be emphasized, but surrounding text should be gently dimmed instead of creating a bright moving blot, fake box, or attention-grabbing patch that flies up and down.
318+
- Teleprompter emotion styling may tint the surface or accents, but reader text itself MUST stay easy to read and must not become harsh, over-bright, or saturated enough to hurt readability.
319+
- Learn and Teleprompter playback timing MUST align with real word-by-word progression in the browser: WPM, speed modifiers, and word counting must match the emitted words, and timing work is not done until a browser-level word-sequence check proves it.
320+
- Reader and Learn tokenization MUST treat punctuation-only tokens such as commas, periods, and dashes as punctuation attached to nearby words or pauses, never as standalone counted words.
321+
- App-shell logo navigation MUST always lead to the main home/library screen; it must not deep-link into Go Live, Teleprompter, or another feature-specific route.
322+
- Learn rehearsal speed MUST default to about 250 WPM and stay user-adjustable upward from that baseline; shipping a 300 WPM startup default is too aggressive.
323+
- Go Live `ON AIR` badges and preview live dots MUST appear only while recording or streaming is actually active; idle selected or armed sources must stay visually non-live.
324+
- Go Live chrome MUST stay operational and generic; do not surface the loaded script title or script preview subtitle in the Go Live header/session bar just because a script is open.
325+
- Go Live back navigation MUST return to the actual previous in-app screen when known, and only fall back to library when there is no valid in-app return target; it must never hardcode teleprompter as the back target.
309326
- Learn and Teleprompter are separate screens with separate style ownership; do not bundle RSVP and teleprompter reader feature styles into one shared screen stylesheet or let one page inherit the other page's visual treatment.
310327
- User preferences persistence MUST sit behind a platform-agnostic user-settings abstraction, with browser storage implemented via local storage and room for other platform-specific implementations; theme, teleprompter layout preferences, camera/scene preferences, and similar saved settings belong there instead of ad-hoc feature stores.
328+
- Streaming destination/platform configuration MUST be user-defined and persisted in settings; Settings and Go Live must not ship hardcoded platform instances, seeded destination accounts, or fixed fake provider rows beyond real runtime capabilities.
329+
- Runtime screens must not keep inline seeded operational data, fake demo rows, or screen-local platform/source presets in page/component code; reusable labels and presets belong in shared contracts or catalogs, while rendered rows must come from persisted settings, workspace state, or live session state.
311330
- Build quality gates must stay green under `-warnaserror`.
312331
- GitHub Pages is the expected CI publish target for the standalone WebAssembly app; publish automation must keep the app browser-only and Pages-compatible.
313332
- GitHub Actions MUST keep separate, clearly named workflows for pull-request validation and release automation; vague workflow names are forbidden.
@@ -359,6 +378,7 @@ Ask first:
359378
### Dislikes
360379

361380
- backend creep in the standalone runtime
381+
- hardcoded fallback reader/test fixtures such as inline `Ready` chunks, fake word models, or synthetic UI state embedded directly in tests when the same behavior can be exercised through shared script fixtures, builders, or production-owned constants
362382
- agent-started local servers taking shared user ports or using ports outside the reserved `5050-5070` agent range
363383
- brittle selectors without `data-testid`
364384
- progress updates that imply a fix is done before there is concrete implementation and verification evidence; keep status factual and let the user verify final behavior personally
@@ -368,8 +388,14 @@ Ask first:
368388
- made-up About/team content or stale attribution; About must point to real Managed Code ownership and official links
369389
- any visible typing latency in the editor; plain input must feel immediate with no observable delay
370390
- teleprompter controls that fade so much they become hard to see during real reading
391+
- teleprompter starting with a narrowed text width instead of the design-max default
371392
- teleprompter paragraph repositioning, line hopping, or per-word vertical transform updates that make the text jump; `design/teleprompter.html` motion is the required reference, with steady bottom-to-top movement and no extra animation layers beyond the reference
393+
- teleprompter words or blocks appearing away from the focus line and only then drifting onto it; activation must look immediate
394+
- teleprompter section changes that introduce odd transition motion instead of the straight reference direction
372395
- any green teleprompter shell or background treatment; Teleprompter must stay on its dark reader palette and use emotion only for accents, not green screen-wide fills
396+
- fragmented per-word underline styling where the intended emphasis should read as one continuous block
397+
- punctuation showing up or being counted as standalone words in Learn or Teleprompter flows
398+
- app logo clicks landing on a feature route instead of the main home/library screen
373399
- Learn and Teleprompter style boundaries bleeding through a shared feature stylesheet; their visuals must stay isolated by page-owned style manifests
374400
- Learn RSVP compositions that shift when shorter or longer words render; changing word length must not move the overall RSVP component or its anchored centerline
375401
- teleprompter camera starting enabled by default; default reader startup should keep the camera off until the user explicitly enables it

design/app.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ function updateAppHeader(screenId) {
7373
break;
7474
case 'rsvp':
7575
center.innerHTML = `${backBtn}<span class="top-bar-title">Product Launch</span><span style="color:var(--text-4);font-size:12px">Intro / Opening Block</span>`;
76-
right.innerHTML = `<span class="top-bar-title" style="font-size:13px">300 WPM</span>${goLiveBtn}`;
76+
right.innerHTML = `<span class="top-bar-title" style="font-size:13px">250 WPM</span>${goLiveBtn}`;
7777
break;
7878
case 'teleprompter':
7979
center.innerHTML = `${backBtn}<span class="top-bar-title">Product Launch</span><span style="color:var(--text-4);font-size:12px" id="rd-header-segment">Intro · Opening Block</span>`;
@@ -93,7 +93,7 @@ function updateAppHeader(screenId) {
9393
// RSVP (Learn mode — simple word-by-word)
9494
// ============================================
9595

96-
let rsvpSpeed = 300;
96+
let rsvpSpeed = 250;
9797
let rsvpPlaying = true;
9898

9999
function changeRsvpSpeed(delta) {

design/rsvp.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
<div class="rsvp-bottom">
8787
<div class="rsvp-speed">
8888
<button class="rsvp-btn" onclick="changeRsvpSpeed(-10)"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="5" y1="12" x2="19" y2="12"/></svg></button>
89-
<div class="rsvp-speed-num"><span id="rsvp-speed">300</span><small>WPM</small></div>
89+
<div class="rsvp-speed-num"><span id="rsvp-speed">250</span><small>WPM</small></div>
9090
<button class="rsvp-btn" onclick="changeRsvpSpeed(10)"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></button>
9191
</div>
9292
<div class="rsvp-play-row">
@@ -108,4 +108,4 @@
108108

109109
<script src="app.js"></script>
110110
</body>
111-
</html>
111+
</html>

docs/Architecture.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ flowchart LR
173173
- `BrowserThemeService` is the first concrete remote consumer and keeps shell appearance aligned across tabs without reload.
174174
- `GoLiveSessionService` is the current publisher and consumer for active `Go Live` session snapshots, including startup catch-up requests.
175175
- `MainLayout` consumes `GoLiveSessionService` and renders the global shell `Go Live` status for every screen.
176+
- `AppShellService` owns the current in-app route and the last valid non-`Go Live` return target so the `Go Live` back control can return to the actual previous screen instead of a hardcoded reader route.
176177
- The contract must stay message-based; tabs do not share live .NET memory.
177178

178179
## Library Contracts

docs/Features/GoLiveRuntime.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,20 @@
77
The current page layout is a production-style studio surface:
88

99
- the routed `Go Live` page owns its own studio chrome and suppresses the shared app header while the route is active, so `design/golive.html` remains the only topbar on that screen
10-
- top session bar follows `design/golive.html`: back to Read, script title + session badge, centered session timer, panel toggles, mode switch, settings shortcut, REC, and the main stream action on the far right
10+
- top session bar follows `design/golive.html`: back to Library, script title + session badge, centered session timer, panel toggles, mode switch, settings shortcut, REC, and the main stream action on the far right
1111
- the studio shell follows the same three-column grid as `design/golive.html`: a compact left input rail, a dominant center canvas/program stage, and a dedicated right operational rail
1212
- left input rail for scene cameras, add-camera action, utility sources, and microphone route status
1313
- center program stage for the selected program source and current script/session state
1414
- scene controls bar for scene chips, layout controls, transitions, and the primary `Take To Air` action
1515
- right rail for the current live preview plus compact stream, audio, and room/runtime panels
16+
- source-card `ON AIR` badges and the preview red live dot only turn on when recording or streaming is actually active; idle routing and armed sources stay visually non-live
1617
- full-program mode collapses both side rails so the center canvas follows the design's focused monitor state
17-
- destination cards that arm OBS, recording, LiveKit, and YouTube from persisted settings instead of editing credentials inline
18+
- destination cards are built from persisted local outputs plus a dynamic browser-stored `ExternalDestinations` list; seeded fake provider rows are forbidden
1819

1920
The runtime now owns real browser media outputs for the composed program scene and the current audio bus:
2021

2122
- `Go Live` auto-seeds the first available browser camera into the scene when the scene is empty and the browser exposes a real camera list
22-
- the center program stage always shows the currently selected scene camera, while the right preview rail shows the currently on-air camera until the operator takes the selected source live
23+
- the center program stage always shows the currently selected scene camera, while the right preview rail shows the current program source and only marks it live once recording or streaming is active
2324
- `Go Live` builds one browser-side program stream from the scene camera cards by drawing the selected primary camera full-frame and then layering additional included cameras as positioned overlays on a canvas
2425
- the scene `AudioBus` is mixed into one program audio track through `AudioContext`, delay, and gain nodes before the final program stream is published or recorded
2526
- OBS browser output stays browser-only and exposes the composed program audio inside an OBS Browser Source environment
@@ -34,7 +35,7 @@ Relay-only destinations stay configuration surfaces:
3435
- YouTube, Twitch, custom RTMP, and similar RTMP-style targets still persist credentials and routing in browser storage
3536
- `Go Live` only exposes quick arm/disarm toggles and readiness summaries for those targets
3637
- detailed destination credentials, ingest URLs, and provider-specific configuration live in `Settings`
37-
- these targets do not publish directly from the browser runtime; they require an external relay or ingest layer outside this standalone WASM app
38+
- these targets do not publish directly from the browser runtime; they require an external relay or ingest layer outside this standalone WASM app, and `Go Live` must not mark the session live unless a direct browser live output actually starts
3839

3940
It is separate from:
4041

@@ -62,8 +63,8 @@ sequenceDiagram
6263
User->>Settings: Configure camera, FPS, mic, sync
6364
Settings->>Studio: Persist device preferences
6465
Settings->>Scene: Persist scene cameras and audio bus
65-
User->>Settings: Configure LiveKit / YouTube / recording settings
66-
Settings->>Studio: Persist provider credentials and destinations
66+
User->>Settings: Add external destinations and configure provider credentials
67+
Settings->>Studio: Persist local outputs and external destination list
6768
User->>GoLive: Open Go Live
6869
GoLive->>Studio: Load live routing settings
6970
GoLive->>Scene: Load current scene sources
@@ -181,14 +182,16 @@ flowchart LR
181182
- `Settings` must expose a visible CTA into `Go Live` so device setup and live routing stay discoverable as separate flows.
182183
- the shared header shell must keep `Go Live` reachable from every non-`Go Live` routed page because it is a primary studio action
183184
- `Go Live` may arm multiple destinations at the same time.
185+
- hardcoded destination instances are forbidden; the external destination list must come from persisted browser settings and may contain zero, one, or many platform entries
184186
- `Go Live` must reuse the browser-composed scene and not invent a separate media graph.
185187
- `Go Live` must auto-seed the first available browser camera into the scene when the scene is empty and devices are available.
186188
- `Go Live` must show the selected program source in the center monitor and the currently on-air source in the right preview rail until the operator explicitly takes the selected source live.
189+
- `Go Live` must not render `ON AIR` source badges or red preview live dots while the session is idle; those indicators only represent active recording or streaming.
187190
- `Go Live` must show a stable empty preview state instead of mounting camera interop when the current scene has no cameras.
188191
- the routed `Go Live` page must not stack the shared app header above the studio topbar; the studio topbar is the only route chrome on that screen
189192
- any shared `Go Live` localized copy must come from `PrompterOne.Shared.Localization.UiTextCatalog`, so supported browser cultures localize the studio surface without feature-local string copies.
190193
- quick destination cards must only expose honest readiness summaries and arm/disarm toggles; fake in-page credential editors are forbidden on the operational studio surface
191-
- legacy streaming settings must normalize to the current included program cameras so existing browser storage keeps working
194+
- legacy streaming settings must normalize to the current included program cameras and migrate legacy provider fields into the canonical external destination list so existing browser storage keeps working
192195
- `VirtualCamera` mode normalizes to OBS armed by default, so browser sessions keep the legacy desktop-capture workflow unless the user explicitly turns OBS off
193196
- Camera source inclusion is persisted through `MediaSceneState`.
194197
- Destination credentials and endpoints are persisted only in browser storage for this standalone runtime.

0 commit comments

Comments
 (0)