Saltar a contenido

SOURCE-003 Pilot Load Python Runner 001

Fecha local: 2026-06-12

Estado: RUNNER CONTROLADO / SEMANTICA PREFLIGHT VS STATUS DEFINIDA

portal_visible = yes

Scope: tenant

tenant_id: alpuntodeventa

Owner: Gabi / Carlos Canu

Fuente de verdad: docs/tenants/alpuntodeventa/business-observer/design/SOURCE-003-PILOT-LOAD-PYTHON-RUNNER-001.md

1. Objetivo

Crear un runner Python controlado para SOURCE-003 que deje preparada la futura orquestacion gobernada:

text preflight -> candidate load -> post-checks -> rollback seguro

Este runner no ejecuta SQL ni toca PostgreSQL en esta tarea. Solo deja la CLI, las validaciones locales, las guardas de ejecucion y el contrato tecnico para una revision futura separada.

2. Script

Script versionado:

text scripts/source_003_pilot_load_runner.py

Caracteristicas:

  • usa solo Python stdlib;
  • valida archivos locales antes de cualquier intento de DB;
  • conoce solo la DB, tenant, tabla, batch, fecha y CSV autorizados;
  • resuelve psql solo desde PATH;
  • acepta unicamente un ejecutable resuelto como psql o psql.exe;
  • no acepta rutas arbitrarias ni argumentos embebidos para psql;
  • no usa shell execution para futuros modos DB;
  • no imprime passwords;
  • no imprime connection strings completas;
  • leeria secretos solo desde variables de entorno en una revision futura;
  • exige ON_ERROR_STOP=1 para cualquier psql futuro;
  • valida existencia de los SQL 004;
  • valida existencia y sha256 del CSV;
  • exige evidencia fuerte de identidad de instancia antes de cualquier modo DB futuro;
  • sanitiza defensivamente la salida de modos DB y no devuelve stdout / stderr completos;
  • deja auditoria monotona de contacto DB para que un fallo no pueda reescribir a falso un intento real de probe o de script SQL autorizado;
  • valida batch, fecha, tenant, record_status, source_row_hash y formato de hora_origen_sgc;
  • define exit codes estables para error de validacion, bloqueo y entorno;
  • no ejecuta rollback automaticamente.

3. Comandos

Comandos implementados:

  • plan
  • validate-files
  • dry-run
  • preflight
  • status
  • verify-existing-pilot
  • load
  • post-checks
  • rollback
  • full

Comandos permitidos en esta tarea:

  • python scripts/source_003_pilot_load_runner.py --help
  • python scripts/source_003_pilot_load_runner.py plan --dry-run
  • python scripts/source_003_pilot_load_runner.py validate-files --dry-run
  • python scripts/source_003_pilot_load_runner.py dry-run

4. Modos permitidos ahora

Permitidos y ejecutables sin DB:

  • plan
  • validate-files
  • dry-run

Lectura DB futura con guardas:

  • preflight
  • status
  • verify-existing-pilot
  • post-checks como alias legacy de status

Modos presentes pero bloqueados en esta revision:

  • load
  • rollback
  • full

Motivo del bloqueo fuerte:

  • la evidencia vigente dice que openclaw_business_observer_dev.business_observer.source_003_sales_items ya tiene 1886 filas del batch 1827f887-9499-4579-b4f3-234d54f41f7f
  • reintentar load o full sobre la misma tabla y el mismo batch no debe hacerse sin un nuevo gate
  • ejecutar rollback sobre ese mismo batch tampoco corresponde sin una aprobacion separada nueva

Semantica funcional de lectura DB:

  • preflight significa preflight-before-load: valida en solo lectura que la tabla este vacia antes de una carga nueva autorizada
  • status significa verify-existing-pilot: valida en solo lectura que el piloto ya cargado siga sano con 1886 filas exactas del batch 1827f887-9499-4579-b4f3-234d54f41f7f
  • verify-existing-pilot es alias explicito de status
  • post-checks se conserva solo como alias legacy de status para no perder compatibilidad con la semantica historica del SQL 004
  • ningun modo de lectura DB habilita load, full ni rollback

5. Guardas de ejecucion

Los modos que tocan DB exigen simultaneamente:

  • --execute
  • --i-understand-this-touches-db
  • --confirm-database openclaw_business_observer_dev
  • --confirm-batch 1827f887-9499-4579-b4f3-234d54f41f7f
  • --confirm-csv-sha256 3f16a957a79fc84d4ca37930988287cb81f05166210d057fcf8b45007f184afe
  • --confirm-instance-fingerprint <fingerprint preflight aprobado>

Ademas, antes de tocar DB el runner revalida localmente:

  • existencia del CSV autorizado
  • sha256 exacto del CSV
  • 1886 filas
  • 83 columnas
  • fecha unica 2026-06-09
  • batch unico 1827f887-9499-4579-b4f3-234d54f41f7f
  • tenant_id = alpuntodeventa
  • record_status = active
  • 0 duplicados (tenant_id, line_key)
  • 0 source_row_hash vacios
  • hora_origen_sgc con formato HHMMSS
  • existencia de los cuatro SQL 004

Y, para cualquier modo DB futuro, la identidad de instancia no puede quedar atada solo al nombre de DB. El runner exige:

  • APV_BO_EXPECTED_POSTGRES_HOST
  • APV_BO_EXPECTED_POSTGRES_PORT
  • APV_BO_EXPECTED_POSTGRES_DB
  • APV_BO_EXPECTED_POSTGRES_USER
  • APV_BO_EXPECTED_POSTGRES_FINGERPRINT

La evidencia de fingerprint debe venir de un preflight separado y controlado. Ademas, para cualquier modo DB futuro, el runner primero debe ejecutar un probe real contra la conexion ya resuelta y comparar esa evidencia runtime contra lo declarado por el operador. La consulta de referencia del probe es:

sql SELECT json_build_object( 'server_addr', COALESCE(inet_server_addr()::text, 'unix_socket'), 'server_port', inet_server_port(), 'database', current_database(), 'user', current_user, 'server_version', current_setting('server_version'), 'version', version() )::text;

Con esa evidencia, el runner deriva un fingerprint canonico:

text <server_addr>:<server_port>|<database>|<user>|<version>

Si la consulta de probe no puede ejecutarse, si devuelve una forma inesperada, o si host, port, database, user o fingerprint no coinciden con la evidencia esperada, el runner debe bloquear la ejecucion antes de cualquier script SQL. El nombre de DB solo no alcanza.

6. Variables esperadas

Si en el futuro se aprobara ejecutar modos con DB, el runner esperaria estas variables de entorno:

  • APV_BO_LOCAL_POSTGRES_HOST opcional; default localhost
  • APV_BO_LOCAL_POSTGRES_PORT opcional; default 5432
  • APV_BO_LOCAL_POSTGRES_USER requerida
  • APV_BO_LOCAL_POSTGRES_PASSWORD requerida
  • APV_BO_LOCAL_POSTGRES_SSLMODE opcional
  • APV_BO_EXPECTED_POSTGRES_HOST requerida para identidad fuerte
  • APV_BO_EXPECTED_POSTGRES_PORT requerida para identidad fuerte
  • APV_BO_EXPECTED_POSTGRES_DB requerida y debe ser openclaw_business_observer_dev
  • APV_BO_EXPECTED_POSTGRES_USER requerida para identidad fuerte
  • APV_BO_EXPECTED_POSTGRES_FINGERPRINT requerida para identidad fuerte

El runner arma PGHOST, PGPORT, PGUSER, PGPASSWORD y PGDATABASE internamente para psql, sin imprimir el password ni una connection string completa. Para futuros modos DB, psql se resuelve solo desde PATH; si no hay un binario seguro llamado psql o psql.exe, el runner debe fallar.

7. Seguridad

Guardas de alcance explicitas:

  • no sync diaria
  • no carga masiva
  • no produccion final
  • no otros tenants
  • no otros schemas
  • no otros batches
  • no otros SQL fuera del paquete 004
  • no rollback automatico

Guardas adicionales de seguridad del runner:

  • stdout y stderr completos de modos DB no se devuelven en el payload;
  • solo se expone exit code, script ejecutado, PASS/FAIL, lineas sanitizadas minimas y un resumen controlado;
  • el payload de auditoria distingue explicitamente: postgresql_touched, postgresql_touch_attempted, fingerprint_probe_attempted, fingerprint_probe_completed, fingerprint_probe_failed y sql_script_executed;
  • esa auditoria es monotona: si un probe o script SQL ya fue intentado, un handler de error posterior no puede volver esos flags a false;
  • la redaccion defensiva cubre password, PGPASSWORD, connection strings y contexto sensible de conexion;
  • nombre de DB solo no alcanza para confiar en la instancia destino.

Semantica de auditoria:

  • modos seguros (plan, validate-files, dry-run): postgresql_touched = false, postgresql_touch_attempted = false, fingerprint_probe_attempted = false, sql_script_executed = false
  • probe futuro de fingerprint: fingerprint_probe_attempted = true antes de lanzar psql; si psql efectivamente corre y consulta, postgresql_touched = true; si el probe termina bien, fingerprint_probe_completed = true; si falla en cualquier punto posterior al intento, fingerprint_probe_failed = true
  • scripts SQL 004 futuros: sql_script_executed = true solo cuando un script autorizado llega a ejecutarse; no debe marcarse en modos seguros ni en bloqueos previos al lanzamiento del script

Semantica de resultado:

  • PASS tecnico del comando: el runner puede resolver psql, validar fingerprint y ejecutar el SQL 004 autorizado sin error de runtime
  • PASS funcional de preflight-before-load: la tabla destino sigue vacia y el batch autorizado todavia no esta cargado
  • BLOQUEADO esperado de preflight-before-load: la tabla ya contiene las 1886 filas del piloto historico; eso no es error tecnico pero si bloqueo funcional para una carga nueva
  • PASS funcional de status / verify-existing-pilot: existen exactamente 1886 filas del batch autorizado, fecha unica 2026-06-09, metadata exacta, 0 nulos criticos, 0 duplicados y line_key / source_row_hash validos
  • estado saludable de piloto ya cargado: debe leerse con status y no reinterpretarse como permiso de escritura

Regla documental critica:

  • la tabla ya tiene 1886 filas del piloto dedicado en verde
  • ese estado no habilita un nuevo load
  • ese mismo estado si puede ser PASS funcional para status
  • cualquier nueva ejecucion real requiere un gate futuro separado, nueva decision humana y probablemente nueva parametrizacion

8. Relacion con SQL 004

El runner no reemplaza los SQL 004. Los gobierna.

Relaciones:

  • preflight apunta a design/sql/004_source_003_dedicated_db_pilot_load_preflight.sql
  • status, verify-existing-pilot y post-checks apuntan a design/sql/004_source_003_dedicated_db_pilot_load_post_checks.sql
  • load apunta a design/sql/004_source_003_dedicated_db_pilot_load_candidate.sql
  • rollback apunta a design/sql/004_source_003_dedicated_db_pilot_load_rollback.sql

El runner agrega arriba de esos SQL:

  • validacion local de archivos;
  • confirmacion exacta de DB, batch y CSV sha256;
  • validacion declarativa de identidad por host, port, database, user y fingerprint esperado;
  • probe runtime obligatorio de fingerprint real antes de ejecutar cualquier script SQL;
  • validacion de que el CSV autorizado siga siendo el esperado;
  • revalidacion inmediata del SHA256 del CSV justo antes de cualquier futuro load o full;
  • bloqueo duro de los modos de escritura en esta revision.

9. Relacion con el generador Python de CSV

Documento relacionado:

text docs/tenants/alpuntodeventa/business-observer/design/SOURCE-003-PREPARED-CSV-PYTHON-GENERATOR-001.md

Relacion:

  • scripts/source_003_prepare_csv.py resuelve raw -> prepared CSV
  • scripts/source_003_pilot_load_runner.py resuelve la capa de control alrededor del eventual uso del CSV preparado

El runner asume como CSV autorizado:

text C:\APV\openclawai\snapshots\source-003\prepared\SOURCE-003-PILOT-LOAD-DEDICATED-DB-2026-06-09.csv

Con sha256 autorizado:

text 3f16a957a79fc84d4ca37930988287cb81f05166210d057fcf8b45007f184afe

10. Por que no es sync diaria

No es sync diaria porque:

  • esta atado a un unico snapshot congelado 2026-06-09
  • esta atado a un unico batch autorizado
  • no implementa ventana movil
  • no implementa upsert
  • no implementa comparacion por source_row_hash entre corridas
  • no implementa last_seen_at de refresh diario
  • no resuelve missing_from_source
  • no maneja fechas vivas ni drift operacional de SGC

11. Por que no es produccion

No es produccion porque:

  • el alcance sigue siendo piloto dedicado y controlado
  • el mismo batch ya fue cargado y queda cerrado como evidencia verde
  • la estrategia futura de operacion real sobre la DB dedicada sigue bloqueada
  • no existe aprobacion para scheduler, sync diaria ni carga masiva
  • no se habilitan otros tenants, otras tablas ni otros entornos

12. Proximo gate necesario

Antes de cualquier ejecucion real futura se necesita un nuevo gate explicito que defina como minimo:

  1. si corresponde solo lectura estricta previa a carga (preflight-before-load) o verificacion de piloto ya cargado (status / verify-existing-pilot), o tambien escritura;
  2. si el batch sigue siendo este o debe ser uno nuevo;
  3. si el CSV autorizado sigue siendo el historico o uno nuevo generado por pipeline;
  4. si el estado cargado actual de 1886 filas se preserva, se audita o se corrige por otra via;
  5. si el runner debe evolucionar a una version nueva para operacion real.