Media resurrection plan (tangl.media)¶
Goal¶
Re-establish tangl.media as a first-class end-to-end pipeline that covers:
script-level media notation,
compile-time provisioning for static assets,
runtime journal fragment emission,
service-layer transformation into client-consumable resources,
optional adapter-driven generated media recipes (avatars, voice-over, etc.).
Status¶
March 9, 2026: Milestone 1 static-media plumbing is now wired through the v38 resolver path on
codex/v38-media.March 14, 2026: Milestone 2 sync inline-spec generation is now wired through story materialization and the resolver path for story-scoped generated media.
March 14, 2026: Milestone 3 server-side async lifecycle is now wired through story-scoped
MediaRITstatus transitions, guarded@on_provisionreconcile/dispatch hooks, aWorkerDispatcherprotocol, and fallback-first service rendering for pending or failed generated media.March 15, 2026: A deterministic
checkermedia harness now exercises both sync and async generated-media paths on the shipped server-side interfaces, giving Phase 3 a concrete in-process test target without requiring a real worker backend.March 30, 2026: The first spec-assembly slice is now in place for Comfy-backed image generation.
shot_typeis authored on the stable-aligned image-spec base, media adaptation now runs against a copied namespace snapshot, and a transientMediaShotPlanmicroconcept normalizes portrait/establishing defaults plus current look/outfit/style contributions beforeComfySpecmaterializes the final workflow.Implemented: authority-chain media inventory discovery, resolver offer generation for static media, story/world/sys inventory layering, canonical journal media fragments, shared service-layer dereference,
/media/story/{story_id}/...serving, story-media cleanup on drop, inlinemedia.specloading for sync and async generation, story-scoped generatedMediaRITprovenance, deterministic adapted-spec hashing and dedupe, typed render profiles, server-side pending/fallback handling, and a workflow-backed Comfy creator surface covering both async worker dispatch and optionalFAST_SYNCcreation.Deferred: named
MediaSpecRegistrytemplates,GenerationHintsand richer authoring surfaces, theget_media_registriesrename / dispatch-generalized media resolution, anticipatory affordance quota policy, and broader client capability negotiation beyond the current compatibility profiles.
Current hooks and what they already provide¶
Script and compile surfaces¶
MediaItemScriptalready supports exactly-one-of declarations (url,data,name,spec) and amedia_role. This is a strong contract to keep.StoryCompilerstill normalizes rawmedialists onto blocks, whileStoryMaterializernow translates staticnamemedia and supported inlinespecmedia intoMediaDepedges.MediaCompilercan indexworld/media/**into aResourceManagerand supports organization hints.
Runtime and journal surfaces¶
Block.mediais currentlylist[dict[str, Any]]and remains payload-oriented.render_block_medianow emits canonicalMediaFragmentpayloads for resolved static media, sync-generated media, and bound async-generated providers (content_format="rit", typedMediaRITcontent, deterministic scope). Fallback text for pending/failed generated media is carried through to the service layer; malformed or unsupported specs still use the placeholder/fallback path.
Service and transport surfaces¶
Runtime controller compatibility path can dereference
MediaRITcontent into stable URLs (/media/world/{world_id}/...,/media/sys/...,/media/story/{story_id}/...) and now applies fallback-first behavior for pending or failed story-scoped generated media.Gateway hooks can still append URL placeholders for media fragments under a
media_urlrender profile, but this path is intentionally generic and should remain the final compatibility fallback, not the primary resolver.
Design principles for the resurrection¶
Keep layer boundaries explicit:
story/compile decides intent and references,
vm/journal emits typed fragments,
service resolves transport resources.
Preserve determinism:
static assets should resolve reproducibly,
generated assets should use auditable recipe + seed records.
Prefer typed records/entities over free-form dicts in cross-layer handoff.
Proposed target model¶
1) Script notation model¶
Keep MediaItemScript as canonical input shape with two categories:
Static declarations
name(registry alias / filename)url(external pass-through)data(embedded literal media payload)
Potential declarations
spec(recipe template to be adapted for story context)
Add a small typed discriminator at compile output (e.g., media_source_kind: static|potential) to avoid repeated string heuristics downstream.
2) Compile-time provisioning model¶
At world compile/load:
Index static media directories into
ResourceManagerinventory.Translate static
namedeclarations into requirements that bind deterministically toMediaRIT.Keep unresolved
specdeclarations as recipe templates (not generated yet unless policy says eager).
Suggested policy options:
static_only(default): index files; do not generate.eager_generate: realize selected recipes at compile and register resultingMediaRIT.lazy_generate: defer recipe realization to runtime first use.
3) Story/runtime representation model¶
Represent block media as typed dependency descriptors rather than opaque dicts:
static descriptor -> points to existing
MediaRITrequirement,potential descriptor -> carries
MediaSpectemplate + adaptation context.
Provisioning step should produce either:
bound
MediaRITfor static/past-generated media,or realized
MediaRITby invoking an adapter pipeline for potential media.
4) Journal fragment contract¶
Emit a normalized MediaFragment contract from story handlers:
fragment_type="media"media_rolescope(world/sys/ external)one canonical content path:
content_format="rit"+content=<MediaRIT>for engine-internal pipeline,content_format="url"for pass-through external references.
optional caption/text metadata.
This makes service transforms simpler and allows profile-specific output (raw, html, cli_ascii) without shape drift.
5) Service-layer client resource model¶
Primary resolver behavior:
resolve
content_format="rit"via world/system resource manager into client URL plusmedia_type.preserve pass-through external URLs as-is.
output flattened JSON transport fragments.
Fallback compatibility behavior:
keep gateway
media_urltransform for non-normalized payloads while migration is active.
Layered media inventories and capability matrix¶
Media resolution should follow three explicit inventory layers, mirroring dispatch-style layering:
System inventory (
sys)Public/shared static assets (branding, UI chrome, install-level banners).
Loaded once per backend and reused across worlds/stories.
World inventory (
world)Static assets and optional compile-time generated assets for a world.
Shared by all stories instantiated from that world.
Story inventory (
story)Dynamic media created or assembled for one story instance and current context.
Scoped to ledger/story lifecycle and safe to evict when story is dropped.
Resolution order for media requests should be story -> world -> sys unless a scope is explicitly pinned.
Availability and policy matrix¶
The same media declaration may be constrained by both backend capabilities and client render profiles.
Backend capability examples
supports dynamic image generation
supports text-to-speech audio generation
supports vector composition only
Client profile examples
accepts raster images
accepts audio playback
text-only / cli-ascii mode
Policy evaluation should therefore gate media realization on the cross-product:
inventory scope×media data type×backend capability×client profile policy.
When unavailable:
emit deterministic diagnostics to journal/service metadata,
fall back to permitted alternatives (e.g., text caption, placeholder token),
avoid silent failure.
Static vs potential media lifecycle¶
Static media (compile-indexed)¶
bundle load indexes media files,
script
nameresolves by alias/hash/path,provisioning binds requirement ->
MediaRIT,journal emits
MediaFragment(content=rit, content_format="rit"),service dereferences into URL.
Potential media (adapter recipe)¶
script provides
spectemplate,adapter selection uses concept + role + world policy,
adapter materializes output and returns
(realized_spec, media_data|path),output registered as
MediaRITwith deterministic identifiers,journal and service follow same
ritflow as static media.
Persist recipe metadata (adapter id, model/version, seed, prompt/context hash) so reruns are reproducible/auditable.
Phased implementation plan¶
Phase 0 — Pin current contracts (now)¶
Add/keep tests for:
media compiler indexing with organization hints,
gateway media URL compatibility transform behavior,
runtime dereference URL conventions for world/sys scopes.
Phase 1 — Typed media declaration handoff¶
Introduce typed block-level media declaration model (compile output type).
Update
render_block_mediato emit canonicalMediaFragmentshape for static declarations.Maintain backward compatibility for legacy dict payloads.
Phase 2 — Provisioning integration¶
Status: landed for static media plus inline
media.specsync generation and server-side async lifecycle records.Route typed declarations through
MediaProvisionerpolicies.Bind static requirements and emit unresolved diagnostics for missing aliases.
Record reuse vs creation via spec-hash-based dedupe and generated-media provenance.
Phase 3 — Adapter recipe pipeline¶
Status: protocol/orchestration slice landed; concrete workers remain next.
Define adapter interface for potential media generation.
Implement reference adapters (avatar image recipe, voice-over recipe) behind
WorkerDispatcher.Add lazy/eager generation policies and deterministic seed strategy.
Phase 4 — Service resource unification¶
Status: largely landed for the runtime controller path; compatibility gateway path remains.
Consolidate media dereference logic behind one service helper used by runtime controller and gateway hook path.
Deprecate URL placeholder transform except as explicit fallback mode.
Phase 5 — Docs and migration¶
Publish media script authoring guide and client fragment contract.
Mark legacy dict payload media path deprecated with timeline.
Risks and mitigations¶
Risk: shape drift between journal and service transforms.
Mitigation: snapshot tests over serialized fragment payloads.Risk: nondeterministic generated media.
Mitigation: require recipe metadata + seed persistence and hash-based IDs.Risk: adapter coupling leaking into core/vm.
Mitigation: keep adapters in service/media layer and pass only typed records into lower layers.