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/mediantegenerate-prepared; - valida CSV prepared historico y generated existente mediante
validate-prepared; - implementa
load-rawen modo seguro por defecto; - implementa
load-raw --executecomo gate local-dev controlado, bloqueado si falta cualquier confirmacion explicita; - implementa
promote-coreen modo seguro por defecto; - implementa
promote-core --executecomo gate local-dev controlado, bloqueado si falta cualquier confirmacion explicita; - implementa la ruta real
promote-core --executedetras de confirmaciones completas, con transaccion RAW -> CORE,INSERTcontrolado en CORE, bloqueo de batch duplicado, fingerprint obligatorio y rollback automatico ante error; - expone
future_write_pathparapromote-core, con fingerprint obligatorio, bloqueopostgres-sandbox, bloqueo de batch duplicado, transaccion futura, idempotencia, post-checkCORE batch rows = 1886, preservacion desource_row_hashyline_key, y rollback/rebuild documentado; - usa
psqlread-only solo para fingerprint y checks RAW cuando ejecutaload-raw,promote-coreobuild-martsin--execute; - implementa
build-marten modo seguro por defecto; - implementa
build-mart --executecomo bloqueo explicito sin tocar la DB; - puede leer variables locales
.envAPV_LOCAL_POSTGRES_ADMIN_*yAPV_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_hashno vacio;line_keyno 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_hashno vacio;line_keyno vacio;- comparacion prepared vs generated:
REPRODUCIBLE ESTRUCTURAL ACEPTADO,82/83columnas coincidentes, diferencia esperada enid; 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; 1886filas 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-sandboxprohibido;- 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-sandboxprohibido;- 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_countreal 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
SELECTread-only enload-raw,promote-coreybuild-mart; psqlsolo enload-raw,promote-coreybuild-martpara 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.