Saltar a contenido

SOURCE-003 Python Importer Skeleton 001

Fecha local: 2026-06-15

Estado: IMPORTER SEGURO CON BUILD-MART SAFE MODE IMPLEMENTADO / WRITE REAL SOLO EN PROMOTE-CORE

portal_visible = yes

Scope: tenant

tenant_id: alpuntodeventa

Owner: Gabi / Carlos Canu

Fuente de verdad: docs/tenants/alpuntodeventa/business-observer/design/SOURCE-003-PYTHON-IMPORTER-SKELETON-001.md

1. Proposito

Documentar el primer skeleton del Python importer para SOURCE-003, alineado al contrato publicado en docs/tenants/alpuntodeventa/business-observer/design/SOURCE-003-PYTHON-IMPORTER-CONTRACT.md.

Este skeleton no es un importer operativo de carga. Expone comandos seguros de lectura documental, implementa inspeccion local real de artefactos SOURCE-003, permite generar un prepared CSV reproducible en ruta ignorada por Git, valida prepared historico contra generated existente sin escribir datos, implementa load-raw como dry-run seguro, agrega un gate explicito para load-raw --execute local-dev, implementa promote-core como safe mode read-only, agrega un gate explicito para promote-core --execute local-dev, implementa la ruta real de escritura CORE local-dev detras de confirmaciones completas y agrega build-mart como safe mode read-only con validacion CORE + MART y estimacion de agregados; solo status y rollback-batch siguen como comandos futuros bloqueados.

2. Script creado

Script: scripts/source_003_importer.py

Caracteristicas:

  • usa solo Python stdlib;
  • no lee secretos;
  • no lee .env;
  • no se conecta a PostgreSQL;
  • no ejecuta SQL;
  • no llama al runner;
  • genera CSV solo en snapshots/source-003/prepared/generated/ mediante generate-prepared;
  • valida CSV prepared historico y generated existente mediante validate-prepared;
  • implementa load-raw en modo seguro por defecto;
  • implementa load-raw --execute como gate local-dev controlado, bloqueado si falta cualquier confirmacion explicita;
  • implementa promote-core en modo seguro por defecto;
  • implementa promote-core --execute como gate local-dev controlado, bloqueado si falta cualquier confirmacion explicita;
  • implementa la ruta real promote-core --execute detras de confirmaciones completas, con transaccion RAW -> CORE, INSERT controlado en CORE, bloqueo de batch duplicado, fingerprint obligatorio y rollback automatico ante error;
  • expone future_write_path para promote-core, con fingerprint obligatorio, bloqueo postgres-sandbox, bloqueo de batch duplicado, transaccion futura, idempotencia, post-check CORE batch rows = 1886, preservacion de source_row_hash y line_key, y rollback/rebuild documentado;
  • usa psql read-only solo para fingerprint y checks RAW cuando ejecuta load-raw, promote-core o build-mart sin --execute;
  • implementa build-mart en modo seguro por defecto;
  • implementa build-mart --execute como bloqueo explicito sin tocar la DB;
  • puede leer variables locales .env APV_LOCAL_POSTGRES_ADMIN_* y APV_BO_LOCAL_POSTGRES_* sin imprimir secretos;
  • no reemplaza el CSV prepared validado;
  • inspecciona artefactos locales existentes sin modificarlos;
  • no carga datos;
  • no habilita sync.

3. Comandos seguros implementados

Comandos disponibles ahora:

  • --help;
  • plan;
  • validate-contract;
  • dry-run;
  • inspect-source;
  • generate-prepared;
  • validate-prepared;
  • load-raw;
  • promote-core;
  • build-mart.

validate-contract valida que existan:

  • contrato importer: docs/tenants/alpuntodeventa/business-observer/design/SOURCE-003-PYTHON-IMPORTER-CONTRACT.md;
  • generator script: scripts/source_003_prepare_csv.py;
  • runner script: scripts/source_003_pilot_load_runner.py;
  • arquitectura data layers: docs/tenants/alpuntodeventa/business-observer/design/BUSINESS-OBSERVER-DATA-LAYERS-ARCHITECTURE.md.

Tambien valida marcadores basicos del contrato, incluyendo comandos futuros y la decision CONTRATO IMPORTER DOCUMENTADO / NO IMPLEMENTADO.

inspect-source valida artefactos locales ya existentes, sin generar ni reemplazar datos:

  • raw snapshot: snapshots/source-003/SOURCE-003-TABLA2-V2-2026-06-09_20260610-210406-0300.csv;
  • raw sha256 esperado: 07092c284b5b636b8a31cd616ef5b4fa5d0ce499b81c767437842b1f7edfcbc3;
  • prepared CSV: snapshots/source-003/prepared/SOURCE-003-PILOT-LOAD-DEDICATED-DB-2026-06-09.csv;
  • prepared sha256 esperado: 3f16a957a79fc84d4ca37930988287cb81f05166210d057fcf8b45007f184afe;
  • filas prepared: 1886;
  • columnas prepared: 83;
  • batch: 1827f887-9499-4579-b4f3-234d54f41f7f;
  • fecha unica: 2026-06-09;
  • record_status = active;
  • CSV preparado fuera de Git: git_ignored=true, git_tracked=false.

Resultado validado:

json { "command": "inspect-source", "result": "PASS", "db_touched": false, "sql_executed": false, "data_written": false, "sync_enabled": false }

generate-prepared orquesta scripts/source_003_prepare_csv.py para generar:

text snapshots/source-003/prepared/generated/SOURCE-003-PILOT-LOAD-DEDICATED-DB-2026-06-09.generated.csv

Validacion observada:

  • raw sha256: 07092c284b5b636b8a31cd616ef5b4fa5d0ce499b81c767437842b1f7edfcbc3;
  • filas: 1886;
  • columnas: 83;
  • fecha unica: 2026-06-09;
  • batch: 1827f887-9499-4579-b4f3-234d54f41f7f;
  • record_status = active;
  • source_row_hash no vacio;
  • line_key no vacio;
  • output fuera de Git: git_ignored=true, git_tracked=false.

Comparacion contra el CSV prepared validado:

text REPRODUCIBLE ESTRUCTURAL ACEPTADO

El resultado mantiene 82/83 columnas coincidentes. La diferencia esperada queda acotada a id por UUID v5 deterministico. El CSV historico validado no se reemplaza.

validate-prepared valida artefactos existentes sin generar CSV nuevo:

  • prepared historico: snapshots/source-003/prepared/SOURCE-003-PILOT-LOAD-DEDICATED-DB-2026-06-09.csv;
  • generated existente: snapshots/source-003/prepared/generated/SOURCE-003-PILOT-LOAD-DEDICATED-DB-2026-06-09.generated.csv;
  • ambos CSV fuera de Git: git_ignored=true, git_tracked=false;
  • prepared sha256: 3f16a957a79fc84d4ca37930988287cb81f05166210d057fcf8b45007f184afe;
  • generated sha256: 6fb44d9870a567e728df9bbdcc6b83279d84791bd732626c9e19ccf3a28dc903;
  • filas: 1886;
  • columnas: 83;
  • fecha unica: 2026-06-09;
  • batch: 1827f887-9499-4579-b4f3-234d54f41f7f;
  • record_status = active;
  • source_row_hash no vacio;
  • line_key no vacio;
  • comparacion prepared vs generated: REPRODUCIBLE ESTRUCTURAL ACEPTADO, 82/83 columnas coincidentes, diferencia esperada en id;
  • db_touched=false;
  • sql_executed=false;
  • data_written=false;
  • sync_enabled=false.

Resultado validado:

json { "command": "validate-prepared", "result": "PASS", "rows": 1886, "columns": 83, "comparison_status": "REPRODUCIBLE ESTRUCTURAL ACEPTADO", "columns_matching": "82/83", "db_touched": false, "sql_executed": false, "data_written": false, "sync_enabled": false }

load-raw valida en modo seguro/dry-run:

  • validate-prepared = PASS;
  • prepared CSV historico existente;
  • generated CSV existente;
  • batch esperado: 1827f887-9499-4579-b4f3-234d54f41f7f;
  • 1886 filas candidatas;
  • tabla RAW: business_observer.raw_source_003_sales_items;
  • DB local-dev autorizada: openclaw_business_observer_dev;
  • fingerprint DB aprobado: ::1/128:5432|openclaw_business_observer_dev|postgres|PostgreSQL 15.15, compiled by Visual C++ build 1944, 64-bit;
  • tabla RAW existe;
  • row_count RAW = 0;
  • columnas destino RAW: 84;
  • db_write=false;
  • sql_write=false;
  • data_written=false;
  • sync_enabled=false;
  • runner no llamado;
  • rollback no ejecutado;
  • CSV no generado.

Resultado validado:

json { "command": "load-raw", "result": "DRY_RUN", "db_touched": true, "db_write": false, "sql_executed": true, "sql_write": false, "data_written": false, "sync_enabled": false, "candidate_rows": 1886, "expected_destination_columns": 84, "target_table": "business_observer.raw_source_003_sales_items" }

Nota: sql_executed=true representa consultas SELECT read-only de fingerprint, catalogo y conteo. sql_write=false confirma que no se ejecuto INSERT, COPY, UPDATE, DELETE, DDL ni rollback.

load-raw --execute queda bloqueado si faltan confirmaciones explicitas y no ejecuta escritura real en esta etapa. La ruta futura de escritura local-dev queda preparada como plan transaccional bloqueado, con duplicate batch en BLOCKED y loaded_at resuelto por politica gobernada de DB.

Confirmaciones requeridas por el gate:

  • --confirm-local-dev;
  • --confirm-write-local-dev;
  • --confirm-tenant-id alpuntodeventa;
  • --confirm-source-id SOURCE-003;
  • --confirm-target-database openclaw_business_observer_dev;
  • --confirm-target-table business_observer.raw_source_003_sales_items;
  • --confirm-batch 1827f887-9499-4579-b4f3-234d54f41f7f;
  • --confirm-raw-empty;
  • --confirm-row-count 1886;
  • --confirm-destination-columns 84;
  • --confirm-prepared-sha256 3f16a957a79fc84d4ca37930988287cb81f05166210d057fcf8b45007f184afe;
  • --confirm-generated-sha256 6fb44d9870a567e728df9bbdcc6b83279d84791bd732626c9e19ccf3a28dc903;
  • --confirm-db-fingerprint "::1/128:5432|openclaw_business_observer_dev|postgres|PostgreSQL 15.15, compiled by Visual C++ build 1944, 64-bit".

Resultado sin confirmaciones:

json { "command": "load-raw", "result": "BLOCKED", "db_touched": false, "db_write": false, "sql_executed": false, "sql_write": false, "data_written": false, "sync_enabled": false }

El payload documenta DB autorizada, tabla RAW, row_count RAW inicial esperado 0, CSV prepared/generated requeridos, 1886 filas candidatas, 84 columnas destino, batch esperado, fingerprint DB obligatorio, postgres-sandbox prohibido, bloqueo de batch duplicado, politica gobernada de loaded_at, transaccion futura preparada, post-check esperado de 1886 filas y rollback por batch separado.

promote-core valida en modo seguro/dry-run:

  • validate-prepared = PASS;
  • batch esperado: 1827f887-9499-4579-b4f3-234d54f41f7f;
  • fingerprint DB aprobado: ::1/128:5432|openclaw_business_observer_dev|postgres|PostgreSQL 15.15, compiled by Visual C++ build 1944, 64-bit;
  • postgres-sandbox prohibido;
  • RAW source: business_observer.raw_source_003_sales_items;
  • CORE target: business_observer.core_source_003_sales_items;
  • RAW batch rows = 1886;
  • CORE row_count = 0;
  • candidate_rows = 1886;
  • target_columns = 66;
  • duplicates CORE = 0;
  • db_write=false;
  • sql_write=false;
  • data_written=false;
  • sync_enabled=false;
  • runner no llamado;
  • CSV no generado.

Resultado validado:

json { "command": "promote-core", "result": "DRY_RUN", "raw_batch_rows": 1886, "core_row_count": 0, "candidate_rows": 1886, "target_columns": 66, "duplicates_core": 0, "db_write": false, "data_written": false, "sync_enabled": false }

promote-core --execute queda bloqueado por confirmaciones explicitas y preserva:

json { "command": "promote-core", "result": "BLOCKED", "db_touched": false, "db_write": false, "sql_executed": false, "sql_write": false, "data_written": false, "sync_enabled": false }

Confirmaciones requeridas por el gate:

  • --confirm-local-dev;
  • --confirm-promote-core-local-dev;
  • --confirm-target-database openclaw_business_observer_dev;
  • --confirm-source-table business_observer.raw_source_003_sales_items;
  • --confirm-target-table business_observer.core_source_003_sales_items;
  • --confirm-batch 1827f887-9499-4579-b4f3-234d54f41f7f;
  • --confirm-raw-row-count 1886;
  • --confirm-core-empty;
  • --confirm-core-initial-row-count 0;
  • --confirm-candidate-rows 1886;
  • --confirm-target-columns 66;
  • --confirm-duplicates-core 0;
  • --confirm-db-fingerprint "::1/128:5432|openclaw_business_observer_dev|postgres|PostgreSQL 15.15, compiled by Visual C++ build 1944, 64-bit".

Aunque todas las confirmaciones futuras coincidan, esta etapa devuelve BLOCKED porque no existe ruta de escritura CORE implementada.

build-mart valida en modo seguro/dry-run:

  • fingerprint DB aprobado: ::1/128:5432|openclaw_business_observer_dev|postgres|PostgreSQL 15.15, compiled by Visual C++ build 1944, 64-bit;
  • postgres-sandbox prohibido;
  • CORE source: business_observer.core_source_003_sales_items;
  • MART target: business_observer.mart_source_003_sales_daily;
  • MART target: business_observer.mart_source_003_sales_by_seller;
  • MART target: business_observer.mart_source_003_sales_by_customer;
  • MART target: business_observer.mart_source_003_sales_by_sku;
  • batch esperado: 1827f887-9499-4579-b4f3-234d54f41f7f;
  • CORE total rows = 1886;
  • CORE batch rows = 1886;
  • row_count real en cada MART: 0;
  • agregados estimados: sales_daily = 1, sales_by_seller = 25, sales_by_customer = 173, sales_by_sku = 180;
  • source_query_versions = 1;
  • business_date_min = 2026-06-09;
  • business_date_max = 2026-06-09;
  • claves vacias excluidas: seller = 0, customer = 0, sku = 0;
  • db_write=false;
  • sql_write=false;
  • data_written=false;
  • sync_enabled=false.

Resultado validado:

json { "command": "build-mart", "result": "DRY_RUN", "core_batch_rows": 1886, "mart_daily_row_count": 0, "mart_seller_row_count": 0, "mart_customer_row_count": 0, "mart_sku_row_count": 0, "candidate_daily_rows": 1, "candidate_seller_rows": 25, "candidate_customer_rows": 173, "candidate_sku_rows": 180, "db_write": false, "data_written": false, "sync_enabled": false }

Nota: sql_executed=true representa consultas SELECT read-only de fingerprint, catalogo, conteos y estimacion de agregados. sql_write=false confirma que no se ejecuto INSERT, COPY, UPDATE, DELETE, DDL ni rollback.

build-mart --execute queda bloqueado explicitamente en esta tarea y preserva:

json { "command": "build-mart", "result": "BLOCKED", "db_touched": false, "db_write": false, "sql_executed": false, "sql_write": false, "data_written": false, "sync_enabled": false }

4. Comandos futuros bloqueados

El skeleton declara pero bloquea:

  • status;
  • rollback-batch.

load-raw --execute, promote-core --execute, build-mart --execute y los comandos futuros pendientes devuelven BLOCKED y preservan:

json { "importer_implemented": true, "db_touched": false, "db_write": false, "sql_executed": false, "sql_write": false, "data_written": false, "sync_enabled": false }

5. Resultado esperado del skeleton

Los comandos seguros deben emitir evidencia JSON legible con:

  • skeleton_only = true;
  • tenant_id = alpuntodeventa;
  • source_id = SOURCE-003;
  • importer_implemented = false;
  • db_touched = false;
  • sql_executed = false;
  • data_written = false;
  • sync_enabled = false.

6. Validaciones ejecutadas

Validaciones de esta etapa:

text python -m py_compile scripts/source_003_importer.py python scripts/source_003_importer.py --help python scripts/source_003_importer.py validate-prepared python scripts/source_003_importer.py load-raw python scripts/source_003_importer.py load-raw --execute python scripts/source_003_importer.py promote-core python scripts/source_003_importer.py promote-core --execute python scripts/source_003_importer.py build-mart python scripts/source_003_importer.py build-mart --execute python scripts/source_003_importer.py dry-run git diff --check .venv-portal\Scripts\mkdocs.exe build --strict

7. Bloqueos preservados

Esta etapa preserva:

  • sin escritura en PostgreSQL;
  • SQL solo SELECT read-only en load-raw, promote-core y build-mart;
  • psql solo en load-raw, promote-core y build-mart para fingerprint/checks read-only;
  • sin runner;
  • sin archivos de datos;
  • sin reemplazo del CSV prepared validado;
  • sin carga;
  • sin modificacion de datos;
  • sin sync diaria;
  • sin carga masiva;
  • sin produccion final;
  • sin OpenClaw executor;
  • sin VPS;
  • sin Docker;
  • sin NPM;
  • sin push;
  • sin deploy.

8. Decision

text IMPORTER SEGURO CON PROMOTE-CORE EXECUTE GATE / SIN CARGA CORE

El skeleton scripts/source_003_importer.py queda creado como primera capa CLI segura y contractual para el futuro importer de SOURCE-003.

Implementa inspect-source como inspeccion local read-only de artefactos ya existentes, generate-prepared como generacion local segura en ruta ignorada por Git y validate-prepared como validacion local read-only del prepared historico contra el generated existente. Implementa load-raw como dry-run seguro con probes DB read-only, implementa --execute como gate local-dev bloqueado por confirmaciones explicitas, implementa promote-core como dry-run seguro con probes DB read-only contra RAW/CORE y bloquea promote-core --execute mediante confirmaciones explicitas, e implementa build-mart como dry-run seguro con probes DB read-only contra CORE/MART y estimacion de agregados. No implementa carga real a MART, no ejecuta SQL de escritura, no llama al runner, no carga datos, no reemplaza el CSV prepared validado y no habilita sync.