**F2.3 pendiente — los 4 sub-pasos restantes son el refactor difícil**:
7. **F2.3h** — operations.ts insertTable / table-row / table-cell / etc. → `extensions/table/operations.ts` (~400-500 LoC, lo más entrelazado)
8. **F2.3i** — wire `tableExtension: WordsExtension` al registry desde la construction del engine. El engine consulta el registry para rutas table; fallback al hardcoded path si no se encuentra.
- **F2.3f** — path.ts navigation. Las refs de table están en BRANCHES dentro de funciones grandes (`resolvePath`, `updateNode`, `inferContainerKind`), NO en helpers aislados. Extracción requiere:
- O bien: el engine consulta registry sólo para "is this a node my extension owns?" y el resto del walk queda en engine
Después F2.4 (code-block, similar plan), F2.5 (docs `EXTENSIONS.md`), F2.6 (verify final).
- Reflexión: ¿cabe redibujar el dispatcher al estilo visitor pattern? Sería más limpio.
**Riesgos del F2.3 completo**:
- **F2.3g** — normalize.ts. Mismo patrón: branches dentro de `normalizeBlock` / `normalizeNode`. Extracción requiere mismo enfoque que F2.3f.
- operations.ts es 2620 líneas con table refs muy entrelazadas con el normalize cascade
- Importante: NO mover operations sin haber cabledado el registry primero (sino tests del motor rompen)
- **F2.3h** — operations.ts (2620 LoC, ~400-500 LoC table). Las funciones `insertTable*`, `deleteTable*`, `toggle-table-*` son funciones standalone — extraíbles. Pero comparten utilities (`tableCellOptions`, `tableOptions`, `replaceAt`) que viven en el engine. Extraer requiere:
- Sugerencia: hacer F2.3i (wire registry con stub table extension vacía) ANTES de F2.3h, así operations.ts se reescribe contra una API estable
- Mover utilities a `extensions/table/utils.ts` o re-exportar desde engine
- Mover los ~20 reducers a `extensions/table/operations.ts`
- El dispatcher central (`applyWordsCommand`) consulta registry.getCommand(opType) y fallback al switch existente
- **F2.3i** — registry wire-up. Crear `tableExtension: WordsExtension` que cabledea TODOS los hooks (commands, render, serialize, etc.) al registry. El engine constructor registra `tableExtension` por defecto para backward compatibility. Después el dispatcher reescrito consulta registry.
- **F2.3j** — verify final.
**Recomendación de orden para próxima sesión** (lo que dije y se ha confirmado al hacer F2.3a-e):
1. Antes de F2.3f/g/h, hacer **F2.3i con stub vacía**: construir `tableExtension: WordsExtension` que registra sólo nodeTypes ['table','table-row','table-cell'], commandNames y events. El engine al boot lo registra. Después en h-i se mueve la lógica gradualmente hacia los hooks.
2. **F2.3h primero** (operations) usando el stub. Cada reducer extraído pasa de `case 'insertTable':` en switch a entrada en `extension.commands`. El switch del engine consulta registry.getCommand() antes del fallback.
3. **F2.3f y F2.3g** al final, donde el engine ya consulta registry para todo el resto.
**Estado del extension system** después de hoy:
- `WordsExtension` interface ✅ (F2.2)
- `WordsExtensionRegistry` con 14 tests verdes ✅ (F2.2)