# Fase Factura 2 — objetos visuales en celdas TTable

## Implementación

La fachada no construye `hContent`, `hObject`, `hSections`, `aLines` ni `aCells`. Resuelve una única `TTable` y delega la creación en `TTable.createObjectInTableCell()`. La tabla ejecuta `createTableCellObject()`, aplica defaults reales, crea y vincula el objeto. Las propiedades solicitadas se aplican después mediante `TDesignerPanelProps.applyPropertyValue()` y la tabla sincroniza su contenido mediante su API pública.

Shape final:

```json
{
  "command": "create",
  "ref": "txt1",
  "type": "TText",
  "targetCell": {
    "table": { "ref": "tabla1" },
    "section": "header",
    "lineIndex": 0,
    "cellIndex": 0
  },
  "properties": { "cText": "\"Título\"" }
}
```

`targetCell.table` admite las identidades ya existentes: `"selection"`, `{"ids":["id_real"]}` y `{"ref":"tabla1"}`. La celda se identifica exclusivamente mediante `section`, `lineIndex` y `cellIndex`.

## Auditoría manual

1. La herramienta activa admite `TText`, `richText`, `TBarcode` o `TImage`.
2. `tryCreateObjectInTableCell()` calcula el punto del documento y busca una celda mediante `findTableCellAtPoint()`.
3. Si el tipo no coincide con el contenido existente, registra historial manual.
4. Llama a `TTable.createObjectInTableCell()`.
5. Si existe el mismo tipo, devuelve el objeto existente; si el tipo cambia, sustituye el contenido único.
6. `createTableCellObject()` instancia el tipo real, aplica defaults de celda, llama `create()` y ejecuta `bindTableCellObject()`.
7. La vinculación fija tabla, sección, línea, celda y capa; el ID real lo genera la tabla.
8. El camino manual cancela la herramienta, selecciona el objeto, refresca diseñador, propiedades, lista, JSON y estado, y marca el documento modificado.

No existe multicontenido. `TFormattedText` no está soportado manualmente en celdas y Commands lo rechaza.

## Pruebas deterministas

Resultado: **10 PASS / 0 FAIL**.

Cubren TText en header/detail, tabla existente, tabla por `ref`, propiedades y delete mediante `ref`, TBarcode, richText, TImage, rechazo esperado de TFormattedText, celda ocupada, sección/línea/celda/tabla inválidas, plan completo de cuatro títulos, atomicidad, rollback, Undo y Redo.

## GPT-OSS real

Se usó exclusivamente `gpt-oss:20b`, `think=low`. Se ejecutaron seis casos únicos. C y D se repitieron una vez tras una única aclaración genérica del contexto; resultado final: **5 PASS / 1 FAIL**.

| Caso | Resultado final | ms | tokens entrada | tokens salida | Observación |
|---|---:|---:|---:|---:|---|
| A | PASS | 6811.0 | 4912 | 303 | Cabecera de 4 columnas y 4 títulos |
| B | PASS | 4253.0 | 4881 | 224 | Detalle de 3 columnas con A/B/C |
| C | FAIL | 4139.0 | 4962 | 127 | Crea tabla y cuatro celdas, pero omite los títulos |
| D | PASS | 8210.2 | 5085 | 382 | Fondo azul oscuro y cuatro títulos blancos |
| E | PASS | 5061.9 | 4855 | 310 | Cuatro textos distintos |
| F | PASS | 8380.9 | 4985 | 431 | Cabecera poblada y detalle vacío |

Mediana final: **5936,45 ms**. Vacíos: **0**. Errores contractuales finales: **0**. Hubo un elemento incompleto en la primera ejecución de D; la fachada rechazó toda la transacción y la repetición corregida fue válida. Estructura privada generada: **0**.

## Tamaño del prompt

Medición representativa con la misma instrucción y el bloque añadido como única diferencia:

- Antes: 19.228 caracteres, 4.807 tokens estimados.
- Después: 19.768 caracteres, 4.942 tokens estimados.
- Incremento: 540 caracteres, 135 tokens estimados.

## Conclusión

La capacidad cumple el umbral indicado de 5/6 sin errores peligrosos. El único fallo restante es de interpretación: GPT-OSS entiende la estructura de “cabecera de factura”, pero omite los literales. No se añadió una regla específica para esa frase. Ya se puede avanzar a la fase de campos y variables disponibles.

## Archivos modificados

- `public/js/Designer/TDesignerCommandFacade.js`
- `public/IA/TLLDominusIA.php`
- `tests/designer/designer-command-create-table-cell.spec.js`
- `tests/ia/tools/run_factura2_table_cell_gptoss.cjs`
