ID3 provenance tags (synthetic speech, generator, version, date, opt-in
voice name) on magazine MP3/ZIP/EPUB exports via a stream-copied temp copy;
verify endpoint and CLI; AudioSeal tier is a documented stub.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Single-voice health endpoint (GET /api/voices/{id}/health), problems stored in
meta on import, shown in the Try-out voice panel; architecture note and docs.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
"Page N" entries come from review stand-ins created after Approve saved only
the visible page's regions. New core/magazine_untitled.py classifies untitled
entries (continuation, article head, advert, picture page, contents, junk),
proposes merges into the previous article with confidence and evidence
(optional LLM check in the ambiguous band), and suggests titles
(deterministic, optional validated and cached LLM titles). Exposed through
derived GET /articles fields, GET /untitled, quality report, undoable
merge-into-previous / accept-title routes, POST /titles/suggest and
scripts/magazine_untitled.py (dry run by default, --apply backs up first).
Merges mark audio_stale; no audio is deleted; real titles are never
overwritten.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Menu is grouped into View (Picture/Text/Split radios), Show and Playback
(real switches) and Theme (Light|Auto|Dark segmented control). Fixes the
Dark option looking disabled: its data-theme=dark attribute matched the
app-wide dark palette selector. Adds automatic advance to the next article
with audio (switch, default on) with End of magazine state.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Real-library audit (270 records) traced the data damage to:
- identity matching on ANY shared token ("Zwerg", "der Zwerg", "Mann") with
"longer text wins" merging (Arthag b02 = Kolon's species/relationships), and
- csRosterCanonicalName renaming a sheet to the first cast name among its
aliases, which saved 16 whole-sheet copies (Zwerg/Kolon = Arthag b03,
Fremder = Mann, Alchimist = Promos ...).
Fixes:
- static/js/character-identity.js + core/character_records.py: generic labels
are never identity evidence; csFindMergeKey, csConsolidateAliasDuplicates,
csRosterCanonicalName, clSameIdentity use it; own name always wins; clUpsert
writes to the exact-name record before any alias scan; no seed rename onto a
name that has its own record.
- _charsheets_parse: in cast-target mode drop other cast members' names from
aliases / first / last name (Kolon: "Sharraz Garthai"), strip reasoning
leakage ("Warte:", "Der Text sagt ...") from every text field.
- _character_scene_evidence: only a quote naming the character is used,
otherwise its own mannerisms (16 panels showed another character's scene).
- _character_age_category: Junge/Mädchen/boy/girl, number words, Sommer/
Winter ages, evidence clause, age-tagged quotes; "15 Jahre älter" is no age.
- scripts/audit_character_records.py (read-only) and
scripts/clean_character_records.py (dry run by default, --apply backs up).
Tests: tests/test_character_record_hygiene.py, tests/character-identity.test.mjs.
Docs: architecture/character-extraction.md, Manual, CHANGELOG.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Extraction notes in race_species that mention another character's species
("Mensch (oder Zwerg, ...)", "... 'Der Zwerg' wird separat erwähnt ...")
switched on the dwarf body lock (short legs, full beard) for human characters
and carried a sentence about another character into the Subject clause.
Confirmed on the real library: Marrad, Kolon and Arthag (book 02).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Index rows reuse the playlist state helper (magListenState): round 44px play/resume/replay button,
smaller muted 'by Author', not played / partly played / played indicator with accessible text, live updates.
Also fix a stale word highlight in the lyrics view that made a driving-mode test fail.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Bind the consistent-image Idempotency-Key to the character request so a reused
key cannot return another character's job; add back-to-back and concurrent
two-character regression tests.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>