Saltearse al contenido

Cauce

Cauce es un archivo TOML que describe por dónde puede correr el material: qué cuentas hay y qué va de cuál a cuál. No publica nada — eso lo sigue haciendo el worker, con su grifo y sus guardas.

Sirve para cuatro cosas, en el orden en que importan: respaldo y desastre, alta masiva, versionar la configuración en git, y replicar a otra instalación.

Un solo formato, dos artefactos

HTTP / panel

sólo CLI

la instalación

exportar

manifiesto

credenciales = ausentes

respaldo

credenciales = cifradas

se puede commitear

NO restaura:

hay que recargar los tokens

restaura de verdad

+ bloque [cifrado]

que dice con qué clave

El respaldo cifrado sale sólo por CLI, y el restore también entra sólo por CLI. Por HTTP los tokens salen vacíos, siempre, y no hay endpoint que los acepte. Ese corte es lo que deja al invariante «ningún endpoint de este servicio devuelve ni acepta texto cifrado» sin excepciones que recordar.

La cabecera no puede mentir. Si el archivo se declara ausentes y trae una credencial, o se declara cifradas y no trae el bloque [cifrado], la validación lo rechaza. No es un aviso: de esto depende que alguien archive un manifiesto creyendo que tiene un respaldo.

Qué trae

declara

declara

si es respaldo

origen

destino

filtra con

CAUCE

int

formato_version

1

text

credenciales

ausentes | cifradas

CUENTA

text

handle

PK

text

plataforma

text

rol

lectura escritura ambos

text

id_remoto

la URL del feed, si es RSS

text

instancia_url

int

max_por_hora

el grifo

int

max_en_vuelo

int

poll_horas

text

via

navegador = suscripción pública

int

video_como_imagenes

text

consentimiento_vigente

SÓLO informativo

text

credencial_cifrada

sólo en respaldo

FLUJO

text

clave

PK

identidad estable

text

origen

FK

text

destino

FK

text

nombre

mutable, no identifica

bool

activa

bool

auto_publica

CIFRADO

text

algoritmo

text

huella_clave

para saber si esta instalación puede abrirlo

CONDICION

text_array

tipo

VIDEO IMAGE CAROUSEL_ALBUM

text_array

tag

sin #

text_array

autor

int

desde_dias

acota lo que se EMITE

Plan y aplicar

Como terraform plan y terraform apply, y el corte no es estético:

no

archivo.toml

cauce importar

sólo mira

+ lo que se crearía

= lo que ya está

~ lo que cambiaría

✗ los conflictos

¿convence?

cauce importar --aplicar

escribe

se corrige el archivo

aplicado

El plan no pide identidad; aplicar sí. La línea es «muta la base = firma». Mirar sólo lee, igual que validar, y pedirle identidad llevaría a saltearlo — justo el paso que evita aplicar a ciegas. Aplicar exige Administrar por el mismo validador que el panel: la CLI no tiene pase libre por correr en el servidor.

Un solo conflicto detiene todo. Aplicar «lo que se pueda» dejaría la instalación a mitad de camino entre dos descripciones, y nadie sabría en cuál está.

Es idempotente. Correrlo dos veces no duplica nada: el segundo plan dice «sin cambios» en todo. Sobre la instalación real, exportar y volver a planificar da 12 cuentas y 5 flujos sin cambios — que es la prueba de que el archivo describe lo que hay.

Restaurar: la otra mitad

cauce importar crea cuentas y flujos. Las credenciales las vuelca cauce restaurar, y son dos comandos porque son dos permisos distintos sobre dos cosas distintas.

respaldo.toml

cauce importar --aplicar

cuentas y flujos

cauce restaurar --aplicar

credenciales

salud: degradada

cargada, sin probar

En ese orden. restaurar no crea cuentas: si la cuenta no existe todavía, lo dice y no escribe nada. Al revés no hay dónde escribir.

Si la clave no es la misma, se niega antes de tocar nada. El bloque [cifrado] trae la huella de la clave con que se cifró; si no coincide con la de esta instalación, sus blobs no se pueden abrir acá. Escribirlos igual dejaría cuentas que parecen tener credencial —la salud diría que sí, el panel las mostraría cargadas— y el fallo aparecería recién al publicar.

Y cada blob se abre antes de escribirlo: aunque la huella coincida, uno puede venir truncado.

Quedan en degradada, no en ok. La credencial está cargada y nadie la ejercitó contra la red. Declarar ok sería afirmar que funciona sin haberlo comprobado — el verde falso justo donde más caro sale, porque quien restaura se va tranquilo.

Lo que el import NO hace

Un import es aditivo y nunca borra lo que el archivo no menciona. Y hay tres cosas que se declaran en el archivo y aun así no se aplican:

El archivo diceEl import hacePor qué
consentimiento_vigente = "..."Nada. Se avisaUn permiso es una afirmación personal y fechada; un lote la degradaría a trámite
activa = trueLo crea pausadoDos pollers sobre el mismo bot de Telegram se roban los updates
auto_publica = trueLo deja apagadoQue algo salga sin que nadie lo mire se decide mirando
una cuenta que ya estáNo la renombra ni le borra configEl handle es lo que la gente lee en el panel; y un null borraría un grifo que alguien puso a mano

Los tres se avisan, no se callan. Un import silencioso dejaría a alguien creyendo que restauró la instalación y que ya está emitiendo — y descubriría que no varios días después, cuando note que no salió nada.

La validación, antes de escribir nada

cauce validar corre entero sobre el archivo, sin tocar la base. Sirve igual en una máquina que no tiene acceso a la instalación: por ejemplo, en la revisión de un merge request.

no

no

archivo.toml

¿es TOML?

error, con línea y columna

¿es un cauce?

la versión del formato

la cabecera no miente

plataformas y roles existen

las claves de filtro son conocidas

los flujos apuntan a cuentas declaradas

via es una que existe

¿hubo errores?

no se puede aplicar

se puede aplicar

+ los avisos de arriba

Una clave de filtro desconocida es un ERROR, no un campo que se ignora. Escribir tags en vez de tag daba antes un archivo válido cuyo flujo publicaba todo: el motor ignoraba lo que no entendía, y una condición sin criterios no filtra nada. El filtro más peligroso es el que parece estar y no está.

Dos formas de escribir un criterio

El motor compara igual contra un valor suelto que contra una lista, y las condiciones que guarda el panel usan la forma corta. Las dos valen:

condicion = { tipo = "VIDEO" }
condicion = { tipo = ["VIDEO", "CAROUSEL_ALBUM"] }

Al exportar sale siempre como lista: una sola forma en el archivo, dos de escribirlo.

Esto no estaba, y el resultado era que el cauce no podía exportar la instalación real: el export se negaba —correctamente, antes que prometer menos filtro del que hay— y dejaba el archivo inservible justo en la instalación que tenía que respaldar.

Los criterios

Se cumplen a la vez. «Videos de Fulana sobre Palestina» quiere las tres cosas; con un O, el flujo prendería con muchísimo más de lo que su autora pidió.

CriterioQué miraFail-closed
tipoLo que declare la fuenteUn ítem sin tipo no pasa
tagTemas, sin #, normalizadosUn ítem sin tags no pasa: no sabemos de qué habla
autorCuando la fuente distingue autor de cuentaUn ítem sin autor no pasa
desde_diasVentana temporalUn ítem sin fecha no pasa

desde_dias acota lo que se EMITE, no lo que se archiva. El histórico completo sigue entrando al archivo; lo que esta ventana evita es que un backfill de dos años se convierta en dos años de publicaciones.

Cuando una clave ya es de otro

no

no

el archivo trae la clave K

¿K ya existe

en la base?

se crea el flujo

¿entre las MISMAS

dos cuentas?

ya existe: se deja

✗ CONFLICTO

el plan entero se niega

Re-apuntar el flujo que existe mandaría lo que se publique después a otro destino, sin que nadie lo decidiera. Por eso es un error y no un ajuste silencioso: hay que cambiar la clave en el archivo.

La identidad de un flujo

Cada flujo tiene una clave: un slug estable, único en toda la instalación e inmutable, sostenido en la base con UNIQUE, NOT NULL, un CHECK de formato y un trigger.

No es nombre. El nombre se edita y se borra: una identidad renombrable haría que cada renombre entrara como un flujo nuevo al importar, en silencio. Una clave que ya existe apuntando a otro par de cuentas es un conflicto que se informa, nunca un re-apuntado callado.