# Auditoria Engine PHP y portabilidad Harbour

Fecha: 2026-07-08

Alcance: `cliente/php`, `servidor/php`, `public/motor`, `public/php` y clases usadas por `preview.php`, `export_ir.php` y runtime.

No se proponen cambios productivos en esta fase. Este documento describe el estado actual, riesgos y orden recomendado de limpieza antes de portar a Harbour.

## Resumen ejecutivo

El Engine PHP ya tiene una separacion inicial valida entre plantilla, datos, contexto, evaluador, composicion, paginacion, documento renderizable y renderizador. La direccion arquitectonica es correcta, pero todavia no esta suficientemente limpio para portarlo a Harbour sin arrastrar deuda.

Los puntos mas delicados son:

- `TTable`: concentra modelo, normalizacion, runtime de tabla, paginacion interna, grupos, acumuladores y composicion de celdas. Es la clase mas dificil de portar.
- `TEvaluadorFormulas`: mezcla parser, evaluador, resolucion de variables y funciones internas de paginacion/runtime.
- `TFuncFormulas`: biblioteca de funciones LL12/Dominus con responsabilidades heterogeneas, incluyendo fechas, transformacion, barcode y lectura de ficheros.
- `TPreviewPHP`: mezcla fachada servidor, paginacion previa, creacion de ficheros temporales, progreso, ejecucion del engine, HTML/CSS/JS de viewer y resolucion de rutas.
- `TSalidaHTML`: esta correctamente aislada como renderer HTML, pero es demasiado grande y mezcla estilos, conversion de unidades y render de todos los tipos.
- `public/php` es modelo compartido, pero tambien contiene metadatos de UI (`getProperties`) y generacion de renderizables (`generarRenderizable`). Para Harbour conviene aislar esas responsabilidades aunque se mantenga compatibilidad en PHP.

Conclusion: no conviene portar directamente. Primero hay que extraer un nucleo minimo que haga:

```text
.lbl / plantilla normalizada + datos
  -> contexto runtime
  -> IR / TDocumentoRenderizable
```

Sin web, sin HTML, sin importador y sin diseñador.

## Diagrama de capas objetivo

```text
Client API
  TLLDominusPHP
      |
Engine Facade
  TEngineRuntime / TPreviewRuntime / TIRRuntime
      |
Template Model
  TDocument, TObjectBase, TText, TRectangle, TEllipse, TLine, TImage, TBarcode
  TTableModel, TTableSection, TTableLine, TTableCell
      |
Runtime Context
  TContextoEjecucion, TConectorDatos, TEstadoEjecucion, TAvisosRuntime
      |
Formula Engine
  TEvaluadorFormulas, TFormulaParser, TFormulaAst, TFormulaRuntimeFunctions, TFuncFormulas
      |
Table Runtime
  TTableRuntime, TTablePaginator, TTableComposer, TAccumulatorRuntime, TGroupRuntime
      |
Pagination Engine
  TMotorPaginacion, TLabelPaginator, TReportPaginator
      |
IR Builder
  TMotorEjecucion, TMotorComposicion, TDocumentoRenderizable
      |
Renderers
  TRenderizador + TSalidaHTML
  futuro Harbour/GDI Renderer
  futuro Printer Renderer
```

Regla objetivo: todo lo que este por encima de `IR Builder` puede existir en PHP sin portarse a Harbour. Todo lo que este por debajo de `Client API` no debe depender de `$_POST`, `php://input`, rutas web, HTML, CSS, JS ni `tempnam`.

## Inventario de clases

| Clase | Archivo | Clasificacion | Responsabilidad actual | Metodos principales | Dependencias | Problemas detectados | SRP | Dividir | Port Harbour |
|---|---|---|---|---|---|---|---|---|---|
| `TLLDominusPHP` | `cliente/php/TLLDominusPHP.php` | Cliente | API cliente: abre job, filtra variables usadas, recibe datos y lanza preview. | `OpenJob`, `CloseJob`, `Preview`, `SendDataVar`, `SendDetalle`, `IsUsedVar`, `SetEtiquetaInicial` | Plantillas en `lbl`, `TPreviewPHP`, estructura JSON del job | Analisis de variables por regex dentro del cliente; dependencia de ruta `lbl`; `Preview` instancia servidor directo. | Parcial | Si | Parcial |
| `TPreviewPHP` | `servidor/php/TPreviewPHP.php` | Servidor/Fachada | Ejecuta jobs del cliente y genera HTML de preview multipagina. | `Preview`, `generarPreviewHtml`, `generarPaginasRuntime`, `ejecutarMotor`, `renderizarPaginas` | Todo el engine, rutas de proyecto, ficheros temporales, `TSalidaHTML`, JS/CSS embebido | Mezcla fachada, runtime, pre-paginacion, viewer HTML, progreso, rutas y temporales. Clase demasiado grande. | No | Si | No |
| `TObjectBase` | `public/php/TObjectBase.php` | Modelo de plantilla | Propiedades comunes, serializacion base, UI de propiedades y visibilidad runtime. | `getProperties`, `save`, `load`, `generarBaseRenderizable`, `esVisibleEnEjecucion` | `TContextoEjecucion` por contrato dinamico | Mezcla modelo, metadatos UI y ayuda de composicion runtime. | Parcial | Si | Si, sin UI |
| `TDocument` | `public/php/TDocument.php` | Modelo de plantilla | Documento/plantilla: papel, objetos, variables, label layout, carga/guarda. | `save`, `load`, `createObjectByType`, `normalizeZIndex`, `isLabelDocument` | Clases de objetos `T*` | Modelo bastante claro, pero normaliza layout y crea objetos por switch. `isListDocument` devuelve siempre false. | Si | No urgente | Si |
| `TRectangle` | `public/php/TRectangle.php` | Modelo de plantilla | Rectangulo visual y renderizable. | `getProperties`, `generarRenderizable` | `TObjectBase`, contexto runtime | Correcta, aunque comparte el problema modelo/UI/renderizable. | Parcial | No urgente | Si |
| `TEllipse` | `public/php/TEllipse.php` | Modelo de plantilla | Elipse visual y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, contexto runtime | Correcta, problema comun modelo/UI/renderizable. | Parcial | No urgente | Si |
| `TLine` | `public/php/TLine.php` | Modelo de plantilla | Linea visual y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, contexto runtime | Correcta, problema comun modelo/UI/renderizable. | Parcial | No urgente | Si |
| `TText` | `public/php/TText.php` | Modelo de plantilla | Texto, propiedades tipograficas, normalizacion y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, contexto runtime | Mezcla metadatos UI, evaluacion de color y composicion IR. | Parcial | Recomendable | Si |
| `TBarcode` | `public/php/TBarcode.php` | Modelo de plantilla | Codigo de barras, propiedades y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, `TBarcodeUtil`, contexto runtime | Correcta, pero debe separar modelo y generacion IR para port limpio. | Parcial | Recomendable | Si |
| `TImage` | `public/php/TImage.php` | Modelo de plantilla | Imagen, origen, propiedades y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, `TImageUtil`, contexto runtime | `TImageUtil` resuelve rutas/contenido; riesgo de dependencia filesystem. | Parcial | Recomendable | Si, parcial |
| `TTable` | `public/php/TTable.php` | Tabla/Paginacion | Tabla completa: modelo, normalizacion, secciones, grupos, acumuladores, paginacion interna y renderizables. | `save`, `load`, `generarRenderizable`, `renderSectionLines`, `pushRecordVariables`, `acumularDetalle`, normalizadores | `TRectangle`, `TText`, `TBarcode`, `TImage`, contexto runtime | Clase gigante. Mezcla modelo, runtime, paginacion, composicion, acumuladores, grupos y reglas visuales. Principal bloqueo para Harbour. | No | Si, obligatorio | Si, tras dividir |
| `TPlantilla` | `public/motor/clases/TPlantilla.php` | Modelo de plantilla | Carga/normaliza plantilla JSON y expone pagina, objetos, vars y layout de etiquetas. | `create`, `fromData`, `getPagina`, `getObjetos`, `getUserVars`, `getAcumVars`, `getLabelLayout` | `LLDominus\TDocument`, filesystem JSON | Mezcla loader de fichero y wrapper de modelo; normalizacion legacy minima. | Parcial | Recomendable | Si, como loader separado |
| `TConectorDatos` | `public/motor/clases/TConectorDatos.php` | Runtime Context | Carga datos JSON y expone variables/registro detalle normalizados. | `create`, `getVariables`, `getData`, `getRegistrosDetalle`, `normalizarDatosRuntime` | Filesystem, JSON, estructura LL12 `DataVar`/`DetalleVar` | Mezcla carga de fichero, normalizacion LL12, validacion, variables binarias y adaptador runtime. | Parcial | Si | Si, sin filesystem |
| `TContextoEjecucion` | `public/motor/clases/TContextoEjecucion.php` | Runtime Context | Estado runtime: variables, pagina, registros, acumuladores, avisos y evaluacion. | `getVariables`, `pushRegistroDetalle`, `setEstadoPagina`, `acumularDetalle`, `evaluarFormula`, `evaluarCondicion` | `TConectorDatos`, `TEvaluadorFormulas` | Bastante central; mezcla estado, acumuladores y puente al evaluador. Puede crecer demasiado. | Parcial | Recomendable | Si |
| `TEvaluadorFormulas` | `public/motor/clases/TEvaluadorFormulas.php` | Formulas | Evalua expresiones sin `eval`, texto, condiciones, aritmetica, comparaciones y funciones runtime. | `evaluarFormula`, `evaluarTexto`, `evaluarCondicion`, separadores, funciones internas | `TFuncFormulas`, estado runtime | Mezcla parser, evaluador, resolucion de variables, funciones internas `PageBy`/grupo. Dificil de validar formalmente. | No | Si, obligatorio | Si, tras parser claro |
| `TFuncFormulas` | `public/motor/clases/TFuncFormulas.php` | Formulas | Biblioteca de funciones Dominus/LL12. | `ejecutar`, `Abs`, `Transform`, `DToC`, `FStr`/equivalentes, `Barcode`, etc. | `TBarcodeUtil`, `DateTimeImmutable`, filesystem en funciones tipo memo | Clase grande y heterogenea; algunas funciones tienen efectos/entorno. | Parcial | Si | Si, parcial |
| `TBarcodeUtil` | `public/motor/clases/TBarcodeUtil.php` | Utilidad | Normaliza y calcula barcode, especialmente EAN13. | `crear`, `normalizarTipo`, `crearEAN13` | Ninguna externa relevante | Correcta y pequena. | Si | No | Si |
| `TImageUtil` | `public/motor/clases/TImageUtil.php` | Utilidad | Resuelve imagen desde contenido/ruta y MIME. | `resolver`, `detectarMime`, `resolverRuta` | Filesystem, rutas relativas al proyecto | Utilidad mezcla contenido y resolucion de rutas PHP/web. | Parcial | Recomendable | Parcial |
| `TMotorComposicion` | `public/motor/clases/TMotorComposicion.php` | Engine Core | Delega composicion en objetos con `generarRenderizable`. | `componer` | Objetos modelo con metodo runtime | Muy simple, pero la responsabilidad real esta en objetos. | Si | No | Si |
| `TMotorPaginacion` | `public/motor/clases/TMotorPaginacion.php` | Pagination Engine | Paginacion actual simple: crea una pagina con objetos. | `paginar` | `TDocumentoRenderizable` | Es placeholder; la paginacion real vive en `TTable` y `TPreviewPHP`. | Parcial | Si | Si, tras mover logica |
| `TMotorEjecucion` | `public/motor/clases/TMotorEjecucion.php` | Engine Core | Coordina plantilla, datos, composicion, paginacion y etiquetas. | `ejecutar`, `ejecutarEtiquetas`, `agregarRenderizableCompuesto` | `TPlantilla`, `TConectorDatos`, `TMotorComposicion`, `TMotorPaginacion`, `TContextoEjecucion` | Mezcla flujo general con layout/paginacion de etiquetas. | Parcial | Recomendable | Si |
| `TDocumentoRenderizable` | `public/motor/clases/TDocumentoRenderizable.php` | IR Builder | Documento intermedio con paginas y objetos resueltos. | `setTamano`, `addPagina`, `getPaginas` | Ninguna relevante | Correcta, aunque necesita schema mas explicito para port. | Si | No | Si |
| `TRenderizador` | `public/motor/clases/TRenderizador.php` | Renderer HTML | Recorre IR y delega en salida concreta. | `render`, `renderObjeto` | `TDocumentoRenderizable`, salida con metodos `texto`, `rectangulo`, etc. | Correcta. Switch por tipo aceptable; podria formalizar interfaz. | Si | No urgente | Parcial |
| `TSalidaHTML` | `public/motor/clases/TSalidaHtml.php` | Renderer HTML | Convierte IR a HTML/CSS. | `iniciarDocumento`, `iniciarPagina`, `texto`, `rectangulo`, `barcode`, `imagen`, helpers CSS | HTML/CSS, escaping, unidades CSS | Grande y monolitica. Esta bien que sea no portable, pero conviene dividir por objeto. | Parcial | Recomendable | No |
| `TNormalizadorFuncionesLL12` | `public/motor/herramientas/TBaseLenguajeLL12.php` | Importador LL12 | Normaliza nombres de funciones LL12. | metodos de normalizacion | Herramientas LL12 | Herramienta, no runtime. | Si | No | No |
| `TBaseLenguajeLL12` | `public/motor/herramientas/TBaseLenguajeLL12.php` | Importador LL12 | Carga/manualiza base de lenguaje LL12. | `create`, lectores, generadores | PDF/texto/JSON de herramientas | Fuera del engine runtime. | Si | No | No |
| `TExtractorPdfTextoLL12` | `public/motor/herramientas/TBaseLenguajeLL12.php` | Importador LL12 | Extrae texto de PDF/manual LL12. | `extraerTexto` | Sistema/PDF externo segun implementacion | Herramienta no portable al engine. | Si | No | No |
| `TAnalizadorLenguajeLST` | `public/motor/herramientas/TAnalizadorLenguajeLST.php` | Importador LL12 | Analiza LST antiguos para extraer uso de funciones. | `create`, `analizar`, recolectores | `TBaseLenguajeLL12`, filesystem | Grande, pero es herramienta de migracion, no engine. | Parcial | Puede esperar | No |
| `TAnalizadorExpresionesLST` | `public/motor/herramientas/TAnalizadorLenguajeLST.php` | Importador LL12 | Analiza expresiones LST y funciones usadas. | analizadores de expresion | Regex/parser propio | Util para importador, no runtime. | Parcial | Puede esperar | No |
| `TInformeLenguajeLST` | `public/motor/herramientas/TAnalizadorLenguajeLST.php` | Importador LL12 | Genera informe HTML/JSON del analisis LST. | `generar` | HTML, filesystem | Renderer de herramienta. No engine. | Si | No | No |
| `TLenguajeDominusBuilder` | `public/motor/herramientas/generar_lenguaje_dominus.php` | Herramientas/tests | Genera catalogo de lenguaje Dominus desde datos LL12. | `create`, `guardar`, `crearFuncionesDominus` | JSON, docs | Herramienta de build/documentacion. | Si | No | No |
| `TGeneradorManualFunciones` | `public/motor/herramientas/generar_manual_funciones.php` | Herramientas/tests | Genera manual HTML de funciones. | `create`, `generarHtml` | JSON, HTML, docs | Herramienta de documentacion. | Si | No | No |
| `TTablePaginationTestContext` | `public/motor/tests/table_pagination/run_tests.php` | Herramientas/tests | Contexto falso para tests de tabla/paginacion. | metodos stub de contexto | Tests, `TTable` | Solo test. | Si | No | No |

## Scripts y endpoints auditados

| Archivo | Clasificacion | Responsabilidad actual | Problemas | Port Harbour |
|---|---|---|---|---|
| `public/motor/index.php` | Herramientas/tests | Demo manual del motor: carga plantilla/datos y renderiza HTML. | Repite bootstrap de clases. Depende de rutas demo. | No |
| `public/motor/preview.php` | Servidor/Fachada + Designer/UI | Endpoint POST para preview real desde diseñador. Prepara datos demo, ejecuta engine y renderiza HTML integrado. | Mezcla `php://input`, HTTP, preparacion de datos diseñador, engine y renderer. No debe ser nucleo. | No |
| `public/motor/export_ir.php` | Servidor/Fachada + IR Builder | Endpoint POST para generar y guardar IR JSON. | Construccion/guardado de IR esta dentro del endpoint; necesita clase `TIRBuilder`/`TIRExporter`. | Parcial, solo logica IR |
| `public/motor/validar_formula.php` | Servidor/Fachada + Formulas | Endpoint para validar formulas del diseñador. | Depende de POST y HTML de barcode para preview. La validacion core debe ir a clase. | Parcial |
| `public/motor/demo_data.php` | Herramientas/tests | Devuelve datos demo. | Endpoint demo. | No |
| `public/motor/recurso_existe.php` | Utilidad web | Comprueba existencia de recurso. | Web/filesystem, no core. | No |
| `cliente/php/preview_demo.php` | Cliente + demo UI | Demo web/CLI de runtime, progreso y seleccion visual de etiqueta inicial. | Mezcla UI HTML, cliente, demo, seleccion de etiquetas y progreso. | No |
| `public/motor/tests/*/run_tests.php` | Herramientas/tests | Tests de formulas, datos, etiquetas y paginacion. | Correctos como proteccion; no forman engine. | No |

## Clases que forman realmente el Engine

Engine core actual:

- `TPlantilla`
- `TConectorDatos`
- `TContextoEjecucion`
- `TEvaluadorFormulas`
- `TFuncFormulas`
- `TMotorComposicion`
- `TMotorPaginacion`
- `TMotorEjecucion`
- `TDocumentoRenderizable`
- Modelo compartido: `TDocument`, `TObjectBase`, `TText`, `TRectangle`, `TEllipse`, `TLine`, `TImage`, `TBarcode`, `TTable`
- Utilidades runtime: `TBarcodeUtil`, `TImageUtil`

Renderer HTML:

- `TRenderizador`
- `TSalidaHTML`

No son nucleo del engine:

- `TLLDominusPHP` como API cliente PHP.
- `TPreviewPHP` como fachada/preview server.
- Endpoints `preview.php`, `export_ir.php`, `validar_formula.php`, `index.php`.
- Herramientas LL12 y generadores de documentacion.
- Tests.

## Problemas encontrados

### 1. `TTable` concentra demasiada logica

Es el principal riesgo de portabilidad. Deberia dividirse en:

- `TTableModel`: estructura persistente de secciones, lineas, celdas y opciones.
- `TTableNormalizer`: migracion/normalizacion de estructuras.
- `TTableRuntime`: recorrido de registros, grupos y acumuladores.
- `TTablePaginator`: decisiones de salto, keep-with-previous, repeat header/footer.
- `TTableComposer`: conversion de lineas/celdas a objetos IR.

### 2. La paginacion real no vive en `TMotorPaginacion`

`TMotorPaginacion` solo empaqueta una pagina. La paginacion de detalle/tablas se hace en `TTable` y la paginacion previa de totales se coordina en `TPreviewPHP`. Para Harbour debe existir un motor de paginacion real sin dependencia de preview HTML.

### 3. `TPreviewPHP` no debe guiar el diseno del core

Hace tareas utiles, pero no es portable:

- resuelve rutas de `lbl`;
- crea ficheros temporales;
- repite ejecuciones para pre-paginacion;
- emite progreso;
- renderiza y envuelve HTML con toolbar CSS/JS;
- parsea HTML con regex para insertar viewer.

La logica de pre-paginacion y generacion de paginas debe salir a una fachada de engine sin HTML.

### 4. Formula engine sin AST explicito

`TEvaluadorFormulas` separa expresiones por operadores top-level y evalua recursivamente. Funciona para el alcance actual, pero para Harbour conviene definir un parser/AST sencillo para evitar divergencias entre lenguajes.

### 5. Modelo compartido mezcla UI y runtime

`getProperties()` pertenece al diseñador. `generarRenderizable()` pertenece al engine. En PHP se puede mantener por compatibilidad, pero el port Harbour deberia recibir modelos limpios y compositores separados.

### 6. Carga de datos acoplada a filesystem

`TConectorDatos` carga JSON, resuelve rutas, carga binarios y normaliza runtime. El core portable deberia aceptar arrays/estructuras ya cargadas; un loader separado puede encargarse del filesystem.

### 7. IR existe pero no esta formalizado como contrato

`TDocumentoRenderizable` es simple y bueno, pero el JSON de `export_ir.php` se construye en funciones globales del endpoint. Falta `TIRBuilder` con schema versionado.

### 8. Bootstrap duplicado

`index.php`, `preview.php`, `export_ir.php` y `TPreviewPHP::cargarMotor()` repiten `require`. Antes del port conviene tener un bootstrap/autoload de engine.

## Refactor obligatorio antes de Harbour

1. Extraer una fachada core sin web: `TEngineRuntime`.
   - Entrada: plantilla ya cargada o ruta abstracta, datos ya cargados, opciones runtime.
   - Salida: `TDocumentoRenderizable`/IR.
   - Sin HTML, sin `$_POST`, sin `php://input`, sin `tempnam`.

2. Extraer `TIRBuilder`.
   - Mover desde `export_ir.php` la construccion del IR.
   - Definir schema estable: paginas, objetos, metadata, warnings, unidades mm.

3. Dividir `TTable`.
   - Minimo antes del port: sacar runtime/paginacion/acumuladores a clases nuevas.
   - Mantener `TTable` como modelo/compatibilidad.

4. Separar parser/evaluador de formulas.
   - `TFormulaTokenizer` o parser top-level.
   - `TFormulaEvaluator`.
   - `TFormulaRuntimeFunctions` para `Page`, `PageBy`, `GroupChanged`, etc.

5. Separar carga de datos de adaptador runtime.
   - `TDatosRuntime` o `TDataSetRuntime` desde array.
   - `TConectorDatosJson`/loader PHP para fichero.

6. Mover paginacion previa fuera de `TPreviewPHP`.
   - Clase `TPaginacionPreviaRuntime` o metodo de `TEngineRuntime`.
   - `TPreviewPHP` debe solo orquestar request/progreso/render HTML.

## Refactor recomendable

1. Separar `getProperties()` del modelo.
   - Crear metadata UI en diseñador o provider PHP separado.

2. Dividir `TSalidaHTML` por tipo de objeto.
   - `THtmlTextRenderer`, `THtmlShapeRenderer`, `THtmlImageRenderer`, `THtmlBarcodeRenderer`.

3. Formalizar interfaz de salida para `TRenderizador`.
   - Aunque PHP no lo requiera, Harbour se beneficiara de contrato claro.

4. Separar `TImageUtil` en resolver de contenido y resolver de rutas.

5. Crear bootstrap unico de engine PHP.

6. Crear tests de contrato IR.

## Refactor que puede esperar

1. Limpieza de herramientas LL12.
2. Generadores de documentacion de funciones.
3. UI del preview demo.
4. Mejoras de `TSalidaHTML` que no afecten IR.
5. Sustituir todos los `require` por autoload completo.

## Nucleo minimo portable para Harbour

Para `.lbl + datos -> IR`, sin diseñador, sin importador y sin web, Harbour necesita estas piezas equivalentes:

### Imprescindibles

- `TDocument`
- `TObjectBase`
- `TText`
- `TRectangle`
- `TEllipse`
- `TLine`
- `TImage`
- `TBarcode`
- `TTableModel` (extraido desde `TTable`)
- `TPlantilla` o `TTemplateLoader` desde estructura ya cargada
- `TDatosRuntime` / `TConectorDatos` sin filesystem
- `TContextoEjecucion`
- `TEvaluadorFormulas`
- `TFuncFormulas` con subconjunto usado
- `TBarcodeUtil`
- `TImageUtil` parcial, sin rutas web
- `TMotorComposicion`
- `TMotorPaginacion`
- `TTableRuntime`
- `TTablePaginator`
- `TTableComposer`
- `TMotorEjecucion`
- `TDocumentoRenderizable`
- `TIRBuilder`

### Parciales o mas adelante

- `TRenderizador`: solo si se quiere un renderer Harbour/GDI con el mismo contrato.
- `TSalidaHTML`: no se porta; se reemplaza por `TSalidaHarbourGDI`/`TSalidaPrinter`.
- `TLLDominusPHP`: se porta conceptualmente como API Harbour, no literal.
- `TPreviewPHP`: no se porta; solo se reutiliza la idea de fachada.

### No portar

- `preview.php`
- `export_ir.php` como endpoint
- `validar_formula.php`
- `index.php`
- `preview_demo.php`
- `demo_data.php`
- `recurso_existe.php`
- Herramientas LL12: `TBaseLenguajeLL12`, `TAnalizadorLenguajeLST`, `TAnalizadorExpresionesLST`, `TInformeLenguajeLST`, `TLenguajeDominusBuilder`, `TGeneradorManualFunciones`
- Tests PHP como clases runtime

## Orden recomendado

1. Crear tests de contrato para `.lbl + datos -> IR`.
2. Extraer `TIRBuilder` desde `export_ir.php`.
3. Crear `TEngineRuntime` y hacer que `preview.php`, `export_ir.php` y `TPreviewPHP` lo usen.
4. Extraer `TDatosRuntime` para aceptar datos en memoria.
5. Mover pre-paginacion desde `TPreviewPHP` al runtime/fachada core.
6. Dividir `TTable` en modelo, runtime, paginador y compositor.
7. Separar `TEvaluadorFormulas` en parser/evaluador/funciones runtime.
8. Congelar schema IR.
9. Portar a Harbour el nucleo minimo.
10. Implementar renderer Harbour/GDI contra IR.

## Riesgos para Harbour

- Diferencias de fechas y formato numerico entre PHP y Harbour.
- Diferencias de precision flotante en mm y redondeos.
- Regex/parser de formulas dificil de replicar exactamente si no hay AST.
- `TTable` contiene muchos casos de salto de pagina; port directo puede introducir regresiones.
- `TImageUtil` y funciones tipo `hb_MemoRead` dependen de filesystem.
- Colores, opacidades, sombras y bordes pueden no mapear 1:1 a GDI/impresora.
- El HTML renderer tolera CSS; Harbour/GDI necesitara medidas explicitas, clipping y fuentes reales.

## Primera prueba minima recomendada

Crear una prueba de contrato, independiente de HTML:

```text
Entrada:
  lbl/prueba_texto.lbl o plantilla minima equivalente
  public/motor/datos/datos_prueba.json

Proceso:
  TEngineRuntime(.lbl, datos, opciones).ejecutarIR()

Asserts:
  - devuelve 1 pagina;
  - ancho/alto en mm coinciden con plantilla;
  - contiene texto evaluado;
  - respeta cCondition;
  - no contiene HTML;
  - IR serializa a JSON estable.
```

Despues repetir con:

- etiqueta A4 con `nEtiquetaInicial`;
- tabla con detalle que corta pagina;
- tabla con grupo y acumuladores;
- formula `Page()`, `Pages()`, `PageBy()` y `TotalPagesBy()`.

## Decision de portabilidad

Estado actual: portable conceptualmente, no recomendable para port literal.

Debe portarse primero el contrato de IR y el flujo core limpio. El HTML, endpoints, preview web, importador LL12 y herramientas deben quedar fuera del primer port.

