H4e: requires OBSERVADOS — dep de runtime divergida = incompatible (SDD 15 §H4)

Cierra la simetría de la vía observada: además de observar lo que un paquete escribe (H4c),
observa de qué depende A UNA VERSIÓN. Fuente observable sin declaración: el paquete se
construyó contra la versión de sus deps que hay en el repo (deps.runtime del .swm +
expected_hash de cada dep en el índice); si el usuario tiene esa dep instalada a OTRO hash,
la divergió -> rechazo duro. Es el caso wayland DERIVADO (el que H4b captura cuando el autor
declara requires, ahora leído del cierre).

- compat::observed_requires(swm, index) + version_conflicts(db, req) — reusan deps del .swm,
  expected_hash del índice e InstalledDb.hash (cero declaración nueva).
- Cableado en install (rechazo duro, no lo salva --force-slots) y en `hammer compat`.
- Verificado e2e real: `hammer compat` marca app INCOMPATIBLE por su dep wayland-protocol
  instalada a un hash divergido del repo (read-only, ve el source_patch sin construirlo).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 06:29:22 -04:00
co-authored by Claude Opus 4.8
parent bbf4411af0
commit 3e520d4477
4 changed files with 226 additions and 5 deletions
+19 -4
View File
@@ -344,9 +344,23 @@ La definición dura de compatibilidad de una config `C` contra mi estado `E`:
colisión (de slot o de fichero) ⇒ elección, si no compatible. **Verificado e2e real**
(`tests/compat_gate.rs`): un repo de dos paquetes se parte correctamente (uno choca de fichero
con lo instalado ⇒ elección, otro limpio ⇒ compatible).
Lo que queda abierto: **derivar la otra mitad** (los `requires` observados: de qué depende el
paquete, no sólo qué escribe), subir el grano del path-slot a superficies más ricas (un módulo
wasm de wawa, un componente), y el **colapso** con el lado proceso.
- **H4e** ✅ — **`requires` OBSERVADOS: la versión contra la que el paquete se construyó.** Cierra
la simetría de H4c: además de observar lo que un paquete *escribe*, observamos de qué *depende a
una versión*. La fuente observable, sin que el autor prometa nada: un paquete se construyó contra
la versión de sus deps que hay **en el repo** (`deps.runtime` del `.swm` + `expected_hash` de cada
dep en el índice); si el usuario tiene esa dep instalada a **otro** hash, la divergió ⇒ rechazo
duro. Es el **caso wayland derivado** — el mismo que H4b captura cuando el autor declara
`requires`, ahora leído del cierre.
- `compat::observed_requires(swm, index)` + `compat::version_conflicts(db, req)` (reusan `deps`
del `.swm`, `expected_hash` del índice y `InstalledDb.hash` — cero declaración nueva).
- Cableado en `install` (rechazo duro, no lo salva `--force-slots`: es un requisito, no una
elección) y en `hammer compat` (bucket incompatibles).
- **Verificado e2e real** (`tests/compat_gate.rs`): `hammer compat` marca `app` INCOMPATIBLE
porque su dep `wayland-protocol` está instalada a un hash divergido del repo — read-only, ve
el `source_patch` sin construirlo.
Con H4e, la vía observada es simétrica: **lo que el paquete escribe** (H4c) *y* **de qué depende**
(H4e), ambas sin declaración. Lo que queda abierto: subir el grano del path-slot a superficies
más ricas (un módulo wasm de wawa, un componente) y el **colapso** con el lado proceso.
**Frontera honesta.** H4a demuestra el *álgebra* sobre hashes abstractos; lo que **no**
resuelve es la **granularidad de los slots** — dos configs pueden no colisionar en el slot
@@ -409,7 +423,8 @@ H3a (design-doc) ──► registrar la visión, barato
└► H4b ✅ (slots en la receta/.swm real + gate en `hammer install`)
└► H4c ✅ (superficies OBSERVADAS: colisión de fichero, sin declarar slots)
└► H4d ✅ (`hammer compat <repo>`: la búsqueda que particiona un repo)
└► [proceso] replay del MonotonicLog ──► plan OS-CRDT (otro agente)
└► H4e ✅ (requires OBSERVADOS: dep divergida = incompatible)
└► [proceso] replay del MonotonicLog ──► plan OS-CRDT (otro agente)
```
Recomendación: **H1 primero** (empuja la frontera que ya tenemos, sin apuestas). **H2a** en