Grounded · 4 exploradores leyeron el código real

Cómo funciona HOY — pantalla por pantalla

El sistema ya es super poderoso (CPA, objetivo×fuente, cliente paga X → partner Y → Relo X−Y, budgets total/none/por-segmento, tiered, per-CID). El problema NO es falta de poder — es que el poder está regado, invisible, inconsistente y en parte es teatro. Esto es la realidad exacta, sin adornos, para aterrizar los flows.

! El patrón — 4 anti-patrones que se repiten en TODO

Anti-patrón 1

Regado

El mismo número se edita en N pantallas: el cap en 6 lugares, la tarifa en 4+, la atribución en 3, la pausa en 5 mecanismos. Ninguno se cruza ni muestra los otros.

Anti-patrón 2

Invisible

La precedencia (qué tarifa gana), la razón de pausa, el warning de sobre-asignación y la salud del pool — todo se calcula en el backend pero no se muestra en ninguna pantalla.

Anti-patrón 3

Inconsistente

Unos paths audit-logean, otros no. El mismo cap se escribe por 2 rutas con checks distintos. "Over budget" significa 2 cosas. El reset mid-month se hace con SQL crudo — no hay UI.

Anti-patrón 4

En parte teatro

El wizard de campaña finge configurar (pasos 2+3 no se envían). La página oficial de reglas no deja editar ("llega en chunk 2B" — nunca llegó). Botones muertos. Features que dicen "coming soon" pero ya existen en el tab de al lado.

1 Planner /v2/c/:slug/planner

MonthlyPlannerPage.tsx · SegmentPlannerTable · monthly-planner.ts (1706 líneas)
La pantalla hoy

Tabla densa por segmento: Client budget · Relo earns · Partner pays · Relo margin · Health. Expandes → tabla por-partner (rate + Payment cap) + tiered deals + Campaign sprints (per-CID). Hero con 4 tiles (budget/payout/margin/status). Botones: Save · Copy last month · Suggest allocation · Approve & notify · Target margin (87%).

Dónde duele
  • No tiene control de pausa ni de reset mid-month aquí — esos viven en OTRA pantalla. Asignar y pausar están partidos.
  • "Partner pays" es un blend read-only ponderado por volumen — no se puede editar en la fila, y no cuadra con un promedio ingenuo de las tarifas de abajo.
  • Los Campaign Sprints escriben al DB al instante (se saltan el botón Save) — todo lo demás es "draft hasta Save", esto no. Modelo mental roto.
  • Target margin (87%) es solo localStorage — no se guarda en el server; cambias de compu y se resetea.
  • El Save sobre-escribe la PSC en su lugar (key partner_id+segment_code, sin fecha) — diverge de la precedencia documentada; no crea fila nueva con vigencia.
  • MonthPicker solo prev/next — saltar de mes lejano = muchos clics.

2 Budgets / caps partner_segment_budgets.budget_amount

control-panel/drawers/BudgetBumpDrawer · budgets/crud.ts · segments.ts (budget_override)
Regado — el MISMO cap, 6 lugares
  • Control Panel → +Budget drawer (el principal) — POST /segment-budgets
  • Planner → Save — batch upsert directo, bypasea el handler del drawer
  • Relo Copilot (AI) — mismo write path, otra puerta
  • Endpoint bulk huérfano — existe, nadie lo llama
  • Onboarding — siembra 12 meses de golpe
  • 6º cap distinto: match_rules budget_override (sprint per-CID) — se aplica ANTES del cap del segmento, y el Control Panel nunca lo consulta → muestra un cap que no es el que el engine enforza.
Invisible + inconsistente
  • El warning de sobre-asignación (Σ caps de partners vs pool de Samsung) se calcula en el backend, pero el drawer lo ignora y el Planner ni lo corre.
  • Unos paths audit-logean, otros no (el Planner no deja rastro; el drawer sí).
  • El reset mid-month (budget_start_from + locked_commission) — NO tiene write path en el código. Se hace con SQL crudo. Todo lo LEE bien, nada lo ESCRIBE por UI.
  • Sin enforcement pool↔caps: son dos números independientes en dos pantallas, reconciliados solo por un warning string que la UI tira + una pausa-cron después del hecho.

3 Pausas paused_at · auto_pause_at_100 · cascade

budgets/pause.ts · budgets/cascade.ts · control-panel drawers
Regado — 5 mecanismos de pausa
  • Per-partner-per-segmento (el único con UI: botón Pause/Resume)
  • Partner completo (todos sus segmentos) — sin botón en la UI
  • Auto-pausa al 100% (auto_pause_at_100, cron)
  • Cascada (pool de Samsung agotado → pausa a TODOS, cron)
  • Global por segmento del clientesin caller en la UI
Invisible
  • La cascada y la global taggean idéntico (inherited_pause_from='client') → indistinguibles en la data.
  • La UI no renderiza razón ni origen de pausa → una cascada-pausa y una pausa manual se ven idénticas en pantalla. No sabes por qué está pausado.
  • /api/clients/:id/budget-health (la única salud del pool) tiene cero callers — la salud del pool es invisible.

4 Lanzar campaña /v2/c/:slug/campaigns → Launch

CampaignLaunch.tsx (1586 líneas) · campaign-launch.ts
La pantalla hoy

Wizard 5 pasos: Type → Tracking → Rules → Partners → Review.

En parte teatro
  • Paso 2 (Tracking) es cosmético — la fuente que eliges nunca se envía.
  • Paso 3 (Reglas/pricing) es decorativo — el pricing que eliges no se lee; el review del paso 5 hardcodea texto falso ("CPA per sale · $50 fixed") sin importar qué clicaste.
  • Solo cablea el PRIMER segmento — una campaña multi-segmento configura de menos todo lo demás.
  • Non-atómico — 5 pasos con try/catch, sin rollback, 207 parcial: puede dejar un partner vinculado sin tarifa o sin budget.

5 Reglas / overrides match_rules · el corazón del poder

RulesEngine.tsx · RateOverrideEditorBody · segments.ts · commissions.md
Regado — tarifas en 4+ editores
  • RateOverrideEditorBody (el más completo — flat + tiered + preview de impacto)
  • CampaignMmpRateEditor (otro editor, flat-only, sin tiered)
  • Editores natural-language (atribución/reclassify por campaña)
  • Drawers del Control Panel (Budget/Pause/Rate)
  • Ninguno se cruza — no ves las reglas del otro para el mismo (partner, segmento)
Invisible + teatro
  • REGRESIÓN 🔥: el viejo RulesLibrary SÍ tenía CRUD completo + un tester que hacía visible la precedencia (segment→partner→reclassify→filter→rate→budget→commission). Se borró (5dfab4d) y el nuevo RulesEngine lo dejó READ-ONLY con un placeholder "chunk 2B" que nunca llegó. Tú hiciste reglas ahí — el rediseño lo empeoró.
  • La precedencia es invisible en TODA pantalla (frozen → tiered → flat CID vs partner-wide → PSC → default). Nadie te muestra la cadena resuelta.
  • RulesEngine ordena por priority — que el engine ni usa para estas reglas (usa tiered-vs-flat, especificidad de CID, y effective_from).
  • 3 sistemas de reglas distintos (match_rules · Zen RuleBuilder · tablas single-purpose) como tabs hermanos, sin señal de cuál gobierna.
  • El tab "Rates and caps" dice "Coming soon" — pero el tab de al lado (Partners) ya deja crear ese override hoy.

6 Onboarding /v2/clients/new

OnboardingWizard.tsx · onboard_client() SQL · OnboardingChecklistCard
La pantalla hoy

Wizard 6 pasos: Identity · Segments · Partners · Attribution · Commissions/Budgets · Review → "Create everything".

Nace muerto
  • La pantalla final es un recibo estático ("✓ Client created" + contadores de filas). Te dice qué se insertó, nunca si el cliente está vivo.
  • Cero verificación de flujo de datos para clientes MMP (la mayoría) — solo los pixel tienen un "Verify installation". Los 2 botones de salida son navegación pura, no gated por salud.
  • El checklist post-onboarding chequea presencia de config, no flujo — sale "Onboarding complete" en verde con el dashboard vacío para siempre.

7 Medir Home · ClientOverview · PartnerProfile

ClientOverview.tsx (scroll único) · Home.tsx · PartnerProfile.tsx (7 tabs)
La pantalla hoy

ClientOverview = scroll único (sin tabs): KPIs → tabla de partners (validado/gross) → Control Panel (Segment/Campaign/Partner) → Performance → Reconciliation waterfall (Attributed → −Paused → −No campaign → −Segment disabled → Billable) → Money flow.

Los números no cuadran — son SEIS, no 3
  • Para UN partner en UN mes, el admin puede ver 6 números distintos: all-clients gated (KPI) · all-clients gross-raw (subtítulo) · este-cliente gated (tab Deals) · este-cliente gated+gross (Overview) · por-segmento (Control Panel) · congelado posiblemente viejo (tab Pagos).
  • 3 ejes cruzados (scope × gated/gross × live/frozen) y ninguno se cruza para explicar por qué difieren.
  • El loop mensual está partido entre zonas de nav: Pagos es solo GLOBAL (ni se linkea desde el cliente), Planner enterrado en "More" → sin botón "cerrar el mes".
  • 3 secciones de código muerto en ClientOverview (tablas viejas nunca borradas).
grounded · 4 code-explorers · 2026-07-04· → Los journeys que lo unen· → El plan de fases