Saltar a contenido

SOURCE-003 Runner Preflight DB 001

Fecha local: 2026-06-12 00:23:02 -03:00

Estado: PREFLIGHT DB RUNNER BLOQUEADO / AMARILLO

portal_visible = yes

Scope: tenant

tenant_id: alpuntodeventa

Owner: Gabi / Carlos Canu

Fuente de verdad: docs/tenants/alpuntodeventa/business-observer/design/SOURCE-003-RUNNER-PREFLIGHT-DB-001.md

1. Objetivo

Validar en modo controlado que el runner Python de SOURCE-003 puede:

  • resolver una conexion segura a la DB dedicada local;
  • ejecutar el probe real de fingerprint de instancia;
  • ejecutar exclusivamente el preflight DB autorizado;
  • dejar evidencia sin ejecutar load, full, rollback, COPY, INSERT, MERGE, UPSERT, DELETE ni TRUNCATE.

2. SAFE POINT

Control Resultado
rama main
git status -sb ## main...origin/main
git rev-parse HEAD 3fc7c25c81bba3d4e85e3f6a697ae11371436161
git ls-remote origin main 3fc7c25c81bba3d4e85e3f6a697ae11371436161 refs/heads/main
ultimo commit 3fc7c25 tools: fix source 003 runner db touch telemetry
decision SAFE POINT PASS

3. Revision previa segura

Comandos seguros ejecutados:

  • python -m py_compile scripts/source_003_pilot_load_runner.py
  • 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

Resultado:

  • py_compile: PASS
  • --help: PASS
  • plan --dry-run: PASS
  • validate-files --dry-run: PASS
  • dry-run: PASS

Telemetria observada en modos seguros:

  • postgresql_touched = false
  • postgresql_touch_attempted = false
  • fingerprint_probe_attempted = false
  • fingerprint_probe_completed = false
  • fingerprint_probe_failed = false
  • sql_script_executed = false
  • sql_executed = false

4. Entorno validado sin secretos

Controles de entorno:

Control Resultado
CSV autorizado existe PASS
sha256 CSV autorizado PASS
batch CSV esperado 1827f887-9499-4579-b4f3-234d54f41f7f PASS
DB autorizada openclaw_business_observer_dev PASS
psql instalado localmente PASS
psql inicialmente visible en PATH del shell NO
basename del binario observado psql.exe
variables del runner presentes tal cual en .env NO

Notas operativas:

  • el host tiene C:\Program Files\PostgreSQL\15\bin\psql.exe, pero no estaba publicado en PATH del shell inicial;
  • para esta tarea se agrego esa carpeta solo al PATH del proceso del comando, sin modificar configuracion persistente del host;
  • .env local contiene APV_BO_LOCAL_POSTGRES_HOST, APV_BO_LOCAL_POSTGRES_PORT y APV_BO_LOCAL_POSTGRES_SSLMODE, pero no contiene APV_BO_LOCAL_POSTGRES_USER ni APV_BO_LOCAL_POSTGRES_PASSWORD;
  • para ejecutar exclusivamente este preflight controlado se mapearon en memoria del proceso APV_LOCAL_POSTGRES_ADMIN_USER/PASSWORD hacia APV_BO_LOCAL_POSTGRES_USER/PASSWORD;
  • APV_BO_EXPECTED_POSTGRES_HOST, PORT, DB, USER y FINGERPRINT se cargaron solo en memoria del proceso para satisfacer la identidad fuerte exigida por el runner;
  • no se imprimieron passwords, PGPASSWORD ni connection strings completas.

5. Fingerprint esperado usado y evidencia real observada

Como no existia una variable persistida APV_BO_EXPECTED_POSTGRES_FINGERPRINT, se obtuvo primero una evidencia minima de solo lectura con la misma consulta de referencia documentada por el runner, sin ejecutar load, rollback ni full.

Fingerprint esperado usado por el runner:

text ::1/128:5432|openclaw_business_observer_dev|postgres|PostgreSQL 15.15, compiled by Visual C++ build 1944, 64-bit

Campos no sensibles observados en la instancia real:

Campo Observado
server_addr ::1/128
server_port 5432
database openclaw_business_observer_dev
user postgres
server_version 15.15

Resultado del fingerprint:

  • fingerprint_probe_attempted = true
  • fingerprint_probe_completed = true
  • fingerprint_probe_failed = false
  • decision fingerprint: PASS

6. Comando del runner ejecutado

Preparacion del proceso antes del comando:

  • carga de .env local en memoria del proceso;
  • agregado de C:\Program Files\PostgreSQL\15\bin al PATH del proceso;
  • mapeo temporal de APV_LOCAL_POSTGRES_ADMIN_USER/PASSWORD hacia APV_BO_LOCAL_POSTGRES_USER/PASSWORD;
  • carga temporal de APV_BO_EXPECTED_POSTGRES_* con la evidencia de fingerprint aprobada para esta corrida.

Comando ejecutado:

text python scripts/source_003_pilot_load_runner.py preflight --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 "::1/128:5432|openclaw_business_observer_dev|postgres|PostgreSQL 15.15, compiled by Visual C++ build 1944, 64-bit"

7. Resultado del runner

Payload principal observado:

  • command = preflight
  • result = PASS
  • postgresql_touch_attempted = true
  • postgresql_touched = true
  • fingerprint_probe_attempted = true
  • fingerprint_probe_completed = true
  • fingerprint_probe_failed = false
  • sql_script_executed = true
  • sql_executed = true
  • psql_bin = psql.EXE
  • returncode = 0

SQL ejecutado por el runner:

text docs/tenants/alpuntodeventa/business-observer/design/sql/004_source_003_dedicated_db_pilot_load_preflight.sql

Extracto saneado del runner:

text current_database | openclaw_business_observer_dev | openclaw_business_observer_dev | t target_table_exists | t | t | t

8. Resultado funcional del preflight

Evidencia de solo lectura levantada despues de la corrida para interpretar el estado funcional del gate:

Check Observado Resultado
filas totales tabla destino 1886 estado esperado del piloto ya cargado
filas tenant_id = alpuntodeventa 1886 estado esperado del piloto ya cargado
filas batch 1827f887-9499-4579-b4f3-234d54f41f7f 1886 estado esperado del piloto ya cargado
target_table_empty_before_pilot_load false BLOQUEADO
source_003_not_loaded_in_dedicated_db false BLOQUEADO

Interpretacion correcta del gate:

PREFLIGHT BLOQUEADO / TABLA NO VACIA ESPERADA POR PILOTO YA CARGADO

Semantica correcta de la corrida:

Capa Resultado
PASS tecnico del comando SI
PASS funcional de preflight-before-load NO
BLOQUEADO esperado de preflight-before-load SI
estado saludable de piloto ya cargado SI, pero debe leerse con status / verify-existing-pilot

Nota importante:

  • el runner devolvio PASS a nivel de ejecucion controlada porque pudo conectar, validar fingerprint y correr el SQL autorizado;
  • el SQL 004 historico publica checks observables, pero no fuerza un returncode distinto de cero cuando los checks de tabla vacia y batch ausente quedan en false;
  • por lo tanto, para esta corrida el resultado operativo correcto es BLOQUEADO, no porque haya fallado la conexion o el fingerprint, sino porque la tabla ya tiene cargadas las 1886 filas del piloto verde.

9. Confirmaciones de alcance

Control Resultado
load ejecutado NO
full ejecutado NO
rollback ejecutado NO
candidate load ejecutado NO
COPY ejecutado NO
INSERT ejecutado NO
MERGE ejecutado NO
UPSERT ejecutado NO
DELETE ejecutado NO
TRUNCATE ejecutado NO
sync diaria NO
carga masiva NO
produccion final NO
cambios en VPS, Docker, OpenClaw, NPM NO
cambios de datos en PostgreSQL NO
DDL ejecutado NO
DML ejecutado NO

10. Decision

Decision final:

PREFLIGHT DB RUNNER BLOQUEADO / AMARILLO

Motivo exacto:

PREFLIGHT BLOQUEADO / TABLA NO VACIA ESPERADA POR PILOTO YA CARGADO

11. Reinterpretacion semantica posterior

  • esta evidencia debe leerse como corrida de preflight-before-load y no como verificacion de piloto ya cargado
  • el modo futuro status / verify-existing-pilot debe reutilizar el SQL 004 de post-checks para validar exactamente 1886 filas del batch 1827f887-9499-4579-b4f3-234d54f41f7f, fecha 2026-06-09, metadata exacta, 0 nulos criticos, 0 duplicados y line_key / source_row_hash validos
  • post-checks queda como alias legacy de status
  • ningun PASS de status debe habilitar load, full ni rollback

12. Proximo paso recomendado

Mantener load, full, rollback, sync diaria, carga masiva y produccion final en estado bloqueado. Si se necesita otra verificacion read-only sobre la DB dedicada, abrir un gate separado y usar status / verify-existing-pilot para el piloto ya cargado; reservar preflight para una futura carga nueva autorizada sobre tabla vacia.