block-handle (también removed). Gutter overlays son ahora
AMBIENT — no se iluminan en hover.
## Sprint Words V2 architecture — R1 cerrado
Tras la discusión de arquitectura (separación contenido/diseño, P1-P8 + decisiones D-SEM-1/2/3 + Q1-Q6), R1 está cerrado.
**Doctrina firmada** (full text en `src/uix/soma/components/words/ARCHITECTURE_PROPOSAL.md`):
- P1-P8 principios firmados (incluido P6 Single Source of Truth + P7 Vocabulario evaluativo único + P8 reglas para qué entra al modelo)
- D-SEM-2 → `CalloutBlock.intent` usa `SemaIntent` canónico (no `warning/info/success/danger`)
- D-Q1-Q6 → id opcional autogenerado, MD lossy total, no presets en core, engine package en R5 (opcional)
**Implementado en R1**:
- `engine/types-v2.ts` (~300 líneas): WordsDocumentV2 v2.0.0, BlockBase con `id` + `visual` opcionales, BlockVisual RAW (números px + hex), per-type `Pick<>` (ParagraphVisual/HeadingVisual/QuoteVisual/CodeVisual/ListVisual/TableVisual/ImageVisual/DividerVisual/CalloutVisual), 9 bloques (paragraph/heading/quote/code/list/table/image + **divider** y **callout** nuevos), marks structured (`{type:'color'|'background', value:'#hex'}` en vez de template literal V1), `WordsEvalIntent` declarado localmente para evitar dependency a `$uix/sema` (con plan de runtime parity assertion).
- `engine/validate-v2.ts` (~500 líneas): validador puro `validateWordsDocument(input) → ValidationResult`. 7 reglas duras + 11 códigos de error. Path JSON-pointer en cada error.
- `engine/validate-v2.test.ts` (50 tests): cubre topo, todos los block types, marks (boolean + structured + rechazo del format V1 + rechazo de tokens), visual con whitelist per-type (P8), id uniqueness, callout SemaIntent + rechazo de "warning"/"info"/etc., divider, quote.cite, link nesting + URL parseability, table headerRow/headerCol/per-cell+per-row visual.
**Estado tras R1**: 135/135 engine tests (85 V1 + 50 V2) · `npm run check` 0 errors. V1 sigue intacto, V2 en paralelo.