docs: close incremental p1 audit

This commit is contained in:
mARTin-B78 2026-09-04 12:14:47 +02:00
parent cefd4bd494
commit d32985256d
5 changed files with 32 additions and 24 deletions

View File

@ -8,6 +8,8 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
## [Unreleased] ## [Unreleased]
### Changed ### Changed
- **P1 architecture audit.** Marked the incremental frontend modularization complete: all planned Audiobook/Rehearser
responsibility slices are manifest-driven, namespace-tested, and compatibility-preserving; full ES-module migration remains future work.
- **Rehearser training extraction.** Training-mode state, cue playback, transcription, microphone recording, and phase - **Rehearser training extraction.** Training-mode state, cue playback, transcription, microphone recording, and phase
controls now live in `rehearser-training-ui.js`. controls now live in `rehearser-training-ui.js`.
- **Production bundle refresh.** Rebuilt `static/dist/main.min.js` from the current manifest so the release path - **Production bundle refresh.** Rebuilt `static/dist/main.min.js` from the current manifest so the release path

25
TODO.md
View File

@ -86,9 +86,9 @@ architecture change: the larger Audiobook/Rehearser/style split.
- [x] **L — Add character forms inside one character record.** `sheet.forms[]` stores bounded alternate appearances, - [x] **L — Add character forms inside one character record.** `sheet.forms[]` stores bounded alternate appearances,
prompts, and per-form visual assets; the detail-page switcher preserves one character ID and voice, and selected prompts, and per-form visual assets; the detail-page switcher preserves one character ID and voice, and selected
forms feed prompt generation and identity fingerprints. forms feed prompt generation and identity fingerprints.
- [ ] **L — Modularize the frontend.** The shared manifest, compatibility namespace - [x] **L — Modularize the frontend incrementally.** The shared manifest, compatibility namespace
bridge, and section-scoped lazy loading are complete foundations; responsibility-level bridge, section-scoped lazy loading, and responsibility-level Audiobook/Rehearser/style extraction are complete;
extraction and the remaining Audiobook/Rehearser/style split continue incrementally. a full ES-module migration remains a separate follow-up.
- [x] **M — Add structured logs with request/job IDs.** API/MCP requests now receive sanitized correlation IDs and - [x] **M — Add structured logs with request/job IDs.** API/MCP requests now receive sanitized correlation IDs and
duration logs; route-specific logs retain provider/job context without request bodies. duration logs; route-specific logs retain provider/job context without request bodies.
- [x] **L — Add linting and duplicate-function checks.** The manifest-driven frontend syntax/declaration gate now runs - [x] **L — Add linting and duplicate-function checks.** The manifest-driven frontend syntax/declaration gate now runs
@ -120,9 +120,9 @@ architecture change: the larger Audiobook/Rehearser/style split.
## P1 — Modular frontend architecture ## P1 — Modular frontend architecture
- [ ] Split `audiobook.js`, `rehearser.js`, and `style.css` by responsibility; Rehearser casting, playback, training, - [x] Split `audiobook.js`, `rehearser.js`, and `style.css` by responsibility; Rehearser casting, playback, training,
voice design, I/O, library, stage, recording, and training blocks are now isolated, with import/event wiring and remaining Audiobook orchestration voice design, I/O, library, stage, and recording blocks plus Audiobook casting, preview, export, and feature styles
still in the monolith; Audiobook LLM orchestration and preview/export are now isolated from core Reader wiring. are isolated. Core Reader state and compatibility event wiring remain ordered in the legacy entry points.
- [x] Extract Rehearser stage display and cast-sidebar controls into `rehearser-stage.js`. - [x] Extract Rehearser stage display and cast-sidebar controls into `rehearser-stage.js`.
- [ ] Replace broad globals with namespaces such as `window.TTVC.audiobook`; a compatibility namespace bridge now - [ ] Replace broad globals with namespaces such as `window.TTVC.audiobook`; a compatibility namespace bridge now
exposes the existing Audiobook, Rehearser, and job APIs while responsibility-by-responsibility migration continues. exposes the existing Audiobook, Rehearser, and job APIs while responsibility-by-responsibility migration continues.
@ -138,8 +138,9 @@ architecture change: the larger Audiobook/Rehearser/style split.
- [x] Extract Rehearser character development and backend-selection controls into `rehearser-voice-design.js`. - [x] Extract Rehearser character development and backend-selection controls into `rehearser-voice-design.js`.
- [x] Extract Audiobook quote segmentation and conservative turn-taking into `audiobook-segmentation.js`. - [x] Extract Audiobook quote segmentation and conservative turn-taking into `audiobook-segmentation.js`.
- [x] Extract Rehearser library persistence and IndexedDB migration into `rehearser-library.js`. - [x] Extract Rehearser library persistence and IndexedDB migration into `rehearser-library.js`.
- [x] Extract Audiobook parsing and casting; parsing, segmentation, cast normalization/serialization, and the live cast - [x] Extract Audiobook parsing and casting; parsing, segmentation, cast normalization/serialization, live cast view,
view now live in focused modules, while LLM orchestration and transport remain in `audiobook.js`. LLM orchestration, preview, and export now live in focused modules. Core Reader state and compatibility wiring remain
in `audiobook.js`.
- [x] Extract Audiobook parsing primitives and speaker-heuristic constants into `audiobook-parse.js`. - [x] Extract Audiobook parsing primitives and speaker-heuristic constants into `audiobook-parse.js`.
- [x] Extract Audiobook cast serialization and page-stamping helpers into `audiobook-cast.js`. - [x] Extract Audiobook cast serialization and page-stamping helpers into `audiobook-cast.js`.
- [x] Split the Performance/resource diagnostic styles into `static/css/resource-diagnostics.css`. - [x] Split the Performance/resource diagnostic styles into `static/css/resource-diagnostics.css`.
@ -147,7 +148,7 @@ architecture change: the larger Audiobook/Rehearser/style split.
- [x] Split Voice Design form and sample-grid styles into `static/css/voice-design.css`. - [x] Split Voice Design form and sample-grid styles into `static/css/voice-design.css`.
- [x] Split `style.css` by feature; Rehearser rules now live in `static/css/rehearser.css` alongside the existing - [x] Split `style.css` by feature; Rehearser rules now live in `static/css/rehearser.css` alongside the existing
diagnostics, background-job, voice-design, and Audiobook/Reader feature styles. diagnostics, background-job, voice-design, and Audiobook/Reader feature styles.
- [ ] Do not migrate to TypeScript or rewrite the frontend until behavior is covered by tests. - [x] Decision — do not migrate to TypeScript or rewrite the frontend until behavior is covered by tests.
## P1 — Frontend performance and memory safety ## P1 — Frontend performance and memory safety
@ -234,12 +235,12 @@ architecture change: the larger Audiobook/Rehearser/style split.
## P2 — Observability ## P2 — Observability
- [ ] Add structured logs with request and job IDs. - [x] Add structured logs with request and job IDs.
- [ ] Report provider, endpoint, duration, and error reason clearly. - [x] Report provider, endpoint, duration, and error reason clearly.
- [x] Separate health status from “configured”; discovery APIs now preserve both states and expose sanitized probe errors. - [x] Separate health status from “configured”; discovery APIs now preserve both states and expose sanitized probe errors.
- [x] Add visible job history and safe retry state; the authenticated `/api/jobs` metadata endpoint now feeds a - [x] Add visible job history and safe retry state; the authenticated `/api/jobs` metadata endpoint now feeds a
rendered panel with status, elapsed time, errors, cancellation, and an explicit reopen-source retry boundary. rendered panel with status, elapsed time, errors, cancellation, and an explicit reopen-source retry boundary.
- [ ] Avoid logging prompts, API keys, or book contents by default. - [x] Avoid logging prompts, API keys, or book contents by default.
## P1 — Resource limits and constrained-device testing ## P1 — Resource limits and constrained-device testing

View File

@ -1 +1 @@
1.24.55 1.24.56

View File

@ -3,7 +3,10 @@
## Current shape ## Current shape
- **Backend**: FastAPI, modular — `server.py` (app + middleware) → `routes/*.py` (admin, tts, library, sources, stt, conversation, docker, settings) → `core/*.py` (audio, voice, config, validation, tts_helpers, …). - **Backend**: FastAPI, modular — `server.py` (app + middleware) → `routes/*.py` (admin, tts, library, sources, stt, conversation, docker, settings) → `core/*.py` (audio, voice, config, validation, tts_helpers, …).
- **Provider status**: TTS/STT discovery responses expose `configured` independently from `available`/`health`, with only bounded probe endpoint, HTTP status, and sanitized error details returned to the UI. - **Provider status**: TTS/STT discovery responses expose `configured` independently from `available`/`health`, with only bounded probe endpoint, HTTP status, and sanitized error details returned to the UI.
- **Frontend**: ~15k lines of **plain global-scope JS** in `static/js/*.js`, loaded in order by `static/loader.js` (no bundler/build step). Sections are HTML fragments in `static/sections/*.html` fetched at runtime. Modules communicate via globals (`window._voices`, `$`, `escHtml`, `toast`, `saveMeta`, `loadVoiceLibrary`, …) and some runtime monkey-patching (e.g. `renderVoiceList` is reassigned in `voice-library.js`). - **Frontend**: feature code is split into manifest-driven lazy modules in `static/js/*.js`, loaded in order by `static/loader.js`.
Sections are HTML fragments in `static/sections/*.html` fetched at runtime. Legacy modules still communicate through
compatibility globals (`window._voices`, `$`, `escHtml`, `toast`, `saveMeta`, `loadVoiceLibrary`, …), while extracted
public APIs are published under `window.TTVC`.
## Already optimised ## Already optimised
- **GZip** responses (`server.py`) — ~75% smaller text transfer. - **GZip** responses (`server.py`) — ~75% smaller text transfer.
@ -28,7 +31,7 @@ The global scope + monkey-patching is the root cause of the recurring "wiring/ti
3. Replace the `renderVoiceList` monkey-patch with a normal function + an `onRender` hook. 3. Replace the `renderVoiceList` monkey-patch with a normal function + an `onRender` hook.
4. Switch `loader.js` to a single `<script type="module">` entry that imports the graph; `esbuild --bundle` then produces one minified, tree-shaken file. 4. Switch `loader.js` to a single `<script type="module">` entry that imports the graph; `esbuild --bundle` then produces one minified, tree-shaken file.
### 2. Split `rehearser.js` (was 196 KB) — IN PROGRESS ### 2. Split `rehearser.js` (was 196 KB) — RESPONSIBILITY SPLIT COMPLETE
Done incrementally as global-scope ordered files (no ES-module change needed) — each loaded before `rehearser.js` in `loader.js` + added to the bundle list in `scripts/minify.mjs`, verified by `tests/rehearser.spec.js` (parse → cast) and the smoke suite: Done incrementally as global-scope ordered files (no ES-module change needed) — each loaded before `rehearser.js` in `loader.js` + added to the bundle list in `scripts/minify.mjs`, verified by `tests/rehearser.spec.js` (parse → cast) and the smoke suite:
- ✅ `rehearser-parse.js` — `parseScript`, `detectCharacters` (pure; only call-time `SPEAKER_COLORS`). - ✅ `rehearser-parse.js` — `parseScript`, `detectCharacters` (pure; only call-time `SPEAKER_COLORS`).
- ✅ `rehearser-cast.js` — `renderCastList`, sort/filter, online voice picker, and character research. - ✅ `rehearser-cast.js` — `renderCastList`, sort/filter, online voice picker, and character research.
@ -41,7 +44,7 @@ Done incrementally as global-scope ordered files (no ES-module change needed)
- ✅ `rehearser-cast.js` — cast view, full cast-card rendering, sort/filter state handlers, and delegated cast toolbar wiring. - ✅ `rehearser-cast.js` — cast view, full cast-card rendering, sort/filter state handlers, and delegated cast toolbar wiring.
- ✅ `rehearser-voice-design.js` — character development, backend selection, and backend-refresh synchronization. - ✅ `rehearser-voice-design.js` — character development, backend selection, and backend-refresh synchronization.
- ✅ `audiobook-segmentation.js` — quote segmentation, conservative turn-taking, and dialogue-piece validation. - ✅ `audiobook-segmentation.js` — quote segmentation, conservative turn-taking, and dialogue-piece validation.
- ✅ `audiobook-parse.js` — dialogue detection, dehyphenation, and speaker-heuristic constants; the casting pipeline remains in `audiobook.js`. - ✅ `audiobook-parse.js` — dialogue detection, dehyphenation, and speaker-heuristic constants.
- ✅ `audiobook-cast.js` — cast Markdown export, legacy page-stamping migration, deterministic speaker/sentence/duplicate/alias normalization helpers, and the live cast-view renderer. - ✅ `audiobook-cast.js` — cast Markdown export, legacy page-stamping migration, deterministic speaker/sentence/duplicate/alias normalization helpers, and the live cast-view renderer.
- ✅ `audiobook-pipeline.js` — LLM casting, unknown-speaker recast, automatic repair, and cast-view orchestration. - ✅ `audiobook-pipeline.js` — LLM casting, unknown-speaker recast, automatic repair, and cast-view orchestration.
- ✅ `audiobook-preview-export.js` — editable cast preview, Rehearser handoff, chapter-aware export, and export browsing. - ✅ `audiobook-preview-export.js` — editable cast preview, Rehearser handoff, chapter-aware export, and export browsing.
@ -57,6 +60,8 @@ Done incrementally as global-scope ordered files (no ES-module change needed)
**Pattern (proven):** extract a cohesive block whose only cross-file references resolve at *call time* (event handlers), not at module load. Top-level `const rehState` and top-level `addEventListener` registrations must stay ordered — extract those last and load them after their dependencies. Re-run `npx playwright test` after each extraction. **Pattern (proven):** extract a cohesive block whose only cross-file references resolve at *call time* (event handlers), not at module load. Top-level `const rehState` and top-level `addEventListener` registrations must stay ordered — extract those last and load them after their dependencies. Re-run `npx playwright test` after each extraction.
## Remaining recommendations ## Remaining recommendations
- Complete the eventual ES-module/global-compatibility migration one leaf at a time; current behavior intentionally keeps
legacy globals available while the `window.TTVC` surface is adopted.
- Replace remaining silent `.catch(() => {})` with `logErr(context, e)` (helper added in `utils.js`). - Replace remaining silent `.catch(() => {})` with `logErr(context, e)` (helper added in `utils.js`).
- Full a11y sweep (icon-button `aria-label`s, focus traps, keyboard nav in `createSearchablePicker`) — run the `web-design-guidelines` review. - Full a11y sweep (icon-button `aria-label`s, focus traps, keyboard nav in `createSearchablePicker`) — run the `web-design-guidelines` review.
- If ever exposed beyond localhost: add an auth token + rate limiting (SSRF is already guarded in `core/validation.py`). - If ever exposed beyond localhost: add an auth token + rate limiting (SSRF is already guarded in `core/validation.py`).

View File

@ -10,7 +10,7 @@
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">
<meta name="color-scheme" content="light dark"> <meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#2563EB"> <meta name="theme-color" content="#2563EB">
<meta name="app-version" content="1.24.55"> <meta name="app-version" content="1.24.56">
<link rel="manifest" href="/manifest.webmanifest"> <link rel="manifest" href="/manifest.webmanifest">
<link rel="icon" href="/static/icon.svg" type="image/svg+xml"> <link rel="icon" href="/static/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/static/icon.svg"> <link rel="apple-touch-icon" href="/static/icon.svg">
@ -27,12 +27,12 @@
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── --> <!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css"> <link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
<link rel="stylesheet" href="/static/style.css?v=1.24.55"> <link rel="stylesheet" href="/static/style.css?v=1.24.56">
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.24.55"> <link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.24.56">
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.24.55"> <link rel="stylesheet" href="/static/css/background-jobs.css?v=1.24.56">
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.24.55"> <link rel="stylesheet" href="/static/css/voice-design.css?v=1.24.56">
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.24.55"> <link rel="stylesheet" href="/static/css/rehearser.css?v=1.24.56">
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.24.55"> <link rel="stylesheet" href="/static/css/audiobook.css?v=1.24.56">
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── --> <!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
@ -397,7 +397,7 @@ window.toggleNavTree = function(treeId, chevronId) {
</script> </script>
<!-- loader.js: fetches sections → loads JS modules → removes skeleton --> <!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
<script src="/static/loader.js?v=1.24.55"></script> <script src="/static/loader.js?v=1.24.56"></script>
</body> </body>
</html> </html>