# Analyzer1 · Referencia operativa

> **Documento Anillo 2 · referencia operativa al cierre s152**
> Fecha: 2026-05-21
> Naturaleza: doc operativo para Claude futuro · cómo trabajar con Analyzer1 sin tener que leer 130 KB de código
> Autoría: Manuel & Claude Opus 4.7
> Material origen: auditoría empírica de `src/pages/Analyzer1/` al cierre s152 + alfiler `lru_alfiler_dataplane_viewer_s152.md`
> Cuándo regenerar: cuando Analyzer1 absorba 7º protocolo · 8ª vista hermana · o cambie su contrato `ProtocolAdapter`/`TapPoint`/`CapturedFrame`

---

## §0 · Para Claude nuevo · leer primero

Bienvenido. Si vas a trabajar sobre Analyzer1, este documento te ahorra leer los 45 KB de `Analyzer1.tsx` + 130 KB acumulados en `bottom/` + `protocols/` + `correlation/`. Está sincronizado al cierre s152 · si ves divergencias con el código actual al arrancar tu sesión, **el código gana** · pero antes de asumirlo, ejecuta `Filesystem:list_directory` sobre `src/pages/Analyzer1/` y compara con el §4 de este doc.

**Tres reglas operativas que NO debes saltarte**:

1. **NO modificar componentes existentes para soportar protocolos nuevos**. Crea hermanos. Sub-patrón "vista hermana adaptativa por protocolo" cristalizado en s152 con 3 aplicaciones formales · ver §6. Si crees que una excepción está justificada, articula via `ask_user_input_v0` antes de codear.

2. **NO inventar adapter sin ProtocolAdapter interface**. El contrato vive en `src/pages/Analyzer1/types.ts` y los 6 protocolos implementados lo respetan religiosamente. Si un protocolo nuevo no encaja, articula antes de modificar la interfaz.

3. **NO añadir tab sin checkpoint en el orquestador**. La selección de qué componente render vive en el switch de `AnalyzerBottomPanel.tsx` · si añades tab, añades case + condición · si la tab es adaptativa por protocolo, replica el patrón Fase 2b/2c (ver §6.4).

---

## §1 · Qué es Analyzer1

Analyzer1 es el **analizador de protocolos** de la plataforma LRU · su rol arquitectural es **capturar + decodificar + visualizar + correlar tráfico** que circula por el proyecto. Tiene **triple vida**: página independiente (`/Analyzer1`), overlay sobre Sim1, y panel registrable en PanelGrid (paridad con el patrón "doble vida" del Anillo 2 ampliado a triple).

Al cierre s152, soporta **6 protocolos de primera clase**:

| Protocolo | Familia | Estado | Adapter | Taps |
|---|---|---|---|---|
| ARINC 429 | aviation | implemented | `Arinc429Adapter` | sim |
| MQTT | iot | implemented | `MqttAdapter` | sim + debugbus |
| WebSocket | iot | implemented | `WebSocketProtocolAdapter` | sim + real (CommsManager) |
| BLE | iot | implemented | `BleAdapter` | sim + real (Comms multi-device) |
| Internal Bus | system | implemented | `InternalBusAdapter` | sim + real (DebugBus) |
| **DataPlane** | system | implemented (s152) | `DataPlaneAdapter` | sim + real |

Y declara **5 protocolos planned** sin adapter (MIL-STD-1553, AFDX, OPC UA, Modbus, PROFINET) · `PROTOCOLS` los lista para que aparezcan en la sidebar como "futuros" pero no son funcionales.

**Inauguración s152**: la integración del DataPlane como 6º protocolo materializa la primera concreción del **subsistema Debug1 viewer** documentado en `LRU_ARQUITECTURA §9.1` como gap mayor del proyecto desde s55. El gap NO está completamente cerrado · queda **Fase 6 candidata** (extracción a viewer externo dedicado) articulada en alfiler s152 §6.E.

---

## §2 · Arquitectura · 4 contratos canónicos

Analyzer1 se sostiene sobre 4 abstracciones declaradas en `types.ts`. Cualquier extensión debe respetarlas o articularse explícitamente como rotura.

### §2.1 · `ProtocolDef` · catálogo declarativo

```typescript
interface ProtocolDef {
  id: string;
  name: string;
  family: 'aviation' | 'industrial' | 'iot' | 'system';
  icon: string;
  color: string;
  description: string;
  osiLayers: number[];
  status: 'implemented' | 'planned' | 'stub';
}
```

Vive en `protocols/index.ts` como `PROTOCOLS: ProtocolDef[]`. Es el catálogo de la sidebar · agrupa por `family` con labels canónicos (`Aviacion`, `Industrial`, `IoT`, `Sistema`).

### §2.2 · `ProtocolAdapter` · interfaz agnóstica

```typescript
interface ProtocolAdapter {
  readonly protocolId: string;
  readonly name: string;
  readonly family: ProtocolFamily;
  decode(raw: string | ArrayBuffer): DecodedFrame;
  inspect(raw: string | ArrayBuffer): string;
  canDecode(raw: string | ArrayBuffer): boolean;
  // encode(fields): ArrayBuffer;  // Fase 5-6 · instructor remoto · no materializado al cierre s152
}
```

Cada protocolo expone un adapter en `protocols/<protocol>/adapter.ts`. El registro está en `protocols/index.ts` como `ADAPTER_REGISTRY: Map<string, ProtocolAdapter>`.

**Disciplina**: el adapter es **puro decodificador semántico** · no captura tráfico (eso lo hace el tap), no renderiza nada (eso lo hace la vista), no mantiene estado (excepto cache LRU para meta cuando hay parsing costoso · ver `MqttAdapter.getMqttMeta` o `DataPlaneAdapter.getDataPlaneMeta` como referencias).

### §2.3 · `TapPointDef` · puntos de captura

```typescript
type TapPointType = 'mqtt' | 'debugbus' | 'websocket' | 'serial' | 'loopback';

interface TapPointDef {
  id: string;
  name: string;
  type: TapPointType;
  icon: string;
  color: string;
  description: string;
  config: Record<string, unknown>;
  status: 'active' | 'idle' | 'error' | 'disconnected';
}
```

Cada protocolo declara sus tap points en `Analyzer1.tsx` como `PROTOCOL_TAPS: Record<string, {id, label, icon}[]>`. Convención: cada protocolo implementado tiene al menos **un tap sim** (`<proto>-sim`) y opcionalmente **un tap real** (`<proto>-real` o nombre del backend como `mqtt-debugbus`).

**Cada tap es un hook React** que vive en `protocols/<protocol>/tap.ts`. Firma canónica:

```typescript
function use<Proto>Tap(opts: { active: boolean; onFrame: (frame: CapturedFrame) => void }): void;
function use<Proto>SimTap(opts: { active: boolean; onFrame: (frame: CapturedFrame) => void }): void;
```

Cuando `active=true`, el hook se suscribe al backend (MQTT topic, BLE notification, DataPlane subscribe, etc.) y llama `onFrame` por cada frame capturado. Cuando `active=false`, se desuscribe.

### §2.4 · `CapturedFrame` · unidad de captura

```typescript
interface CapturedFrame {
  id: number;                            // Counter global · offset por protocolo para evitar colisiones
  timestamp: number;                     // ms epoch del momento de captura
  tapPointId: string;                    // Ej: 'mqtt-sim' · 'dataplane-real'
  protocolId: string;                    // Ej: 'mqtt' · 'dataplane'
  direction: 'rx' | 'tx' | 'internal';   // Sentido del tráfico
  raw: string;                           // Payload crudo (JSON string, hex, etc.)
  decoded?: DecodedFrame;                // Resultado de adapter.decode(raw)
  size: number;                          // Bytes del raw
  starred?: boolean;                     // s152 Fase 1.5 · marca usuario · export selectivo
}
```

**Convención counter offset** (palanca contra colisiones): cada protocolo arranca el counter en un offset distinto. MQTT empieza en 1000, BLE en 50000, DataPlane en 90000+, etc. Los offsets se asignan al primer hook que captura · no hay registry central · si añades 7º protocolo, escoge offset ≥100000.

---

## §3 · Topología · 3 columnas + 1 panel inferior

```
┌─────────────────────────────────────────────────────────────────────────┐
│ HEADER: ▶ Capturar │ 🗑 Limpiar │ ⬇ Export ▾ │ ❄ Freeze │ stats │ ●   │
├──────────────┬──────────────────────────────┬──────────────────────────┤
│              │                              │                          │
│  SIDEBAR     │  CENTER · Frame list         │  RIGHT · FrameInspector  │
│              │  ┌───────────────────────┐   │  ┌────────────────────┐  │
│  Aviación    │  │ filter: ____________   │   │  │ campos decoded     │  │
│  ─ ARINC 429 │  │ [proto][dir][type] ×   │   │  │ raw payload         │  │
│              │  ├───────────────────────┤   │  │ errors             │  │
│  Industrial  │  │ ✩ ← 10:23:45.123 MQTT │   │  │                    │  │
│  ─ OPC UA    │  │ ★ → 10:23:45.456 DP   │   │  │                    │  │
│  ─ Modbus    │  │ ✩ · 10:23:45.789 INT  │   │  └────────────────────┘  │
│              │  └───────────────────────┘   │                          │
│  IoT         │                              │                          │
│  ─ MQTT      │                              │                          │
│  ─ WebSocket │                              │                          │
│  ─ BLE       │                              │                          │
│              │                              │                          │
│  Sistema     │                              │                          │
│  ─ Internal  │                              │                          │
│  ─ DataPlane │                              │                          │
│              │                              │                          │
├──────────────┴──────────────────────────────┴──────────────────────────┤
│ BOTTOM PANEL · 7 tabs adaptativas al protocolo del frame seleccionado   │
│ ∿ Scope/Waveform │ ◇ Timeline │ ✦ Constellation │ Δ Latency │           │
│ ≡ Diff │ ▤ Stats │ ⛓ Trace                                              │
└─────────────────────────────────────────────────────────────────────────┘
```

**5 zonas funcionales**:

- **Header**: control global de captura · 3 modos de export · freeze (congela vista, sigue capturando en buffer) · stats agregadas.
- **Sidebar izquierda**: catálogo de protocolos agrupados por familia · play individual por protocolo · sub-lista de taps cuando protocolo activo · panel BLE config con presets HM-10/Nordic/HRP/etc + UUIDs custom + multi-device manager.
- **Center**: filtro de texto + smart filters (chips por protocolo · dirección · tipo de mensaje) · lista de frames con star clickable · scroll virtualizado lógico (cap MAX_FRAMES = 2000).
- **Right · FrameInspector**: campos decoded por el adapter · raw payload · errores · ver `FrameInspector.tsx` (36 KB · vive aparte del orquestador).
- **Bottom panel**: 7 vistas adaptativas al protocolo seleccionado (ver §5).

---

## §4 · Inventario de ficheros · estado s152

```
src/pages/Analyzer1/
├── Analyzer1.tsx                       ← Orquestador principal (46 KB)
├── Analyzer1Overlay.tsx                ← Vida overlay sobre Sim1 (4 KB)
├── AnalyzerBottomPanel.tsx             ← Orquestador del panel inferior (9 KB)
├── FrameInspector.tsx                  ← Panel derecho · decode detallado (37 KB)
├── analyzer1.css                       ← Estilos globales (24 KB)
├── exportCapture.ts                    ← s152 Fase 1.5 · export JSON 3 modos (8 KB)
├── index.ts                            ← Barrel root (123 B)
├── types.ts                            ← Contratos canónicos (4 KB)
│
├── protocols/                          ← Adapters + taps + simulators
│   ├── index.ts                        ← Catálogo PROTOCOLS + ADAPTER_REGISTRY
│   ├── arinc429/                       ← {adapter, tap, simulator, index}.ts
│   ├── mqtt/                           ← {adapter, tap, simulator, index}.ts
│   ├── websocket/                      ← {adapter, tap, simulator, index}.ts
│   ├── ble/                            ← {adapter, tap, simulator, index}.ts
│   ├── internal/                       ← {adapter, tap, simulator, index}.ts
│   └── dataplane/                      ← s152 · idem · ~25 KB
│
├── bottom/                              ← Vistas del panel inferior
│   ├── constants.ts                    ← PROTO_COLORS centralizado
│   ├── index.ts                        ← Barrel
│   ├── WaveformView.tsx                ← Forma de onda ARINC429
│   ├── MqttFlowView.tsx                ← Flujo MQTT
│   ├── WsFlowView.tsx                  ← Flujo WebSocket
│   ├── BleFlowView.tsx                 ← Flujo BLE
│   ├── TimelineView.tsx                ← Timeline genérico zoom/pan/minimap
│   ├── StatsView.tsx                   ← Donut por proto + top topics MQTT
│   ├── TopicConstellation.tsx          ← Grafo radial de topics MQTT
│   ├── LatencyAnalyzer.tsx             ← Histograma latencia inter-frame
│   ├── PayloadDiff.tsx                 ← Diff side-by-side payload
│   ├── DataPlaneScopeView.tsx          ← s152 Fase 2 · osciloscopio analógico DP (21 KB)
│   ├── TraceView.tsx                   ← s152 Fase 3 · trace cross-protocol (16 KB)
│   ├── DataPlaneConstellation.tsx      ← s152 Fase 2b · árbol SIM_CATALOG (19 KB)
│   └── DataPlaneStatsView.tsx          ← s152 Fase 2c · stats por source (14 KB)
│
└── correlation/                         ← s152 Fase 3 · correlation engine
    ├── index.ts                        ← Barrel
    ├── extractors.ts                   ← identityTokens por protocolo (14 KB)
    └── traceEngine.ts                  ← computeTrace + buildTraceExport (11 KB)
```

**Total cierre s152**: ~330 KB de código fuente · 8 ficheros nuevos s152 (~129 KB) + 6 modificados acumulados.

---

## §5 · Las 7 vistas del bottom panel

El bottom panel es un orquestador adaptativo. Las tabs visibles dependen del protocolo del frame seleccionado · la vista renderizada dentro de cada tab puede variar también.

| Tab | Icon | Componente · ARINC429 | Componente · MQTT | Componente · DataPlane |
|---|---|---|---|---|
| Scope/Flow/Waveform | ∿ ⮂ | `WaveformView` | `MqttFlowView` | `DataPlaneScopeView` |
| Timeline | ◇ | `TimelineView` (genérico) | `TimelineView` (genérico) | `TimelineView` (genérico) |
| Constellation | ✦ | — | `TopicConstellation` | `DataPlaneConstellation` |
| Latency | Δ | `LatencyAnalyzer` (genérico) | idem | idem |
| Diff | ≡ | `PayloadDiff` (genérico) | idem | idem |
| Stats | ▤ | `StatsView` (genérico) | `StatsView` (genérico) | `DataPlaneStatsView` |
| Trace | ⛓ | `TraceView` (cross-protocol) | idem | idem |

**Vistas genéricas** (3): Timeline, Latency, Diff. Funcionan sobre cualquier protocolo sin conocer su semántica.

**Vistas adaptativas** (4): Scope/Flow/Waveform, Constellation, Stats, Trace. Cambian de componente según protocolo seleccionado o cambian su algoritmo internamente.

**Tabs condicionalmente visibles**: la tab Constellation solo aparece si `hasMqtt || hasDataPlane`. El resto siempre.

### §5.1 · WaveformView · ARINC429

Forma de onda bipolar 5V/-5V de los bits del label ARINC 429. Lee el campo `bits` del decoded frame.

### §5.2 · MqttFlowView · MQTT

Diagrama de flujo del topic + payload + QoS + retain del frame MQTT seleccionado. Usa `getMqttMeta(raw)` del adapter (cache LRU).

### §5.3 · WsFlowView · WebSocket

Diagrama tipo `{type, topic, payload}` característico del schema WS de Node-RED del proyecto.

### §5.4 · BleFlowView · BLE

Diagrama device→characteristic→value para BLE. Usa todos los frames para mostrar dispositivos activos en el sidebar interno + frame seleccionado destacado.

### §5.5 · DataPlaneScopeView · s152 Fase 2

Osciloscopio analógico para frames DataPlane. 13 features:
- Curva del sensor seleccionado en el tiempo (cap 500 puntos/sensor)
- Bandas verde/rojo del rango operativo (catálogo min/max)
- Marcadores con color por source (paleta `SOURCE_COLORS` del adapter)
- Highlight frame seleccionado (3px borde blanco + línea vertical punteada)
- Cursores A/B clickables con Δt + Δvalor en etiqueta amarilla central
- Toggle Mode: 1ch (single) vs 6ch (multi · top 6 por frecuencia · sub-plots apilados)
- Toggle Y-scale: cat (rango catálogo) vs auto (auto-fit datos)
- Eje X adaptativo: mm:ss.ms / mm:ss / HH:mm:ss según tSpan

**Cita gold s152**: Manuel arbitró *"prefiero crear una vista nueva hermana en lugar de modificar la existente"* · esto fue 1ª aplicación del sub-patrón "vista hermana adaptativa por protocolo".

### §5.6 · TimelineView · genérico

Vista temporal global con zoom/pan/minimap/tooltips. Cada frame es un dot en eje temporal. Click salta al frame en lista central. **Funciona gratis para todos los protocolos** porque solo necesita `timestamp + protocolId + size`.

### §5.7 · TopicConstellation · MQTT

Grafo radial de los topics MQTT presentes en el buffer. Nodos = topics distintos · arcos = padre-hijo en jerarquía de topic (separador `/`). Solo aparece si hay tráfico MQTT.

### §5.8 · DataPlaneConstellation · s152 Fase 2b

Árbol COMPLETO del SIM_CATALOG · NO derivado del tráfico. Muestra displays→systems→sensors aunque estén dormidos. **Estados por sensor**:
- **live** (<2s): color brillante + halo pulso + radio +0.5
- **stale** (2-10s): color tenue opacity 0.4
- **dead** (sin writes o >10s): gris #3a3d52 opacity 0.3

Interacción: click en display header → toggle colapso · click en sensor con writes → salta al último frame de ese sensorId · highlight con borde blanco si frame seleccionado matcha sensorId.

**Acoplamiento documentado T-S152-N2**: importa `useSimCatalog` · primera dependencia explícita del Analyzer1 al catálogo del proyecto · deuda relevante para Realm v2 cuando catálogo migre a Firestore.

### §5.9 · LatencyAnalyzer · genérico

Histograma de latencia inter-frame. Para cada par (frame_i, frame_i+1) calcula `dt = ts(i+1) - ts(i)` · agrupa en buckets · muestra distribución. Sirve para detectar jitter o picos de latencia.

### §5.10 · PayloadDiff · genérico

Side-by-side diff entre el frame seleccionado y el frame anterior del mismo `protocolId + tapPointId`. Útil para ver qué bytes cambiaron entre dos capturas consecutivas.

### §5.11 · StatsView · genérico (por proto)

3 columnas: donut por protocolo + métricas TX/RX + sparkline 20s + top 5 topics MQTT.

### §5.12 · DataPlaneStatsView · s152 Fase 2c

3 columnas reformuladas para vocabulario DataPlane:
- **Col 1**: donut por SOURCE (sim-engine, registry, router-svc, hw_*, etc.) · paleta `SOURCE_COLORS`
- **Col 2**: métricas DataPlane (sensores únicos, writes/s, %OOR semáforo, sparkline 20s)
- **Col 3**: top 5 sensores por count con barras coloreadas por source dominante

### §5.13 · TraceView · s152 Fase 3 · cross-protocol

Vista heurística temporal+semántica · NO instrumentación productiva. Materializa cita gold Manuel: *"saber si una señal entra por un sitio y llega a otro o por donde va pasando"*.

**Cómo funciona** (motor en `correlation/traceEngine.ts`):
1. Extrae `identityTokens` del frame origen via `extractors.ts` (sensorId · channel · topic · UUID · label ARINC · etc).
2. Para cada otro frame dentro de la ventana temporal configurable (±100ms a ±10s), calcula `searchableContent` (raw + decoded.summary + decoded.fields lowercase).
3. Match score = `sum(token.weight × kindWeight) × temporalDecay`. `kindWeight`: exact 1.0 · substring 0.7 · derived 0.5. Decay lineal de 1.0 (hasta 10ms) a 0.4 (borde ventana).
4. Filtra por threshold · cap maxMatches 200 · ordena cronológicamente.

**Render**: pistas horizontales por protocolo (orden canónico: dataplane → internal → mqtt → ws → ble → arinc429). Pista del protocolo origen sólida · resto punteadas. Línea vertical amarilla t=0 + estrella ⭐ amarilla del origen. Nodos circulares con tamaño proporcional a score · opacidad inversa a |dt|. Click en nodo cambia origen.

**Controles**: ventana (±100ms/±500ms/±2s/±10s) · umbral (amplio 0.2 / medio 0.35 / estricto 0.5 / fuerte 0.7) · toggle "mismo proto" · botón "↓ trace" descarga JSON estructurado.

**Limitación T-S152-N3**: tokens cortos (ARINC labels 1-3 dígitos) pueden dar matches espurios. Mitigación: usuario sube umbral a estricto/fuerte cuando ARINC429 es origen.

---

## §6 · Patrones operativos · cómo extender Analyzer1

### §6.1 · Añadir 7º protocolo

**Plantilla canónica** (paridad con los 6 implementados):

```
src/pages/Analyzer1/protocols/<newproto>/
├── adapter.ts        ← <NewProto>Adapter implementa ProtocolAdapter
├── tap.ts            ← use<NewProto>Tap + use<NewProto>SimTap
├── simulator.ts      ← <NewProto>Simulator (clase con start/stop · usado por SimTap)
└── index.ts          ← Barrel · re-exporta los 3 anteriores
```

**Wiring obligatorio en 2 ficheros**:

1. `protocols/index.ts`:
   - Añadir import del adapter.
   - Añadir entry en `PROTOCOLS` (con `family`, `icon`, `color`, `osiLayers`, `status: 'implemented'`).
   - Añadir entry en `ADAPTER_REGISTRY`.

2. `Analyzer1.tsx`:
   - Añadir import de los hooks tap.
   - Añadir entry en `PROTOCOL_TAPS` con `sim` y opcionalmente `real`.
   - Añadir llamadas a los hooks (al final del bloque de taps existentes).
   - Añadir case en `protoColor()`.
   - Añadir label corto en `an1-fr-proto` (lista central) y en el badge del bottom panel.

**Disciplina**: NO modificar las 5 entradas existentes · NO renombrar contratos · NO cambiar firma de hooks. Si el protocolo nuevo NO encaja en `ProtocolAdapter`, articula via `ask_user_input_v0` con 3 opciones (modificar contrato · ampliar contrato · crear contrato hermano).

### §6.2 · Añadir 8ª vista genérica

Si la vista funciona sobre cualquier protocolo (como Timeline · Latency · Diff):

1. Crear `bottom/<NewView>.tsx` con props canónicos `{ frame?, frames, width, height, onSelectFrame? }`.
2. Exportar en `bottom/index.ts`.
3. En `AnalyzerBottomPanel.tsx`:
   - Añadir `TabId` con el nuevo id.
   - Añadir entry en `TABS` con `{ id, label, icon }`.
   - Añadir case en `renderContent()` switch.

### §6.3 · Añadir vista específica de un protocolo existente

Si la vista solo tiene sentido para un protocolo concreto (como WaveformView para ARINC429):

1. Crear `bottom/<Proto><View>.tsx`.
2. Exportar en `bottom/index.ts`.
3. En `AnalyzerBottomPanel.tsx`, dentro de un case existente, añadir branch por `protocol === '<proto>'`. **NO crear tab nueva si la conceptualmente es la misma slot** (ver §6.4).

### §6.4 · Aplicar sub-patrón "vista hermana adaptativa por protocolo"

**Cristalizado en s152 con 3 aplicaciones formales** (T-S152-N1 · candidato firme a destilado canónico Anillo 2 con 4ª aplicación).

Cuándo aplicar: tienes una tab existente (ej. Stats) que muestra una vista válida para algunos protocolos · quieres que muestre vista DISTINTA para otro protocolo · pero la tab conceptualmente es la misma slot.

Mecánica:

1. **NO modificar** componente original (preserva regresión cero).
2. **Crear componente hermano** con sufijo `<Proto><View>` en mismo directorio. Mismo prop shape.
3. **Selección en switch case** del orquestador por condición tipo:
   ```typescript
   if (protocol === 'dataplane' || (!hasMqtt && hasDataPlane)) {
     return <DataPlaneStatsView ... />;
   }
   return <StatsView ... />;
   ```
4. **Misma tab** percibida por el usuario · el componente cambia adaptativamente.

**3 aplicaciones formales al cierre s152**:
- `WaveformView` (ARINC429) ↔ `DataPlaneScopeView` (DataPlane)
- `TopicConstellation` (MQTT) ↔ `DataPlaneConstellation` (DataPlane)
- `StatsView` (por proto) ↔ `DataPlaneStatsView` (por source)

Si emerge 4ª aplicación (candidatos: `DataPlaneTimelineView` o `DataPlaneLatencyAnalyzer` reformulado), cristalizar como destilado canónico Anillo 2.

### §6.5 · Añadir source nuevo al DataPlane

`SOURCE_COLORS` en `protocols/dataplane/adapter.ts` declara colores deterministas por source tag conocido. Sources nuevos no listados reciben color por hash determinista del nombre. Para añadir un source con color fijo:

1. Añadir entry en `SOURCE_COLORS` con su color preferido.
2. Si es un prefijo familia (como `hw_*`), añadir branch en `colorForSource()` antes del fallback hash.

### §6.6 · Mantener consistencia visual

- Variables CSS: usar `--sim1-*` (tx, tx2, tx3, bg) · NO inventar tokens nuevos.
- Iconos: emoji UTF-16 con `\uXXXX` en strings JS (NO copy-paste literal para evitar problemas de encoding).
- Colores por protocolo: definidos en `protoColor()` de `Analyzer1.tsx` y en `bottom/constants.ts` `PROTO_COLORS`. Si añades protocolo nuevo, actualiza ambos.

---

## §7 · Export & captura · cómo entregar capturas a Claude

s152 Fase 1.5 materializó el workflow de auditoría empírica de Manuel. Camino canónico:

### §7.1 · Marcar frames con star (tecla S)

Mientras capturas, selecciona un frame interesante (click en lista central) y pulsa tecla `S` · aparece estrella ★ ámbar a la izquierda. La estrella es clickable también. Permite marcar selectivamente frames relevantes durante una sesión larga.

### §7.2 · Tres modos de export

Botón "⬇ Export ▾" en header abre menú desplegable:

| Modo | Contenido | Cuándo usar |
|---|---|---|
| **Todo el buffer** | Todos los frames del buffer (cap MAX_FRAMES=2000) | Diagnóstico amplio · pasar contexto completo a Claude |
| **Solo marcados** | Solo frames con `starred=true` | Pasar a Claude solo los frames de interés · más eficiente en tokens |
| **Vista filtrada** | Respeta filtros activos (proto · dir · type · texto) | Pasar a Claude un subset por protocolo o tipo |

### §7.3 · Estructura del JSON exportado

`exportCapture.ts` define `ExportPayload`:

```typescript
{
  meta: {
    exportedAt: ISO8601 string,
    sourceUrl: window.location.href,
    captureMode: 'all' | 'starred' | 'filtered',
    totalFramesInBuffer: number,
    framesExported: number,
  },
  summary: {
    byProtocol: { [proto: string]: number },
    byDirection: { tx: number, rx: number, internal: number },
    byDataPlaneSource: { [source: string]: number },   // Solo si hay DataPlane
    uniqueSensorIds: string[],                          // Solo si hay DataPlane
    timeSpanMs: number,
    avgFps: number,
  },
  frames: CapturedFrame[],
}
```

Workflow para Claude: usuario marca frames con S · descarga JSON · sube a Claude · Claude lee `summary` primero para overview · luego `frames` selectivamente. Patrón conversacional típico: *"te paso captura JSON · revisa el flujo del sensor X"*.

### §7.4 · Export del Trace (Fase 3)

Adicionalmente, dentro de la tab Trace hay botón "↓ trace" que descarga JSON con la correlación heurística calculada para el frame origen actual. Estructura distinta a la captura general · incluye `tokens` extraídos del origen + `config` (ventana, umbral, mismo proto) + `summary.matchedProtocols` + `matches` con score+dt por cada match.

---

## §8 · Tap points · cómo capturar tráfico de un nuevo backend

Si emerge necesidad de capturar de un backend nuevo (ej. CAN bus físico vía gateway), patrón canónico:

### §8.1 · Tap real (suscripción a backend vivo)

`use<Proto>Tap` en `protocols/<proto>/tap.ts` patrón:

```typescript
export function use<Proto>Tap(opts: { active: boolean; onFrame: (f: CapturedFrame) => void }): void {
  const counterRef = useRef(<OFFSET>);
  useEffect(() => {
    if (!opts.active) return;
    // Suscribirse al backend (ej. mgr.subscribe('<proto>', handler))
    const handler = (rawData) => {
      const frame: CapturedFrame = {
        id: ++counterRef.current,
        timestamp: Date.now(),
        tapPointId: '<proto>-real',
        protocolId: '<proto>',
        direction: 'rx',
        raw: serialize(rawData),
        decoded: <Proto>Adapter.decode(serialize(rawData)),
        size: byteLength(rawData),
      };
      opts.onFrame(frame);
    };
    backend.subscribe('<proto>', handler);
    return () => backend.unsubscribe('<proto>', handler);
  }, [opts.active, opts.onFrame]);
}
```

### §8.2 · Tap sim (generador sintético)

`use<Proto>SimTap` consume `<Proto>Simulator` (clase con métodos `start(onFrame)` y `stop()`):

```typescript
export function use<Proto>SimTap(opts: { active: boolean; onFrame: (f: CapturedFrame) => void }): void {
  const simRef = useRef<<Proto>Simulator | null>(null);
  useEffect(() => {
    if (!opts.active) return;
    simRef.current = new <Proto>Simulator();
    simRef.current.start(opts.onFrame);
    return () => simRef.current?.stop();
  }, [opts.active, opts.onFrame]);
}
```

El simulador en `protocols/<proto>/simulator.ts` genera frames sintéticos a intervalo controlado · útil para desarrollo offline y para validar que las vistas funcionan sin backend real activo.

---

## §9 · Estado de validación · al cierre s152

**T-S152-VALIDACION · bloqueante para frentes superiores**: 4 fases NO validadas empíricamente.

| Fase | Componente principal | Validación |
|---|---|---|
| Fase 1 | DataPlane adapter + tap + simulator | ✓ implícita (Fase 2 captura DataPlane real) |
| Fase 1.5 | exportCapture · 3 modos · tecla S | ✗ **pendiente s153** |
| Fase 2 | DataPlaneScopeView (osciloscopio) | ✓ Manuel *"Todo funciona"* |
| Fase 2b | DataPlaneConstellation (SIM_CATALOG) | ✗ **pendiente s153** |
| Fase 2c | DataPlaneStatsView (por source) | ✗ **pendiente s153** |
| Fase 3 | TraceView + correlation engine | ✗ **pendiente s153** |

Plan de validación Paso 1 obligatorio s153 (30-45 min): activar DataPlane Sim + DataPlane Real + MQTT Sim + Internal Sim simultáneamente · acumular 30s · probar las 4 fases end-to-end. Protocolo detallado en `lru_handoff_s152_s153.md §4.A`.

---

## §10 · Frentes futuros articulados · NO materializar sin arbitraje

Articulados en alfiler s152 §6 · listados aquí por completitud. **Disciplina P11**: no materializar sin Manuel arbitrando.

### Fase 4 · LatencyAnalyzer producer→consumer (~2h)
Instrumentación lado lector (IB_04 bindings · RegistryBridge · sliders) para emparejar `write → read` del mismo slot. Completa el viewer DataPlane con dimensión temporal causal (no solo correlación heurística como Fase 3).

### Fase 5 · Replay capture → DataPlane (~3h)
Botón "Replay capture → DataPlane" que reescribe writes capturados en orden temporal. Primera materialización del modelo multipista s22. Requiere coordinación con SimService (¿quién es `lastWriter` durante replay?).

### Fase 6 · Extracción Debug1 viewer externo (~6-8h · alto riesgo)
Refactor extractivo del viewer DataPlane fuera de Analyzer1 · cierra completamente T-S55-A2 (M6 SessionRecording como viewer externo). Material articulado · NO materializado.

### Cristalización canónica del patrón "vista hermana adaptativa por protocolo" (~30 min)
3 aplicaciones formales en s152 · candidato firme a destilado Anillo 2 con nombre propio.

---

## §11 · Glosario rápido

| Término | Significado |
|---|---|
| **Adapter** | Implementación de `ProtocolAdapter` · decodifica raw → DecodedFrame · puro · sin estado salvo cache LRU |
| **Tap point** | Hook React que captura tráfico vivo · uno por backend · firma `(active, onFrame)` |
| **Simulator** | Clase que genera frames sintéticos · método `start(onFrame)/stop()` |
| **CapturedFrame** | Unidad de captura · id + timestamp + tapPointId + protocolId + direction + raw + decoded + size + starred |
| **DecodedFrame** | Resultado de adapter.decode(raw) · summary + fields[] + errors[] |
| **Counter offset** | Cada protocolo arranca contador en offset distinto · evita colisiones cross-protocol |
| **Vista hermana** | Sub-patrón s152 · componente nuevo `<Proto><View>` mismo prop shape · selección por switch case · NO modifica original |
| **identityTokens** | Cadenas que identifican un frame · usadas como query en `computeTrace` |
| **searchableContent** | Texto del frame donde se buscan tokens de otros · normalizado lowercase |
| **Star (★)** | Marca de frame por usuario · tecla S · export selectivo |
| **Freeze** | Congela vista · sigue capturando en buffer · sin perder frames |
| **Smart filter** | Chips de filtro automáticos por proto/dir/type detectados en buffer |

---

## §12 · Citas gold del Analyzer1 (Patrón 3 · preservación literal)

> *"saber si una señal entra por un sitio y llega a otro o por donde va pasando"* — Manuel s152 · materializada como Fase 3 TraceView heurístico.

> Manuel arbitrando arquitectura de Fase 2: *"prefiero crear una vista nueva hermana en lugar de modificar la existente"* — paráfrasis empírica · cristalizó el sub-patrón "vista hermana adaptativa por protocolo" con 3 aplicaciones formales en sesión única.

---

## §13 · Cierre

Analyzer1 al cierre s152 es **6 protocolos + 7 vistas + 3 contratos canónicos + correlation engine + export estructurado** · ~330 KB de código fuente · inauguración del subsistema Debug1 viewer documentado como gap mayor desde s55.

**Disciplina mantenida**:
- P11 anti-anticipación: 5 protocolos planned sin adapter · esperan trigger natural.
- P12 hardware físico como sustrato: el DataPlane (slots Float64Array) es sustrato · las vistas son lectura/visualización.
- Patrón 3 preservación voz: 2 citas gold s152 + nomenclatura preservada (sigla `DP` para DataPlane · prefijo `Data Plane*` para hermanos).
- Patrón 6 honest pushback: T-S152-VALIDACION bloqueante explícito.
- Disciplina alfiler s125: 3ª aplicación operativa con `lru_alfiler_dataplane_viewer_s152.md`.

Si vas a tocar Analyzer1 en sesión futura, **regenera este doc** cuando: añadas 7º protocolo · 8ª vista hermana adaptativa · cambies contrato `ProtocolAdapter`/`TapPoint`/`CapturedFrame` · materialices Fase 4/5/6. Conserva el sufijo `_sNNN` · el doc anterior queda en git como foto histórica.

---

*Fin del documento · `lru_analyzer1_referencia_operativa_s152.md` · 2026-05-21 · Manuel & Claude Opus 4.7 · referencia operativa Anillo 2 · estado completo Analyzer1 al cierre s152 (6 protocolos + 7 vistas + 4 contratos canónicos + correlation engine + export 3 modos) · 13 secciones · ~30 KB · si Claude futuro arranca sesión que toca Analyzer1, leer este doc primero ahorra ~330 KB de auditoría de código · regenerar cuando emerja extensión estructural (7º protocolo · 8ª vista hermana · nuevo contrato)*
