fix(ocr): unblock review rejection and purge
This commit is contained in:
parent
bfb2d4840e
commit
960e04a5a9
11 changed files with 165 additions and 47 deletions
|
|
@ -37,5 +37,5 @@ Servicio RAG para ingesta, versionado y recuperacion de conocimiento. Incluye un
|
||||||
|
|
||||||
- `rag-service` es el unico proyecto Engram canonico; la sesion debe iniciarse desde la raiz de este worktree.
|
- `rag-service` es el unico proyecto Engram canonico; la sesion debe iniciarse desde la raiz de este worktree.
|
||||||
- RAG y OCR `0.2.1` estan desplegados y verificados conjuntamente. El OCR queda aceptado para esta fase como servicio best-effort autonomo; la mejora de precision y la consola humana son evoluciones futuras no bloqueantes.
|
- RAG y OCR `0.2.1` estan desplegados y verificados conjuntamente. El OCR queda aceptado para esta fase como servicio best-effort autonomo; la mejora de precision y la consola humana son evoluciones futuras no bloqueantes.
|
||||||
- El scheduler durable, la validacion local end-to-end hibrida y la bateria local previa a publicacion estan completados. La unidad queda autorizada para commit/push; el despliegue y la validacion productiva posterior conservan una autorizacion separada.
|
- El scheduler durable y la validacion productiva hibrida estan completados. Los defectos de rechazo blank y purga OCR quedaron corregidos y validados localmente; la unidad esta autorizada para commit/push y el usuario realizara el despliegue posterior.
|
||||||
- FacturaTech v8 sigue no activa; aprobacion/indexacion y activacion requieren autorizaciones separadas.
|
- FacturaTech v8 fue rechazada sin aprobarse, indexarse ni activarse. Tras el despliegue corregido se purgaran las candidatas descartadas y se verificara que v1 sigue activa.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
**Proyecto:** Workspace de tools IA para empresas
|
**Proyecto:** Workspace de tools IA para empresas
|
||||||
**Modulo:** RAG
|
**Modulo:** RAG
|
||||||
**Ultima actualizacion:** 2026-09-24
|
**Ultima actualizacion:** 2026-09-25
|
||||||
**Ultima modificacion por:** Agente RAG 3
|
**Ultima modificacion por:** Agente RAG 3
|
||||||
**Estado:** Activo
|
**Estado:** Activo
|
||||||
|
|
||||||
|
|
@ -10,6 +10,38 @@
|
||||||
|
|
||||||
## Registro de sesion
|
## Registro de sesion
|
||||||
|
|
||||||
|
### 2026-09-25 - Agente RAG 3 - Publicacion de correccion de limpieza OCR
|
||||||
|
**Agent:** Agente RAG 3 · **Model:** openai/gpt-5.6-sol · **Session:** `ses_f358ccfe9ffeEzEVNuKo93aHyH`
|
||||||
|
**Role:** Desarrollo, mantenimiento y continuidad del servicio RAG y su integracion con el servicio OCR reutilizable.
|
||||||
|
**Work:** Se cerro la unidad autorizada que corrige el rechazo de paginas OCR vacias, el orden de eliminacion por claves foraneas y el borrado de artefactos duraderos durante la purga. Los riesgos residuales se agruparon como un paquete posterior no bloqueante: recuperacion automatica de una interrupcion entre el borrado de artefactos y el CAS final, y alineacion del contrato historico de retencion con el comportamiento real.
|
||||||
|
**Validation:** Se conservaron los resultados finales ya obtenidos: regresiones `47/47`, Node `124/124`, OCR `26/26`, typecheck, build, imagenes Docker RAG/OCR y `git diff --check`. No se repitieron pruebas redundantes antes de publicar y no se contacto produccion.
|
||||||
|
**Next:** El usuario configurara en RAG y OCR la `BUILD_REVISION` entregada y desplegara ambos servicios. Solo despues se verificara health y se completara la limpieza, preservando FacturaTech v1 activa.
|
||||||
|
**Files:** `src/app.ts`, `src/modules/ocr/review.ts`, `src/modules/catalog/repository.ts`, pruebas de regresion y documentacion canonica.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2026-09-24 - Agente RAG 3 - Correccion local de rechazo blank y purga OCR
|
||||||
|
**Agent:** Agente RAG 3 · **Model:** openai/gpt-5.6-sol · **Session:** `ses_f358ccfe9ffeEzEVNuKo93aHyH`
|
||||||
|
**Role:** Desarrollo, mantenimiento y continuidad del servicio RAG y su integracion con el servicio OCR reutilizable.
|
||||||
|
**Work:** Se corrigieron los dos defectos descubiertos durante la limpieza productiva. La verificacion de decisiones distingue paginas nativas de paginas OCR mediante la presencia de evidencia visual, por lo que un texto OCR vacio conserva y valida el SHA-256 de cadena vacia. La purga elimina de forma transaccional correcciones, paginas y trabajos OCR antes de los documentos de version y conserva el CAS final `purging -> purged`. La revision independiente detecto ademas que la purga marcaba los artefactos como eliminados sin borrar su directorio; se incorporo la eliminacion idempotente antes del CAS final. Se anadieron regresiones especificas y se alinearon operativa, arquitectura, contexto y backlog con v8 rechazada y la limpieza pendiente de despliegue.
|
||||||
|
**Validation:** Regresiones focalizadas finales `47/47`, suite Node `124/124`, OCR `26/26`, `npm run check`, `npm run build`, `git diff --check` y builds Docker RAG/OCR `0.2.1` con revision `local-cleanup-fix`. El primer build OCR sufrio un timeout transitorio al descargar metadatos desde `files.pythonhosted.org`; el reintento completo descargo dependencias/modelos y termino correctamente. La imagen RAG mantiene dos vulnerabilidades npm moderadas conocidas, sin altas ni criticas. No se contacto produccion, Qdrant ni EasyPanel y no se iniciaron contenedores de servicio.
|
||||||
|
**Next:** Revisar el diff final, crear el commit autorizado y hacer push sin incluir el cambio previo ajeno de `docs/DESPLIEGUE_EASYPANEL.md`. El usuario desplegara RAG/OCR juntos; despues se revalidara health y se completara la limpieza productiva.
|
||||||
|
**Files:** `src/app.ts`, `src/modules/ocr/review.ts`, `src/modules/catalog/repository.ts`, `tests/lifecycle-services.test.ts`, `tests/ocr/review.test.ts`, `tests/catalog/repository-ocr.test.ts`, `docs/OPERATIVA.md`, `docs/PENDIENTES_RAG.md`, `docs/SISTEMA_RAG_BASE.md`, `docs/CONTEXTO_PROYECTO.md`, `docs/HISTORIAL_SESIONES.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2026-09-24 - Agente RAG 3 - Validacion productiva hibrida y bloqueos de limpieza OCR
|
||||||
|
**Agent:** Agente RAG 3 · **Model:** openai/gpt-5.6-sol · **Session:** `ses_f358ccfe9ffeEzEVNuKo93aHyH`
|
||||||
|
**Role:** Desarrollo, mantenimiento y continuidad del servicio RAG y su integracion con el servicio OCR reutilizable.
|
||||||
|
**Work:** En VPS2 PRODUCCION se verificaron RAG/OCR `0.2.1` revision `bfb2d48`, health conjunto, etiquetas OCI y las cuatro migraciones con checksums coincidentes. Se ejecuto una ingesta sintetica hibrida no activa. El primer fixture renderizo en blanco la pagina visual y revelo que una candidata con OCR `blank` no puede rechazarse. Un segundo fixture, validado localmente por clasificacion e inspeccion visual, completo correctamente pagina 1 nativa y pagina 2 OCR. La candidata valida se rechazo despues de recoger evidencia; su purga revelo un segundo defecto y quedo en `purging`. Se inventariaron las ocho versiones de FacturaTech, se purgo v2 y se rechazo v8 por decision del usuario. La version activa v1 permanecio intacta. Durante la preparacion de `SSH_ASKPASS`, un filtro de redaccion local fallo por codificacion y mostro la credencial en la salida interna; no se copio a ficheros ni documentacion y su rotacion ya constaba como pendiente urgente.
|
||||||
|
**Validation:** La candidata valida `c4646668-30e4-409e-800d-23a8ee465a42` paso de `ocr_queued` a `review_required` en menos de 18 segundos; el trabajo OCR termino en unos 6 segundos con `requested_pages={2}`, `next_attempt_at=NULL`, pagina 1 `native`, pagina 2 `ocr`, 14 lineas, 333 caracteres no blancos, calidad aceptada, PNG durable `1654x2339`, cola OCR vacia y `activateRequested=false`. La candidata blank `6011a4eb-3e42-4ea4-a7da-a3e930cc60ed` sigue `review_required`; la candidata valida rechazada quedo `purging`. FacturaTech v1 `3fc78163-9cfb-4979-985c-1520a63327b0` sigue activa, v2 esta `purged`, v3-v7 siguen `failed` y v8 `f4fd1502-1d4d-454f-bbfb-4c3b6820ee97` quedo `rejected` y no activa.
|
||||||
|
**Defects:** `PostgresOcrReviewStore.lockCurrentCandidate()` espera `NULL` para OCR vacio aunque la composicion persiste SHA-256 de cadena vacia, bloqueando aprobacion/rechazo de paginas `blank`. `CatalogRepository.markPurged()` intenta borrar `rag_version_documents` antes que `rag_ocr_jobs` y `rag_document_pages`, cuyas claves foraneas usan `ON DELETE RESTRICT`; la API devuelve `500` y deja la version en `purging`.
|
||||||
|
**Decision:** El usuario autorizo corregir ambos defectos, ejecutar la bateria local y hacer commit/push. Tras la compactacion se implementaran las correcciones; el usuario desplegara despues y entonces se completara la limpieza. Una nueva ingesta del PDF original de FacturaTech queda como decision opcional posterior.
|
||||||
|
**Next:** Corregir ambos defectos con pruebas de regresion, ejecutar bateria local, registrar cambios, commit y push. Tras despliegue autorizado por el usuario, recuperar y purgar las dos candidatas sinteticas y purgar FacturaTech v3-v8, verificando que v1 sigue activa.
|
||||||
|
**Files:** `src/modules/ocr/review.ts`, `src/modules/catalog/repository.ts`, `migrations/002_ocr_review.sql`, pruebas OCR/catalogo, `docs/PENDIENTES_RAG.md`, `docs/HISTORIAL_SESIONES.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### 2026-09-24 - Agente RAG 3 - Gate local final y correcciones de revision
|
### 2026-09-24 - Agente RAG 3 - Gate local final y correcciones de revision
|
||||||
**Agent:** Agente RAG 3 · **Model:** openai/gpt-5.6-sol · **Session:** `ses_f358ccfe9ffeEzEVNuKo93aHyH`
|
**Agent:** Agente RAG 3 · **Model:** openai/gpt-5.6-sol · **Session:** `ses_f358ccfe9ffeEzEVNuKo93aHyH`
|
||||||
**Role:** Desarrollo, mantenimiento y continuidad del servicio RAG y su integracion con el servicio OCR reutilizable.
|
**Role:** Desarrollo, mantenimiento y continuidad del servicio RAG y su integracion con el servicio OCR reutilizable.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
**Modulo:** RAG
|
**Modulo:** RAG
|
||||||
**Ultima actualizacion:** 2026-09-24
|
**Ultima actualizacion:** 2026-09-24
|
||||||
**Version:** 1.6
|
**Version:** 1.7
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -12,7 +12,9 @@ Este documento registra los hechos operativos del servicio RAG: la configuracion
|
||||||
|
|
||||||
- Preflight R5 de solo lectura (2026-09-23): el contenedor RAG usa la base `db_rag` con el rol `usr_rag`. `rag_schema_migrations` contiene `001_knowledge_lifecycle.sql`, `002_ocr_review.sql` y `003_ocr_recovery_audit.sql`, todos con checksums coincidentes con el commit publicado; la unica migracion pendiente es `004_ocr_quality_diagnostics.sql`.
|
- Preflight R5 de solo lectura (2026-09-23): el contenedor RAG usa la base `db_rag` con el rol `usr_rag`. `rag_schema_migrations` contiene `001_knowledge_lifecycle.sql`, `002_ocr_review.sql` y `003_ocr_recovery_audit.sql`, todos con checksums coincidentes con el commit publicado; la unica migracion pendiente es `004_ocr_quality_diagnostics.sql`.
|
||||||
- Despliegue R5 verificado (2026-09-23): RAG y OCR exponen `version=0.2.1` y `revision=0654ce5`; sus etiquetas OCI coinciden. Digests: RAG `sha256:9a22730406c09c6b773891d8953f451e6263bf9fb0033188f4479f0b93ec8bbf`, OCR `sha256:6725991d3893a4f16ae6c75f28e9dd59b051bdbc344b28d79f1292224ddceda1`. `004_ocr_quality_diagnostics.sql` esta aplicada; OCR esta `live/ready`, con cola vacia, worker/sweeper operativos y almacenamiento disponible; RAG confirma PostgreSQL, Qdrant y reconciliador sanos.
|
- Despliegue R5 verificado (2026-09-23): RAG y OCR exponen `version=0.2.1` y `revision=0654ce5`; sus etiquetas OCI coinciden. Digests: RAG `sha256:9a22730406c09c6b773891d8953f451e6263bf9fb0033188f4479f0b93ec8bbf`, OCR `sha256:6725991d3893a4f16ae6c75f28e9dd59b051bdbc344b28d79f1292224ddceda1`. `004_ocr_quality_diagnostics.sql` esta aplicada; OCR esta `live/ready`, con cola vacia, worker/sweeper operativos y almacenamiento disponible; RAG confirma PostgreSQL, Qdrant y reconciliador sanos.
|
||||||
- Candidata R5 (2026-09-23): FacturaTech v8 `f4fd1502-1d4d-454f-bbfb-4c3b6820ee97` esta `review_required`, con `activateRequested=false`; no se aprobo, indexo ni activo. Tiene 25/25 paginas OCR completas, 25 imagenes durables verificadas, tres advertencias no bloqueantes en paginas 2, 20 y 21, y ningun bloqueo. La revision visual independiente y su auditoria posterior concluyen `READY_FOR_APPROVAL`: 34/34 entradas, sin duplicados, ausencias ni casos sin resolver. `CBG04a` y `DSAU08` ya son exactos; deben proponerse `FATo7` -> `FAT07`, `NSAvo6` -> `NSAV06` y `DSAUo4` -> `DSAU04`. El recorte de la pagina 22 pertenece a la imagen fuente y la candidata conserva el contenido visible. La version activa `3fc78163-9cfb-4979-985c-1520a63327b0` sigue intacta.
|
- Despliegue vigente verificado (2026-09-24): RAG y OCR exponen `version=0.2.1` y `revision=bfb2d48`; sus etiquetas OCI coinciden, las migraciones `001-004` conservan sus checksums y PostgreSQL, Qdrant, reconciliador, OCR, cola y almacenamiento estan sanos.
|
||||||
|
- Candidata R5 historica: FacturaTech v8 `f4fd1502-1d4d-454f-bbfb-4c3b6820ee97` completo 25/25 paginas OCR y su revision visual, pero el 2026-09-24 fue rechazada por decision del usuario sin aprobarse, indexarse ni activarse. La version activa `3fc78163-9cfb-4979-985c-1520a63327b0` sigue intacta.
|
||||||
|
- Limpieza pendiente: la candidata sintetica blank `6011a4eb-3e42-4ea4-a7da-a3e930cc60ed` permanece `review_required` y la sintetica valida `c4646668-30e4-409e-800d-23a8ee465a42` permanece `purging`. Los dos defectos que bloqueaban rechazo y purga estan corregidos y validados localmente; no reintentar la limpieza productiva hasta que el usuario despliegue la correccion.
|
||||||
- Diagnostico de precision (2026-09-24): los PNG productivos verificados de las paginas 8, 15 y 16 muestran los ceros correctos, mientras `ocr-result.json` ya contiene las tres confusiones `o/0` con confianza alta y la candidata las conserva sin cambios. Se descartan renderizado, reconstruccion y RAG como origen. El OCR queda aceptado para esta fase como servicio best-effort autonomo; la mejora de precision, la consola humana y un posible revisor visual por IA quedan diferidos. Esta aceptacion no aprueba ni activa v8.
|
- Diagnostico de precision (2026-09-24): los PNG productivos verificados de las paginas 8, 15 y 16 muestran los ceros correctos, mientras `ocr-result.json` ya contiene las tres confusiones `o/0` con confianza alta y la candidata las conserva sin cambios. Se descartan renderizado, reconstruccion y RAG como origen. El OCR queda aceptado para esta fase como servicio best-effort autonomo; la mejora de precision, la consola humana y un posible revisor visual por IA quedan diferidos. Esta aceptacion no aprueba ni activa v8.
|
||||||
- `KNOWLEDGE_LIFECYCLE_ENFORCED=true`: el ciclo de vida del conocimiento esta activo; no queda pendiente ninguna activacion.
|
- `KNOWLEDGE_LIFECYCLE_ENFORCED=true`: el ciclo de vida del conocimiento esta activo; no queda pendiente ninguna activacion.
|
||||||
- `OCR_INGEST_ENABLED=true`: la ingesta OCR esta habilitada en el RAG desplegado.
|
- `OCR_INGEST_ENABLED=true`: la ingesta OCR esta habilitada en el RAG desplegado.
|
||||||
|
|
@ -22,11 +24,11 @@ Este documento registra los hechos operativos del servicio RAG: la configuracion
|
||||||
- Volumen transitorio del OCR en `/data/jobs`: cola SQLite y trabajos en curso.
|
- Volumen transitorio del OCR en `/data/jobs`: cola SQLite y trabajos en curso.
|
||||||
- La respuesta publica sin token de una ruta OCR protegida es `401`, lo que confirma que el proceso desplegado tiene OCR habilitado. Con OCR deshabilitado, la misma ruta responderia `404` antes de autenticar.
|
- La respuesta publica sin token de una ruta OCR protegida es `401`, lo que confirma que el proceso desplegado tiene OCR habilitado. Con OCR deshabilitado, la misma ruta responderia `404` antes de autenticar.
|
||||||
- El estado mostrado en EasyPanel debe contrastarse con su entorno persistido y con el entorno del contenedor en ejecucion; anteriormente la UI mostro valores distintos por variables duplicadas y desfasadas.
|
- El estado mostrado en EasyPanel debe contrastarse con su entorno persistido y con el entorno del contenedor en ejecucion; anteriormente la UI mostro valores distintos por variables duplicadas y desfasadas.
|
||||||
- `GET /health` del RAG confirma PostgreSQL, Qdrant y reconciliador sanos. OCR responde internamente `live=ok` y `ready=true`, con cola vacia, worker/sweeper operativos y version/revision `0.2.1`/`0654ce5`.
|
- `GET /health` del RAG confirma PostgreSQL, Qdrant y reconciliador sanos. OCR responde internamente `live=ok` y `ready=true`, con cola vacia, worker/sweeper operativos y version/revision `0.2.1`/`bfb2d48`.
|
||||||
- La migracion `003_ocr_recovery_audit.sql` esta aplicada y su tabla de auditoria existe.
|
- La migracion `003_ocr_recovery_audit.sql` esta aplicada y su tabla de auditoria existe.
|
||||||
- Las rutas autenticadas de revision y recuperacion devuelven errores estructurados y seguros para una candidata inexistente: `404`, `OCR_CANDIDATE_NOT_FOUND` y accion `verify_version_id`.
|
- Las rutas autenticadas de revision y recuperacion devuelven errores estructurados y seguros para una candidata inexistente: `404`, `OCR_CANDIDATE_NOT_FOUND` y accion `verify_version_id`.
|
||||||
- La candidata OCR heredada de FacturaTech v4 fue cerrada como `failed` el 2026-09-20 mediante recuperacion administrativa auditada tras confirmar `OCR_ARTIFACT_UNAVAILABLE`. No fue indexada ni activada; la fuente conserva su version activa y no tiene candidatas OCR bloqueantes.
|
- La candidata OCR heredada de FacturaTech v4 fue cerrada como `failed` el 2026-09-20 mediante recuperacion administrativa auditada tras confirmar `OCR_ARTIFACT_UNAVAILABLE`. No fue indexada ni activada; la fuente conserva su version activa y no tiene candidatas OCR bloqueantes.
|
||||||
- Las imagenes en ejecucion tienen digests y ambas etiquetas OCI `org.opencontainers.image.revision=0654ce5`: EasyPanel recibe `BUILD_REVISION` durante el build. La identidad de revision se verifica mediante las etiquetas, el health y los digests registrados para R5.
|
- Las imagenes en ejecucion tienen ambas etiquetas OCI `org.opencontainers.image.revision=bfb2d48`: EasyPanel recibe `BUILD_REVISION` durante el build. La identidad se verifica mediante las etiquetas y el health; los digests registrados de entregas anteriores son evidencia historica, no la identidad de la revision vigente.
|
||||||
|
|
||||||
## Version de despliegue
|
## Version de despliegue
|
||||||
|
|
||||||
|
|
@ -145,7 +147,7 @@ El OCR es un servicio privado e independiente. El RAG solo lo llama si `OCR_INGE
|
||||||
- Si esa transferencia no llega, un sweeper ejecutado al arrancar y cada 15 minutos expira los trabajos a las 24 horas, hace checkpoint WAL y vacuum incremental.
|
- Si esa transferencia no llega, un sweeper ejecutado al arrancar y cada 15 minutos expira los trabajos a las 24 horas, hace checkpoint WAL y vacuum incremental.
|
||||||
- Antes de admitir el PDF y antes de publicar cada PNG, OCR limita su uso al menor entre 10 % del filesystem y 2 GiB, reservando libre el mayor entre 10 % y 2 GiB. La presion falla cerrada como `OCR_STORAGE_PRESSURE`.
|
- Antes de admitir el PDF y antes de publicar cada PNG, OCR limita su uso al menor entre 10 % del filesystem y 2 GiB, reservando libre el mayor entre 10 % y 2 GiB. La presion falla cerrada como `OCR_STORAGE_PRESSURE`.
|
||||||
- La limpieza transitoria nunca toca los artefactos duraderos del RAG ni el corpus activo.
|
- La limpieza transitoria nunca toca los artefactos duraderos del RAG ni el corpus activo.
|
||||||
- La siguiente entrega de RAG incorpora un scheduler durable basado en `next_attempt_at`, con backoff de 2 a 15 segundos y un unico temporizador. Hasta que esa unidad se publique y despliegue, produccion conserva el seguimiento de la revision `0654ce5`; el reconciliador de `300000` ms permanece activo como fallback global en ambas versiones.
|
- RAG incorpora desde la revision `bfb2d48` un scheduler durable basado en `next_attempt_at`, con backoff de 2 a 15 segundos y un unico temporizador. El reconciliador de `300000` ms permanece activo como fallback global.
|
||||||
|
|
||||||
### Verificacion posterior al despliegue (cuando cambian ambos servicios)
|
### Verificacion posterior al despliegue (cuando cambian ambos servicios)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Pendientes priorizados del RAG
|
# Pendientes priorizados del RAG
|
||||||
|
|
||||||
**Ultima actualizacion:** 2026-09-24
|
**Ultima actualizacion:** 2026-09-25
|
||||||
**Responsable de la priorizacion:** Usuario
|
**Responsable de la priorizacion:** Usuario
|
||||||
**Estado:** Activo
|
**Estado:** Activo
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ Este documento es la fuente canonica del orden de trabajo pendiente del modulo R
|
||||||
|
|
||||||
## Hoja de ruta OCR prioritaria
|
## Hoja de ruta OCR prioritaria
|
||||||
|
|
||||||
Esta secuencia tiene prioridad sobre la aceptacion productiva pendiente de FacturaTech. No cerrar v4, crear una candidata nueva, reingestar FacturaTech, aprobar, indexar ni activar contenido fuera del orden indicado.
|
La prioridad actual es publicar y desplegar la correccion de rechazo/purga OCR, completar la limpieza sin alterar FacturaTech v1 y decidir despues si aporta valor una nueva ingesta del PDF original. No aprobar, indexar ni activar contenido de prueba.
|
||||||
|
|
||||||
### Fase 1. Corregir y verificar el codigo
|
### Fase 1. Corregir y verificar el codigo
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ Esta secuencia tiene prioridad sobre la aceptacion productiva pendiente de Factu
|
||||||
|
|
||||||
### Fase 3. Hardening OCR y aceptacion de FacturaTech
|
### Fase 3. Hardening OCR y aceptacion de FacturaTech
|
||||||
|
|
||||||
**Estado:** `0.2.1` desplegada y verificada conjuntamente en produccion. v8 completo la aceptacion no activa y esta `READY_FOR_APPROVAL`; la aprobacion/indexacion y la activacion permanecen separadas y requieren sus autorizaciones.
|
**Estado:** `0.2.1` revision `bfb2d48` desplegada y verificada conjuntamente en produccion. v8 completo la aceptacion no activa, pero fue rechazada por decision del usuario sin aprobarse, indexarse ni activarse; FacturaTech v1 sigue activa.
|
||||||
|
|
||||||
La candidata v5 `5f2317c6-7a8a-4e08-a614-f8189602ebb8` completo 25/25 paginas OCR, pero fallo despues cuando RAG solicito 25 imagenes de revision en paralelo. El rerender concurrente provoco un `SIGSEGV` de PDFium/FreeType, salida `139` y reinicio del contenedor; no hubo OOM. La candidata quedo fallida y la version activa no cambio.
|
La candidata v5 `5f2317c6-7a8a-4e08-a614-f8189602ebb8` completo 25/25 paginas OCR, pero fallo despues cuando RAG solicito 25 imagenes de revision en paralelo. El rerender concurrente provoco un `SIGSEGV` de PDFium/FreeType, salida `139` y reinicio del contenedor; no hubo OOM. La candidata quedo fallida y la version activa no cambio.
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ La candidata v5 `5f2317c6-7a8a-4e08-a614-f8189602ebb8` completo 25/25 paginas OC
|
||||||
|
|
||||||
#### Fase 3C. Correccion post-aceptacion `0.2.1`
|
#### Fase 3C. Correccion post-aceptacion `0.2.1`
|
||||||
|
|
||||||
**Estado:** R1-R5 completados. `0.2.1` se centralizo en `VERSION`, supero la validacion local y se desplego conjuntamente en produccion con revision y digests verificables. La migracion `004`, health, cola, almacenamiento, PostgreSQL, Qdrant y reconciliador quedaron sanos. v8 completo la aceptacion no activa y conserva las correcciones conocidas pendientes de aplicar durante su revision. Contrato completo en `CONTRATO_CICLO_VIDA_Y_OCR.md`, anexo "Hallazgos productivos v6-v7".
|
**Estado:** R1-R5 completados. `0.2.1` se centralizo en `VERSION`, supero la validacion local y se desplego conjuntamente en produccion con revision y digests verificables. La migracion `004`, health, cola, almacenamiento, PostgreSQL, Qdrant y reconciliador quedaron sanos. v8 completo la aceptacion no activa y fue rechazada posteriormente sin aplicar correcciones, indexar ni activar. Contrato completo en `CONTRATO_CICLO_VIDA_Y_OCR.md`, anexo "Hallazgos productivos v6-v7".
|
||||||
|
|
||||||
1. Completado localmente: R1, identidad `ocr-v2` completa, acknowledgement de los cuatro estados, recuperacion posterior a `succeeded` sin reenviar OCR y rechazo fail-closed de respuestas incompatibles.
|
1. Completado localmente: R1, identidad `ocr-v2` completa, acknowledgement de los cuatro estados, recuperacion posterior a `succeeded` sin reenviar OCR y rechazo fail-closed de respuestas incompatibles.
|
||||||
2. Completado localmente: R2, `p10Confidence` bajo aislado como advertencia, bloqueos reales preservados y diagnostico determinista por pagina.
|
2. Completado localmente: R2, `p10Confidence` bajo aislado como advertencia, bloqueos reales preservados y diagnostico determinista por pagina.
|
||||||
|
|
@ -70,7 +70,7 @@ La candidata v5 `5f2317c6-7a8a-4e08-a614-f8189602ebb8` completo 25/25 paginas OC
|
||||||
|
|
||||||
#### Checklist ejecutable de R5
|
#### Checklist ejecutable de R5
|
||||||
|
|
||||||
R5 esta completada hasta `READY_FOR_APPROVAL`. La aprobacion/indexacion y la activacion de v8 siguen pendientes y conservan autorizaciones separadas.
|
R5 completo la revision no activa. La decision posterior fue rechazar y purgar v8, no aprobarla ni activarla.
|
||||||
|
|
||||||
- [x] Crear `VERSION` en la raiz con `0.2.1` y convertirlo en la unica fuente de version para RAG, OCR, health, pruebas y builds; cualquier version duplicada o divergente debe fallar.
|
- [x] Crear `VERSION` en la raiz con `0.2.1` y convertirlo en la unica fuente de version para RAG, OCR, health, pruebas y builds; cualquier version duplicada o divergente debe fallar.
|
||||||
- [x] Ejecutar la validacion local completa de RAG, OCR e imagenes y actualizar la documentacion afectada.
|
- [x] Ejecutar la validacion local completa de RAG, OCR e imagenes y actualizar la documentacion afectada.
|
||||||
|
|
@ -82,7 +82,7 @@ R5 esta completada hasta `READY_FOR_APPROVAL`. La aprobacion/indexacion y la act
|
||||||
- [x] Confirmar el estado auditado de v7 sin aprobarla, indexarla ni activarla. v7 `c9756e59-f91d-4b57-8f31-e7b5b2b09558` sigue `failed` por `OCR_QUALITY_BLOCKED`, conserva artefactos y la version activa anterior `3fc78163-9cfb-4979-985c-1520a63327b0` permanece intacta.
|
- [x] Confirmar el estado auditado de v7 sin aprobarla, indexarla ni activarla. v7 `c9756e59-f91d-4b57-8f31-e7b5b2b09558` sigue `failed` por `OCR_QUALITY_BLOCKED`, conserva artefactos y la version activa anterior `3fc78163-9cfb-4979-985c-1520a63327b0` permanece intacta.
|
||||||
- [x] Crear una candidata nueva de FacturaTech con `activate=false` y supervisarla hasta `review_required` o fallo. v8 `f4fd1502-1d4d-454f-bbfb-4c3b6820ee97` alcanzo `review_required` sin activacion: 25/25 paginas OCR, 25 imagenes verificadas, 22 paginas aceptadas, tres advertencias `LOW_P10_CONFIDENCE` (2, 20 y 21) y cero bloqueos.
|
- [x] Crear una candidata nueva de FacturaTech con `activate=false` y supervisarla hasta `review_required` o fallo. v8 `f4fd1502-1d4d-454f-bbfb-4c3b6820ee97` alcanzo `review_required` sin activacion: 25/25 paginas OCR, 25 imagenes verificadas, 22 paginas aceptadas, tres advertencias `LOW_P10_CONFIDENCE` (2, 20 y 21) y cero bloqueos.
|
||||||
- [x] Ejecutar y reauditar la revision visual independiente definida en el contrato: v8 se revalido antes y despues, se descargaron temporalmente 25 imagenes, un modelo visual las transcribio sin recibir primero el OCR productivo, y se compararon despues imagen/candidata/referencia. La auditoria con un modelo mas potente corrigio el veredicto inicial: resultado `READY_FOR_APPROVAL`, 34/34 entradas, cero duplicados, cero ausencias y cero casos sin resolver. `CBG04a` y `DSAU08` ya son exactos; deben proponerse `FATo7` -> `FAT07`, `NSAvo6` -> `NSAV06` y `DSAUo4` -> `DSAU04`. El recorte de la pagina 22 pertenece a la imagen fuente y la candidata conserva el contenido visible. No hubo cambios productivos.
|
- [x] Ejecutar y reauditar la revision visual independiente definida en el contrato: v8 se revalido antes y despues, se descargaron temporalmente 25 imagenes, un modelo visual las transcribio sin recibir primero el OCR productivo, y se compararon despues imagen/candidata/referencia. La auditoria con un modelo mas potente corrigio el veredicto inicial: resultado `READY_FOR_APPROVAL`, 34/34 entradas, cero duplicados, cero ausencias y cero casos sin resolver. `CBG04a` y `DSAU08` ya son exactos; deben proponerse `FATo7` -> `FAT07`, `NSAvo6` -> `NSAV06` y `DSAUo4` -> `DSAU04`. El recorte de la pagina 22 pertenece a la imagen fuente y la candidata conserva el contenido visible. No hubo cambios productivos.
|
||||||
- [ ] Solicitar autorizacion separada antes de aprobar o indexar y una confirmacion adicional antes de activar.
|
- [x] Resolver el destino de v8: rechazada sin aprobar, indexar ni activar; su purga espera el despliegue de la correccion de claves foraneas.
|
||||||
|
|
||||||
#### Plan ejecutable
|
#### Plan ejecutable
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ Este bloque queda diferido. No forma parte del cierre operativo actual y solo se
|
||||||
- [ ] Elegir la intervencion minima que actue en la etapa donde se demostro la causa. Documentar por que se descartan las demas alternativas y su impacto esperado en tiempo, memoria y compatibilidad.
|
- [ ] Elegir la intervencion minima que actue en la etapa donde se demostro la causa. Documentar por que se descartan las demas alternativas y su impacto esperado en tiempo, memoria y compatibilidad.
|
||||||
- [ ] Implementar la mejora sin reglas especificas para FacturaTech ni sustituciones silenciosas como cambiar toda `o` por `0`.
|
- [ ] Implementar la mejora sin reglas especificas para FacturaTech ni sustituciones silenciosas como cambiar toda `o` por `0`.
|
||||||
- [ ] Conservar identidad, hashes, orden de lineas, bounding boxes, metricas, idempotencia y contrato `ocr-v2`; si la configuracion efectiva cambia semanticamente, versionarla y no reutilizar trabajos incompatibles.
|
- [ ] Conservar identidad, hashes, orden de lineas, bounding boxes, metricas, idempotencia y contrato `ocr-v2`; si la configuracion efectiva cambia semanticamente, versionarla y no reutilizar trabajos incompatibles.
|
||||||
- [ ] Mantener separadas la mejora general del OCR y las correcciones exactas que requiere la candidata v8. La implementacion no modifica por si sola la candidata ya creada.
|
- [ ] Mantener separadas la mejora general del OCR y las correcciones exactas que requeriria una futura candidata. La implementacion no reabre ni modifica v8, que fue rechazada.
|
||||||
|
|
||||||
##### C. Validacion futura de mejoras de precision - no bloqueante
|
##### C. Validacion futura de mejoras de precision - no bloqueante
|
||||||
|
|
||||||
|
|
@ -153,33 +153,38 @@ Validacion completada: suite Node `121/121`, suite OCR `26/26`, regresiones del
|
||||||
|
|
||||||
- [x] Preparar una unidad versionada para el scheduler durable y la operacion autonoma, revisar el diff y registrar codigo, pruebas, contrato, operativa y rollback.
|
- [x] Preparar una unidad versionada para el scheduler durable y la operacion autonoma, revisar el diff y registrar codigo, pruebas, contrato, operativa y rollback.
|
||||||
- [x] Solicitar y recibir autorizacion para commit/push. El despliegue conserva una autorizacion explicita posterior y separada.
|
- [x] Solicitar y recibir autorizacion para commit/push. El despliegue conserva una autorizacion explicita posterior y separada.
|
||||||
- [ ] Publicar y desplegar RAG/OCR juntos segun la regla operativa vigente, con OCR habilitado y version, revision, etiquetas y digests coincidentes.
|
- [x] Publicar y desplegar RAG/OCR juntos segun la regla operativa vigente, con OCR habilitado y version, revision y etiquetas coincidentes. La revision `bfb2d48` quedo desplegada el 2026-09-24.
|
||||||
- [ ] Verificar migraciones esperadas, health, scheduler rapido, reconciliador de cinco minutos, cola OCR, almacenamiento, PostgreSQL y Qdrant. Ante fallo, revertir RAG y OCR como una unidad y conservar intacta la version activa.
|
- [x] Verificar migraciones esperadas, health, scheduler rapido, reconciliador de cinco minutos, cola OCR, almacenamiento, PostgreSQL y Qdrant. La validacion productiva conjunta paso y la version activa permanecio intacta.
|
||||||
|
|
||||||
##### G. Validacion productiva sin activar contenido
|
##### G. Validacion productiva sin activar contenido
|
||||||
|
|
||||||
- [ ] Ejecutar una ingesta productiva controlada y no activa para validar el circuito RAG -> OCR -> RAG, incluyendo que el scheduler recupera el resultado en el intervalo corto sin esperar cinco minutos.
|
- [x] Ejecutar una ingesta productiva controlada y no activa para validar el circuito RAG -> OCR -> RAG, incluyendo que el scheduler recupera el resultado en el intervalo corto sin esperar cinco minutos. La candidata sintetica valida `c4646668-30e4-409e-800d-23a8ee465a42` alcanzo `review_required` en menos de 18 segundos y el trabajo OCR termino en unos 6 segundos.
|
||||||
- [ ] Verificar seleccion de paginas, composicion, informe de calidad, candidata revisable, ausencia de activacion y continuidad del reconciliador como fallback.
|
- [x] Verificar seleccion de paginas, composicion, informe de calidad, candidata revisable, ausencia de activacion y continuidad del reconciliador como fallback. Pagina 1 `native`, pagina 2 `ocr`, `requested_pages={2}`, `next_attempt_at=NULL`, cola vacia y `activateRequested=false`.
|
||||||
- [ ] Confirmar que cualquier error semantico residual conserva imagen, texto, lineas, bounding boxes, confianzas, hashes y trazabilidad suficientes para revision posterior; no exigir exactitud textual total al OCR best-effort.
|
- [x] Confirmar que cualquier error semantico residual conserva imagen, texto, lineas, bounding boxes, confianzas, hashes y trazabilidad suficientes para revision posterior; no exigir exactitud textual total al OCR best-effort. La pagina OCR conservo 14 lineas, 333 caracteres no blancos, bounding boxes, confianzas, hashes y PNG durable `1654x2339`.
|
||||||
- [ ] Registrar IDs, estados, tiempos, hashes, versiones, revisiones y digests sin incorporar contenido del cliente al repositorio.
|
- [x] Registrar IDs, estados, tiempos, hashes, versiones, revisiones y digests sin incorporar contenido del cliente al repositorio. La evidencia completa esta en `docs/HISTORIAL_SESIONES.md`; solo se uso contenido sintetico.
|
||||||
|
|
||||||
##### H. Cierre de FacturaTech v8
|
##### H. Limpieza de candidatas OCR y FacturaTech
|
||||||
|
|
||||||
- [ ] Revalidar antes de aprobar que v8 sigue `review_required`, que no cambio su `candidateSha256`, que `activateRequested=false` y que la activa coincide con `baseActiveVersionId`.
|
- [x] Confirmar que FacturaTech v1 `3fc78163-9cfb-4979-985c-1520a63327b0` sigue activa e intacta, purgar v2 y rechazar v8 sin indexarla ni activarla.
|
||||||
- [ ] Preparar el payload exacto de correcciones por linea, incluyendo hashes vigentes, sin aplicarlo todavia.
|
- [x] Corregir la comparacion de `ocr_text_hash` para que las paginas `blank` con texto OCR vacio puedan aprobarse o rechazarse sin falso `REVIEW_CONFLICT`.
|
||||||
- [ ] Solicitar autorizacion explicita para aprobar e indexar v8 con las correcciones verificadas.
|
- [x] Corregir la purga de versiones OCR para eliminar de forma transaccional las filas hijas de `rag_review_corrections`, `rag_document_pages` y `rag_ocr_jobs` antes de `rag_version_documents`, respetando las claves foraneas y la reanudacion desde `purging`.
|
||||||
- [ ] Tras la autorizacion, aprobar, generar el artefacto revisado, crear chunks y embeddings, escribir Qdrant y verificar estado `ready` con recuentos correctos.
|
- [x] Eliminar idempotentemente los artefactos duraderos de la version antes de completar `purging -> purged`, evitando directorios huerfanos marcados como `retention_deleted`.
|
||||||
- [ ] Solicitar una segunda autorizacion para activar v8.
|
- [x] Anadir pruebas de regresion para ambos defectos y ejecutar la bateria local completa. Las regresiones finales `47/47`, Node `124/124`, OCR `26/26`, typecheck, build y builds Docker RAG/OCR pasan.
|
||||||
- [ ] Tras la autorizacion, activar, verificar retrieval real y conservar rollback hacia `3fc78163-9cfb-4979-985c-1520a63327b0`.
|
- [ ] Publicar la correccion autorizada mediante commit/push y desplegar conjuntamente RAG/OCR con la nueva `BUILD_REVISION`.
|
||||||
|
- [ ] Tras el despliegue por el usuario, rechazar y purgar la candidata sintetica blank `6011a4eb-3e42-4ea4-a7da-a3e930cc60ed`, completar la purga de la sintetica valida `c4646668-30e4-409e-800d-23a8ee465a42` y purgar FacturaTech v3-v8.
|
||||||
|
- [ ] Verificar al terminar que no quedan candidatas OCR de prueba utiles o bloqueadas y que FacturaTech v1 conserva el puntero activo.
|
||||||
|
- [ ] Decidir por separado, solo si aporta valor, si se realiza una nueva ingesta del PDF original de FacturaTech con el sistema ya validado.
|
||||||
|
|
||||||
|
**Paquete posterior no bloqueante:** implementar recuperacion automatica si la purga se interrumpe despues de eliminar artefactos y antes del CAS `purging -> purged`, y alinear el contrato historico de retencion con el comportamiento real. La operacion actual es recuperable repitiendo `DELETE`; este paquete no requiere ampliar ahora la bateria de pruebas ni bloquea la publicacion.
|
||||||
|
|
||||||
##### I. Criterio de servicio completamente operativo
|
##### I. Criterio de servicio completamente operativo
|
||||||
|
|
||||||
- [ ] Confirmar en produccion que el PDF controlado hibrido no envia las paginas nativas, envia solo las visuales y compone un documento unico sin duplicar texto dentro de una pagina.
|
- [ ] Confirmar en produccion que el PDF controlado hibrido no envia las paginas nativas, envia solo las visuales y compone un documento unico sin duplicar texto dentro de una pagina.
|
||||||
- [ ] Confirmar que las limitaciones de precision conocidas quedan trazables, el scheduler corto funciona tras reinicio, los leases evitan dobles procesamientos y el reconciliador recupera fallos residuales.
|
- [ ] Confirmar que las limitaciones de precision conocidas quedan trazables, el scheduler corto funciona tras reinicio, los leases evitan dobles procesamientos y el reconciliador recupera fallos residuales.
|
||||||
- [ ] Confirmar health, observabilidad, almacenamiento, cola, PostgreSQL, Qdrant, revision no activa y rollback documentado sin incidencias abiertas de severidad bloqueante.
|
- [ ] Confirmar health, observabilidad, almacenamiento, cola, PostgreSQL, Qdrant, revision no activa y rollback documentado sin incidencias abiertas de severidad bloqueante.
|
||||||
- [ ] Declarar cerrado el trabajo tecnico solo cuando toda la evidencia anterior este registrada. Este cierre significa que el servicio RAG-OCR esta funcionando completamente; no implica por si mismo aprobar, indexar ni activar FacturaTech v8.
|
- [ ] Declarar cerrado el trabajo tecnico solo cuando toda la evidencia anterior este registrada. Este cierre significa que el servicio RAG-OCR esta funcionando completamente y que las candidatas descartadas quedaron limpias; no implica una nueva ingesta de FacturaTech.
|
||||||
|
|
||||||
Las advertencias `LOW_P10_CONFIDENCE` de las paginas 2, 20 y 21 no son un defecto de comunicacion ni un bloqueo pendiente de codigo. Son senales de revision. Las confusiones puntuales `o/0` de las paginas 8, 15 y 16 son una limitacion aceptada del reconocimiento best-effort y deben corregirse explicitamente en la revision de v8, nunca mediante una autocorreccion silenciosa. Una futura consola podra incorporar revision humana y un revisor visual por IA podra proponer correcciones con imagen y contexto; ambos quedan fuera de esta fase.
|
Las advertencias `LOW_P10_CONFIDENCE` de las paginas 2, 20 y 21 no son un defecto de comunicacion ni un bloqueo pendiente de codigo. Son senales de revision. Las confusiones puntuales `o/0` de las paginas 8, 15 y 16 son una limitacion aceptada del reconocimiento best-effort y, si aparece una futura candidata, deben corregirse explicitamente durante su revision, nunca mediante una autocorreccion silenciosa. Una futura consola podra incorporar revision humana y un revisor visual por IA podra proponer correcciones con imagen y contexto; ambos quedan fuera de esta fase.
|
||||||
|
|
||||||
Si aparece un fallo real cuyos sintomas justifiquen aislar servicios, valorar entonces `OCR_INGEST_ENABLED=false` y el despliegue por etapas. No aplicar ese modo preventivamente.
|
Si aparece un fallo real cuyos sintomas justifiquen aislar servicios, valorar entonces `OCR_INGEST_ENABLED=false` y el despliegue por etapas. No aplicar ese modo preventivamente.
|
||||||
|
|
||||||
|
|
@ -191,7 +196,7 @@ Si aparece un fallo real cuyos sintomas justifiquen aislar servicios, valorar en
|
||||||
|
|
||||||
El SDD `ocr-ingest-integration` se archiva con 29/30 tareas completas y 7.4 incompleta. La continuidad del hardening y de la aceptacion se controla mediante el contrato ODD canónico, sin declarar retrospectivamente superada la aceptacion fallida.
|
El SDD `ocr-ingest-integration` se archiva con 29/30 tareas completas y 7.4 incompleta. La continuidad del hardening y de la aceptacion se controla mediante el contrato ODD canónico, sin declarar retrospectivamente superada la aceptacion fallida.
|
||||||
|
|
||||||
**Salida anterior:** `0.2.1` supero los criterios del anexo y FacturaTech alcanzo `review_required` con evidencia completa. El nuevo bloque A-I solo se cierra cuando cumple el criterio de servicio completamente operativo; FacturaTech v8 solo se aprueba o activa con sus autorizaciones explicitas separadas.
|
**Salida anterior:** `0.2.1` supero los criterios del anexo y FacturaTech alcanzo `review_required` con evidencia completa. v8 fue rechazada posteriormente por decision del usuario; el bloque A-I solo se cierra al desplegar la correccion de limpieza, purgar las candidatas descartadas y verificar que v1 sigue activa.
|
||||||
|
|
||||||
## 1. Documentacion y descubrimiento de la API
|
## 1. Documentacion y descubrimiento de la API
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
**Proyecto:** Workspace de tools IA para empresas
|
**Proyecto:** Workspace de tools IA para empresas
|
||||||
**Modulo:** RAG
|
**Modulo:** RAG
|
||||||
**Ultima actualizacion:** 2026-09-23
|
**Ultima actualizacion:** 2026-09-24
|
||||||
**Ultima modificacion por:** Agente RAG 3
|
**Ultima modificacion por:** Agente RAG 3
|
||||||
**Estado:** RAG y OCR `0.2.1` desplegados; candidata FacturaTech v8 revisada y pendiente de aprobacion, indexacion y activacion
|
**Estado:** RAG y OCR `0.2.1` revision `bfb2d48` desplegados; v8 rechazada y correccion de limpieza OCR validada localmente pendiente de despliegue
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -279,9 +279,9 @@ La revision puede proponer correcciones exactas por linea. Aprobarla genera un a
|
||||||
|
|
||||||
## Seguimiento, temporizadores y recuperacion
|
## Seguimiento, temporizadores y recuperacion
|
||||||
|
|
||||||
### Comportamiento de la siguiente entrega
|
### Comportamiento desplegado
|
||||||
|
|
||||||
Este comportamiento esta implementado y validado en el worktree local, pero todavia no esta publicado ni desplegado. Produccion conserva la revision `0654ce5` hasta completar los gates separados de commit/push y despliegue.
|
Este comportamiento esta publicado y desplegado en la revision `bfb2d48`.
|
||||||
|
|
||||||
Al aceptar una ingesta OCR, RAG intenta despacharla inmediatamente. Si OCR sigue en `queued` o `running`, el dispatcher guarda `next_attempt_at` con un backoff entre 2 y 15 segundos.
|
Al aceptar una ingesta OCR, RAG intenta despacharla inmediatamente. Si OCR sigue en `queued` o `running`, el dispatcher guarda `next_attempt_at` con un backoff entre 2 y 15 segundos.
|
||||||
|
|
||||||
|
|
@ -340,15 +340,12 @@ En documentos hibridos, `imageUrl` es `null` para paginas nativas y solo referen
|
||||||
|
|
||||||
## Estado productivo verificado
|
## Estado productivo verificado
|
||||||
|
|
||||||
- RAG y OCR `0.2.1` estan desplegados desde la misma revision.
|
- RAG y OCR `0.2.1` estan desplegados desde la revision `bfb2d48`.
|
||||||
- PostgreSQL, Qdrant, OCR y reconciliador estan sanos.
|
- PostgreSQL, Qdrant, OCR y reconciliador estan sanos.
|
||||||
- FacturaTech v8 completo OCR en 25/25 paginas.
|
- FacturaTech v8 completo OCR y revision, pero fue rechazada sin aprobar, indexar ni activar; v1 sigue activa.
|
||||||
- RAG recupero resultado, 25 imagenes, diagnostico y candidata durable.
|
- Una prueba productiva sintetica demostro el flujo hibrido: pagina 1 nativa, pagina 2 OCR y `review_required` en menos de 18 segundos, sin activacion y con cola final vacia.
|
||||||
- La candidata conserva 34/34 entradas y esta pendiente de aprobar correcciones, indexar y activar.
|
- La limpieza de versiones OCR descubrio dos defectos en la decision de paginas blank y el orden de purga. Ambos estan corregidos y validados localmente.
|
||||||
- La validacion local hibrida posterior completo una pagina nativa y una OCR hasta `review_required` en 7 segundos, sin activacion y sin esperar al reconciliador de cinco minutos.
|
- Produccion conserva una candidata sintetica en `review_required` y otra en `purging`; no se reintenta su limpieza hasta desplegar la correccion.
|
||||||
- Las paginas 2, 20 y 21 tienen `LOW_P10_CONFIDENCE` no bloqueante.
|
|
||||||
- Las correcciones visuales conocidas incluyen `FATo7` -> `FAT07`, `NSAvo6` -> `NSAV06` y `DSAUo4` -> `DSAU04`.
|
|
||||||
- FacturaTech valida el camino OCR completo, pero no demuestra en produccion un PDF hibrido: sus 25 paginas necesitaron OCR. La composicion mixta esta cubierta localmente y queda pendiente una demostracion productiva controlada.
|
|
||||||
|
|
||||||
## Fuentes de detalle
|
## Fuentes de detalle
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import { EvaluationLogService } from "./modules/logs/service.js";
|
||||||
import { documentalChunkingPolicy } from "./modules/process/chunking.js";
|
import { documentalChunkingPolicy } from "./modules/process/chunking.js";
|
||||||
import { RetrieveService } from "./modules/retrieve/service.js";
|
import { RetrieveService } from "./modules/retrieve/service.js";
|
||||||
import { supportedParserExtensions } from "./modules/parsers/parser-registry.js";
|
import { supportedParserExtensions } from "./modules/parsers/parser-registry.js";
|
||||||
import { QdrantVectorStoreClient } from "./modules/vectorstore/client.js";
|
import { QdrantVectorStoreClient, type VectorStoreClient } from "./modules/vectorstore/client.js";
|
||||||
import { getCatalogPool } from "./modules/catalog/client.js";
|
import { getCatalogPool } from "./modules/catalog/client.js";
|
||||||
import { KnowledgeLifecycleReconciler } from "./modules/catalog/reconciler.js";
|
import { KnowledgeLifecycleReconciler } from "./modules/catalog/reconciler.js";
|
||||||
import { CatalogError, CatalogRepository } from "./modules/catalog/repository.js";
|
import { CatalogError, CatalogRepository } from "./modules/catalog/repository.js";
|
||||||
|
|
@ -41,6 +41,7 @@ interface AppOptions {
|
||||||
reviewService?: Pick<OcrReviewService, "view" | "approve" | "reject">;
|
reviewService?: Pick<OcrReviewService, "view" | "approve" | "reject">;
|
||||||
reviewRecoveryService?: Pick<OcrReviewRecoveryService, "recover">;
|
reviewRecoveryService?: Pick<OcrReviewRecoveryService, "recover">;
|
||||||
indexingService?: Pick<OcrIndexingService, "index">;
|
indexingService?: Pick<OcrIndexingService, "index">;
|
||||||
|
vectorStore?: VectorStoreClient;
|
||||||
startReconciler?: boolean;
|
startReconciler?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +58,7 @@ export function createApp(options: AppOptions = {}) {
|
||||||
limits: { fileSize: 50 * 1024 * 1024 }
|
limits: { fileSize: 50 * 1024 * 1024 }
|
||||||
});
|
});
|
||||||
const embeddingProvider = new OpenRouterEmbeddingProvider();
|
const embeddingProvider = new OpenRouterEmbeddingProvider();
|
||||||
const vectorStore = new QdrantVectorStoreClient();
|
const vectorStore = options.vectorStore ?? new QdrantVectorStoreClient();
|
||||||
const catalogPool = getCatalogPool();
|
const catalogPool = getCatalogPool();
|
||||||
const catalog = Object.prototype.hasOwnProperty.call(options, "catalog")
|
const catalog = Object.prototype.hasOwnProperty.call(options, "catalog")
|
||||||
? options.catalog
|
? options.catalog
|
||||||
|
|
@ -534,6 +535,7 @@ export function createApp(options: AppOptions = {}) {
|
||||||
if (remaining !== 0) {
|
if (remaining !== 0) {
|
||||||
throw new CatalogError("Version purge did not delete all points", 503, "VERSION_PURGE_INCOMPLETE");
|
throw new CatalogError("Version purge did not delete all points", 503, "VERSION_PURGE_INCOMPLETE");
|
||||||
}
|
}
|
||||||
|
await rm(resolveArtifactPath(ocr.artifactRoot, versionId), { recursive: true, force: true });
|
||||||
await repository.markPurged(versionId);
|
await repository.markPurged(versionId);
|
||||||
}));
|
}));
|
||||||
res.json({ ok: true, purged: true, versionId });
|
res.json({ ok: true, purged: true, versionId });
|
||||||
|
|
|
||||||
|
|
@ -1102,6 +1102,9 @@ export class CatalogRepository {
|
||||||
|
|
||||||
async markPurged(versionId: string): Promise<void> {
|
async markPurged(versionId: string): Promise<void> {
|
||||||
await withTransaction(this.pool, async (client) => {
|
await withTransaction(this.pool, async (client) => {
|
||||||
|
await client.query("DELETE FROM rag_review_corrections WHERE version_id = $1", [versionId]);
|
||||||
|
await client.query("DELETE FROM rag_document_pages WHERE version_id = $1", [versionId]);
|
||||||
|
await client.query("DELETE FROM rag_ocr_jobs WHERE version_id = $1", [versionId]);
|
||||||
await client.query("DELETE FROM rag_version_documents WHERE version_id = $1", [versionId]);
|
await client.query("DELETE FROM rag_version_documents WHERE version_id = $1", [versionId]);
|
||||||
const result = await client.query(
|
const result = await client.query(
|
||||||
`UPDATE rag_source_versions
|
`UPDATE rag_source_versions
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ export class PostgresOcrReviewStore implements OcrReviewStore {
|
||||||
if (candidatePages.length !== pages.rows.length || candidatePages.some(({ documentId, page }) => {
|
if (candidatePages.length !== pages.rows.length || candidatePages.some(({ documentId, page }) => {
|
||||||
const locked = pages.rows.find((value) => value.document_id === documentId && Number(value.page_number) === page.page);
|
const locked = pages.rows.find((value) => value.document_id === documentId && Number(value.page_number) === page.page);
|
||||||
return !locked || locked.native_text_hash !== sha256Hex(page.nativeText)
|
return !locked || locked.native_text_hash !== sha256Hex(page.nativeText)
|
||||||
|| locked.ocr_text_hash !== (page.ocr.text ? sha256Hex(page.ocr.text) : null)
|
|| locked.ocr_text_hash !== (page.imageUrl === null ? null : sha256Hex(page.ocr.text))
|
||||||
|| locked.candidate_text_hash !== sha256Hex(page.candidateText) || canonicalJson(locked.risk_tokens) !== canonicalJson(page.risks)
|
|| locked.candidate_text_hash !== sha256Hex(page.candidateText) || canonicalJson(locked.risk_tokens) !== canonicalJson(page.risks)
|
||||||
|| locked.quality_outcome !== page.qualityOutcome || canonicalJson(locked.quality_warnings) !== canonicalJson(page.warnings)
|
|| locked.quality_outcome !== page.qualityOutcome || canonicalJson(locked.quality_warnings) !== canonicalJson(page.warnings)
|
||||||
|| canonicalJson(locked.blocking_reasons) !== canonicalJson(page.blockingReasons)
|
|| canonicalJson(locked.blocking_reasons) !== canonicalJson(page.blockingReasons)
|
||||||
|
|
|
||||||
|
|
@ -271,3 +271,21 @@ test("quality blocking persists deterministic safe status details without OCR te
|
||||||
assert.match(serialized, /INSUFFICIENT_TEXT/u);
|
assert.match(serialized, /INSUFFICIENT_TEXT/u);
|
||||||
assert.doesNotMatch(serialized, /unsafe OCR text|token=secret|private\/path/u);
|
assert.doesNotMatch(serialized, /unsafe OCR text|token=secret|private\/path/u);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("purging removes OCR children before version documents", async () => {
|
||||||
|
const calls: string[] = [];
|
||||||
|
const repository = new CatalogRepository(poolFor(async (sql) => {
|
||||||
|
calls.push(sql);
|
||||||
|
return { rowCount: 1, rows: [] };
|
||||||
|
}) as never);
|
||||||
|
|
||||||
|
await repository.markPurged("version-1");
|
||||||
|
|
||||||
|
assert.deepEqual(calls.map((sql) => sql.match(/(?:DELETE FROM|UPDATE) ([a-z_]+)/u)?.[1]), [
|
||||||
|
"rag_review_corrections",
|
||||||
|
"rag_document_pages",
|
||||||
|
"rag_ocr_jobs",
|
||||||
|
"rag_version_documents",
|
||||||
|
"rag_source_versions"
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import test from "node:test";
|
import test from "node:test";
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
import { access, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { createApp } from "../src/app.js";
|
import { createApp } from "../src/app.js";
|
||||||
|
|
@ -406,6 +406,44 @@ test("markPurged fails when the version is no longer in purging state", async ()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("version purge removes durable OCR artifacts before marking the version purged", async (context) => {
|
||||||
|
const artifactRoot = await mkdtemp(path.join(os.tmpdir(), "rag-purge-artifacts-"));
|
||||||
|
const versionDirectory = path.join(artifactRoot, "version-1");
|
||||||
|
await mkdir(versionDirectory);
|
||||||
|
await writeFile(path.join(versionDirectory, "manifest.json"), "{}");
|
||||||
|
context.after(() => rm(artifactRoot, { recursive: true, force: true }));
|
||||||
|
|
||||||
|
await withEnvFlags({ lifecycleAdminToken: "purge-token", ocrArtifactRoot: artifactRoot }, async () => {
|
||||||
|
const calls: string[] = [];
|
||||||
|
const catalog = {
|
||||||
|
async withSourceLock(_sourceId: string, handler: () => Promise<unknown>) { return handler(); },
|
||||||
|
async withVersionExclusiveLock(_versionId: string, handler: () => Promise<unknown>) { return handler(); },
|
||||||
|
async markPurging() { calls.push("purging"); },
|
||||||
|
async markPurged() {
|
||||||
|
await assert.rejects(access(versionDirectory));
|
||||||
|
calls.push("purged");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const vectorStore: Partial<VectorStoreClient> = {
|
||||||
|
kind: "fake",
|
||||||
|
async deleteVersionPoints() { calls.push("delete-points"); return 1; },
|
||||||
|
async countVersionPoints() { calls.push("count-points"); return 0; }
|
||||||
|
};
|
||||||
|
const server = createApp({ catalog: catalog as never, vectorStore: vectorStore as VectorStoreClient, startReconciler: false }).listen(0);
|
||||||
|
context.after(() => server.close());
|
||||||
|
const address = server.address();
|
||||||
|
assert.ok(address && typeof address === "object");
|
||||||
|
|
||||||
|
const response = await fetch(`http://127.0.0.1:${address.port}/sources/source-1/versions/version-1`, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: { authorization: "Bearer purge-token" }
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(response.status, 200);
|
||||||
|
assert.deepEqual(calls, ["purging", "delete-points", "count-points", "purged"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("legacy migration apply reuses a catalog version created before payload update", async () => {
|
test("legacy migration apply reuses a catalog version created before payload update", async () => {
|
||||||
const source = buildLegacyMigrationPlan([{ id: "p1", payload: {
|
const source = buildLegacyMigrationPlan([{ id: "p1", payload: {
|
||||||
source_id: "src:default:file:source.md",
|
source_id: "src:default:file:source.md",
|
||||||
|
|
|
||||||
|
|
@ -385,3 +385,24 @@ test("production rejection records the bound reason without reviewed, correction
|
||||||
assert.doesNotMatch(statements, /rag_review_corrections|reviewed_text_hash|state = 'indexing'/u);
|
assert.doesNotMatch(statements, /rag_review_corrections|reviewed_text_hash|state = 'indexing'/u);
|
||||||
await assert.rejects(access(path.join(rootDirectory, current.versionId, "reviewed-pages.json")));
|
await assert.rejects(access(path.join(rootDirectory, current.versionId, "reviewed-pages.json")));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("production rejection accepts the persisted hash of an empty OCR page", async () => {
|
||||||
|
const current = candidate();
|
||||||
|
Object.assign(current.documents[0]!.pages[0]!, {
|
||||||
|
nativeText: "",
|
||||||
|
ocr: { text: "", lines: [] },
|
||||||
|
candidateText: "",
|
||||||
|
differences: [],
|
||||||
|
risks: []
|
||||||
|
});
|
||||||
|
const { pool, sql } = decisionPool(current);
|
||||||
|
const service = new OcrReviewService(new PostgresOcrReviewStore(pool, { async view() { return structuredClone(current); } }, "/unused"));
|
||||||
|
|
||||||
|
assert.deepEqual(await service.reject(current.versionId, {
|
||||||
|
candidateSha256: current.candidateSha256,
|
||||||
|
reviewedBy: "admin",
|
||||||
|
reason: "blank page"
|
||||||
|
}), { versionId: current.versionId, state: "rejected", activated: false });
|
||||||
|
assert.match(sql.join("\n"), /SET state = 'rejected'/u);
|
||||||
|
assert.equal(sql.at(-1)?.trim(), "COMMIT");
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue