test: add book two attribution fixture

This commit is contained in:
mARTin-B78 2026-09-04 09:18:41 +02:00
parent 4300d22cd9
commit 8ed1f122a3
5 changed files with 23 additions and 3 deletions

View File

@ -33,6 +33,8 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
status/cancellation endpoints with queue state, timeout and failure handling; existing synchronous callers remain compatible.
- **Optional Background Casting.** `/api/match-characters-voices` now accepts `background: true` and exposes bounded
job status/cancellation endpoints while reusing the existing casting validation, retries, and idempotency behavior.
- **Attribution Fixture Coverage.** Added a neutral multi-speaker Book 2-style fixture regression to verify parser
normalization across named speakers and narration without requiring a live provider.
- **STT Cancellation Safety.** Queued transcription cancels before consuming the single STT slot, and timed-out
requests keep the device slot held until the underlying worker actually exits.
- **Credential Boundary Review.** Provider credentials are now documented as server-only; only the explicitly

View File

@ -65,8 +65,9 @@ the first block before investing in architecture or polish.
- [ ] **L — Add background jobs and bounded queues.** Image generation already has the full interactive job path,
and transcription, voice design, and casting now have optional ID/status/cancel/timeout paths while preserving
synchronous callers. Durable persistence and retry policy still need to be added.
- [ ] **L — Run the Book 2 generalization regression.** Confirm speaker-attribution and
confidence rules are not overfit to *Der Sturm*.
- [ ] **L — Run the Book 2 generalization regression.** Added a neutral multi-speaker fixture and parser regression;
a real Book 2 auto-cast/attribution output still needs to be captured and reviewed to confirm rules are not overfit
to *Der Sturm*.
- [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
forms feed prompt generation and identity fingerprints.

View File

@ -1 +1 @@
1.22.6
1.22.7

5
tests/fixtures/book2_attribution.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"book": "book-2-neutral-fixture",
"known_characters": ["Captain Vale", "Mira", "The Ferryman"],
"raw": "{\"segments\":[{\"speaker\":\"Narrator\",\"type\":\"narration\",\"text\":\"At dawn the ferry reached the northern lock.\",\"emotion\":\"\"},{\"speaker\":\"Captain Vale\",\"type\":\"dialogue\",\"text\":\"Keep the lanterns covered.\",\"emotion\":\"cautious\"},{\"speaker\":\"The Ferryman\",\"type\":\"dialogue\",\"text\":\"Then we cross before the tide turns.\",\"emotion\":\"firm\"},{\"speaker\":\"Mira\",\"type\":\"dialogue\",\"text\":\"I can hear bells beyond the reeds.\",\"emotion\":\"alert\"}]}"
}

View File

@ -2,6 +2,7 @@
from __future__ import annotations
import os
import json
import tempfile
import unittest
@ -51,6 +52,17 @@ class AttributionParserTests(unittest.TestCase):
self.assertTrue(dialogue["text"].endswith("Land. Lieblich bisweilen, mild und voll der guten Menschen. ‹"))
self.assertEqual(narration["text"], "Zitiert aus dem Buch.")
def test_book2_neutral_fixture_preserves_multiple_speakers(self):
fixture_path = os.path.join(os.path.dirname(__file__), "fixtures", "book2_attribution.json")
with open(fixture_path, encoding="utf-8") as handle:
fixture = json.load(handle)
result = _attribution_parse(fixture["raw"], " ".join(fixture["known_characters"]))
self.assertEqual(
[segment["speaker"] for segment in result["segments"]],
["Narrator", "Captain Vale", "The Ferryman", "Mira"],
)
self.assertTrue(all(segment["type"] == "dialogue" for segment in result["segments"][1:]))
def test_consistent_image_job_can_be_cancelled(self):
from fastapi.testclient import TestClient
from server import app