dec-0019

Vista generada de dec-0019: r23 — Canonical Media Factory (arquitectura codec-agnostic + pipeline)

ImplementadoSin versión del tren todavía· generada desde docs/decisions/dec-0019-canonical-media-factory.md
track/docsdec-0124track/docs:DC10

Vista generada desde docs/decisions/dec-0019-canonical-media-factory.md. No se edita a mano: bun run docs:gen la regenera y bun run docs:check falla si difiere. El estado aquí es el del model: si discrepa con otra página, manda el model.

CampoValor
EstadoLOCKED
Fecha2026-06-21
Referencia legadar23
Ficherodocs/decisions/dec-0019-canonical-media-factory.md

Nodos del roadmap que lo citan en refs: ninguno.

Páginas de la documentación que lo citan: ninguna todavía.

Texto del ADR

Leído de docs/decisions/dec-0019-canonical-media-factory.md, el fichero canónico.

r23 — Canonical Media Factory (arquitectura codec-agnostic + pipeline)

Contexto

Styx ingesta contenido vía ARR/torrent/IPTV/remote sources. r23 formaliza el modelo en el que el archivo descargado no es automáticamente la fuente permanente de verdad. Es un AcquisitionArtifact temporal que Styx convierte en una CanonicalRepresentation inmutable, enriquecida, verificada y versionada. Esta tesis fue validada por 6 pythia en research adversarial y por auditoría adversarial de ChatGPT (2026-06-21).

waxin lockeó las decisiones vía AskUserQuestion (sesión CMF, 2026-06-21):

  • Codec: AV2-first. Arquitectura codec-agnostic. Roles dinámicos, no Tiers. CanonicalCodecPolicy v1.
  • Representación: full bleeding-edge native manifest+packs. Se exige prototype que confirme viabilidad.
  • Audio: preservación selectiva del lossless/immersivo del idioma principal + derivados bajo demanda. CanonicalAudioPolicy v1.
  • Workflow: Postgres FSM + NATS JetStream + Valkey. SIN BullMQ.

Decisiones

1. Arquitectura codec-agnostic

La arquitectura de Styx NO acopla el modelo de dominio a codecs concretos. El codec es una policy versionada y reemplazable, no una categoría arquitectónica.

CanonicalRepresentation se modela con capabilities + descriptores, no con tipos de codec:

CanonicalRepresentation:
  - id, edition_id, generation
  - codec_descriptor (family, profile, level, tier)
  - bit_depth, chroma_subsampling
  - hdr_metadata (format, primaries, transfer, mastering display, CLL/FALL)
  - random_access_characteristics (GOP structure, keyframe interval, seek points)
  - quality_class (metrics snapshot)
  - decoder_requirements (hw/sw, minimum profile, reference frames)
  - storage_cost, processing_cost
  - recipe_version
  - lifecycle_state (candidate | active | retained | evicted | experimental)

Los codecs tienen roles dinámicos, no Tiers rígidos: frontier-preferred | canonical-active | production-fallback | compatibility | legacy | experimental

Una misma representación puede cambiar de rol cuando el ecosistema madure, sin migrar la arquitectura. Añadir AV3, VVC, un nuevo perfil AV2 o cualquier codec futuro no debe requerir cambiar el modelo de dominio ni el media graph: solo registrar capabilities, encoder/decoder adapters y una nueva policy/recipe.

2. CanonicalCodecPolicy v1

RolCodecNota
frontier-preferredAV2Objetivo real del máster canónico. Corpus piloto con recipe pinneada + known-issues matrix + decode validation + source retention.
production-fallbackAV1Provisional operativo. NO es destino estratégico. Content-adaptive recipes, quality gates.
compatibilityHEVC Main10Fallback de compatibilidad (modo Xtream legacy). No necesariamente permanente por asset.

La promoción es por generaciones inmutables:

AV1 canonical generation actual
  → AV2 candidate generation (encode + QC)
    → AV2 promoted as active canonical (pointer swap)
      → AV1 retained temporarily or evicted by policy

NO se fijan CRF, thresholds exactos, encoder flags ni fechas de maduración en esta decisión arquitectónica. Eso pertenece a recipes versionadas y al corpus piloto.

3. AcquisitionArtifact vs CanonicalRepresentation

  • AcquisitionArtifact: materia prima temporal. Se conserva solo para QC, rollback, seeding (torrent) y política de retención configurable. Tras promoción del canonical + expiración de leases → DELETE o cold storage pack (r11).
  • CanonicalRepresentation: inmutable, versionada por generations. Promoción atómica vía pointer swap. Rollback soportado (últimos N releases). QC completo antes de liberar el source.
  • El source NO se borra automáticamente tras el primer QC. Debe pasar: todos los gates + seeding lease expirado + retention policy.

4. Pipeline de canonicalización (ownership)

13 estados (ACQUIRED → ... → PROMOTED → ACQUISITION_RELEASED), cada uno idempotente, resumible, cancelable, content-addressed.

Arquitectura de workflow:

  • Postgres: durable state machine (FSM), leases, lineage, recipes, manifests
  • NATS JetStream (r18): task dispatch (cmd.*), events (evt.*), retries operacionales
  • Valkey: cache, rate-limit, presence, locks efímeros
  • SIN BullMQ: no añadir Redis adicional. JetStream + Valkey cubren. Solo reconsiderar si prototype demuestra carencia concreta.

Ownership por etapa:

EtapaOwnerToca bytes?
ACQUIRED→IDENTIFIEDworkers-svc (Bun)No
IDENTIFIED→PROBEDstyx-media-daemon (Zig, libav)Sí (probe)
PROBED→REPAIREDdaemon ZigSí
REPAIRED→ENRICHEDworkers-svcNo
ENRICHED→ENCODE_PLANNEDworkers-svc (PlaybackPlanner)No
ENCODE_PLANNED→VIDEO_ENCODEDdaemon Zig (libav)Sí
ENCODE_PLANNED→AUDIO_NORMALIZEDdaemon ZigSí
ENCODE_PLANNED→SUBTITLESworkers-svc + daemon ZigMixto
→PACKAGEDdaemon ZigSí
→VERIFIEDworkers-svc + daemon ZigMixto
→PROMOTEDworkers-svc (tx atómica)No
→ACQUISITION_RELEASEDworkers-svc (NATS evt)No

Principio: Bun orquesta y decide; Zig procesa bytes vía libav C ABI. Bytes de media NUNCA atraviesan JavaScript (r01, r22). Frontera Bun↔Zig = IPC Unix socket (r22).

5. Representación canónica (manifest + packs content-addressed)

El modelo lógico de CanonicalRepresentation es codec-agnostic (manifest versionado + generations inmutables + payload/track independence + materializaciones derivadas). El formato físico de payload es decisión de implementación, no arquitectónica.

Dirección bleeding-edge (waxin): full native manifest + packs content-addressed como source-of-truth universal. MKV/MP4 como materializaciones bajo demanda. Se exige prototype que confirme viabilidad adversarial: recovery, seek random, remote SFTP, GC, corrupción parcial, export, disaster recovery sin Postgres.

Mientras el prototype no esté validado, AV1 usa MKV portable (mkvmerge + mkclean) y AV2 usa elementary OBU stream + sidecar manifest. La arquitectura NO depende de esta provisionalidad.

6. Negotiacion order (post-canonicalization)

  1. Direct canonical delivery (codec/profile/level/HDR compatible)
  2. Repack/remux sin cambiar codec (ej: MKV→fMP4)
  3. Persistent compatibility representation existente (derived cacheada)
  4. Generate + persist compatibility representation
  5. Server transcode on-the-fly (solo cuando cached no viable)
  6. Client transmux/transcode (fallback explícito)

7. CanonicalAudioPolicy v1

Preservar (stream copy): lossless/immersivo del idioma principal + pistas marcadas como valiosas por el usuario. NO preservar: commentary, idiomas secundarios lossless, pistas duplicadas. Derivados: solo bajo demanda del cliente (E-AC-3 5.1 640kbps, Opus stereo 192kbps). Loudness: medir (EBU R128), NO normalizar destructivamente.

La policy es versionada y configurable (CanonicalAudioPolicy), no hardcodeada en la arquitectura.

8. Metadata 3-layer

  • Postgres: autoridad semántica completa (TVDB/TMDB/IMDb/Wikidata, localized, órdenes, cast/crew, artwork, overrides)
  • Embedded subset: proyección portable estandarizada (IDs provider, título, synopsis, track names/flags, chapters, BCP47, encoder)
  • Provenance manifest: lineage técnico (hashes, comandos, tool versions, métricas QC, recipe, Styx IDs)

Postgres es la fuente de verdad. El manifest es provenance. Los tags de contenedor son proyección.

9. Quality gates (principios, NO thresholds)

Los thresholds exactos (SSIMULACRA2 ≥90, VMAF ≥93, etc.) son hipótesis de corpus piloto, no criterios arquitectónicos. Lo que se lockea:

  • Content-adaptive admission (NO CRF universal)
  • Recipe versionada e inmutable
  • Gates por tipo de contenido (film grain, animación, SDR, HDR)
  • Métricas primarias: SSIMULACRA2 + VMAF v1 + Butteraugli según tipo
  • 9 gates pre-release: decode completo, timestamps, frame count, sync A/V, HDR/color, capítulos/subs, hashes, manifest, verificación subjetiva sampling
  • Promoción atómica: staging → gates → pointer swap → event → GC posterior
  • Rollback: mantener últimos 3 releases

Consecuencias para otras decisiones

DecisiónEfecto
r01 (Bun decide, Zig ejecuta)REALIZA — pipeline completa con ownership por etapa
r08 (Work→Edition→MediaAsset→SourceBinding)EXTIENDE — CanonicalRepresentation como modelo codec-agnostic
r09 (media graph adapters)REFUERZA — añadir codec = solo adapters + policy, no toca modelo
r10 (delivery plane)APLICA — negotiation order con direct canonical first
r11 (Storage Box)APLICA — canonical storage + packfiles para cold storage del acquisition
r16 (lab bleeding-edge)ENCARNA — AV2-first, native pack store, owned pipeline
r17 (microservicios)REFUERZA — pipeline con ownership claro por servicio
r18 (NATS JetStream)UTILIZA — task dispatch + events en el pipeline
r20 (PlaybackPlan composicional)EXTIENDE — negotiation order + capabilities como selector de representation
r22 (Zig data plane)REALIZA — daemon Zig como ejecutor byte-level de la pipeline

Trade-offs

IDTrade-offAceptado porque
T1AV2 es frontier con bugs conocidos, no production-ready → corpus pilotowaxin: bleeding-edge. AV2 es el norte estratégico. Source retention + gates mitigan.
T2Native pack store requiere construir tooling de filesystem propio → riesgo de scopewaxin: full bleeding-edge. Se exige prototype adversarial antes de lockear como universal.
T3Pipeline 13 estados con FSM en Postgres → complejidad de estadoworkers-svc con SKIP LOCKED + LISTEN/NOTIFY + idempotencia. Patrón probado (DBOS, HotMesh).
T4Metadata 3-layer → sincronización entre capasPostgres es la autoridad. Embedded y manifest son proyecciones derivadas, no independientes.

Referencias

  • docs/research/canonical-media-factory-2026-06-21/ (dossier completo, 6 pythia)
  • docs/updates/styx-canonical-media-factory-research-brief.md (brief original ChatGPT)
  • styx-cmf-adversarial-audit-2026-06-21.md (auditoría adversarial ChatGPT)
  • docs/decisions/r22-...md (Zig data plane)