sergio/takana
> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…
declarar: `/proc` pasa a ser un lector del centro — y había DOS emisores de tarjetas, mal los dos
1"""Lector del CENSO (lo que `/proc` dice que corre) → modelo pivote «servicio» (SDD 29).
2
3El tercer lector de la familia, y el que no tiene equivalente en ningún init: `systemd` y `openrc`
4leen **lo declarado**, que es exactamente lo que miente — en gioser `rc-status` daba `stopped` para
5cinco servicios que estaban vivos, y los `no-declarado` (15 de 39) no aparecen en ninguna
6declaración porque, por definición, nadie los declaró. Éste lee **lo que corre**.
7
8Los tres se complementan y ninguno solo alcanza. Que los tres desemboquen en el mismo escritor es
9justamente el punto del pivote: la tarjeta de arje se emite en UN lugar, no uno por procedencia.
10
11── LO QUE ESTE LECTOR NO PUEDE ─────────────────────────────────────────────────────────────────
12El censo **no lee `/proc/<pid>/environ`** — trae tokens y contraseñas, y un censo se guarda en un
13fichero que se manda por ahí. Así que el `envp` de toda tarjeta sale VACÍO. Un servicio que dependa
14de variables de entorno va a arrancar y fallar, y eso se dice por su nombre, no en una nota general.
15"""
16import sys, os, tomllib
17sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
18from modelo import Servicio, Sistema # noqa: E402
19from formatos import lector # noqa: E402
20
21
22@lector("proc", familia="servicio")
23def leer(texto, nombre=""):
24 sis = Sistema(formato_origen="proc")
25 acta = sis.acta
26 censo = tomllib.loads(texto)
27 servicios = censo.get("servicio", [])
28 if not servicios:
29 acta.anota(0, "SIN-TRADUCIR", nombre or "censo",
30 "el censo no tiene ningún `[[servicio]]`: ¿es el fichero correcto?")
31 return sis
32
33 decididos = [s for s in servicios if s.get("decision") == "muda"]
34 if not decididos:
35 # Salir con cero tarjetas y código 0 sería una semilla VACÍA que parece un éxito. Es el mismo
36 # modo de fallo que un artefacto vacío en el store: un ausente falla ruidosamente, un vacío
37 # llega hasta el final diciendo que todo fue bien.
38 acta.anota(0, "SIN-TRADUCIR", nombre or "censo",
39 f"ninguno de los {len(servicios)} servicios tiene `decision = \"muda\"`. La "
40 "semilla saldría VACÍA y parecería un éxito: decidí primero (`planear.py --decide`)")
41 return sis
42
43 for s in decididos:
44 srv = Servicio(nombre=s["name"], tipo="simple")
45 srv.cmd = (s.get("cmdline") or "").strip()
46 srv.cwd = (s.get("cwd") or "").strip()
47 srv.usuario = (s.get("usuario") or "").strip()
48 if srv.usuario:
49 srv.lineas["usuario"] = 0
50 # Está corriendo y se decidió mudarlo ⇒ se quiere arriba. Es una decisión, y se anota como
51 # tal: el censo no dice si estaba en el arranque, dice que está VIVO ahora.
52 srv.arranque_auto = True
53 srv.reinicio = "siempre"
54 if not srv.cmd:
55 acta.anota(0, "SIN-TRADUCIR", s["name"],
56 "no se pudo leer su línea de comando en el origen: NO se emite tarjeta. Una "
57 "tarjeta que no arranca es peor que una ausente — la ausente falla ruidosamente "
58 "al primer arranque, la rota deja el servicio caído sin que nada avise")
59 continue
60 if s.get("ports"):
61 acta.anota(0, "traducido", f"{s['name']} sirve {', '.join(str(p) for p in s['ports'])}")
62 sis.servicios.append(srv)
63
64 # ⚠ UNA entrada, no una por servicio. La limitación es del LECTOR y vale igual para todos, así
65 # que repetirla 26 veces no informa 26 veces: tapa los hallazgos que sí son de un servicio
66 # concreto (el que corre como `sergio`, el que no tiene cmdline). Un acta en la que casi todo es
67 # la misma línea se deja de leer, y entonces no queda ningún acta.
68 if sis.servicios:
69 acta.anota(0, "decision", f"supervisión de las {len(sis.servicios)} tarjetas",
70 "el censo dice que CORREN, no si el origen las levantaba al arrancar; se declaran "
71 "con reinicio automático porque se decidió mudarlas. Sacá del `genesis` las que no "
72 "quieras al boot")
73 acta.anota(0, "SIN-TRADUCIR", f"envp VACÍO en las {len(sis.servicios)} tarjetas",
74 "el censo NO lee `/proc/<pid>/environ` (trae tokens), así que ninguna tarjeta "
75 "lleva entorno. El que dependa de variables arranca y falla: " +
76 " ".join(x.nombre for x in sis.servicios))
77 return sis