2ebc9efeb2
- scratchpad/gen_docs.py - scratchpad/gen_intel.py - scratchpad/gen_verify.py - scratchpad/intel_build.json - scratchpad/intel_lineage.json - scratchpad/lineage_graph.json - scratchpad/trace_intel.py - scratchpad/trace_lineage.py Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
127 lines
6.3 KiB
Python
127 lines
6.3 KiB
Python
"""Genera 00c_VERIFICACION.txt (chequeo de completitud del linaje) y
|
|
06_otros_outputs_clientes_intel/ (SQL de las tablas de clientes_intel que NO acaban
|
|
en customer_marts, para no dejar ninguna atras).
|
|
"""
|
|
import json
|
|
import os
|
|
import textwrap
|
|
|
|
DEST = "/mnt/c/Users/egutierrez/Desktop/linaje_customer_marts"
|
|
PROJECT = "autingo-159109"
|
|
builds = json.load(open("scratchpad/intel_build.json"))
|
|
lin = json.load(open("scratchpad/intel_lineage.json"))
|
|
involved = set(lin["intel_involved"])
|
|
|
|
# Catalogo completo de clientes_intel (40 objetos) reconstruido: involved + leftovers conocidos.
|
|
LEFTOVER = [
|
|
"_presupuesto_persona", "_veh_cluster_feat", "_veh_tec_feat", "audit_persona_divergencias",
|
|
"calidad_email_snapshot", "f0_audit_keys", "fact_impacto_campana", "map_mutualista_particular",
|
|
"reco_promo_personalizada", "reco_promo_segmento", "rpt_campana", "rpt_campana_lift",
|
|
"rpt_campana_usuario", "rpt_impacto_persona", "seg_audiencia", "seg_vega_persona",
|
|
"sf_contact_map", "tipologia_cliente_resumen", "veh_cluster",
|
|
]
|
|
|
|
# Clasificacion por proposito (a donde va cada leftover).
|
|
CATEGORY = {
|
|
"rpt_campana": "Informe de campanas (BI / dashboards de marketing)",
|
|
"rpt_campana_lift": "Informe de campanas: lift (BI / dashboards)",
|
|
"rpt_campana_usuario": "Informe de campanas por usuario (BI / dashboards)",
|
|
"rpt_impacto_persona": "Informe de impacto por persona (BI / dashboards)",
|
|
"fact_impacto_campana": "Hechos de impacto de campana (base de los informes)",
|
|
"reco_promo_personalizada": "Recomendacion de promo personalizada (activacion)",
|
|
"reco_promo_segmento": "Recomendacion de promo por segmento (activacion)",
|
|
"seg_audiencia": "Audiencias para activacion (probable push a Salesforce/Marketing)",
|
|
"sf_contact_map": "Mapa de contactos Salesforce (sincronizacion de IDs)",
|
|
"audit_persona_divergencias": "Auditoria de calidad: divergencias en resolucion de persona",
|
|
"calidad_email_snapshot": "Auditoria de calidad: snapshot de emails",
|
|
"f0_audit_keys": "Auditoria de claves (control interno del pipeline)",
|
|
"_presupuesto_persona": "Auxiliar: presupuestos por persona (interim)",
|
|
"_veh_cluster_feat": "Auxiliar: features para clustering de vehiculo (interim)",
|
|
"_veh_tec_feat": "Auxiliar: features tecnicas de vehiculo (interim)",
|
|
"veh_cluster": "Clustering de vehiculo (resultado; no lo usan los marts hoy)",
|
|
"tipologia_cliente_resumen": "Resumen de tipologia de cliente (BI)",
|
|
"map_mutualista_particular": "Vista auxiliar: mapa mutualista/particular",
|
|
"seg_vega_persona": "Segmentacion VEGA por persona (contactabilidad; lee fuentes de cliente)",
|
|
}
|
|
|
|
SEP = "=" * 78 + "\n"
|
|
|
|
def w(path, text):
|
|
full = os.path.join(DEST, path)
|
|
os.makedirs(os.path.dirname(full), exist_ok=True)
|
|
with open(full, "w", newline="\r\n", encoding="utf-8") as f:
|
|
f.write(text)
|
|
|
|
# --- 06: SQL de los leftovers que tengan build capturado ---
|
|
written = []
|
|
for t in LEFTOVER:
|
|
b = builds.get(t)
|
|
if not b:
|
|
continue
|
|
out = [SEP, f"OBJETO : {PROJECT}.clientes_intel.{t}\n",
|
|
f"TIPO : {b['stmt']} (NO alimenta customer_marts)\n",
|
|
f"ULTIMA EJECUCION CAPTURADA: {b['last_run']}\n", SEP,
|
|
"\nQUE ES / A DONDE VA\n-------------------\n",
|
|
textwrap.fill(CATEGORY.get(t, "(sin clasificar)"), width=78) + "\n"]
|
|
if b["refs"]:
|
|
out.append("\nLEE DE\n------\n")
|
|
for r in b["refs"]:
|
|
out.append(f" - {PROJECT}.{r}\n")
|
|
out.append("\nSQL DE CONSTRUCCION (copiable)\n------------------------------\n\n")
|
|
out.append(b["query"].strip() + "\n")
|
|
w(f"06_otros_outputs_clientes_intel/{t}.txt", "".join(out))
|
|
written.append(t)
|
|
|
|
# --- 00c: verificacion de completitud ---
|
|
v = [SEP, "VERIFICACION DE COMPLETITUD DEL LINAJE\n", SEP, "\n"]
|
|
v.append("PREGUNTA: todo esto acaba en customer_marts? Comprobado.\n\n")
|
|
v.append("""RESPUESTA CORTA
|
|
---------------
|
|
La cadena customer_marts -> fuentes esta COMPLETA (todas las referencias resueltas,
|
|
0 tablas sin identificar). PERO customer_marts NO es el unico destino: es UNO de los
|
|
consumidores de la capa clientes_intel.
|
|
|
|
- clientes_intel tiene 40 objetos.
|
|
- 21 de ellos alimentan (directa o indirectamente) las 14 vistas de customer_marts.
|
|
- 19 NO van a customer_marts: son OTRAS salidas del mismo pipeline (informes de
|
|
campana, recomendaciones de promo, audiencias, auditorias, auxiliares).
|
|
|
|
El unico dataset MODELADO que lee clientes_intel es customer_marts. El resto de lo que
|
|
lee clientes_intel y customer_marts son consultas de BI / ad-hoc (tablas temporales
|
|
_hexhash / anon...), es decir Metabase u otros lo consumen directamente. En ese sentido
|
|
customer_marts SI es terminal en el modelo (aguas abajo solo hay BI).
|
|
|
|
""")
|
|
|
|
v.append(SEP + "1) LAS 21 TABLAS DE clientes_intel QUE SI ALIMENTAN customer_marts\n" + SEP + "\n")
|
|
for t in sorted(involved):
|
|
b = builds.get(t, {})
|
|
v.append(f" - {t} ({b.get('stmt','(sin job)')})\n")
|
|
|
|
v.append("\n" + SEP + "2) LAS 19 TABLAS DE clientes_intel QUE NO VAN A customer_marts\n" + SEP + "\n")
|
|
v.append(" (SQL de cada una en 06_otros_outputs_clientes_intel/)\n\n")
|
|
for t in LEFTOVER:
|
|
sql_note = "" if t in written else " [sin SQL de job capturado]"
|
|
v.append(f" - {t:28s} {CATEGORY.get(t,'')}{sql_note}\n")
|
|
|
|
v.append("\n" + SEP + "3) FUENTES BASE ALCANZADAS (fin del linaje)\n" + SEP + "\n")
|
|
v.append(" Fuera de clientes_intel, el pipeline lee de:\n\n")
|
|
for s in sorted(lin["external_sources"]):
|
|
v.append(f" - {PROJECT}.{s}\n")
|
|
|
|
v.append("\n" + SEP + "4) NOTAS DE COBERTURA\n" + SEP + "\n")
|
|
v.append(""" - score_clv y seg_cluster_vehiculo: usadas por customer_marts pero sin CTAS reciente
|
|
en el historial de jobs (son modelos ML / cargas antiguas). Su esquema esta en
|
|
02_intermedio_clientes_intel/; no hay un SQL de un solo job que las reconstruya.
|
|
- El SQL de construccion se tomo del ULTIMO job exitoso de cada tabla
|
|
(INFORMATION_SCHEMA.JOBS, region europe-west1, ventana 120 dias). Si una tabla se
|
|
reconstruye con otra logica fuera de esa ventana, no se captura aqui.
|
|
- customer_marts: 14 vistas = el dataset entero (no falta ninguna).
|
|
""")
|
|
|
|
w("00c_VERIFICACION.txt", "".join(v))
|
|
|
|
print(f"06_otros_outputs_clientes_intel/ -> {len(written)} archivos")
|
|
print("00c_VERIFICACION.txt -> escrito")
|
|
print("\nLeftovers sin SQL capturado:", [t for t in LEFTOVER if t not in written] or "ninguno")
|