// public/docs-app/v1/doc/lru_alfiler_egress_mesa_s210.md
// 2026-06-12T12:00:00Z

# LRU · Alfiler · Egress por la mesa · estadificación del eje bidireccional · s210

> **Nota s212 (renombre):** el término *egress* de este alfiler se renombró a **actuación / actuador** — el actuador convierte señales eléctricas en señales del mundo físico (complemento del sensor, que hace lo inverso). El código vigente usa `enlacesActuador` / `actuadorAdapter` / `ActuadorDebug` y "eje de actuación". Se conservan el nombre de este fichero, los códigos de etapa E0–E7 y el id `T-S209-EGRESS-MESA` como históricos. El topic `to/act` no cambió (ya estaba alineado: "act" = actuar).

**Ubicación canónica**: `public/docs-app/v1/doc/lru_alfiler_egress_mesa_s210.md`
**Sesión origen**: s210 · 2026-06-12 · Manuel & Claude
**Naturaleza**: alfiler de estadificación (patrón R5/colapso · rebanadas con punto de no retorno explícito) · anillo 2 · **NO canónico · regla de disputa activa**
**Tensión**: `T-S209-EGRESS-MESA` · este alfiler ES el camino que la tensión pedía antes de código
**Relación con el corpus**: materializa el eje DIRECCIÓN del destilado `lru_destilado_modelo_unificado_senales_s183.md` (§2.3 + §4 + §7) en su mitad egress. Dialoga con T-S182 (señal→señal), T-S184 (inhibición per-canal firmware), T-S183 (umbrella). Hereda el actuator model s79 (el actuador NO es un sensor invertido).
**Propósito**: fijar las rebanadas E0–E7 del eje "las señales viajan en las DOS direcciones por la mesa y los legos", con los arbitrajes de s210 cerrados y los abiertos nombrados.
**No-propósito**: NO toca código · NO construye el grabador/replay sobre actuadores · NO aborda señal→señal con conversión (T-S182, familia hermana) · NO diseña la UI fina de la arista en la mesa.

---

## §0 · Voz fundacional (Patrón 3, verbatim)

> *"los actuadores son nuestras manos para interactuar con el mundo fisico no solo lo leemos sino que deberemos mas adelante de interactuar con el, sin eso solo somos un gran cerebro con mucha inteligencia pero encerrado en un mundo virtual"* — Manuel, s183

> *"Más adelante las desarrollaremos mucho más"* — Manuel, s209, sobre las luces de Mus1 (primeros actuadores virtuales)

---

## §1 · Problema y triggers materializados

Hoy la mesa (EnlacesPanel) solo conecta consumidores (agujas) con señales: es un patch bay **de entrada**. Los actuadores virtuales del músico (s209: `led_rojo/verde/azul` 1-bit + `rgb1..3` 8-bit; vibrate como reflejo local) son conducibles únicamente por la bidireccionalidad s206b de Mus1 (siguen su propio `from/events` entrante), **sin ruta por la mesa**. No hay forma de decir "esta señal alimenta este puerto-actuador" desde la autoridad de enrutado del sistema.

Triggers reales, no hipotéticos:
- **T3 de T-S182 (s207)**: Manuel quiso que el slider de un músico moviera el puerto de otro.
- **Luces s209**: actuadores virtuales sin arista en la mesa.
- **Vibrate s209**: reflejo local que pide su versión enrutada.

## §2 · Decisiones arbitradas en s210

- **D-s210-1 · Transporte egress = canal de comando `to/act` (canónico)**. El peer model `sim/from/events` (camino s206b) **no es el contrato egress**: (a) no distingue comando de valor ejecutado — la tripla del actuador (comandado → dinámica → ejecutado → feedback, s183 §2.3 + actuator model s79) no es expresable; (b) la exclusividad atómica como invariante de seguridad (s183 §4.4) no puede ser estructural en un topic que cualquiera publica (el LruBar-HwSim ya lo hace). Con `to/act`: la mesa publica el comando; el dispositivo lo aplica; **su telemetría normal `from/events` ES el feedback de ejecutado** — el lazo cierra sin segundo bus. El camino s206b queda recolocado en su sitio canónico: lazo de realimentación, no canal de mando.
- **D-s210-2 · A solo como andamiaje**. La ruta peer (publicar `sim/from/events` hacia un puerto-out) se usa únicamente en E2 como validación punta-a-punta barata (las luces ya escuchan HOY), marcada provisional y **retirada en E4**. No se persiste nada sobre ella.
- **D-s210-3 · Paridad firmware DENTRO de la estadificación** (rebanada propia E5): `dir` en `sensors_cfg.h` + handler `to/act` en el ESP32. El hardware es modificable (confirmado s210); el firmware no bloquea las rebanadas app-side previas.

## §3 · El contrato egress

**Dirección en la partitura.** `SensorCapabilityDef` gana `dir?: 'in' | 'out' | 'bidi'`, **opcional con default `'in'`** — retrocompatible por construcción: firmware/músicos que no lo envían siguen siendo válidos, y todos los consumidores actuales pueden ignorarlo. La partitura declara el papel (s183 §2.4); el sentido es parte del papel.

**Canal de comando.** `mqttTopicTo.act = (hwObjId) => '<net>/<id>/to/act'`. Payload candidato: espejo plano de `from/events` (`{ puerto: valor, ... }` + metadatos `ts/seq/src`) — misma forma que la telemetría para que el dispatch sea simétrico. La forma fina se arbitra en E3 (D-abierta-1).

**Tripla del actuador.** comandado (`to/act`) → dinámica (en el dispositivo: instantánea en luces virtuales, planta real en actuadores físicos) → ejecutado → feedback (`from/events` normal). En Mus1 sale casi gratis: handler `to/act` que aplica al puerto y deja que la publicación existente haga de feedback.

**Exclusividad atómica estructural.** Un único adaptador egress app-side (propiedad de la mesa) emite `to/act`; **un solo escritor autoritativo por puerto-out**. En egress es propiedad de seguridad, no de UX (s183 §4.4 · "una sola mano en la palanca"). Semilla del adaptador de dos caras (s183 §4): este adaptador es la primera materialización de la cara egress del contrato.

## §4 · Estadificación · rebanadas E0–E7

Cada rebanada: trigger explícito, build verde, reversible salvo donde se marca. El orden E0→E4 es secuencial; E5 puede correr en paralelo tras E3; E6/E7 detrás de E4.

- **E0 · Auditoría fina (solo lectura · Camino Y).** Camino s206b exacto en `Mus1.tsx` (suscripción, supresión de eco por `src`, throttle) + dispatch del CommsManager por sufijo de topic + cómo publica LruBar-HwSim (`mqttTopicSim.events`) + gate per-señal del ControlBus. **Los hallazgos pueden revisar este alfiler** (sub-patrón "audit empírico previo refina contrato del destilado").
- **E1 · `dir` en la partitura.** Campo opcional en `SensorCapabilityDef` (`src/datosLru01/types.ts`) + Mus1 declara `out` (o `bidi`) en `led_*`/`rgb*`. Cero cambio de comportamiento; los consumidores lo ignoran. Reversible.
- **E2 · Validación andamiaje (provisional · D-s210-2).** Un lego existente (candidato: HwObjPopup) escribe un puerto-out de Mus1 vía `sim/from/events`. Valida punta a punta HOY sin firmware ni handler nuevo. Marcado en código como andamiaje E2; **se retira en E4**. Reversible total.
- **E3 · Canal `to/act`.** `act` en `mqttTopicTo` + handler en Mus1 (recibe → aplica al puerto → la publicación normal es el feedback) + **adaptador egress único** app-side que emite el comando. El comando es QUIRÚRGICO (solo los puertos objetivo, nunca la placa entera — E0-H1) y se enruta por el canal donde el hwObj fue oído por última vez (`CommsEvent.channel` — E0-H4). Nada persiste todavía. Reversible.
- **E4 · PUNTO DE NO RETORNO · arista en la mesa.** Enlace señal→puerto-out en EnlacesPanel: modelo de datos del enlace egress (D-abierta-2: ¿extensión de `MatrizEnlaces` o estructura hermana `EnlacesEgress`? — la matriz actual es swObj×hwObj de entrada y la arista nueva es señal×puerto) + **persistencia versionada** en localStorage + exclusividad atómica estructural (rechazo de segundo escritor por puerto-out) + retirada del andamiaje E2. A partir de aquí hay formato persistido en máquinas de usuarios: migraciones, no reversiones.
- **E5 · Paridad firmware (D-s210-3 · paralela tras E3).** `dir` en `sensors_cfg.h` (espejo de E1) + handler `to/act` en el ESP32 aplicando a puertos de salida físicos. Conecta con T-S184 (la máscara per-canal de `to/sim` es pariente).
- **E6 · Legos.** LruBar/Mixer/Chart/HwObjPopup muestran puertos out (la faceta `dir` ya viaja en la partitura desde E1) y los operan donde proceda. Lente/agrupación por dirección como faceta consultable (coherente con el régimen de facetas firmes).
- **E7 · Eje de modos en egress.** Quién tiene derecho a escribir un actuador: espejo del gate per-señal de entrada. Candidato lean: generalizar el ControlBus existente antes que crear un árbitro nuevo (s183 §7 "dónde vive el árbitro"). Última rebanada deliberadamente: necesita que E3/E4 hayan enseñado el uso real. Estructura `SIGNAL_PERMISSIONS` reutilizable y despliegue candidato en modo sombra (patrón s167) — E0-H6.

## §5 · Mapeo capas → rebanadas

| Capa (T-S209-EGRESS-MESA) | Rebanada |
|---|---|
| 1 · Contrato adaptador dos caras + exclusividad | E3 (+invariante en E4) |
| 2 · Dirección en la partitura (core + firmware) | E1 (app) + E5 (firmware) |
| 3 · Arista nueva en EnlacesPanel | E4 |
| 4 · Legos con puertos de salida | E6 |
| 5 · Modos en egress | E7 |

## §6 · Invariantes y guardas

1. **Un solo escritor autoritativo por puerto-out** (estructural desde E4).
2. **El feedback no es el comando**: nunca se reinyecta `from/events` como `to/act` (corta lazos infinitos; el adaptador egress solo emite desde la señal-fuente del enlace).
3. **Sin enlace, sin comando**: un puerto-out sin arista en la mesa no recibe `to/act` de la app (la bidireccionalidad s206b peer queda como está para músico↔músico, fuera del contrato mesa).
4. **Comando quirúrgico**: `to/act` lleva exclusivamente los puertos comandados — nunca la placa entera (anti-clobber, E0-H1; contraste: el publicador HwSim actual emite todo `hw1`).
5. **Replay→actuador real queda FUERA** (s183 §6 horizonte): reproducir comandos grabados sobre actuador físico es el rincón más peligroso; requerirá guardas propias cuando llegue.

## §7 · Qué NO entra (P11)

- Señal→señal con conversión de unidades (T-S182, familia hermana — la arista E4 es señal→puerto, sin transformación).
- Dinámica de planta declarada en catálogo (`ActuatorDef` UI) — el sustrato `sendActuatorCommand`/`feedbackSensorId` del SimService espera su propio trigger.
- Web STOMP / nuevos transportes (TD-s209-1).
- Grabador/reproductor del eje tiempo.

## §8 · Decisiones abiertas (se arbitran al materializar, D-s111-1)

- **D-abierta-1**: forma fina del payload `to/act` (espejo plano vs comando con eco de confirmación).
- **D-abierta-2**: hogar de la arista egress (extender `MatrizEnlaces` vs estructura hermana) — decisión de E4, informada por E0.
- **D-abierta-3**: quién bombea el egress (push on-change desde el slot del DataPlane vs tick) — pariente del desacople del run-state (s183 §4.5).
- **D-abierta-4**: fan-out — ¿una señal puede alimentar N puertos-out? (probable sí, simétrico al ingress; la exclusividad es por puerto, no por señal).
- **D-abierta-5**: reconciliar `sendActuatorCommand` (ControlBus s83 · topic `lru/cmd/actuator/{actuatorId}` · sin gate, T-S83-T4-gate) con `to/act` — direccionamiento por actuador vs por dispositivo. Recomendación E0: supersede (migrar su emisión a `to/act` o retirarlo). Se arbitra en E3.

## §9 · Disciplina

Alfiler propone, núcleo dispone, Manuel arbitra. Rebanadas reversibles hasta E4 (punto de no retorno nombrado); cada una con trigger, dryRun donde aplique y build verde. E0 puede revisar este documento — eso es Camino Y funcionando, no un fallo del alfiler.

## §10 · Hallazgos E0 (auditoría fina · s210 · ya incorporados arriba)

- **H1** · El publicador HwSim (`handleChangeSliderhw1Sw`, ComponenteLru) emite la placa entera (`{hw1: clonedHwObj.hw1}`) con la copia local del LruBar — al conducir un músico multi-fuente re-asienta puertos que no se movieron, pisando lo que dictan sus sensores en la UI remota. Sin bucle (Mus1 no republica al recibir). Registrado como deuda técnica al cierre s210; NO se corrige en este eje (P11).
- **H2** · Ese publish va sin `src` y sin `channelId` (sale por el primer adaptador online): transporte indeterminado en el mundo dual mqtt/wss de s209b.
- **H3** · Canal de comando latente preexistente: `ControlBus.sendActuatorCommand` (s83) → `lru/cmd/actuator/{actuatorId}`, sin gate. Ver D-abierta-5.
- **H4** · `CommsEvent.channel` (comms/types.ts) identifica el adaptador de origen per-mensaje → el egress puede enrutar por el canal de última escucha del hwObj.
- **H5** · Camino s206b confirmado: suscripción sufijo `'from/events'` → filtro `parseEventsTopic().hwObjId` → supresión de eco por `src` per-pestaña → recibir nunca publica. El handler `to/act` de E3 es efecto hermano; `'to/act'` (2 segmentos) clasifica como sufijo en el CommsManager (correcto); falta mini-parser del topic to/act.
- **H6** · `SIGNAL_PERMISSIONS` (ControlBus s166) y el modo sombra (s167) son sustrato y técnica de despliegue reutilizables para E7.
