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.
ECXM OPS cobreix la cadena completa d'un negoci de dropshipping COD, d'espiar la competència a tancar el mes, en un sol dashboard i una CLI de 35 comandes. El mode de fallada no és que Streamlit peti: és que el pivot afirmi amb tota fluïdesa una utilitat neta falsa. Un decimal mal atribuït és el sou d'una altra persona.
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.En ús diari al meu propi negoci des del maig del 2026, amb 6.286 anuncis de la competència indexats. Construït en solitari, amb IA.
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.
No són set scripts solts: és una sola cadena on la sortida de cada etapa és l'entrada de la següent, i on l'estat viu en fitxers que les altres etapes saben llegir. Prem qualsevol estació per veure què fa, què costa i amb què se sincronitza.
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.Guió: escaneig de l'Ads Library → producte al LAB (preus + copy + títols) → rèplica de la landing en $0 → creatius → control diari → tancament de mes → la taula que diu quin producte és 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.Aquestes 7 etapes del cicle del producte viuen en 6 pestanyes del dashboard (tancar i vendre comparteixen FINANCES). N'hi ha 3 més de suport (FEEDBACK, ACADÈMIA i ROADMAP, que renderitza el mapa d'arquitectura del mateix dashboard) 9 en total.
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.
El contracte de l'equip té una clàusula curta: un producte és winner si tanca el mes amb utilitat neta positiva, i llavors el repartiment passa de 50/50 a 40/60 a favor del col·laborador. Tota la maquinària de sota existeix per produir aquell número. El dashboard està fet perquè jo m'hi confiï i tanqui de pressa: aquesta confiança és exactament el que converteix un error d'atribució en diners mal repartits.
Pellizca para acercar y leer el detalle ↔Pinch to zoom in and read the detail ↔Pessiga per apropar i llegir el detall ↔
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.
La convenció de noms de campanya a Meta ([NOM]_[PRODUCTE]_[DATA]) no és cosmètica: és el que permet que la despesa publicitària baixi fins al producte correcte. Si una campanya no la respecta, el sistema ho marca, sense ella l'atribució falla i la liquidació es reparteix malament.
| FuenteSourceFont | Qué esWhat it isQuè és | Regla duraHard ruleRegla dura | UsoUseÚs |
|---|---|---|---|
| LIMPIO | ventas, estatus y flete del export de Dropisales, status and shipping from the Dropi exportvendes, estats i port de l'export de Dropi | 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 yetnomés els 4 estats finals compten per al mes; una comanda en trànsit encara no té resultat | basebasebase |
| FACTURA (OCR) | costes, servicios y publicidad leídos de los PDFscosts, services and ad spend read from the PDFscostos, serveis i publicitat llegits dels 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és el que es va pagar de veritat; un cobrament amb estat «Error» no compta | caja · liquidacióncash · payoutcaixa · liquidació |
| CSV Ads | impresiones, visitas y compras de Metaimpressions, visits and purchases from Metaimpressions, visites i compres de 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 statemai substitueix la factura com a cost real: no porta ni desglossament per campanya ni estat del cobrament | rendimiento · CPAperformance · CPArendiment · CPA |
| PRORRATEOALLOCATIONPRORRATEIG | servicios repartidos entre productosservices split across productsserveis repartits entre productes | 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és una estimació i s'etiqueta com a tal; mai es presenta com a cost directe del producte | estimadoestimatedestimat |
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.
Abstenir-se costa 5 segons; una xifra falsa costa una liquidació. Davant d'una dada incompleta (divisa desconeguda, factura sense desglossament, mes sense tancar) el sistema torna None i avisa en vermell. Mai un número plausible sense font.
Aquell bug era real i estava viu: la conversió silenciosa a taxa 1.0 feia passar una factura en dòlars per pesos colombians. No el va caçar cap test verd: el va caçar preguntar al codi d'on surt aquest número.
Per això cada dada porta la seva procedència i les fonts no se substitueixen entre si. Barrejar la factura (el que vaig pagar) amb el CSV de Meta (com va rendir) va ser un bug de veritat, no una discussió teòrica. Avui és una regla escrita.
$ 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.
$ 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 les FUNCIONS REALS del tancament — pivot.calcular_neta_mes() # i pivot.utilidad_mes() — contra tres mesos tancats i verificats a mà. # Sense reimplementar la lògica: si el golden i producció divergeixen, és un bug # del golden, no del negoci. # # Igualtat EXACTA, no ±tolerància: l'OCR queda fora d'aquest camí, així que # dues corregudes sobre els mateixos inputs donen el mateix número al peso. Una # tolerància del 0,5 % emmascararia una regressió real. # # Si BLOQUEJA, el canvi no es tanca. No és un avís: és un no.
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.
Cap agent pot verificar que una factura sigui real ni que un port sigui correcte. El que sí és verificable per execució és que la xifra és reproduïble des d'inputs congelats i que cada número diu d'on surt. El golden comprova aritmètica i traçabilitat, no veritat de negoci: això ho signa una persona mirant el mes real. El pipe proposa; jo confirmo. I el ground-truth del golden el fixo jo, no el pipe: si el pipe pogués reescriure'l per aprovar, el gate seria un segell de goma.
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.
És aritmètica pura: precio = (coste × n + costes_fijos) / (1 − margen), arrodonit al següent preu psicològic acabat en .900, més un petit optimitzador que busca la progressió de descomptes més creïble. Zero tokens. Un LLM aquí no aportaria res i sí que podria equivocar-se diferent cada vegada.
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).El port JS i l'original Python coincideixen als 9 camps, inclosos els límits (lliurament 0 %, CPA explícit).
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.Arrodoniment a 2 decimals només per neutralitzar el soroll del float. Res més es perdona.
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.
Clonar la landing d'un competidor va començar com ho comença tothom: enviar-li captures a un model de visió i demanar-li que la reconstrueixi. Funcionava, costava ~$0,05 per landing i era diferent en cada correguda. Avui la mateixa feina la fan 26 extractors deterministes i 9 parsers de ressenyes sobre l'HTML real: mateix input, mateix output, $0. Vision hi segueix, però només darrere d'un flag explícit, mai com a fallback silenciós.
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.Shopify, Funnelish, GemPages, Pagefly i Tiendanube, cadascuna amb la seva manera d'amagar el mateix contingut.
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.Un set real de competidors. Es regeneren una a una i es fa diff de l'HTML: el validator en verd no n'hi ha prou.
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.Partits per zona (copy · CSS · footer) i amb les URLs normalitzades, perquè el diff detecti drift i no soroll.
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 preu real de la determinació: cada cas rar de cada builder, escrit i cobert pel set.
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.
El validator existia des de feia setmanes, amb la seva llista de placeholders prohibits i els seus checks d'estructura. I tot i així, onze dies de landings amb fallades van passar el gate, perquè el gate només imprimia un warning.
Una defensa que només avisa entrena el seu amo a ignorar-la. Avui la regla del repo és explícita: tota defensa nova ha d'avortar: exit ≠ 0, raise, o una fallada detectable aigües avall. Si cal no bloquejar en un cas concret, es fa amb un flag visible, no amb silenci per defecte.
El mateix principi va arreglar una altra fallada més subtil: un sys.exit() dins d'una llibreria llança SystemExit, que no hereta d'Exception, així que travessava tots els except Exception del dashboard i s'enduia per davant la interfície sencera.
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.
L'actiu que no es pot fingir no és el codi: és el criteri. Cadascuna d'aquestes idees era raonable i temptadora; totes van morir amb una dada concreta al davant. Diverses anaven en contra del que jo volia que fos veritat, i per això són aquí.
| IdeaIdeaIdea | Por qué tentabaWhy it temptedPer què temptava | Qué encontréWhat I foundQuè vaig trobar | VeredictoVerdictVeredicte |
|---|---|---|---|
| CSV de Meta como fuente de costeMeta CSV as the cost sourceCSV de Meta com a font de costun solo archivo con todo el gasto del mesone file with the whole month's spendun sol fitxer amb tota la despesa del mes | un download y listo, sin OCRone download and done, no OCRun download i llestos, sense 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 bothsense desglossament per campanya ni estat Pagat/Error; els PDFs sí que ho porten | Descartado como costeRuled out as costDescartat com a cost |
| Contar el flete de todos los pedidosCount shipping on every orderComptar el port de totes les comandesal fin y al cabo es flete que se pagaafter all, it's shipping that gets paidal capdavall és port que es paga | parecía más conservadorit looked more conservativesemblava més conservador | la suma por producto dejaba de cuadrar con el total del mesthe per-product sum stopped matching the month totalla suma per producte deixava de quadrar amb el total del mes | Solo 4 estatus finalesFinal 4 statuses onlyNomés 4 estats finals |
| Vision para clonar reseñasVision to clone reviewsVision per clonar ressenyescada competidor pinta sus reseñas distintoevery competitor renders reviews differentlycada competidor pinta les seves ressenyes diferent | «un modelo lo resuelve todo»"one model solves everything"«un model ho resol tot» | 9 parsers cubren el set entero; sin parser → sección omitida, no invención9 parsers cover the whole set; no parser → section omitted, nothing invented9 parsers cobreixen el set sencer; sense parser → secció omesa, no invenció | Fuera del pipe · $0Out of the pipe · $0Fora del pipe · $0 |
| Servidor, n8n, FastAPI, PostgresServer, n8n, FastAPI, PostgresServidor, n8n, FastAPI, Postgresla arquitectura «seria»the "serious" architecturel'arquitectura «seriosa» | se ve mejor en un diagramait looks better on a diagrames veu millor en un diagrama | 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 upkeep5–15 tests/setmana i un operador → infra sense usuaris i amb manteniment | Local + SQLiteLocal + SQLiteLocal + SQLite |
| Tasa 1.0 para divisa desconocida1.0 rate for unknown currencyTaxa 1.0 per a divisa desconegudaasí el importe nunca sale vacíothat way the amount is never emptyaixí l'import mai surt buit | una tabla sin huecos da confianzaa table with no gaps feels trustworthyuna taula sense forats dona confiança | 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 winnersubestimava un cost en USD ~4.200× → podia convertir un perdedor en winner | None + avisowarningavís |
| Borrar la caché de LLM al cambiar un promptWipe the LLM cache on prompt changeEsborrar la memòria cau d'LLM en canviar un prompt«está sucia, mejor empezar limpio»"it's dirty, better start clean"«està bruta, millor començar net» | higiene aparenteapparent hygienehigiene aparent | 268 entradas borradas = 268 llamadas ya pagadas que hubo que repagar268 entries deleted = 268 already-paid calls that had to be paid again268 entrades esborrades = 268 crides ja pagades que es van haver de repagar | Nunca sin permisoNever without askingMai sense permís |
| Forzar COP en la publicidadForce COP on ad spendForçar COP a la publicitathoy todas las cuentas facturan en pesostoday every account bills in pesosavui tots els comptes facturen en pesos | funciona… hasta que deje de hacerloit works… until it doesn'tfunciona… fins que deixi de fer-ho | la primera cuenta que facture en USD escondería un ×4.200 sin avisarthe first USD-billing account would silently hide a ×4,200el primer compte que facturi en USD amagaria un ×4.200 sense avisar | Riesgo documentadoDocumented riskRisc documentat |
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.
L'última fila no és una fallada meva que se'm va oblidar: és un footgun conegut, escrit i datat al backlog, amb la condició exacta que el dispararà. Prefereixo un risc documentat i visible a un risc resolt a mitges en silenci.
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.
Tot el repo està muntat sobre una idea aritmètica molt simple: si cada pas d'una cadena és un 90 % fiable, cinc passos seguits et deixen en 59 %. Per això la IA no executa: orquestra. Les instruccions viuen en workflows en markdown, el criteri el posa l'agent, i la feina real la fan scripts de Python testejables i repetibles.
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.SOPs en markdown: objectiu, entrades necessàries, quina eina fer servir i com tractar els casos rars. Escrits com se li explica a una persona de l'equip, i actualitzats quan el procés aprèn alguna cosa.
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.Llegeix el workflow, encadena les eines en l'ordre correcte, es recupera dels errors i pregunta quan falta informació. No calcula preus ni commuta números: connecta intenció amb execució.
~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.~34.500 línies de Python a ecxm/: scraping, pandas, openpyxl, OCR, generació. Consistents, ràpides i testejables. Tota crida a un model passa per core/llm.py: un únic punt que fa cau per hash i comptabilitza el cost.
Pellizca para acercar y leer el detalle ↔Pinch to zoom in and read the detail ↔Pessiga per apropar i llegir el detall ↔
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.
Un canvi de dues línies al tancament de finances és més perillós que refactoritzar-ne cinc-centes d'estils. Per això el procés no es calibra per línies canviades sinó per on es toca, i aquest conjunt de superfícies és immutable: no el pot ampliar ni relaxar cap procés automàtic.
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.Allà el número es converteix en un pagament. També compta esborrar la memòria cau d'LLM ja pagada i trencar la convenció de noms de campanya.
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.Fa mal si es trenca, però es recupera. Aquí el gate ja existeix: validator, golden i set de regressió.
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.Recomputable i visible a l'instant. Aquí el procés pesat seria teatre: llegir, canviar, verificar i dir-ho.
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.
Cap «el subagent ha reportat OK» tanca res aquí: l'orquestrador corre ell mateix el gate i enganxa la sortida real al prompt del pas següent.
$ 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.
$ 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) # Els goldens amb xifres reals del negoci NO es versionen: l'arnès es # comparteix, cada màquina captura el seu propi baseline. Sense baseline el gate # ni aprova ni bloqueja — avisa que falta. Un gate que aprova en buit # és pitjor que no tenir gate.
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.Verd local ≠ correcte. Que el dashboard arrenqui no diu res sobre si la utilitat neta que va calcular el pivot és la real. L'únic senyal amb dents és el gate golden, i el corro jo abans de tancar res.
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.En trobar una fallada, la pregunta obligatòria és: existeix el mateix bug als camins anàlegs? Un invariant com «el port només compta als 4 estats finals» viu en un lloc i el criden totes les etapes: ingerir, netejar, creuar, pivotar i tancar.
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.
El sistema està en producció i es fa servir cada dia, però no està «acabat», i dir el contrari seria el primer número fals d'aquesta pàgina.
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.La resta del mètode (l'agent cec que audita els meus plans, el ledger que converteix una fallada en regla) és el mateix als cinc sistemes i està explicat una vegada: a l'índex.
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.
Si busques algú per a applied-AI, automatització d'operacions o forward-deployed engineering, que construeix sistemes perquè la IA no s'enganyi a si mateixa ni a tu, parlem-ne.
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.Tot el d'aquesta pàgina ho vaig construir en solitari, amb IA i sense formació tècnica prèvia.