dec-0129

Vista generada de dec-0129: Transferencias como columna vertebral: subidas, descargas, offline, p2p y adquisición en un solo plano

ImplementadoSin versión del tren todavía· generada desde docs/decisions/dec-0129-transferencias-columna-vertebral.md
track/docsdec-0124track/docs:DC10

Vista generada desde docs/decisions/dec-0129-transferencias-columna-vertebral.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-10-01
Ficherodocs/decisions/dec-0129-transferencias-columna-vertebral.md

Enmienda a: r26, dec-0117, dec-0121

Por qué importa (del frontmatter del ADR):

Fija que subidas, descargas, offline, p2p/swarm y adquisición son un solo plano de transferencias del byte runtime, con un modelo de transferencia reanudable común, identidad verificable por rangos (BLAKE3 en árbol con grupos de 16 KiB y outboard de bao; el árbol SHA-256 de BitTorrent v2 se calcula bajo demanda sólo para sembrar) e indexado inmediato de todo lo que entra. Hace de la descarga un ciudadano de primera clase igual que el stream: original byte a byte con Range/If-Range, o derivada (remux determinista con tamaño exacto, o transcodificación materializada por ExtentMap en la caché direccionada por hash) en el formato o códec pedido, con los metadatos incrustados. Abre el scope SCT download y el permiso asset:download, añade clases al GlobalByteScheduler para que una descarga nunca degrade una reproducción, y fija objetivos de rendimiento medibles contra referentes (nginx sendfile+kTLS, aria2, rsync, qBittorrent). Sin este ADR cada dirección inventaría su propio modelo de reanudación, de integridad y de cuota, y la descarga quedaría como un GET suelto con un token de reproducción de 10 minutos.

Nodos del roadmap que lo citan en refs: track/byte-runtime/egress, track/byte-runtime/ingest-web, track/byte-runtime/dedup, outcome/federated-storage/remote-backends, track/media-engine/download-output

Páginas de la documentación que lo citan: Transferencias (especificado)

Texto del ADR

Leído de docs/decisions/dec-0129-transferencias-columna-vertebral.md, el fichero canónico.

dec-0129 — Transferencias como columna vertebral: subidas, descargas, offline, p2p y adquisición en un solo plano

  • Fecha: 2026-10-01
  • Estado: LOCKED (2026-10-02). waxin, vía AskUserQuestion: lockear este ADR con la enmienda de P3 que propone docs/track/byte-runtime/plans/conduit-wire-v2.md (rama w13/conduit-v2): BLAKE3 + bao con hojas de 16 KiB como identidad interna, y el árbol SHA-256 de BEP 52 calculado bajo demanda, sólo para sembrar. Añade que el dominio de dedup es configurable (household por defecto; user y server, este último con aviso). El resto de §12 se lockea con la recomendación del propio ADR como parámetros reversibles, o queda diferido de forma explícita. Todo está en Lock (2026-10-02, waxin). Donde el texto de §1–§13 y el lock difieren, gana el lock. Las enmiendas de §11 entran en vigor hoy.
  • Propone: workflow de visión (rama w10/adr-transferencias, desde w10/vision). La implementación cae en track/byte-runtime, track/media-engine, track/offline-continuity, track/swarm-core, track/acquisition-core, track/identity y los clientes. Este ADR no crea nodos ni milestones: los propone como pregunta (§12, P1).
  • Enmienda pendiente (propuesta, no lock): dec-0132 (LOCKED 2026-10-02, §9 y su tabla de relación con transferencias) propone que el origin de §3.7 gane device (volcado desde una consola) y que la ingesta agrupe una carpeta como N transferencias más un manifiesto, con bundleId y manifestRoot en @styx/api-contracts ingest.ts. Ningún lock la recoge en este ADR: hasta que waxin la lockee (AskUserQuestion), §3.7 y el contrato de ingesta no cambian.
  • Numeración: dec-0127 (modelo de datos), dec-0128 (dispositivos), dec-0130 (modo público y plataforma) y dec-0131 (federación) están reservados para el mismo workflow. Se citan por número; su contenido no se presupone.
  • Dirección de waxin que cumple (2026-10-01, ledger docs/overview/vision-ledger.yml):
    • V-N07: "y ojo con las descargas . que eso no es una idea suelta, eso e sLOAD BEARING , todo lo d descargas, subidas, p2p etc , y mas siporte que haremos , es una columna vertebrak y debe ser ultrarapida y state of the art."
    • V-XFER-01: "jelyfin nisiquiera ofrece para subir un fichero directaenre y es un coñazo tener que tirar rsync o ftp o lo q sea y liego esperar el refresh o relwanzar el scan, nosotros hacemos todo eso y ademas con conduit ofrecemos descargas y subidas a prueba de cortes, reanudables, ultrarrapidas ."
    • V-XFER-02: "y ls descargas igual de importantes que el stream, lo mismo. byteruntime si hace falta si solicita descargarlo con algun format. o codec que actualmente no esta , se hace on the fly como el stream. muy importantes las descargas."
    • V-XFER-03: "no solo adquisicion de contenido de torrents o demas como jellyfin plugins para utomatizarlo".
    • V-N10: "Federación + offline" (offline y descargas reanudables, ligado a N7).
    • También cubre en parte V-XFER-04 (BitTorrent propio), V-XFER-05 (Acquisition Runtime, dec-0034) y toca V-N03 (backend remoto), V-N06 (federación) y V-N08 (modo público: "stream, descarga o ambos").
  • Cita:
    • r01: Bun decide, Zig ejecuta; los bytes no atraviesan JS ni NATS.
    • r04 / C14: SeekableMediaSource, cancel(requestId) por request.
    • r05: PlaybackPlan composicional; este ADR añade la entrega file.
    • r12 / r45: caché de 3 tiers; L2 desaloja por coste de regeneración.
    • r16: frontier salvo blocker.
    • r23 / dec-0019: CanonicalCodecPolicy, AcquisitionArtifact, seeding lease.
    • r26: byte runtime en todas las direcciones, ReadIntent, GlobalByteScheduler, multi-source reads, crate swarm.
    • r27 / dec-0034: nodos, Acquisition Runtime, varilla SOTA contra qBittorrent.
    • r61 / dec-0094 / dec-0098: OfflineBundle, track/offline-continuity.
    • dec-0106 (PROPOSED): ExtentMap con known_length y sealed.
    • dec-0110: MediaEngine dual; §1.2 audio a AAC; el encode de vídeo no está decidido.
    • dec-0114 / dec-0126 (PROPOSED): huella sobre el payload; metadatos dentro del fichero.
    • dec-0117: I1–I12, SCT v1 y sus scopes.
    • dec-0119 / dec-0120: control y bus por spire, BUS_ROUTES.
    • dec-0121: ingesta con conduit, SCT ingest, cuotas, cmd.catalog.registerIngested.
    • dec-0124 (PROPOSED): doc como contrato y superficie headless.
    • dec-0125 (PROPOSED): permisos <recurso>:<acción> y concesiones de biblioteca.

1. Contexto: qué existe hoy

Verificado sobre el árbol de w10/vision.

DirecciónEstado
SubidaExiste y está cerrada (track/byte-runtime/ingest done, IN1–IN3 pass). styx-upload (Zig) → IngestSink del daemon con el wire v1 de conduit, SCT ingest, cuotas por fichero, actor y raíz, SHA-256 por chunk y del fichero, staging fd-relativo, alta en catálogo por cmd.catalog.registerIngested (dec-0121). No hay cliente web ni de la app: sólo el CLI.
DescargaNo existe como tal. El daemon sirve byte-ranges por H3/WT con una SCT read que dura 600 s, y la entrega se cierra a los 630 s (plan vertical-vod-web, rama w8/vertical-plan, fila "Sesión / entrega"). No hay permiso asset:download (packages/authz/src/policy.ts:20 sólo tiene play y scan), ni Content-Disposition, ni descarga en otro formato.
Formato al vueloPara reproducir: remux a fMP4/CMAF y HLS (native/zig/transmux/), passthrough de h264 hevc av1 vp9 aac mp3 opus flac ac3 eac3. Transcodificación de audio a AAC permitida por dec-0110 §1.2 y sin implementar. El encode de vídeo no está decidido (dec-0110, "Lo que este ADR NO decide").
Wire de conduitSólo sube: cinco rutas (session, chunk, status, complete, abort; MKS2508/conduit spec/wire-v1.md §4). La frase de waxin "con conduit ofrecemos descargas" no tiene todavía soporte en el wire ni en el SDK.
OfflineOfflineBundle existe como tipo en r61 D1 (dec-0094). track/offline-continuity está queued sin consumidor real, como excepción nominada (dec-0098).
P2P / swarmtrack/swarm-core y track/swarm-progressive queued. El crate swarm (BitTorrent v1/v2/hybrid) está en r26 §4 como plan. 0 líneas de código.
Adquisicióntrack/acquisition-core y track/acquisition-native queued (dec-0034). 0 líneas de código.
Rendimiento medidoNo hay línea base honesta del daemon. Los ~20 MB/s de H3 medidos en la ronda 3 del motor eran el techo del cliente aioquic, no del daemon (docs/track/byte-runtime/evidence/media-engine-2026-09-28/hardening-r4/README.md, fila "Evidencia de throughput honesta"). La subida no tiene medida de goodput. Ninguna cifra de este ADR se puede afirmar hoy: todas son objetivos.

2. Referentes y estado del arte

Lo que hacen los demás, y qué se toma. Fuentes en §13.

ReferenteQué haceQué se toma / qué no
JellyfinNo sube ficheros (rsync/FTP + re-scan). Descarga el original; las descargas convertidas para offline no son de primera clase.Es la vara: subir e indexar sin re-scan, y descargar en el formato pedido, son superset directo.
PlexDescargas convertidas a una calidad menor en el servidor, para llevar al móvil.La idea de perfil de descarga. No su modelo: aquí el derivado se cachea direccionado por hash y se reutiliza entre usuarios y entre stream y descarga.
HTTP Range / If-Range / ETag fuerte (RFC 9110)Reanudar una descarga en cualquier cliente (navegador, VLC, curl, aria2) sin protocolo propio.Es el wire de la descarga. Nada propio en el cable: cualquier gestor de descargas reanuda.
IETF Resumable Uploads (draft-ietf-httpbis-resumable-upload-12, julio 2026, Standards Track, aún no RFC)Subida reanudable estándar sobre HTTP (sucesor de tus).Se sigue. conduit v1 sigue siendo el wire de subida (está hecho, verificado y es más estricto: digest por chunk, cuotas por identidad). Un adaptador al draft se decide cuando sea RFC (P8).
aria2 / gestores multi-conexiónVarias conexiones y rangos en paralelo para saturar enlaces con BDP alto o por-flujo limitados.El cliente de descarga de conduit pide rangos en paralelo (§3.4.4).
BitTorrent v2 (BEP 52) y web seeds (BEP 19)Árbol Merkle SHA-256 por fichero con bloques de 16 KiB: cada bloque se verifica al llegar; la raíz por fichero deduplica entre torrents. Web seeds: HTTP como un peer más.La identidad verificable de §3.2 es ese árbol. Un asset de Styx es sembrable como v2 sin rehashear, y un rango de cualquier fuente se verifica por bloque.
iroh-blobs / BLAKE3 + baoStreaming verificado por rangos sobre QUIC, con BLAKE3 como hash de árbol.El modelo (rangos verificables de fuentes no confiables). BLAKE3 se evalúa frente al árbol de BEP 52 (P3): es más rápido, pero rompe la interoperabilidad directa con el swarm.
Background Fetch + OPFSDescarga gestionada por el navegador que sobrevive a cerrar la pestaña (Chrome y Edge; no Firefox ni Safari). OPFS guarda ficheros grandes y sirve rangos sin leer desde el principio.La descarga offline de la web (§3.5). Fallback en pestaña donde no hay Background Fetch.
"QUIC is not Quick Enough over Fast Internet" (2024)Por encima de ~500–600 Mbit/s, QUIC/HTTP3 en navegadores entrega hasta un 45 % menos que TCP+TLS+HTTP/2, por coste de recepción (ACKs en espacio de usuario).La descarga de fichero completo necesita un camino TCP, no sólo H3. Se mide (T1) y la elección es por medida, no por dogma. Choca con que no hay ADR del delivery-edge TCP (ledger V-PLAY-07).
kTLS + sendfile (nginx ≥ 1.21.4)Cifrado TLS en el kernel y cero copias de fichero a socket: 8–29 % más rendimiento según el SO, ~30 % en ficheros de 10 MB.Es el referente del original (T1). La vara de la descarga del original es "igual que nginx sirviendo el mismo fichero en la misma máquina".

Enmendado en el lock (P3). Las filas de BEP 52 y de iroh-blobs/BLAKE3 se leen al revés: la identidad interna es BLAKE3 + bao (§3.2) y el árbol de BEP 52 se calcula bajo demanda para sembrar.

3. Decisión

3.1 Un plano, cuatro direcciones, un modelo de transferencia

Las transferencias son un solo plano del byte runtime (r26 §1: "owners completos del flujo de bytes en todas las direcciones"), no cuatro features sueltas.

DirecciónEntra / saleProductor de bytes (Zig)Decide (Bun)
Subidacliente → nodoIngestSink (conduit servidor)playback-svc (dec-0121)
Descarganodo → clienteegress del daemon: fichero original o derivadoplayback-svc
P2P / nodospeer ↔ nodo, nodo ↔ nodocrate swarm (BitTorrent) y rangos verificados nodo↔nodoacquisition-svc / federación (dec-0131)
Adquisiciónfuente externa → nodo (torrent, HTTP, Jellyfin, otro Styx, backend remoto)swarm, HTTP source, backends de outcome/federated-storageacquisition-svc (dec-0034)

Todas comparten:

  1. Un modelo de transferencia reanudable: Transfer { id, direction, content (§3.2), spec, progress (ExtentMap de lo hecho), actor, quota class, scheduler class (§3.8) }. La reanudación siempre es "pedir lo que falta según el mapa de extents", nunca "empezar otra vez".
  2. Una identidad de contenido verificable por rangos (§3.2).
  3. Una sola entrada al catálogo: todo lo que entra al nodo, venga de donde venga, termina en el mismo contrato de alta (cmd.catalog.registerIngested generalizado, §3.7). Nada se indexa por re-scan.
  4. Un scheduler: el GlobalByteScheduler de r26 §2, con clases nuevas (§3.8).
  5. Bytes sólo en Zig (r01). Bun firma capabilities, decide políticas y ve progreso; nunca ve un byte de vídeo.

3.2 Identidad e integridad: BLAKE3 en árbol, grupos de 16 KiB

Texto del lock (enmienda de P3, docs/track/byte-runtime/plans/conduit-wire-v2.md §2.1 en la rama w13/conduit-v2). Sustituye a la propuesta original de un árbol SHA-256 de BEP 52 como identidad.

  • La raíz de transferencia de un fichero es BLAKE3(bytes exactos) — lo que imprime b3sum —, que ya es un árbol de Merkle. La verificación por rangos va a grupos de 16 KiB con un outboard pre-order (pares de CVs de los nodos padre sobre los grupos; 64 B por 16 KiB, 0,39 %), el layout de bao/iroh-blobs, definido en conduit spec/wire-v2.md §3 con vectores. Rangos de una fuente no confiable se verifican en streaming (slices), grupo a grupo, antes de escribirse o servirse, con memoria O(log n).

  • El outboard se guarda como caché regenerable en L2 de r45, direccionada por la raíz. Se calcula en el mismo y único pase de la ingesta (conduit v2: el servidor hashea cada chunk a su offset, guarda los CVs de grupo y deriva el outboard sin releer el fichero) o del escaneo.

  • BEP 52 bajo demanda: sus hojas (SHA-256 de 16 KiB) son los mismos rangos que los grupos. Al sembrar o contrastar un torrent v2, un pase verifica cada grupo contra el outboard BLAKE3 y calcula el SHA-256 en la misma lectura; el resultado (32 B por 16 KiB) se guarda como segundo outboard. Un torrent v2 que entra por adquisición se verifica con su propio árbol al bajar y recibe su outboard BLAKE3 en el pase que lo escribe.

  • Para qué sirve:

    • verificar cada rango que llega de una fuente no confiable (peer, otro nodo, servidor federado, backend remoto) antes de escribirlo o de entregarlo;
    • descargar de varias fuentes a la vez y saber cuál mintió;
    • sembrar como torrent v2 con un pase bajo demanda, sólo de lo que se siembra (la pieces root de BEP 52 sale de ese pase, verificado contra el outboard BLAKE3);
    • deduplicar el mismo fichero entre torrents, subidas y nodos, dentro del dominio de dedup (lock, punto 3).
  • Tres identidades, tres trabajos (y no se confunden):

    IdentidadSobre quéCambia al incrustar metadatosPara qué
    Huella de asset (dec-0126 §3.3)payload (mdat / Clusters) + facts en lista blancano"es la misma película": identidad en el catálogo
    Raíz de transferencialos bytes exactos del fichero, BLAKE3síintegridad por rangos, swarm, dedup de bytes
    ETag fuerte de la descargaraíz de transferencia (+ perfil, si es derivado)síIf-Range: reanudar sólo si los bytes no cambiaron
  • Con la enmienda, BLAKE3 es la única familia de hash de identidad del sistema (la huella de asset de dec-0126 §3.3 y AssetId/metadataHash de dec-0127 ya lo son). SHA-256 queda para interoperar (BEP 52, el perfil compat de conduit con cloudreve-mirror) y para lo que ya firma con él: las SCT no cambian.

  • Consecuencia con dec-0126: una escritura de metadatos in-place cambia la raíz de transferencia. El daemon no edita un fichero con una transferencia activa (descarga, siembra o subida a otro nodo): la transferencia toma un lease, como el de seeding de dec-0019, y la edición espera o se reprograma. Si la edición ocurre entre dos intentos, el If-Range falla y la descarga recibe un 200 completo, que es el comportamiento correcto de HTTP.

3.3 Subidas: directas, reanudables e indexadas al terminar

Se mantiene dec-0121 entero. Lo que añade este ADR:

  1. Clientes web y app. El wire v1 de conduit tiene codec TypeScript con vectores de conformidad (@mks2508/chunk-engine) y el SDK Zig compila a WASM. La web sube con ese cliente desde un worker: el navegador lee el File por rodajas, calcula el CV BLAKE3 de cada chunk (un pase) con el WASM del SDK de conduit, puede enviar los chunks en cualquier orden y reanuda con el bitmap stored de v2 tras un corte o al reabrir la pestaña (el estado local mínimo, uploadId + tamaño + mtime + nombre, vive en IndexedDB; los bytes los vuelve a leer del fichero que el usuario re-elige). La app Swift usa el C-ABI del SDK. No hay un segundo protocolo de subida.
  2. Lotes y carpetas = N sesiones de ingesta, una por fichero (dec-0121 §3: una sesión, un fichero), con concurrencia acotada por la cuota de sesiones por actor.
  3. Indexado inmediato. complete → registerIngested → el asset está en el catálogo y es reproducible y descargable sin re-scan. Después, en segundo plano y con la clase background del scheduler: identificación por contenido (dec-0114), enriquecimiento y metadatos al fichero (dec-0126, que dec-0127 revisa hacia fichero-SSOT, N1), y la proyección del índice (dec-0127). El objetivo es medible (T4).
  4. Destino: la raíz de ingesta local del daemon. La promoción al Storage Box y a backends remotos (outcome/federated-storage, V-N03) es una transferencia más del mismo modelo, nodo → backend, con la clase background.
  5. Árbol de transferencia (§3.2) calculado en la misma pasada que verifica cada chunk; no hay un segundo hash del fichero.
  6. Dedup antes de transferir (conduit v2 §5–§6): fichero entero por raíz, o manifiesto de blobs que sólo sube lo que falta. Sólo dentro del dominio de dedup que el Authorizer del IngestSink da con la SCT ingest (configurable, household por defecto: lock, punto 3), sin ninguna señal entre dominios ni descuento de cuota (oráculo de confirmación de ficheros).

3.4 Descargas de primera clase

3.4.1 Qué se puede descargar

Una descarga se pide con un DownloadProfile, que se resuelve igual que un stream: el planner (r05) produce un plan composicional con una entrega nueva, delivery: file.

PerfilQué produceCoste
originalel fichero byte a bytelectura
remuxotro contenedor (MKV → MP4 con moov delante, o al revés), selección de pistas, subtítulos incrustados o apartelectura + muxer Zig
transcodeotro códec, resolución o bitrate (audio por dec-0110 §1.2; vídeo cuando su ADR lo permita, §3.4.3)CPU/GPU, se cachea
+metadata (flag)cualquiera de los anteriores con los metadatos y la portada incrustados en la salida (dec-0126, N1)gratis si ya hay remux

original con +metadata sobre un fichero sin metadatos fuerza remux: el contenedor de salida se escribe nuevo de todas formas, así que los tags y la portada entran sin coste extra. Es lo que hace que "el fichero descargado y reproducido en VLC/AirPlay/lo que sea ya lleva sus metadatos" (N1) también valga para bibliotecas que no han activado la escritura en origen.

3.4.2 Remux determinista con tamaño exacto

  • Para remux, el muxer conoce todas las muestras de antemano (índice del origen, dec-0109): puede calcular el moov completo y el tamaño final antes de enviar el primer byte.
  • Se exige determinismo: mismo origen (raíz de transferencia) + mismo perfil + misma versión del muxer → la misma salida, byte a byte. Con eso:
    • la respuesta lleva Content-Length exacto y acepta Range sin haber materializado nada;
    • cualquier rango se produce bajo demanda leyendo sólo las muestras que caen en él;
    • el ETag es hash(raíz de transferencia ‖ perfil ‖ versión del muxer) y la reanudación con If-Range funciona aunque el derivado nunca se haya escrito en disco.
  • Es el camino "como el stream": el mismo muxer que empaqueta HLS, con salida progresiva.

3.4.3 Transcodificación materializada por ExtentMap

  • Una transcodificación no conoce su tamaño de antemano. Se materializa en la caché L2 como un artefacto derivado direccionado por hash(huella de asset ‖ perfil ‖ versión del motor), con un ExtentMap (dec-0106): pending mientras se produce, available lo hecho, known_length + sealed al terminar.
  • La descarga lee de ese artefacto: los rangos ya producidos salen a velocidad de disco, los pending esperan (cancelable por request, r04), y un corte se reanuda sin re-transcodificar. Mientras no está sealed la respuesta va sin Content-Length (fMP4 progresivo); una vez sellado, con tamaño, Range y ETag.
  • Se comparte: el mismo derivado sirve a la siguiente descarga del mismo perfil, de cualquier usuario con permiso, y a un stream cuyo plan coincida. La L2 lo desaloja por coste de regeneración (r45): un transcode de minutos de CPU no cae por un original que se relee en ms.
  • Encode de vídeo: dec-0110 no lo decide. Este ADR no lo decide tampoco, pero fija una restricción: sin GPL, así que x264 y x265 quedan fuera. Los candidatos son encoders por hardware a través de libavcodec (VAAPI, QSV, NVENC, VideoToolbox) y encoders con licencia permisiva (SVT-AV1, libaom, libvpx, OpenH264), siempre como capability versionada del motor (r23). La licencia exacta de cada uno la verifica el ticket que lo integre. La política de códec de salida es CanonicalCodecPolicy (AV1 como production_fallback).

3.4.4 Wire y cliente de descarga

  • Wire: HTTP estándar (GET + Range + If-Range + ETag fuerte + Content-Disposition: attachment; filename*= según RFC 6266). Sin protocolo propio en el cable: el navegador, VLC, curl, aria2 o el gestor de descargas del sistema reanudan solos.
  • Transporte: H3 y también HTTP/1.1 y HTTP/2 sobre TCP con sendfile/splice y kTLS para el original. La elección por cliente es por medida (T1), no fija. Esto necesita el ADR del delivery-edge TCP que hoy no existe (ledger V-PLAY-07); este ADR no lo sustituye, lo pide.
  • Cliente de descarga en el SDK de conduit: la otra mitad de "conduit ofrece descargas y subidas a prueba de cortes". conduit gana una máquina de descarga sans-IO (como la de subida): rangos en paralelo con ventana, verificación por bloque contra el árbol de §3.2 (slices BLAKE3 de conduit v2 §3.4; la API del árbol va a zkit.blake3_tree, dec-0103), estado de reanudación persistente ($XDG_STATE_HOME/styx, IndexedDB/OPFS en la web), renovación de la capability y varias fuentes a la vez (§3.4.5). La usan styx download, la app y la web. No cambia el wire de conduit: la descarga va por HTTP Range; lo que se añade es el cliente (P2).

3.4.5 Multi-fuente

  • En el servidor, el ByteSource del origen ya es multi-fuente (r26 §2: RAM, NVMe, Storage Box, peers, HTTP, otro nodo, puntuados y con hedged reads). Una descarga de un asset que vive en un backend remoto se sirve mientras se lee, con el árbol verificando cada rango.
  • En el cliente, el SDK puede pedir el mismo contenido a varias fuentes que lo tengan (el nodo local, otro nodo del mismo dueño, un servidor federado con concesión), verificando cada bloque. La lista de fuentes la da playback-svc con una capability por fuente.

3.5 Offline

  • El contenedor es OfflineBundle (r61 D1, dec-0094): un Source adapter (r04), no un player aparte. Una descarga para offline es un OfflineBundle con un fichero completo (bundleType: 'mixed' o un tipo nuevo full, P5) más su árbol y los metadatos del cliente.
  • Los metadatos viajan en el fichero (N1): la lista offline se reconstruye leyendo los ficheros descargados, sin servidor. La caché del cliente es la única duplicación (N1).
  • Por plataforma:
    • Web: Background Fetch donde exista (Chrome, Edge) y descarga en pestaña con reanudación por rangos donde no; ficheros en OPFS; un service worker sirve rangos desde OPFS al reproductor.
    • App Swift: URLSession en segundo plano con el C-ABI de conduit para verificar y reanudar.
    • CLI: styx download.
  • Estado de usuario offline (progreso, visto): cola local que se sincroniza al reconectar, con "último escritor gana por perfil y asset" (el modelo de sincronización es de dec-0127).
  • Claves: si un OfflineBundle se cifra, la clave se co-diseña con identity (r61 D3). Por defecto no se cifra lo descargado por su dueño en su dispositivo (P6).
  • Relación con track/offline-continuity: las descargas son el primer consumidor real de OfflineBundle. Eso cambia el caso de dec-0098 (nodo sin consumidor): se propone que el nodo dependa de la descarga y deje de ser excepción (P1).

3.6 P2P, swarm y nodo ↔ nodo

  • Swarm (track/swarm-core): el crate swarm (r26 §4) es, a la vez, un ByteSource (adquisición, stream mientras descarga) y un egress (sembrar). BitTorrent v1/v2/hybrid; el árbol de §3.2 es el de v2, así que todo asset es sembrable como v2. seedPolicy sigue r26 §3.
  • Web seed (BEP 19): el daemon puede actuar de web seed de sus propios assets, opt-in por raíz y nunca por defecto: anunciar un fichero en un swarm público es una decisión de privacidad y de derechos del operador.
  • Nodo ↔ nodo y federación: rangos verificados por el árbol sobre QUIC entre daemons, con una SCT del nodo de origen. Es el transporte de la sincronización de bibliotecas y del compartir entre servidores (dec-0131). No usa DHT ni trackers públicos.
  • P2P entre clientes (copiar del móvil a la TV en la LAN): fuera de este ADR; idea para dec-0128 (dispositivos).

3.7 Adquisición: todo lo que entra pasa por la misma puerta

  • dec-0034 sigue: el Acquisition Runtime sustituye a Sonarr/Radarr/Prowlarr/Bazarr.
  • Fuentes de adquisición: torrent (swarm), HTTP directo, otro Styx (dec-0131), Jellyfin (outcome/jellyfin-compat), backends remotos (outcome/federated-storage) y la subida del usuario (dec-0121).
  • Una sola entrada al catálogo: cmd.catalog.registerIngested se generaliza con origin: upload | acquisition | import | federation y la raíz de transferencia. Lo adquirido entra como AcquisitionArtifact (dec-0019) y se indexa al completar, igual que una subida: reproducible al momento, canonicalización después y en segundo plano.

3.8 Scheduler: una descarga nunca degrada una reproducción

Enmienda propuesta a la lista de prioridades de r26 §2 (el GlobalByteScheduler no existe en código; esto fija la política para cuando exista):

interactive-seek > playback-starvation > startup > live-ingest > **download-foreground** > **ingest** > canonicalization-foreground > **transcode-for-download** > torrent-acquisition > **offline-sync** > **peer-upload** > pack-flush > background-scrub > metadata-cleanup

  • download-foreground: el usuario espera la descarga con la app abierta.
  • ingest: la clase que dec-0121 dejó para un ADR aparte.
  • transcode-for-download: producir un derivado para descarga; cede ante cualquier reproducción.
  • offline-sync: descargas en segundo plano.
  • peer-upload: servir a otros nodos o peers.
  • Lo que se mide es T8: ninguna reproducción concurrente empeora su arranque ni sus stalls por culpa de una transferencia.

4. Objetivos de rendimiento medibles

Ninguna cifra existe hoy (§1). Los umbrales son la propuesta para el gate y los fija waxin (P4). Todos se miden con un harness nuevo, tools/transfer-bench, en la misma máquina y la misma red que el referente, con N ≥ 10 ejecuciones y mediana + p95.

#ObjetivoMétricaReferente (misma máquina y red)Umbral propuesto
T1Descarga del original a velocidad de líneagoodput y CPU por GiB, 1 y 10 Gbit/s, H3 y TCPnginx con sendfile + kTLS sirviendo el fichero≥ 95 % del goodput de nginx; CPU/GiB ≤ 1,2× nginx
T2Descarga por WAN con BDP altotiempo hasta completar, RTT 50–150 ms con pérdidaaria2 con 8 conexiones≤ el de aria2
T3Reanudaciónbytes reenviados y tiempo hasta el primer byte tras un corte en punto aleatorio—bajada: 0 bytes repetidos; subida: ≤ 1 chunk; ≤ 1 RTT + renovar capability
T4Subida y tiempo hasta reproduciblegoodput de subida; tiempo de complete a reproducible y descargablersync/scp por SSH + re-scan de Jellyfingoodput ≥ rsync; reproducible ≤ 2 s tras complete, sin re-scan
T5Remux al vuelotiempo hasta el primer byte y goodput de remuxT1 del originalprimer byte ≤ el arranque del stream; goodput ≥ 80 % de T1
T6Transcode para descargavelocidad de producción (× tiempo real) y segunda descarga del mismo perfil—segunda descarga a velocidad T1 (sale de caché)
T7Integridadbytes corruptos aceptados con inyección de fallos (bit flips, truncado, fuente que miente)—0
T8Equidad con la reproducciónarranque y stalls de una reproducción con transferencias concurrentesla misma reproducción sin transferenciassin diferencia estadística (p95)
T9Swarmtiempo hasta completar el mismo torrentqBittorrent / libtorrent (r27: varilla SOTA)≤ qBittorrent

Notas:

  • T1 mide H3 y TCP. Si H3 no llega a T1 en enlaces rápidos (lo que predice el estudio de §2), la descarga de fichero completo va por TCP y el stream sigue por H3/MoQT.
  • Las cifras de cliente no cuentan como medida del servidor: un cliente que satura la CPU antes que el daemon invalida la ejecución (lección de la ronda 3 del motor, §1).
  • Cada objetivo tiene su control negativo: un mutante del daemon (por ejemplo, sin sendfile, o sin verificación por bloque en T7) tiene que salir rojo.

5. Seguridad

  • Scope SCT nuevo download (enmienda a dec-0117 I3 y al formato de §4.1): resource = asset + perfil (o raíz de transferencia + perfil), range = todo el fichero, sid ligado por IPC como en dec-0121. Vida mayor que la de read porque un gestor de descargas del navegador reanuda con la misma URL y no puede renovar el token (P7 fija el tope). La revocación sigue siendo inmediata: el daemon re-autoriza cada petición contra la sesión ligada (I2), y playback-svc la desliga al revocar.
  • Permiso nuevo asset:download, distinto de asset:play (dec-0125 §5): el modo público (dec-0130) y el compartir entre servidores (dec-0131) necesitan "stream sí, descarga no" y al revés. restricted no lo recibe.
  • Cuotas (I4), además de las de subida de dec-0121:
    • descargas concurrentes y ancho de banda por actor;
    • presupuesto de transcodificación por actor (minutos de CPU/GPU): un perfil caro es la forma más barata de DoS; se rechaza antes de empezar si no cabe, y la deduplicación por caché cuenta a favor del actor;
    • huecos de caché L2 que un actor puede ocupar con derivados que sólo él pidió.
  • Entrada no confiable: los bytes de peers, nodos federados y backends remotos se verifican por bloque (§3.2) antes de escribirse o servirse; los parsers siguen I5; todo staging es fd-relativo (I7); el código de swarm (peer wire, bencode, extensiones) es un parser de entrada no confiable con su fuzz.
  • Fuga del token en la URL: la SCT en la URL de descarga no se loguea (I12), la respuesta lleva Referrer-Policy: no-referrer y Cache-Control: private, no-store sobre la URL firmada. El riesgo residual (historial del navegador) lo acota el binding al actor y al asset (§7).
  • Nombre de fichero: Content-Disposition con filename* saneado (sin rutas ni controles), derivado del título del catálogo; el cliente nunca elige una ruta del servidor.
  • Privacidad del swarm: sembrar o actuar de web seed es opt-in por raíz (§3.6); por defecto ningún asset se anuncia fuera del servidor.
  • Audit: apertura y fin de descargas, perfiles caros y rechazos por cuota salen por evt.security.* (spire), sin el token.

6. Superficie headless (dec-0124 §6.1)

Ids provisionales; la paridad la comprueba check:headless-parity.

OperaciónQuéCLI
transfer.upload.opensesión de ingesta (existe: dec-0121)styx upload <fichero…|carpeta>
transfer.download.planresolver un DownloadProfile y explicar el plan (r05), sin ejecutarlostyx download <asset> --profile … --dry-run
transfer.download.openfirmar la capability y devolver URL(s) y fuentesstyx download <asset> [--profile …] [--out …]
transfer.listtransferencias del actor (subidas, descargas, offline), con progresostyx transfers [--json]
transfer.cancelcancelar y liberar cuotastyx transfers cancel <id>
transfer.offline.syncsincronizar la lista offline de un dispositivostyx offline sync

Contratos del socket de control y del bus (nombres provisionales, los fija el ticket con su consumidor y entran en BUS_ROUTES): cmd.media.openDownload, cmd.media.closeDownload y qry.media.downloadStatus (playback-svc → daemon); cmd.catalog.registerIngested generalizado (§3.7).

7. Riesgos

#RiesgoMitigación
R1El remux no es determinista (orden de cajas, timestamps de creación, padding) y rompe la reanudacióntest de propiedad: dos producciones del mismo perfil dan los mismos bytes; la versión del muxer entra en el ETag; un cambio de muxer invalida
R2DoS por perfiles carospresupuesto de transcode por actor, admisión antes de empezar, deduplicación por caché, clase transcode-for-download por debajo de todo playback
R3La caché L2 se llena de derivados de un solo usuariotope por actor de derivados no compartidos; desalojo por coste (r45)
R4Token de vida larga en una URLbinding a actor + asset + perfil, revocación por sesión ligada, sin log, no-referrer; tope de vida (P7)
R5H3 por debajo de TCP en enlaces rápidosT1 mide los dos; camino TCP con sendfile/kTLS; requiere el ADR del delivery-edge TCP
R6Editar metadatos durante una transferencialease de transferencia (§3.2); If-Range falla de forma segura
R7Coste del árbol en bibliotecas grandesse calcula en la pasada que ya lee el fichero (ingesta, escaneo); outboard regenerable; niveles superiores sólo
R8Encoders de vídeo con licencia incompatiblesin GPL (x264/x265 fuera); licencia verificada por ticket; capability versionada
R9Background Fetch sólo en Chromiumdescarga en pestaña con reanudación por rangos como fallback; la app y el CLI no dependen del navegador
R10Derechos y privacidad al sembrar o federaropt-in por raíz; nada se anuncia por defecto; federación por concesión (dec-0131)
R11Dos árboles para un asset sembrado (BLAKE3 y SHA-256)el SHA-256 sólo existe para lo que se siembra; se deriva verificando contra BLAKE3, nunca de bytes sin verificar
R12have de dedup como oráculo de existenciadominio de dedup configurable + sin señal entre dominios + cuota por tamaño lógico (conduit v2 §6); server sólo con aviso explícito (lock, 3)

8. Alternativas rechazadas

  • Protocolo propio en el cable para descargar. Ningún cliente de terceros lo hablaría; HTTP Range ya reanuda en todos. Lo propio va en el cliente (SDK de conduit), no en el wire.
  • Descarga = la SCT read de reproducción. Dura 10 minutos y está pensada para un player que renueva; un gestor de descargas no renueva. Y mezcla "puede ver" con "puede llevárselo".
  • Transcodificar a fichero completo antes de empezar la descarga. Mata el "al vuelo como el stream". La materialización por ExtentMap da las dos cosas.
  • Transcodificar sin cachear. Repite minutos de CPU por cada reanudación y por cada usuario.
  • Árbol SHA-256 de BEP 52 como identidad (era la propuesta original; descartada en el lock). 8× más lento con la std de Zig sin SHA-NI, exige un segundo pase para la raíz del fichero y no aporta nada interno que BLAKE3 no tenga; su único valor, sembrar en el swarm v2, se conserva calculándolo bajo demanda (§3.2).
  • Sólo H3 para todo. Contradice la medida publicada en enlaces rápidos; se decide por T1.
  • rsync/SFTP como vía de subida de usuario. Es exactamente el flujo que waxin quiere eliminar (V-XFER-01): fuera de banda, sin cuotas por identidad y con re-scan.

9. Lo que este ADR no decide

  • El encode de vídeo concreto (encoders, calidad, HW): sólo la restricción sin GPL.
  • El delivery-edge TCP (ledger V-PLAY-07): lo pide, no lo sustituye.
  • La sincronización de estado offline en detalle: dec-0127.
  • El protocolo nodo ↔ nodo y las concesiones entre servidores: dec-0131.
  • Descargas en el modo público y por enlace compartido: dec-0130 y dec-0131.
  • Nodos, milestones y gate items en styx.model.yml: P1. track/byte-runtime/egress y track/media-engine/download-output son alta propuesta queued en el model, pendiente de ratificar en P1; los gate items, no.

10. Consecuencias

  • Dónde cae:
    • track/byte-runtime: egress de descarga (original, Range/If-Range, TCP + sendfile/kTLS y H3), árbol de transferencia, lease, clases del scheduler, scope download en el daemon.
    • track/media-engine: salida progresiva del muxer, remux determinista con tamaño exacto, transcodificación materializada, +metadata en la salida.
    • track/identity (sec): scope download, permiso asset:download, cuotas de descarga y transcode.
    • track/offline-continuity: OfflineBundle completo en web, app y CLI.
    • track/swarm-core / track/acquisition-core: el árbol de v2 compartido y la entrada única.
    • Repo conduit: la máquina de descarga del SDK (Zig, TS/WASM, C-ABI).
    • Clientes: subida y descarga en la web y la app.
  • Gate propuesto (items, no en el model hasta P1; los milestones sí, como alta propuesta queued), cada uno con su doc (dec-0124 §9):
    • TR1 descarga del original con Range/If-Range y reanudación (T1, T3);
    • TR2 remux determinista (propiedad de R1) y +metadata;
    • TR3 transcode materializado y compartido (T6);
    • TR4 subida web y app con indexado inmediato (T4);
    • TR5 integridad por árbol con fuentes que mienten (T7);
    • TR6 equidad con la reproducción (T8);
    • TR7 offline en web (OPFS + service worker) y CLI;
    • TR8 scope download, permiso y cuotas con sus tests de rotura.
  • La página explicacion/transferencias (estado especificado) se ata a este ADR.

11. Enmiendas propuestas (efectivas en el lock)

  • r26 §2: clases download-foreground, ingest, transcode-for-download, offline-sync y peer-upload en la lista de prioridades (§3.8).
  • dec-0117 I3 / §4.1: scope download con su vida y su re-autorización por petición.
  • dec-0121: registerIngested generalizado con origin y raíz de transferencia (§3.7); el árbol de transferencia en la pasada de ingesta; clientes web y app del mismo wire.

12. Preguntas para waxin (bloquean el lock)

Contestadas o diferidas en el lock. Se conservan como registro.

  • P1 — Nodos: ¿un milestone nuevo track/byte-runtime/egress (descarga y árbol) y otro en track/media-engine (salida progresiva y transcode materializado), con TR1–TR8 como gate? ¿Y track/offline-continuity pasa a depender de la descarga (deja de ser la excepción de dec-0098)?
  • P2 — conduit: ¿la máquina de descarga va en el SDK de conduit (recomendado: un solo SDK de transferencias a prueba de cortes en las dos direcciones) o en un SDK aparte?
  • P3 — Identidad de transferencia: árbol SHA-256 de 16 KiB de BEP 52 (recomendado: interoperable con el swarm v2) o BLAKE3/bao (más rápido, sin interoperabilidad directa). Resuelta (waxin, 2026-10-02): BLAKE3/bao a 16 KiB como identidad interna; BEP 52 bajo demanda para sembrar (§3.2).
  • P4 — Umbrales: ¿valen los de §4 como gate, o se fijan otros? ¿Qué hardware y qué enlaces son la referencia (1 Gbit/s LAN, 10 Gbit/s, el enlace real del Storage Box)?
  • P5 — Offline: ¿tipo nuevo full en OfflineBundle o mixed?
  • P6 — Cifrado offline: ¿sin cifrar por defecto para el dueño en su dispositivo (recomendado) o siempre cifrado?
  • P7 — Vida de la SCT download: ¿cuál es el tope (por ejemplo, horas, ligado a la duración estimada de la descarga), sabiendo que la revocación es inmediata por la sesión?
  • P8 — IETF Resumable Uploads: ¿adaptador al draft cuando sea RFC, o sólo conduit?
  • P9 — Encode de vídeo para descargas: ¿entra ya (con qué encoders sin GPL) o las descargas arrancan con original, remux y audio transcodificado?
  • P10 — Web seed y siembra: ¿opt-in por raíz (recomendado) o desactivado del todo hasta la federación?

13. Fuentes externas

Lock (2026-10-02, waxin)

Decisión de waxin vía AskUserQuestion (2026-10-02): lockear este ADR con la enmienda de P3 que propone la lane w13/conduit-v2 (docs/track/byte-runtime/plans/conduit-wire-v2.md §2, sobre la spec wire v2 de conduit y su ADR 0002-wire-v2-blake3), más un dominio de dedup configurable. Las demás preguntas de §12 no tuvieron respuesta separada.

  1. P3 — Identidad de transferencia: BLAKE3 + bao, BEP 52 bajo demanda. Respuesta de waxin: "lo más SOTA". Queda el texto del plan, ya aplicado en §3.2, §3.3, §3.4.4, §7 y §8:
    • BLAKE3 + bao con hojas (grupos) de 16 KiB como identidad interna. La raíz de transferencia es BLAKE3(bytes exactos); el outboard pre-order (64 B por 16 KiB) es caché regenerable en L2, calculada en el único pase de la ingesta o del escaneo;
    • árbol SHA-256 de BEP 52 calculado bajo demanda, sólo para sembrar o contrastar un torrent v2, en un pase que verifica cada grupo contra BLAKE3 y guarda el SHA-256 como segundo outboard;
    • BLAKE3 pasa a ser la única familia de hash de identidad del sistema; SHA-256 queda para interoperar y para las SCT, que no cambian;
    • la API del árbol (CV de subárbol, outboard, slices) va a zkit.blake3_tree, que el daemon consume sin reimplementarla (dec-0103). Mientras zkit no la publique vive en conduit.
  2. Medidas que lo sostienen (plan §1, host de referencia de 4 vCPU sin SHA-NI, std de Zig): SHA-256 ~257 MB/s por core frente a BLAKE3 ~2 100–2 250 MB/s; una subida v1 hace dos pases SHA-256 por byte en cada lado (más una relectura del servidor) y v2 hace uno, sin relectura.
  3. Dominio de dedup: configurable (decisión de waxin, añadida al plan). El Authorizer del IngestSink da el dominio con la SCT ingest, y el dedup (§3.3 punto 6, conduit v2 §5–§6) sólo responde dentro de él, sin señal entre dominios ni descuento de cuota. Valores:
    • household (hogar) — por defecto. Los miembros de un hogar comparten dominio. Si el actor no pertenece a ningún hogar (los hogares son opcionales, dec-0125), su dominio es él mismo. Consecuencia aceptada: un miembro puede inferir que otro miembro del mismo hogar ya subió un fichero;
    • user: un dominio por actor. No filtra nada entre usuarios, ni dentro de un hogar. Es el valor que recomendaba el plan (Q1);
    • server: un dominio para todo el servidor. Ahorra más bytes, pero permite inferir qué tiene otro usuario (el have del dedup es un oráculo de confirmación de ficheros). La configuración y el asistente lo muestran con un aviso explícito de ese riesgo, y no se activa sin confirmarlo. El dominio es configuración del operador (servidor), no de cada usuario. Cambiarlo no mueve bytes: sólo cambia a quién responde el have desde ese momento. La cuota se cuenta por tamaño lógico en cualquier modo (R12). Invariante que la configuración no relaja (dec-0117, conduit ADR 0002 decisión 5 y su lock): un hash nunca es una capability de lectura. En un dominio más ancho que lo que el actor puede leer (household con permisos más finos que el hogar, o server), el riesgo aceptado es inferir existencia; obtener el objeto sin tener los bytes no se acepta. Para eso hace falta una prueba de posesión (reto sobre grupos de 16 KiB verificados contra el outboard), que el wire v2 no tiene. Hasta que conduit la añada, el índice de dedup de styx responde have sólo con objetos que el actor puede leer dentro del dominio. El dedup ahorra algo menos, pero no hay fuga ni acceso.
  4. Resto de §12, sin respuesta separada: recomendación del ADR como parámetro reversible. Se cambian sin ADR nuevo:
    • P2 — conduit: la máquina de descarga va en el SDK de conduit: un solo SDK de transferencias a prueba de cortes en las dos direcciones (§3.4.4).
    • P6 — Cifrado offline: sin cifrar por defecto lo que descarga su dueño en su dispositivo (§3.5). El cifrado, cuando exista, se co-diseña con identity (r61 D3).
    • P8 — IETF Resumable Uploads: sólo conduit como wire de subida; el adaptador al draft se decide cuando sea RFC (§2, fila de IETF Resumable Uploads).
    • P9 — Encode de vídeo: las descargas arrancan con original, remux y audio transcodificado (dec-0110 §1.2). El encode de vídeo sigue sin decidir (§3.4.3, §9) y entra con su propio ADR, con la restricción sin GPL.
    • P10 — Web seed y siembra: opt-in por raíz; ningún asset se anuncia fuera del servidor por defecto (§3.6).
    • P4 — Umbrales: los de §4 (T1–T9) valen como gate, con las referencias que ya nombra T1 (1 y 10 Gbit/s, H3 y TCP). El hardware concreto de referencia y el enlace real del Storage Box los fija el ticket de tools/transfer-bench cuando mida el primer baseline.
    • P7 — Vida de la SCT download: el ADR no da una cifra, sólo la forma. Se toma esa forma: tope en horas, ligado a la duración estimada de la descarga, con revocación inmediata por la sesión ligada (I2). El número lo propone el ticket del scope download (TR8) a waxin antes de cerrar.
  5. Diferidas de forma explícita (el ADR no da recomendación; no bloquean el resto):
    • P1 — Nodos: este lock no crea nodos ni milestones en styx.model.yml. La forma que propone el ADR (milestone track/byte-runtime/egress con descarga y árbol, otro en track/media-engine con salida progresiva y transcode materializado, TR1–TR8 como gate, y track/offline-continuity dependiente de la descarga) queda como propuesta para la wave que lo implemente, que la lleva a waxin con check:roadmap.
    • P5 — Offline: full o mixed en OfflineBundle. Lo decide el primer ticket de track/offline-continuity que materialice la descarga offline.
  6. Enmiendas que entran en vigor hoy (§11): r26 §2 (clases del scheduler), dec-0117 I3 y §4.1 (scope download) y dec-0121 (registerIngested generalizado con origin y raíz de transferencia, árbol en la pasada de ingesta, clientes web y app del mismo wire). Los tres llevan banner de enmienda desde este lock. Con P3, la raíz de transferencia que lleva registerIngested es BLAKE3 (plan, §3 y CV2-03).
  7. Lo que no cambia: §3.1 (un plano, un modelo de transferencia), §3.4.1–§3.4.3 y §3.4.5 (perfiles, remux determinista, transcode materializado, multi-fuente), §3.5–§3.8 salvo P5/P10, §5 (seguridad, scope download, permiso asset:download, cuotas) y §6 (superficie headless).

El lock desbloquea el código de producción que depende de este ADR. La ingesta v2 de conduit y los tickets CV2-01..CV2-05 del plan cuelgan de track/byte-runtime sin nodo nuevo.

Back-refs

  • r26, dec-0117 y dec-0121 llevan banner de enmienda desde el lock (2026-10-02).
  • Enmienda de P3: docs/track/byte-runtime/plans/conduit-wire-v2.md (rama w13/conduit-v2) y conduit docs/decisions/0002-wire-v2-blake3.md.
  • dec-0126 §4.3: el lease de transferencia (§3.2) amplía sus exclusiones.
  • Ledger: V-N07, V-N10, V-XFER-01, V-XFER-02, V-XFER-03, V-XFER-04, V-XFER-05 (docs/overview/vision-ledger.yml).
  • Relacionados: dec-0019, dec-0034, dec-0094, dec-0098, dec-0106, dec-0110, dec-0124, dec-0125; reservados dec-0127, dec-0128, dec-0130, dec-0131.