SDD 30 §4a: el perfil ya sabe HABILITAR — y avisa del demonio que nadie arranca

`paquetes` decía qué se INSTALA; no había dónde decir qué se LEVANTA. El sshd
del producto arrancaba porque su Card estaba escrita a mano en una constante de
Rust, no porque nadie lo hubiera declarado.

`servicios = [...]` por perfil (se hereda como `paquetes`, mismo orden y dedup)
+ `targets.py --servicios <perfil>`, que cruza label → receta → exec contra los
`[[service]]` del corpus y la membresía de perfil de build-state.json.

Lo que vale más es la comprobación INVERSA: avisa de los paquetes que están en
la imagen, TRAEN un demonio y el perfil no arranca. Es la versión servicios de
la lección de `foot` —la métrica mide la clausura de lo DECLARADO y no ve lo que
falta en la declaración— y no es hipotética: antes de escribir `servicios =
["sshd"]` el resolutor ya avisaba «openssh está en la imagen y TRAE este
servicio, pero el perfil no lo arranca».

Probado con roturas A PROPÓSITO, 5/5, y con un control que TIENE que pasar:
habilitado sin declarar (ERROR) · dos recetas con el mismo label (ERROR) · lo
declara una receta que no está en el perfil (ERROR: el card apuntaría a un
binario ausente y arje lo encarnaría con ENOENT en cada backoff) · la inversa
(AVISO, no rompe el cron) · el caso bueno (rc=0). Los 8 perfiles siguen
expandiendo igual y los llamadores de shell no cambian.
This commit is contained in:
Sergio
2026-09-12 10:59:59 +00:00
parent 1445f2f91e
commit 556fcad5fa
2 changed files with 129 additions and 0 deletions
+14
View File
@@ -1005,3 +1005,17 @@ paquetes = [
# suyo por configuración, pero nada más lo hace.
"logrotate",
]
# ── QUÉ ARRANCA (el «enable»; SDD 30 §3) ────────────────────────────────────────────────────────
# `paquetes` dice qué se INSTALA; esto dice qué se LEVANTA. Son dos hechos distintos y hasta hoy la
# distro sólo sabía escribir el primero: el `sshd` de la imagen del producto arrancaba porque su
# Card estaba escrita a mano en una constante de Rust (`takana_bootstrap::SSHD_SERVICE_CARD`), no
# porque alguien lo hubiera declarado en ningún sitio.
#
# Cada entrada es el `label` de un `[[service]]` declarado por una receta DEL PERFIL.
# `scripts/targets.py --servicios servidor` resuelve label → receta → exec, y además hace la
# comprobación INVERSA: avisa de los paquetes de la imagen que TRAEN un demonio que nadie arranca.
# Es la versión servicios de la lección de `foot` — la métrica mide la clausura de lo declarado y no
# puede ver lo que falta en la declaración. Comprobado antes de escribir esta línea: el resolutor
# avisaba «`openssh` está en la imagen y TRAE este servicio, pero el perfil no lo arranca».
servicios = ["sshd"]