/diego/ecxm-ops EscríbemeWrite to me
AI Engineer · operaciones · e-commerce COD ColombiaAI Engineer · operations · COD e-commerce, Colombia

Construí el sistema operativo de un negocio entero, y el gate que le impide mentir con dinero.

I built the operating system of an entire business, and the gate that stops it lying about money.

ECXM OPS cubre la cadena completa de un negocio de dropshipping COD, de espiar a la competencia a cerrar el mes, en un solo dashboard y una CLI de 35 comandos. El modo de fallo no es que Streamlit pete: es que el pivot afirme con total fluidez una utilidad neta falsa. Un decimal mal atribuido es el sueldo de otra persona.

ECXM OPS covers the full chain of a COD dropshipping business, from spying on competitors to closing the month, in one dashboard and a 35-command CLI. The failure mode isn't Streamlit crashing: it's the pivot fluently asserting a false net profit. One misattributed decimal is somebody else's pay.

En uso diario en mi propio negocio desde mayo de 2026, con 6.286 anuncios de la competencia indexados. Construido en solitario, con IA.In daily use in my own business since May 2026, with 6,286 competitor ads indexed. Built solo, with AI.

etapas encadenadas · espiar → analizar → clonar → crear → vender → cerrar → decidirchained stages · spy → analyse → clone → create → sell → close → decide
pedidos conciliados en 6 meses cerrados · 136 facturas OCR en 4 divisasorders reconciled across 6 closed months · 136 OCR invoices in 4 currencies
$
coste LLM del clonador de landings · era ~$0,05 por landing con VisionLLM cost of the landing cloner · it used to be ~$0.05 per landing with Vision
/3
gates golden en verde por igualdad exacta · uno de ellos decide una liquidacióngolden gates green on exact equality · one of them decides a payout
RecorridoWalkthrough

Un producto entra por un extremo y sale una liquidación por el otro

A product goes in one end and a payout comes out the other

No son siete scripts sueltos: es una sola cadena donde la salida de cada etapa es la entrada de la siguiente, y donde el estado vive en archivos que las demás etapas saben leer. Pulsa cualquier estación para ver qué hace, qué cuesta y con qué se sincroniza.

These aren't seven loose scripts: it's a single chain where each stage's output is the next one's input, and where state lives in files the other stages know how to read. Click any station to see what it does, what it costs and what it syncs with.

vista previa · corte heropreview · hero cut

Guion: escaneo de la Ads Library → producto al LAB (precios + copy + títulos) → réplica de la landing en $0 → creativos → control diario → cierre de mes → la tabla que dice qué producto es winner.Script: Ads Library scan → product into the LAB (pricing + copy + titles) → landing replica at $0 → creatives → daily control → month close → the table that says which product is a winner.

Estas 7 etapas del ciclo del producto viven en 6 pestañas del dashboard (cerrar y vender comparten FINANZAS). Hay 3 más de soporte (FEEDBACK, ACADEMIA y ROADMAP, que renderiza el mapa de arquitectura del propio dashboard) 9 en total.These 7 product-cycle stages live in 6 dashboard tabs (sell and close share FINANCE). There are 3 more support tabs (FEEDBACK, ACADEMIA and ROADMAP, which renders the dashboard's own architecture map) 9 in total.

Flagship · la superficie irreversibleFlagship · the irreversible surface

La única cifra del sistema que se convierte en el pago de una persona

The one figure in the system that turns into somebody's pay

El contrato del equipo tiene una cláusula corta: un producto es winner si cierra el mes con utilidad neta positiva, y entonces el reparto pasa de 50/50 a 40/60 a favor del colaborador. Toda la maquinaria de abajo existe para producir ese número. El dashboard está hecho para que yo confíe y cierre rápido: esa confianza es exactamente lo que convierte un error de atribución en dinero mal repartido.

The team contract has one short clause: a product is a winner if it closes the month with positive net profit, and then the split moves from 50/50 to 40/60 in the collaborator's favour. All the machinery below exists to produce that number. The dashboard is built so I trust it and close fast: that trust is exactly what turns an attribution error into money paid out wrong.

WALLET DropiDropi WALLET fletes reales por pedidoreal shipping cost per order FACTURAS · OCRINVOICES · OCR 136 PDFs · 4 divisas · caja real136 PDFs · 4 currencies · real cash SERVICIOS + ADMINSERVICES + ADMIN repartidos ∝ ventas entregadasallocated ∝ delivered sales PEDIDOS · DropiORDERS · Dropi export del mesmonth export LIMPIO solo los 4 estatus finalesonly the 4 final statuses UTILIDAD NETANET PROFIT ventas ENT − flete − costo − facturasDELIVERED sales − shipping − cost − invoices pivot.utilidad_mes() /eval-finanzas igualdad exacta exact equality ¿neta > 0?net > 0? cláusula 4.1clause 4.1 WINNER · 40 / 60 60 % para el colaborador60 % to the collaborator NORMAL · 50 / 50STANDARD · 50 / 50 reparto por defectodefault split

Pellizca para acercar y leer el detalle ↔Pinch to zoom in and read the detail ↔

La convención de nombres de campaña en Meta ([NOMBRE]_[PRODUCTO]_[FECHA]) no es cosmética: es lo que permite que el gasto publicitario baje hasta el producto correcto. Si una campaña no la respeta, el sistema lo marca, sin ella la atribución falla y la liquidación se reparte mal.

The Meta campaign naming convention ([NAME]_[PRODUCT]_[DATE]) isn't cosmetic: it's what lets ad spend flow down to the right product. If a campaign breaks it, the system flags it, without it attribution fails and the payout is split wrong.

FuenteSource Qué esWhat it is Regla duraHard rule UsoUse
LIMPIO ventas, estatus y flete del export de Dropisales, status and shipping from the Dropi export solo los 4 estatus finales cuentan para el mes; un pedido en tránsito no tiene resultado todavíaonly the 4 final statuses count for the month; an in-transit order has no outcome yet basebase
FACTURA (OCR) costes, servicios y publicidad leídos de los PDFscosts, services and ad spend read from the PDFs es lo que se pagó de verdad; un cobro con estado «Error» no cuentait's what was actually charged; a payment in "Error" state doesn't count caja · liquidacióncash · payout
CSV Ads impresiones, visitas y compras de Metaimpressions, visits and purchases from Meta nunca reemplaza a la factura como coste real: no trae ni desglose por campaña ni estado del cobronever replaces the invoice as real cost: it carries neither per-campaign breakdown nor payment state rendimiento · CPAperformance · CPA
PRORRATEOALLOCATION servicios repartidos entre productosservices split across products es una estimación y se etiqueta como tal; jamás se presenta como coste directo del productoit's an estimate and is labelled as one; never presented as a direct product cost estimadoestimated
# la garantía no la da el prompt — la fuerza un `return None` # ecxm/finanzas/facturas.py :: _convertir_cop tasa = _TASAS_COP.get(divisa_norm, None) if tasa is None: # divisa desconocida: NO inventar tasa 1.0 print(f"AVISO: divisa '{divisa}' desconocida") return None # el dashboard muestra " — " return round(imp * tasa, 2) # antes devolvía el importe SIN convertir: # una factura de 29,75 USD entraba como 29,75 COP # → coste subestimado ~4.200× → un producto # perdedor podía aparecer como winner
# the guarantee isn't the prompt: a `return None` forces it # ecxm/finanzas/facturas.py :: _convertir_cop rate = _TASAS_COP.get(currency_norm, None) if rate is None: # unknown currency: do NOT invent a 1.0 rate print(f"WARNING: currency '{currency}' unknown") return None # the dashboard shows ", " return round(amount * rate, 2) # it used to return the amount UNCONVERTED: # a 29.75 USD invoice landed as 29.75 COP # → cost understated ~4,200× → a losing # product could show up as a winner

Abstenerse cuesta 5 segundos; una cifra falsa cuesta una liquidación. Ante un dato incompleto (divisa desconocida, factura sin desglose, mes sin cerrar) el sistema devuelve None y avisa en rojo. Nunca un número plausible sin fuente.

Ese bug era real y estaba vivo: la conversión silenciosa a tasa 1.0 hacía pasar una factura en dólares por pesos colombianos. No lo cazó ningún test verde: lo cazó preguntarle al código de dónde sale este número.

Por eso cada dato lleva su procedencia y las fuentes no se sustituyen entre sí. Mezclar la factura (lo que pagué) con el CSV de Meta (cómo rindió) fue un bug de verdad, no una discusión teórica. Hoy es una regla escrita.

Abstaining costs 5 seconds; a false figure costs a payout. Faced with incomplete data (unknown currency, invoice with no breakdown, month not closed) the system returns None and warns in red. Never a plausible number with no source.

That bug was real and live: the silent 1.0-rate conversion passed a dollar invoice off as Colombian pesos. No green test caught it: what caught it was asking the code where does this number come from.

That's why every value carries its provenance and the sources never substitute for one another. Mixing the invoice (what I paid) with the Meta CSV (how it performed) was a genuine bug, not a theoretical debate. Today it's a written rule.

/eval-finanzas check-all
$ python tests/golden_finanzas/eval_finanzas.py check-all

[check] ENERO 2026 — VEREDICTO: PASA (5 productos, igualdad exacta)
[check] MARZO 2026 — VEREDICTO: PASA (4 productos, igualdad exacta)
[check] ABRIL 2026 — VEREDICTO: PASA (3 productos, igualdad exacta)

# el gate corre las FUNCIONES REALES del cierre — pivot.calcular_neta_mes()
# y pivot.utilidad_mes() — contra tres meses cerrados y verificados a mano.
# Sin reimplementar la lógica: si el golden y producción divergen, es un bug
# del golden, no del negocio.
#
# Igualdad EXACTA, no ±tolerancia: el OCR queda fuera de este camino, así que
# dos corridas sobre los mismos inputs dan el mismo número al peso. Una
# tolerancia del 0,5 % enmascararía una regresión real.
#
# Si BLOQUEA, el cambio no se cierra. No es un aviso: es un no.
$ python tests/golden_finanzas/eval_finanzas.py check-all

[check] JANUARY 2026 — VERDICT: PASS (5 products, exact equality)
[check] MARCH   2026 — VERDICT: PASS (4 products, exact equality)
[check] APRIL   2026 — VERDICT: PASS (3 products, exact equality)

# the gate runs the REAL closing functions — pivot.calcular_neta_mes() and
# pivot.utilidad_mes() — against three closed, hand-verified months.
# No reimplemented logic: if golden and production diverge, it's a bug in
# the golden, not in the business.
#
# EXACT equality, not ±tolerance: OCR is out of this path, so two runs over
# the same inputs give the same number to the peso. A 0.5 % tolerance would
# mask a real regression.
#
# If it BLOCKS, the change does not ship. It isn't a warning: it's a no.
El límite honesto del gateThe gate's honest limit

Ningún agente puede verificar que una factura sea real o que un flete sea correcto. Lo que sí es verificable por ejecución es que la cifra es reproducible desde inputs congelados y que cada número dice de dónde sale. El golden comprueba aritmética y trazabilidad, no verdad de negocio: eso lo firma una persona mirando el mes real. El pipe propone; yo confirmo. Y el ground-truth del golden lo fijo yo, no el pipe: si el pipe pudiera reescribirlo para aprobar, el gate sería un sello de goma.

No agent can verify that an invoice is real or that a shipping charge is right. What is verifiable by execution is that the figure is reproducible from frozen inputs and that every number states its source. The golden checks arithmetic and traceability, not business truth: a human signs that off looking at the real month. The pipe proposes; I confirm. And the golden's ground truth is set by me, not by the pipe: if the pipe could rewrite it to pass, the gate would be a rubber stamp.

Determinismo · pruébalo túDeterminism · try it yourself

El precio de venta no lo decide una IA

The selling price is not decided by an AI

Es aritmética pura: precio = (coste × n + costes_fijos) / (1 − margen), redondeado al siguiente precio psicológico terminado en .900, más un pequeño optimizador que busca la progresión de descuentos más creíble. Cero tokens. Un LLM aquí no aportaría nada y sí podría equivocarse distinto cada vez.

It's pure arithmetic: price = (cost × n + fixed_costs) / (1 − margin), rounded up to the next psychological price ending in .900, plus a small optimiser that finds the most believable discount progression. Zero tokens. An LLM would add nothing here and could get it wrong differently every time.

coste del producto en Dropiproduct cost at Dropi $30.000 COPCOP
x1
$87.900
anteswas $200.000 · 55% off
x2
$118.900
descuento mostradodisplayed discount 65%
x3
$150.900
descuento mostradodisplayed discount 75%
CPA de equilibrio: lo máximo que puedo pagar por una venta antes de perder dinero. Es el número que decide si un anuncio sigue vivo o se apaga. Break-even CPA: the most I can pay for one sale before losing money. It's the number that decides whether an ad stays on or gets killed. $4.967CPA breakeven COPbreak-even CPA, COP
flete basebase shipping $17.063 % entregadelivery rate 75% admin/pedidoadmin/order $2.909 CPA objetivotarget CPA $15.000 margenmargin 5%
Esto no es una maqueta: es el algoritmo de ecxm/predev/precios.py portado a JavaScript línea por línea, incluido el redondeo bancario de Python y el optimizador de progresión de descuentos. Lo verifiqué contra los mismos 7 casos golden que blindan la versión en Python: los 9 campos coinciden al peso en los 7. Los parámetros de arriba son los valores por defecto del repo; en producción se leen del Excel de la tienda. This is not a mock-up: it's the algorithm from ecxm/predev/precios.py ported to JavaScript line by line, including Python's banker's rounding and the discount-progression optimiser. I verified it against the same 7 golden cases that guard the Python version: all 9 fields match to the peso across all 7. The parameters above are the repo defaults; in production they're read from the store's spreadsheet.
7/7

casos golden idénticosidentical golden cases

El port JS y el original Python coinciden en los 9 campos, incluidos los bordes (entrega 0 %, CPA explícito).The JS port and the Python original agree on all 9 fields, edge cases included (0 % delivery, explicit CPA).

0

toleranciatolerance

Redondeo a 2 decimales solo para neutralizar el ruido del float. Nada más se perdona.Rounding to 2 decimals only to neutralise float noise. Nothing else is forgiven.

Ingeniería con resultado económicoEngineering with a financial result

El pipeline que dejó de pagar por pensar

The pipeline that stopped paying to think

Clonar la landing de un competidor empezó como lo empieza todo el mundo: mandarle capturas a un modelo de visión y pedirle que la reconstruya. Funcionaba, costaba ~$0,05 por landing y era distinto en cada corrida. Hoy el mismo trabajo lo hacen 26 extractores deterministas y 9 parsers de reseñas sobre el HTML real: mismo input, mismo output, $0. Vision sigue ahí, pero solo detrás de un flag explícito, nunca como fallback silencioso.

Cloning a competitor's landing page started the way everyone starts: send screenshots to a vision model and ask it to rebuild the page. It worked, it cost ~$0.05 per landing and it was different on every run. Today the same job is done by 26 deterministic extractors and 9 review parsers over the real HTML: same input, same output, $0. Vision is still there, but only behind an explicit flag, never as a silent fallback.

5

plataformas cubiertasplatforms covered

Shopify, Funnelish, GemPages, Pagefly y Tiendanube, cada una con su forma de esconder el mismo contenido.Shopify, Funnelish, GemPages, Pagefly and Tiendanube, each hiding the same content its own way.

27

landings de regresiónregression landings

Un set real de competidores. Se regeneran una a una y se diffea el HTML: el validator en verde no basta.A real competitor set. Regenerated one by one with an HTML diff: a green validator isn't enough.

4

goldens congeladosfrozen goldens

Partidos por zona (copy · CSS · footer) y con las URLs normalizadas, para que el diff detecte drift y no ruido.Split by zone (copy · CSS · footer) with normalised URLs, so the diff catches drift, not noise.

8.549

líneas del extractorextractor lines

El precio real de la determinación: cada caso raro de cada builder, escrito y cubierto por el set.The real price of determinism: every builder's weird case, written down and covered by the set.

# el gate no avisaba: dejaba pasar # replicar_plantilla.py, durante 11 días report = validar_landing(output_dir) if not report.passed: print("[WARN] la réplica tiene fallos") # "no abortamos un generado # imperfecto, solo avisamos" # ── después ────────────────────────── if not report.passed: raise ReplicaValidatorFailed( output_dir, report.failures) # CLI → exit 1 · dashboard → captura la # excepción y expone el HTML para debug
# the gate didn't warn: it let things through # replicar_plantilla.py, for 11 days report = validar_landing(output_dir) if not report.passed: print("[WARN] the replica has failures") # "we don't abort an imperfect # build, we just warn" # ── after ──────────────────────────── if not report.passed: raise ReplicaValidatorFailed( output_dir, report.failures) # CLI → exit 1 · dashboard → catches the # exception and exposes the HTML to debug

El validator existía desde hacía semanas, con su lista de placeholders prohibidos y sus checks de estructura. Y aun así, once días de landings con fallos pasaron el gate, porque el gate solo imprimía un warning.

Una defensa que solo avisa entrena a su dueño a ignorarla. Hoy la regla del repo es explícita: toda defensa nueva tiene que abortar: exit ≠ 0, raise, o un fallo detectable aguas abajo. Si hace falta no bloquear en un caso concreto, se hace con un flag visible, no con silencio por defecto.

El mismo principio arregló otro fallo más sutil: un sys.exit() dentro de una librería lanza SystemExit, que no hereda de Exception, así que atravesaba todos los except Exception del dashboard y se llevaba por delante la interfaz entera.

The validator had existed for weeks, with its forbidden-placeholder list and its structure checks. And still, eleven days of broken landings sailed through the gate, because the gate only printed a warning.

A defense that merely warns trains its owner to ignore it. The repo rule is now explicit: every new defense must abort: exit ≠ 0, raise, or a failure detectable downstream. If a specific case genuinely shouldn't block, that's done with a visible flag, not with silence by default.

The same principle fixed a subtler failure: a sys.exit() inside a library raises SystemExit, which doesn't inherit from Exception, so it sailed straight through every except Exception in the dashboard and took the whole UI down.

Lo que decidí NO construirWhat I decided NOT to build

Decisiones medidas, no intuidas

Measured decisions, not guessed

El activo que no se puede fingir no es el código: es el juicio. Cada una de estas ideas era razonable y tentadora; todas murieron con un dato concreto delante. Varias iban en contra de lo que yo quería que fuera verdad, y por eso están aquí.

The asset you can't fake isn't the code: it's judgment. Every one of these ideas was reasonable and tempting; all of them died with a concrete piece of data in front of them. Several went against what I wanted to be true, which is exactly why they're here.

IdeaIdea Por qué tentabaWhy it tempted Qué encontréWhat I found VeredictoVerdict
CSV de Meta como fuente de costeMeta CSV as the cost sourceun solo archivo con todo el gasto del mesone file with the whole month's spend un download y listo, sin OCRone download and done, no OCR sin desglose por campaña ni estado Pagado/Error; los PDFs sí lo traenno per-campaign breakdown, no Paid/Error state; the PDFs have both Descartado como costeRuled out as cost
Contar el flete de todos los pedidosCount shipping on every orderal fin y al cabo es flete que se pagaafter all, it's shipping that gets paid parecía más conservadorit looked more conservative la suma por producto dejaba de cuadrar con el total del mesthe per-product sum stopped matching the month total Solo 4 estatus finalesFinal 4 statuses only
Vision para clonar reseñasVision to clone reviewscada competidor pinta sus reseñas distintoevery competitor renders reviews differently «un modelo lo resuelve todo»"one model solves everything" 9 parsers cubren el set entero; sin parser → sección omitida, no invención9 parsers cover the whole set; no parser → section omitted, nothing invented Fuera del pipe · $0Out of the pipe · $0
Servidor, n8n, FastAPI, PostgresServer, n8n, FastAPI, Postgresla arquitectura «seria»the "serious" architecture se ve mejor en un diagramait looks better on a diagram 5–15 tests/semana y un operador → infra sin usuarios y con mantenimiento5–15 tests/week and one operator → infra with no users and real upkeep Local + SQLiteLocal + SQLite
Tasa 1.0 para divisa desconocida1.0 rate for unknown currencyasí el importe nunca sale vacíothat way the amount is never empty una tabla sin huecos da confianzaa table with no gaps feels trustworthy subestimaba un coste en USD ~4.200× → podía convertir un perdedor en winnerunderstated a USD cost ~4,200× → could turn a loser into a winner None + avisowarning
Borrar la caché de LLM al cambiar un promptWipe the LLM cache on prompt change«está sucia, mejor empezar limpio»"it's dirty, better start clean" higiene aparenteapparent hygiene 268 entradas borradas = 268 llamadas ya pagadas que hubo que repagar268 entries deleted = 268 already-paid calls that had to be paid again Nunca sin permisoNever without asking
Forzar COP en la publicidadForce COP on ad spendhoy todas las cuentas facturan en pesostoday every account bills in pesos funciona… hasta que deje de hacerloit works… until it doesn't la primera cuenta que facture en USD escondería un ×4.200 sin avisarthe first USD-billing account would silently hide a ×4,200 Riesgo documentadoDocumented risk

La última fila no es un fallo mío que se me olvidó: es un footgun conocido, escrito y fechado en el backlog, con la condición exacta que lo disparará. Prefiero un riesgo documentado y visible a un riesgo resuelto a medias en silencio.

That last row isn't a mistake I forgot about: it's a known footgun, written down and dated in the backlog, with the exact condition that will trigger it. I'd rather have a documented, visible risk than one half-fixed in silence.

Arquitectura · WATArchitecture · WAT

La IA razona; el código determinista ejecuta

The AI reasons; deterministic code executes

Todo el repo está montado sobre una idea aritmética muy simple: si cada paso de una cadena es un 90 % fiable, cinco pasos seguidos te dejan en 59 %. Por eso la IA no ejecuta: orquesta. Las instrucciones viven en workflows en markdown, el juicio lo pone el agente, y el trabajo real lo hacen scripts de Python testeables y repetibles.

The whole repo rests on one very simple piece of arithmetic: if each step in a chain is 90 % reliable, five steps in a row leave you at 59 %. That's why the AI doesn't execute: it orchestrates. Instructions live in markdown workflows, judgment comes from the agent, and the real work is done by testable, repeatable Python scripts.

CAPA 01 · WORKFLOWS

Las instruccionesThe instructions

SOPs en markdown: objetivo, entradas necesarias, qué herramienta usar y cómo tratar los casos raros. Escritos como se le explica a una persona del equipo, y actualizados cuando el proceso aprende algo.Markdown SOPs: objective, required inputs, which tool to use and how to handle edge cases. Written the way you'd brief a teammate, and updated whenever the process learns something.

CAPA 02 · AGENTE

La decisiónThe decision

Lee el workflow, encadena las herramientas en el orden correcto, se recupera de los errores y pregunta cuando falta información. No calcula precios ni conmuta números: conecta intención con ejecución.Reads the workflow, chains the tools in the right order, recovers from errors and asks when information is missing. It doesn't compute prices or crunch numbers: it connects intent to execution.

CAPA 03 · HERRAMIENTAS

La ejecuciónThe execution

~34.500 líneas de Python en ecxm/: scraping, pandas, openpyxl, OCR, generación. Consistentes, rápidas y testeables. Toda llamada a un modelo pasa por core/llm.py: un único punto que cachea por hash y contabiliza el coste.~34,500 lines of Python in ecxm/: scraping, pandas, openpyxl, OCR, generation. Consistent, fast and testable. Every model call goes through core/llm.py: a single point that caches by hash and accounts for cost.

LA CADENA (la salida de cada pipe es la entrada del siguiente THE CHAIN) each pipe's output is the next one's input SNIPE Ads Library · PlaywrightAds Library · Playwright LAB precios · copy · títulospricing · copy · titles REP réplica de landing · $0landing replica · $0 CREATIVE estáticos · vídeo · UGCstatics · video · UGC ANALYTICS reglas · $0 LLMrules · $0 LLM FINANZASFINANCE irreversible · el cierreirreversible · the close /eval-finanzas SUPERFICIE COMPARTIDASHARED SURFACE un único dashboard de 17.296 líneas · session_state global · CSS y JS globales · constantes y helpers comunes one 17,296-line dashboard · global session_state · global CSS and JS · shared constants and helpers COMPES_TRACKER.xlsx · ecxm.db · fb_cookies.json · dashboard_state.json cada línea punteada es una vía por la que un cambio en UNA pestaña puede romper OTRA every dotted line is a path by which a change in ONE tab can break ANOTHER por eso existe dashboard_map.json: qué hace cada pestaña, con qué se sincroniza y QUÉ SE ROMPE al tocarla hence dashboard_map.json: what each tab does, what it syncs with and WHAT BREAKS when you touch it se lee ANTES de editar y se actualiza DESPUÉS (es la fuente de verdad, no un diagrama decorativo read BEFORE editing and updated AFTER) it's the source of truth, not a decorative diagram Cross-Pipe Safety · ninguna tarea se cierra sin comprobar que los demás pipes siguen vivos Cross-Pipe Safety · no task closes without checking the other pipes are still alive un bug en SNIPE que rompe el pipe de réplicas cuesta más en diagnóstico que el cambio original en desarrollo a bug in SNIPE that breaks the replica pipe costs more to diagnose than the original change cost to build

Pellizca para acercar y leer el detalle ↔Pinch to zoom in and read the detail ↔

Calibrado de ceremoniaCeremony calibration

El riesgo lo marca la superficie, no el tamaño del diff

Risk is set by the surface, not by the size of the diff

Un cambio de dos líneas en el cierre de finanzas es más peligroso que refactorizar quinientas de estilos. Por eso el proceso no se calibra por líneas cambiadas sino por dónde se toca, y ese conjunto de superficies es inmutable: no lo puede ampliar ni relajar ningún proceso automático.

A two-line change in the finance close is more dangerous than refactoring five hundred lines of styling. So the process is calibrated not by lines changed but by where you touch, and that set of surfaces is immutable: no automated process can widen or relax it.

IrreversibleIrreversible

El cierre de mesThe month close

Ahí el número se convierte en un pago. También cuenta borrar la caché de LLM ya pagada y romper la convención de nombres de campaña.That's where the number becomes a payment. Also: deleting already-paid LLM cache, and breaking the campaign naming convention.

ritual completo + doble pase independientefull ritual + independent second pass
Sensible · reversibleSensitive · reversible

Réplicas, pivot, dashboardReplicas, pivot, dashboard

Duele si se rompe, pero se recupera. Aquí el gate ya existe: validator, golden y set de regresión.It hurts when it breaks, but it recovers. The gate already exists here: validator, golden and regression set.

ceremonia media + gate automáticomedium ceremony + automated gate
No sensibleNot sensitive

Precios, copy de UI, estilosPricing, UI copy, styling

Recomputable y visible al instante. Aquí el proceso pesado sería teatro: leer, cambiar, verificar y decirlo.Recomputable and instantly visible. Heavy process here would be theatre: read, change, verify, say so.

ceremonia mínimaminimal ceremony
Cómo trabajo con IAHow I work with AI

El modo de fallo real no es planificar mal: es reportar sin verificar

The real failure mode isn't bad planning: it's reporting without verifying

Ningún «el subagente reportó OK» cierra nada aquí: el orquestador corre él mismo el gate y pega la salida real en el prompt del siguiente paso.

No "the subagent reported OK" closes anything here: the orchestrator runs the gate itself and pastes the real output into the next step's prompt.

los otros dos gates · el de finanzas está arribathe other two gates · the finance one is above
$ python tests/golden_precios/eval_precios.py check
[check] precios — VEREDICTO: PASA (7 casos, igualdad exacta)

$ python tests/golden_control_diario/eval_control_diario.py check
[check] control_diario — VEREDICTO: PASA (6 casos, igualdad exacta)

# Los goldens con cifras reales del negocio NO se versionan: el arnés se
# comparte, cada máquina captura su propio baseline. Sin baseline el gate
# ni aprueba ni bloquea — avisa de que falta. Un gate que aprueba en vacío
# es peor que no tener gate.
$ python tests/golden_precios/eval_precios.py check
[check] pricing — VERDICT: PASS (7 cases, exact equality)

$ python tests/golden_control_diario/eval_control_diario.py check
[check] control_diario — VERDICT: PASS (6 cases, exact equality)

# Goldens holding real business figures are NOT versioned: the harness is
# shared, each machine captures its own baseline. With no baseline the gate
# neither passes nor blocks — it reports the baseline is missing. A gate that
# passes on nothing is worse than no gate at all.

Verificación por ejecuciónVerification by execution

Verde local ≠ correcto. Que el dashboard arranque no dice nada sobre si la utilidad neta que calculó el pivot es la real. La única señal con dientes es el gate golden, y lo corro yo antes de cerrar nada.Green locally ≠ correct. The dashboard booting says nothing about whether the net profit the pivot computed is the real one. The only signal with teeth is the golden gate, and I run it myself before closing anything.

Un bug nunca vive soloA bug never lives alone

Al encontrar un fallo, la pregunta obligatoria es: ¿existe el mismo bug en los caminos análogos? Un invariante como «el flete solo cuenta en los 4 estatus finales» vive en un sitio y lo llaman todas las etapas: ingerir, limpiar, cruzar, pivotar y cerrar.On finding a defect, the mandatory question is: does the same bug exist in the analogous paths? An invariant like "shipping only counts on the 4 final statuses" lives in one place and is called by every stage: ingest, clean, cross-match, pivot and close.

Lo que sigue abierto

What's still open

El sistema está en producción y se usa todos los días, pero no está «terminado», y decir lo contrario sería el primer número falso de esta página.

The system is in production and used every day, but it isn't "finished", and saying otherwise would be the first false number on this page.

aplazado a propósitodeliberately deferredAuditoría integral del dashboard. Con 17.296 líneas en un solo archivo, una auditoría hecha a trozos genera más ruido que señal. Decisión tomada y fechada: esperar y hacer una sola pasada acotada, con tres focos definidos.Full dashboard audit. At 17,296 lines in a single file, a piecemeal audit generates more noise than signal. Decision made and dated: wait and do a single scoped pass with three defined focuses.
riesgo conocidoknown riskForzado de divisa en publicidad. Hoy inocuo porque todas las cuentas facturan en pesos; se disparará con la primera que facture en dólares. Está escrito, con su condición de disparo, esperando el arreglo correcto en lugar de un parche.Currency forcing on ad spend. Harmless today because every account bills in pesos; it will fire with the first one billing in dollars. It's written down, with its trigger condition, waiting for the right fix instead of a patch.
cobertura parcialpartial coverageGoldens de landing. 4 congelados de 27 landings del set de regresión. Los tres canónicos cubren los builders más frágiles; el resto se compara por diff, que detecta cambios pero no juzga si son correctos.Landing goldens. 4 frozen out of the 27 landings in the regression set. The three canonical ones cover the most fragile builders; the rest are compared by diff, which detects changes but doesn't judge whether they're right.

El resto del método —el agente ciego que audita mis planes, el ledger que convierte un fallo en regla— es el mismo en los cinco sistemas y está contado una vez: en el índice.The rest of the method —the blind agent auditing my own plans, the ledger that turns a failure into a rule— is the same across all five systems and is told once: on the index.

Disponible para trabajarAvailable for work

Cojo un negocio entero, lo descompongo en pipelines y orquesto IA para construir cada pieza, sin perder el rigor donde hay dinero.

I take an entire business, break it into pipelines and orchestrate AI to build every piece, without losing rigor where money is involved.

Si buscas a alguien para applied-AI, automatización de operaciones o forward-deployed engineering, que construye sistemas para que la IA no se engañe a sí misma ni a ti, hablemos.

If you're looking for someone in applied-AI, operations automation or forward-deployed engineering who builds systems so the AI can't fool itself or you, let's talk.

Todo lo de esta página lo construí en solitario, con IA y sin formación técnica previa.Everything on this page I built solo, with AI and with no prior technical background.

ECXM OPS · Diego · 2026 Sistema en producción · construido con IASystem in production · built with AI