250 líneas de comentario en 151 scripts. Control verificado: el diff no toca NI UNA línea que no empiece por #, y la sintaxis de los 151 pasa. El barrido saltea heredocs y cadenas triples, y el guardián DISPARÓ 3 veces: las tres eran el MOTD que el script escribe DENTRO de la imagen construida — texto del producto, no comentario del script. Se cambiaron aparte y a propósito, que es rebranding, no limpieza. Y el hallazgo caro: casaba contra , que es el TARGET de tracing — o sea el module_path!, o sea el nombre del crate. La etapa 4 lo movió a y el script quedó casando NADA. No fallaba: imprimía cero atribuciones, indistinguible de un log sin problemas. Comprobado con el binario (RUST_LOG=info sobre zlib), no deducido. Ahora acepta las dos, y tiene que seguir aceptándolas porque los logs viejos en disco dicen la vieja. Además 14 rutas de módulo en docs, que el barrido anterior no tocó porque no es frontera de palabra.
143 lines
6.9 KiB
Markdown
143 lines
6.9 KiB
Markdown
# SDD 08 — Integración de la IA
|
|
|
|
La IA es un **artesano hiperveloz en el taller**; el humano es **el dueño que decide si el
|
|
mueble entra a la casa o se va a la basura.** Esta sección define el bucle agéntico, sus
|
|
garantías de seguridad, y cómo una intención en lenguaje natural se vuelve un cambio real.
|
|
|
|
## 1. La terminal como runtime de la IA
|
|
|
|
La IA no es un chat en una ventana que te dice qué teclear. Opera directamente sobre el sistema
|
|
a través del **bus de agente** ([SDD 07](07-agent-bus.md)) y de un **overlay**
|
|
([SDD 04](04-overlay.md)). Su entorno de trabajo es el sistema real, con red de seguridad.
|
|
|
|
## 2. El bucle agéntico
|
|
|
|
```
|
|
intención (NL)
|
|
│ "que grep ignore binarios por defecto y use regex Perl,
|
|
│ y que la red use IP estática 192.168.1.100"
|
|
▼
|
|
┌─────────────┐
|
|
│ PLAN │ la IA traduce la intención a un .swm: qué herramienta,
|
|
│ │ qué patch de fuente, qué flags, qué config editar
|
|
└──────┬──────┘
|
|
▼
|
|
┌─────────────┐
|
|
│ BUILD │ COMPILE por el bus → el lab clona repo@commit, aplica patch,
|
|
│ (lab) │ compila estático con zig cc → artifact_hash
|
|
└──────┬──────┘
|
|
▼
|
|
┌─────────────┐
|
|
│ TRY │ takana try → overlay temporal; INJECT del artefacto y de las
|
|
│ (overlay) │ ediciones de config en la capa. El sistema real intacto.
|
|
└──────┬──────┘
|
|
▼
|
|
┌─────────────┐
|
|
│ VERIFY │ corre el test harness; escucha BUILD_FAILED / CRASHED por el bus.
|
|
│ │ si falla → corrige fuente → recompila (vuelve a BUILD).
|
|
└──────┬──────┘
|
|
▼
|
|
┌─────────────┐
|
|
│ PROPOSE │ la IA avisa: "listo, probé esto, aquí el diff y el resultado".
|
|
│ │ presenta el .swm y la evidencia.
|
|
└──────┬──────┘
|
|
▼
|
|
┌─────────────┐
|
|
│ HUMANO │ tú decides: takana commit (promueve + diario) o takana discard.
|
|
│ decide │ La IA NUNCA promueve al FHS real por su cuenta (ver §4).
|
|
└─────────────┘
|
|
```
|
|
|
|
## 3. Por qué esta arquitectura se presta (y otras no)
|
|
|
|
- **Determinismo del lab** → la IA puede recompilar y volver atrás sin dramas; el resultado es
|
|
predecible.
|
|
- **Texto plano + binarios atómicos** → la IA lee/escribe archivos e inspecciona binarios con
|
|
`readelf`/`objdump`; no parsea bases de datos opacas.
|
|
- **musl legible** → el código C de la libc base es comprensible en el contexto de un LLM
|
|
(glibc es un laberinto de macros).
|
|
- **Enlazado estático** → una herramienta mutada corre sin romper enlaces de otros programas.
|
|
- **Mutabilidad + overlay** → agencia real con red de seguridad; sin rollbacks pesados.
|
|
|
|
En distros inmutables/declarativas, la IA tendría que lidiar con generadores de config y
|
|
políticas read-only; en tradicionales, no tendría provenance. `takana` mantiene las **tuberías
|
|
expuestas y de baja entropía**, que es justo lo que un agente necesita.
|
|
|
|
## 4. Garantías de seguridad (no negociables)
|
|
|
|
1. **La IA trabaja en overlay por defecto.** Sin capacidad `inject-real`, no puede tocar el
|
|
FHS base. El flujo es siempre overlay → `commit` humano.
|
|
2. **Capacidades mínimas y explícitas.** El humano concede `query`/`compile`/`inject` por
|
|
separado vía la política del bus ([SDD 07](07-agent-bus.md)).
|
|
3. **Toda acción es reversible y registrada.** `discard` revierte el overlay; el `commit`
|
|
entra al diario firmado ([SDD 05](05-journal.md)).
|
|
4. **Recetas, no binarios.** La IA produce `.swm` (fuente + flags + config), no binarios
|
|
opacos. Lo que comparte es verificable por terceros ([SDD 06](06-swm-format.md)).
|
|
5. **El humano tiene la última palabra.** Ningún cambio se vuelve permanente sin `commit`.
|
|
|
|
## 5. De la intención al `.swm`: el rol del modelo
|
|
|
|
El traductor intención→`.swm` se conecta detrás del trait `IntentTranslator` del crate
|
|
`takana-agent`. Contrato:
|
|
|
|
- **Entrada:** intención en NL + `SystemContext` (lo que el orquestador recolecta por
|
|
`QUERY`: `BaseRef` local, extras JSON).
|
|
- **Salida:** un `Swm` válido ([SDD 06](06-swm-format.md)).
|
|
|
|
Fase 6 entrega un `MockTranslator` que resuelve intentos contra un `IntentCatalog` YAML
|
|
(intent exacto → `.swm` inline o `swm_path` relativo). Eso permite probar el bucle sin LLM:
|
|
el humano que descubrió la intención con un modelo real congela el resultado y los CI lo
|
|
reproducen byte-a-byte. El traductor LLM (Claude API u otro) implementa el mismo trait y se
|
|
enchufa sin tocar el `Orchestrator`.
|
|
|
|
**El modelo nunca ejecuta nada directamente:** emite comandos por el bus, que `hammerd`
|
|
valida contra las capacidades concedidas, y el `Orchestrator` traduce las mutaciones a
|
|
`takana-core::apply` o a `Compile` por el bus.
|
|
|
|
## 6. Lenguaje de consulta/transformación (visión, Fase posterior)
|
|
|
|
Para que la IA refiera partes del sistema sin rutas absolutas frágiles, un mini-lenguaje de
|
|
consulta sobre el grafo del sistema:
|
|
|
|
```
|
|
find /service/web -where "depends_on(libssl)" -> replace_with my_tls
|
|
```
|
|
|
|
El daemon traduce esa consulta estructurada a acciones reales del bus. La terminal sigue siendo
|
|
el lugar de validación final. Esto es visión, no Fase 0 — se diseñará cuando el bucle básico
|
|
esté probado.
|
|
|
|
## 7. Interfaz
|
|
|
|
El crate `takana-agent` (Fase 6) expone:
|
|
|
|
```rust
|
|
// takana_agent::client
|
|
pub struct AgentClient { pub welcome: Welcome, /* … */ }
|
|
impl AgentClient {
|
|
pub fn connect(sock: &Path) -> Result<Self>;
|
|
pub fn compile(&mut self, recipe: RecipeInline, timeout: Duration) -> Result<String>; // artifact
|
|
pub fn inject(&mut self, artifact: &str, target: &str, overlay: Option<&str>, t: Duration) -> Result<usize>;
|
|
pub fn query_file(&mut self, path: &str, timeout: Duration) -> Result<serde_json::Value>;
|
|
pub fn init(&mut self, cmd: &str, timeout: Duration) -> Result<()>;
|
|
pub fn drain_async(&self) -> Vec<Event>;
|
|
pub fn next_async(&self, timeout: Duration) -> Result<Event>;
|
|
}
|
|
|
|
// takana_agent::translator
|
|
pub trait IntentTranslator { fn translate(&self, intent: &str, ctx: &SystemContext) -> Result<Swm, TranslateError>; }
|
|
pub struct MockTranslator { /* HashMap<intent, Swm> */ }
|
|
pub struct IntentCatalog { pub intents: Vec<CatalogEntry> } // YAML loader
|
|
|
|
// takana_agent::orchestrator
|
|
pub struct Orchestrator<T: IntentTranslator> { /* … */ }
|
|
impl<T> Orchestrator<T> {
|
|
pub fn new(t: T, base: BaseRef, apply: ApplyTarget, compile: CompileMode) -> Self;
|
|
pub fn run(&self, intent: &str) -> Result<Proposal>;
|
|
}
|
|
```
|
|
|
|
Los tipos del protocolo (`Command`/`Event`/`Cap`/`Peer`/`RecipeInline`) viven en
|
|
`takana-core::proto` para ser compartidos por `hammerd`, `takana-agent` y cualquier cliente
|
|
externo escrito en Rust.
|