8.7 KiB
Continue tomorrow
Fecha de corte: 2026-05-29. Rama: active-uix.
TL;DR de la sesión
V1 del editor Words ELIMINADO. V2 es ahora el único motor.
La sesión arrancó con una auditoría del componente Words
(codex-full-audit.md en la raíz) y la pregunta del usuario: "elimina
v1 y continua v2, ¿qué sentido tiene v1?". Decisión firmada y
ejecutada de cabo a rabo (F1 → F6). Ya no hay coexistencia V1/V2 ni
migrador: el modelo de documento público es WordsDocumentV2 y punto.
Decisiones firmadas (vinculantes)
- D1 = "V2 puro, sin legacy": borrados
engine/document.ts+engine/migrate-v2.ts. SIN importador de retrocompatibilidad. La API pública pasa deWordsDocument→WordsDocumentV2. Los docs persistidos en V1 dejan de cargar (ruptura aceptada por el usuario). - D2 = "Aceptar el drop": eliminados por completo los controles /
props / commands / atributos morfo de tabla
striped,compactycell-tone. NO se re-mapean ni se re-portan.
Qué se borró (V1) y a dónde se movió (V2)
Borrado — motor V1 (engine/*.ts):
commands.ts, document.ts, dom-selection.ts, engine.test.ts,
find-replace.ts, history.ts, index.ts (barrel V1), input.ts,
migrate-v2.ts (+test), operations.ts, render.ts,
serialize-html.ts, serialize-json.ts, serialize-markdown.ts,
serialize-text.ts.
Borrado — árbol extensions/ entero: extension-registry (+test),
extension-types, image/*, table/*. El modelo V2 no usa el sistema
de extensiones; tabla/imagen/divider/callout son bloques nativos del
union WordsBlockV2.
El motor V2 vive SOLO en engine/operations-v2/ + un puñado de
.ts en la raíz de engine/ (types-v2, validate-v2, normalize,
render-v2, serialize-html-v2, serialize-markdown-v2, sema-parity,
code-highlight, path, selection, dom). Esta tanda portó al namespace
V2 lo que faltaba de V1: commands, history, input,
find-replace, render-dom, serialize-text, extra-ops,
insert-block-types, markdown (input-rule shortcuts), factories,
dom-helpers, dom-selection — además de cerrar R4A.2→R4A.8
(text / delete / marks-ops / paragraph-ops / delete-ops / block-format /
list-ops / link-ops / table-ops / selection-walkers / inline-split).
NO existe parser HTML / Markdown / JSON-schema en V2. Las
serializaciones HTML y Markdown son export-only (lossy → sin
inverso fiel). El import sólo acepta JSON (JSON.parse +
validateWordsDocument) y texto plano (parseWordsPlainText).
Superficie pública V2 (lo que consume cualquier app)
- Tipos:
WordsDocumentV2,WordsBlockV2,WordsInlineV2,WordsSelection,WordsExportFormat,WordsImportFormat— todos re-exportados desde$soma/components/words. WORDS_DOCUMENT_VERSION_V2 = '2.0.0'desdeengine/types-v2.- Provider (
words-provider.svelte.ts):importContent(text + json),exportContent(json / text / html / markdown),plainTextderivado víarenderWordsPlainText. - Serializers:
serializeHtmlV2(doc),serializeMarkdownV2(doc),renderWordsPlainText(doc),renderWordsDocumentV2,renderWordsDomHtml/Pretty. - Comando central:
applyWordsCommand(state, WordsCommandV2)enoperations-v2/commands.ts.
Forma de los contenedores V2 (recordatorio — NO hay discriminador type en sub-nodos)
- Tabla:
{ type:'table', rows, headerRow?, headerCol? }; fila{ cells, visual? }; celda{ children, align?, verticalAlign?, colspan?, rowspan?, visual? }. Celda usaalign, notextAlign. - Lista:
{ type:'list', kind, items }; item{ children, checked?, indent? }.items, nochildren. Sintype:'list-item'. - Bloques con alineación: paragraph/heading/quote llevan
textAlign?(a nivel bloque).
⚠️ Decisión consecuente NO firmada — export HTML
serializeHtmlV2 emite HTML semántico limpio, no un formato
roundtrip-lossless. Como V2 no tiene parser HTML, HTML y Markdown son
export-only. Si el usuario quería export HTML roundtrip-friendly (re-
importable), es un encargo aparte. Pendiente de confirmar con él.
Verificación al cierre (todo verde)
| Gate | Status | Notas |
|---|---|---|
npm run check |
0 errors / 5168 files | 26 warnings pre-existentes, ninguno en archivos tocados |
npx vitest run src/uix/soma/components/words |
455/456 | el único fallo es el flake de sema-parity por timeout 5s bajo carga paralela |
sema-parity aislado |
6/6 en 362ms | confirma que el flake es de infra, no regresión |
npm run morfo:vocabulary |
exit 0 | sólo WARN suaves (vocabularios noveles legítimos) |
Browser smoke /uix/components/words |
OK | mount limpio, 0 console errors |
Smoke detallado: el doc sample V2 renderiza (tabla 2×2 con
headerRow, 4 list-items incl. el indentado); export markdown emite
tabla GFM válida; import texto round-trip ("imported text"); import
JSON válido round-trip a través del gate ("imported json"); import
JSON inválido (versión mala) → "invalid json" y deja el doc intacto
(la razón de añadir el gate validateWordsDocument: un doc malo
asignado al value bindeado rompería los $derived).
Consumidores re-cableados a V2
words-provider.svelte.ts+words-provider.svelte.test.tsexports.ts+types.ts(superficie pública)morfo/components/words.ts(drop de atributos striped/compact/tone)- eidos:
words.svelte,words-drawer.svelte,words-block-handle,words-block-inserter,words-command-icon,words-heading-picker,words-toolbar-family-menu,words.css,types.ts - soma
components/words.svelte test/words-content-harness.svelte(importaba el barrel V1 borrado; reescrito aoperations-v2+types-v2+WordsDocumentV2)web/routes/uix/components/words/+page.svelte(último consumidor; imports V2, importFormats →['json','text'], docs sample/empty/long a forma V2, walkersreadPlainText/blockToPlainText/readInlineTextsobre el union V2,exportWordsDocument+importDraftDocumentreescritos, prosa de la API-tab limpiada de striped/tone)
Cerrado en la continuación (2026-05-29)
✅ Limpieza de huérfanos del drop D2
Borrados los selectores CSS muertos de words.css
([data-command='table-cell-tone-*'], table[data-words-table-striped],
[data-words-table-compact], [data-words-cell-tone] + focus-within, y
los [data-words-cell-header] huérfanos — los headers se renderizan como
<th>). README actualizado a la realidad V2 (tabla lista solo formato
vivo; HTML/MD export-only; import JSON + texto). ARCHITECTURE_PROPOSAL.md
intacto: documenta la decisión de eliminarlos, no features stale.
Verificado en browser (tabla 2×2 renderiza, <th> conserva su tinte vía
:where(th)). Commit 4a0661a5.
✅ R5 — POLISH-1b (image visuals)
El panel de imagen del drawer
(eidos/components/words/words-drawer.svelte > imagePanel) ya tenía radius
slider + shadow/border toggles. Añadido lo que faltaba: shadow blur
slider, shadow color picker, border color picker y background
color picker, vía un snippet reutilizable imageColorField (presets +
<input type=color> + clear opcional), mismo patrón que el color de texto
del panel format. Todos despachan setBlockVisual → block.visual.* →
visualToStyle → inline style en el <figure>. Verificado en browser: el
panel renderiza los 4 controles nuevos; click en swatch de Background
actualiza el figure (background-color:#22c55e) preservando
radius/border/shadow (shallow-merge correcto). npm run check 0 errors.
Pendiente para mañana
P1 — Drag handle FUERA del rail sobre bloques <code> (heredado)
El grip se va fuera de la rail al hacer hover sobre un code block. Sin diagnosticar. Lugar: `eidos/components/words/words-block-handle.svelte
measureFromEl()
. Pasos: comparargetBoundingClientRect().leftdevs
; si difieren, buscar padding/margin/transform en[data-words-content] :where(pre)enwords.css`.
P1 — Heading inline level change (h1 ↔ h2 ↔ h3) (heredado)
Cambiar nivel de heading inline sin abrir drawer. Recomendación:
empezar por el Block panel del drawer (verificar que el HeadingPicker
se muestra cuando currentBlock === 'heading').
P2 — Heredados
- POLISH-3: topbar del demo (breadcrumb, Edit/Preview, Saved).
- WORDS-DRAGDROP-SOMA: migrar drag-drop a soma
DragDrop.Provideren vez de HTML5 nativo (intento previo falló — requiere reestructurar el render del engine).
Notas de infra
sema-parity.test.tsflakea por timeout de 5s sólo bajo carga paralela (full-suite). Aislado pasa 6/6 en <500ms. Si molesta, subir eltestTimeoutde ese archivo; no es regresión..claude/scheduled_tasks.lockes un artefacto transitorio — NO commitear.