"""M10: the seam a future media provider plugs into, and nothing behind it. This package is **readiness, not media**. Nothing here generates an image, a video, audio, speech or a transcription; nothing here opens a socket; nothing here is required for the storyteller to run. A campaign plays exactly as it did in M9 with none of this configured, which is M10's central acceptance condition — see `test_m10_no_media.py`. ## What M10 found already built, and therefore did not build again The largest finding of the milestone is how little of it needed inventing. `MEDIA-EXTENSION-CONTRACT.md` §5 asks the story system to persist a structured scene snapshot with a campaign, a lineage, a source position, a location and the characters present. **All of that already exists**, and has since M5: state["scene"] = {"summary": …, "location": , "present": [], "at": {"branch_id": …, "depth": …}} written only by the validated `set_scene` typed event (ADR 010), snapshotted per node in `actions.narrative_state_after` (M5), restored on every head movement by `attempts.restore_state` (M3/M4), and carried per position in the M9 v3 bundle. So it is already authoritative, already lineage-safe, already survives Undo, Redo, Save Point restore, divergence and restart, and already round-trips into a clean data directory. Building a `scenes` table beside that would have been a second representation of information the application already stores authoritatively — the one thing the M10 brief forbids — and it would have needed its own lineage rules, its own restore path and its own bundle carriage, each a chance to disagree with the state document. **So M10 stores no scene rows.** It reads the scene that is already there. ## What was actually missing Three things, and this package is each of them: * `profiles.py` — **visual profiles.** Stable descriptors for how an entity *looks*, which nothing recorded. Campaign-scoped rather than per-position, because a character does not change appearance when the story forks (K02, K03). * `packet.py` — **the Scene Packet.** A bounded, provider-neutral, hidden-information-safe view of one scene, built on demand from authoritative state. Persisted nowhere, because it is a pure function of things that are. * `providers.py` — **the provider contracts.** Types and protocols for image, video, audio, TTS and STT, with no provider vocabulary anywhere in them, plus the loopback-only endpoint rule the media contract asks for. ## The authority direction, which never reverses accepted story -> narrative state -> scene packet -> future provider Every arrow points away from authority. A visual profile is not a story fact; a scene packet is a read; a future asset would be a depiction. Nothing in this package writes `narrative_state`, emits a state event, or moves the head — and `test_m10_authority.py` asserts that by running each operation and comparing the authoritative document byte for byte either side. That is the rule `MEDIA-EXTENSION-CONTRACT.md` §35 and §49 state, and the reason it is enforced structurally rather than by convention: the only code that may change authoritative state is the M5 event pipeline, and nothing here imports it. """ from . import packet, profiles, providers __all__ = ["packet", "profiles", "providers"]