IA360 G5–G10 desde el VPS (payment breaker, opener, ruteo BNI, quien_intro, stages P2)#67
Open
AlekZen wants to merge 43 commits into
Open
IA360 G5–G10 desde el VPS (payment breaker, opener, ruteo BNI, quien_intro, stages P2)#67AlekZen wants to merge 43 commits into
AlekZen wants to merge 43 commits into
Conversation
… arranque en frio Snapshot de la implementacion viva (warm path funcional end-to-end: deal id=5 con Zoom+Calendar reales) como red de seguridad antes de desplegar el fix de arranque en frio (alias texto->ID de plantilla). Solo archivos fuente; secretos (.env.bak, .forgechat-credentials) excluidos.
…book + areaMap - webhook.js:865 lookup cold-start independiente de message_body (reply100m[replyId]) - G-G: hot lead que llega a Requiere Alek emite handoff a EspoCRM (visible aunque no agende) - handleIa360FreeText maneja action=book como offer_slots (no dead-end con fecha+hora exacta) - areaMap: erp/bi y agentes ia (botones plantilla-7 sin handler) Verificado end-to-end: tap firmado type:button Diagnostico rapido -> deal avanza a Intencion detectada (stage 8) + responde micro-paso. Regresion: deal id=5 intacto. Deployed == container (StartedAt 01:04:32Z > backup).
…l ya emite requires_alek) syncIa360Deal ya emite el handoff requires_alek (priority high) al entrar a Requiere Alek (ramas create+move, transicion idempotente). El bloque agregado en flow100m era redundante y causaba doble handoff. FIX#1/action=book/areaMap intactos.
…ada) + nits copy cancelacion + logs verbosos wantsList: mensajes tipo cuales tengo (sin palabras cita/reunion) eran inalcanzables con el deal en Reunion agendada (el gate solo dejaba pasar agendar/reagendar/cancelar), asi list_bookings nunca corria. Se agrego clausula wantsList. Nits: plural Le queda 1 reunion vs Le quedan N reuniones; quita doble punto tras a.m. en el aviso de cancelacion al contacto. Logs verbosos: ia360-agent (clasificacion), ia360-list, ia360-multicita append/remove. Validado en prueba viva 2026-06-03: 12 caminos PASS, borrado GCal verificado en n8n. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…emind-git#5 webhook + add-to-calendar + templates (estado vivo en prod) Captura el working tree desplegado COPY-baked que vivia sin commitear desde f12325b: - services/ia360Reminders.js: scheduler 4 recordatorios por cita (1d/sameday_am/1h/starting), self-contained, E2E verificado al owner - index.js: wiring startReminderScheduler - routes/webhook.js: fixes gap Forgemind-git#1 (bot no mudo agendado) y Forgemind-git#5 (list_bookings reconcilia meeting_links) + anti-zombi cancel - routes/ia360-calendar.js: endpoints add-to-calendar (/api/r,/api/cal) + ia360_meeting_links - routes/ia360-intake.js, routes/templates.js, services/messageSender.js: soporte intake/templates/interactive audit Punto de restauracion previo al deploy de Revenue OS (V3). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…) — gate_slots EN CUARENTENA Protege el trabajo vivo del modelo COPY-bake (host editado, nunca commiteado). Incluye handleRevenueOsButton (Pipeline 5, maquina de estados ia360_revenue_state). BUG VIVO conocido y EN CUARENTENA (no se toca en este commit): - Al clicar Si, ver horarios el sub-gate de Hablar con Alek reusa los IDs globales gate_slots_yes/no y dispara ia360_os_revenue_ahora_no (despedida) justo antes de los slots. Fix sugerido: IDs namespaced rev_gate_yes/no + gateo estricto por ia360_revenue_state. Backup: webhook.js.bak-pre-revenueos-20260609T002702 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r + /sim + handback)
…o; fire-and-forget no afecta ACK)
…) en sendQueue + fallback texto owner-pipe
…t-readout + handler owner_approve_send con gate de allowlist de prueba - Tras el readout persona-first, el owner recibe tarjeta: Aprobar y enviar / Editar copy / Solo guardar / No contactar / Tomar manual (patrón de la tarjeta de cancelación). - handler owner_approve_send valida: no-owner/no-bot, contexto de tarjeta, estado persistido coincide con el último readout, do_not_contact, copy no bloqueado, allowlist IA360_APPROVE_SEND_ALLOWLIST (vacía = NO envía), ventana 24h (texto dentro; template validado vía templateValidator fuera). - Egress único vía messageSender; persiste approved_by/approved_at/sent_at/ send_status/outbound_message_id; avanza deal a Diagnóstico enviado. - E2E approve-send-e2e.sh (fase negativa 12/12 contra producción). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ner autoriza) + fix ventana 24h (account.phoneNumberId camelCase) - IA360_APPROVE_SEND_ALLOWLIST=* : la aprobación explícita del owner desde la tarjeta autoriza el envío a cualquier contacto (pedido de Alek en vivo). - El chequeo de ventana pasaba account.phone_number_id (undefined, el objeto es camelCase) → siempre fuera de ventana; ahora account.phoneNumberId. - E2E vivo: opener cliente_expansion entregado a contacto de prueba, deal 31 a Diagnóstico enviado, approved_by/sent_at/wamid persistidos. - Template ia360_aliado_mapa_colaboracion (id 43) SUBMITTED a Meta para envíos en frío fuera de ventana. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ye memory (facts+events) en el payload; el monolito lo inyecta al prompt El agente respondia sin contexto del contacto aunque la memoria existiera: buildIa360AgentPayload solo mandaba texto+stage+historial. Ahora carga lookupIa360MemoryContext (best-effort) y lo adjunta como payload.memory; el nodo Build Prompt del monolito (republicado via API v1) lo convierte en bloque de expediente para personalizar sin re-preguntar lo ya sabido. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…do no debe desplazar el contexto base) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uteo (Produccion/Documentar/CRM/Rechazar), endpoint interno de captura para Brain v2, cola ia360_docs_sync
… entrega mapa real (sin offer_router) + botones Agendar/Llamada
…iente read-only de facts+events (resolución por nombre tolerante a acentos/typos, candidatos si ambiguo, sin expediente nunca mudo; interceptor antes del canary Brain v2, patrón idea:)
… + cold-send 43/41 + fallback global + quien_intro - Catálogo IA360_PERSONA_SEQUENCE_FLOWS: 24 copys v2 con contexto de relación, firma única "soy la IA de Alek" (cero Alek Zen / TransformIA), saludo con primer nombre (D9) y openerOptions (botones <=3 / lista 4+, ids seq_<id>:<opcion>). - buildIa360OpenerInteractive + approve-send dentro de ventana envía interactive (dedupSuffix :opener:<contacto>); fuera de ventana ya no bloquea para aliado_mapa_colaboracion (template 43) ni referido_permiso_agenda (template 41). - Guardia requiresLiveDeal en cliente_expansion: solo dispara con deal open en P2/P7; bloqueo con aviso al owner (deny no_live_deal). - Fallback global de interactive al final del dispatcher: ningún button/list reply sin handler queda mudo (acuse al contacto + aviso al owner). - quien_intro en alta vCard cuando el que comparte no es el owner (D6). - Endpoint interno POST /internal/ia360-openers/preview (auth directiva): vista previa fiel del opener SOLO al owner. - E2E contra producción: previews 5 críticos delivered, T4/T5 cold-send sin outside_window_no_template, T6 guardia negativa (0 egress), T7 opener interactive dentro de ventana, fallback id inexistente + Sí-cuéntame, quien_intro sim vCard. Deuda anotada para G-C: try/catch guardia, sanitizar quien_intro, dedupe doble tap, ruteo de respuestas seq_*. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…udas G-B - Router handleIa360SequenceReply: cada botón/fila seq_* de los 24 openers v2 registra la respuesta (custom_fields + deal) y responde paso 2 del catálogo (step2), manejo semántico (alek_directo/ahora_no/horarios) o acuse específico con aviso al owner (nextAction). Ningún seq_* válido cae al fallback genérico. - Anti-loop 100M: guard de estado (agenda/reunión/handoff no se reabre, con reuniones FUTURAS vía loadIa360BookingsForList), mapa ia360_100m_visited con nodo condensado para visitas repetidas, No prioritario sin botón Aplicarlo. - CTAs únicos: alias de quick replies de template (Sí, cuéntame / Ahora no) resuelto por estado del contacto (pf.send) hacia ids seq_* únicos; Revenue OS sigue gateado por ia360_revenue_state; templateAliasOption en referidos. - Deudas G-B: try/catch fail-closed en guardia requiresLiveDeal, sanitización de quien_intro (control chars, invisibles Unicode, surrogates, no-pisar, sin auto-introducción), dedupe de doble tap en owner_approve_send (permite reintento tras envío fallido). - Guard de estado también en el router seq_* (botón viejo no regresa deals) y limpieza de ia360_seq_last_response al reenviar opener (review adversarial). - gc-e2e.sh: suite E2E de sims firmados HMAC (31 checks) contra producción. E2E: 31/31 PASS + T6 (seq stale -> continuidad) + T7/T7b (dedupe tras envío exitoso / reintento tras fallo). Backup: webhook.js.bak-pre-gc-20260610T182557Z Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sed sin LLM) La tarjeta "Elegir secuencia" del flujo vCard deja de ser estática: un ranker rule-based consulta señales reales de la base (deal vivo + pipeline/etapa, quien_intro/referido_por, ia360_memory_facts/events, última interacción) y ordena las secuencias de la persona con la sugerida primero y el porqué en su descripción. El cuerpo trae un resumen de 2 líneas del contacto (deal/fase + último evento o fact). Honestidad estricta: sin señales → orden default del catálogo, cero razones inventadas y línea única honesta; referido_por se ignora si es owner/bot/self y solo se cita con nombre presentable. Fail-open por consulta (try/catch individual): error de DB → selector default, nunca mudo. Ranking auditable en custom_fields.ia360_selector_ranking y message_body enriquecido con la sugerida. - gatherIa360ContactSignals: 5 consultas con tope LIMIT 1 e índices existentes; memoria keyed solo por contact_number (doble keying documentado). - rankIa360Sequences: función pura, solo reordena dentro de la persona elegida; ids owner_seq:* y label owner_sequence_selector_* intactos. - buildIa360ContactSummaryLines: líneas acotadas (180/120) para que el body jamás exceda los 1024 de Meta. - E2E gd-e2e.sh 26/26 PASS (3 perfiles QA: deal P7+fact sugiere expansión citando el deal; quien_intro sugiere referido_contexto citando al introductor; sin datos → default sin razones) + regresión approve-send-e2e.sh 15/15 PASS. - approve-send-e2e.sh: fix del harness — phone_number_id real 873315362541590 (el falso 123456789 rompía la ventana 24h). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…z y modo template_only con IMAGE Harness scripts/qa-pipeline-harness.sh: Revenue OS E2E via POST /internal/ia360-revenue/opener (22/22 PASS, contacto QA dedicado), repro negativa del bug gate_slots (7/7: ahora_no NO se emite en handoff, fix vigente desde d10dea5), router 100M con anti-loop G-C (7/7), ruteo seq_* (3/3) y cadena cold-send completa via owner_approve_send (11/11). Inyector HMAC con phone_number_id real, eventos marcados entry.id=qa-harness, guard estricto de numeros QA (52199900 + 5 digitos) y aborto si faltan secretos. scripts/qa-template-send.js reemplaza al obsoleto /tmp/send_ia360_pipeline_test.js: metadata veraz obligatoria (pipeline/route_type/test_run/expected_handler en raw_payload.interactive) y soporte de headers IMAGE; template_only nunca cuenta como pipeline probado. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…liente/CFO) PASO 1: saldos que no cuadran -> Hallazgo/Impacto/Dato faltante (tabla EN TEXTO; el bot no lee imagenes)/Siguiente accion, sin pitch y sin agenda. PASO 2: tabla pegada -> mapa estructurado + nota completa en deal P7 + cola ia360_docs_sync (AlekContenido) + readout al owner; deal avanza a Quick win entregado (solo hacia adelante). Handler de media pide version en texto. Gates: tema cartera + persona cliente_activo; owner nunca entra. Endpoint /internal/ia360-cartera/preview (copy de los 3 pasos al owner). Harness scripts/qa-cartera-quickwin.sh: E2E 30/30 PASS en produccion (forgechat_monolith_e2e, solo numeros QA; cero egress a Andres real). Deudas documentadas (no bloquean): dedupe en rafaga del PASO 2, celdas vacias recorren columnas, filas descartadas sin aviso, mapa >4096 chars. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- metaTemplateName mapeado en las 24 secuencias del catálogo (44-50 APPROVED previos + 17 nuevos ids 51-67, todos APPROVED por Meta el mismo día)
- UX pre-aprobación fuera de ventana 24h: selector marca disponibilidad real por secuencia, readout avisa antes de aprobar, tarjeta sin fila Aprobar cuando no puede salir
- Cinturón en approve-send: re-verifica status APPROVED antes de encolar (tarjetas viejas/races) con diagnóstico honesto
- enqueueIa360Template: vars para {{2}} (quien_intro sanitizado) y allowTextFallback=false en frío (sin éxitos falsos)
- resolveIa360TemplateButtonAlias: match por título antes del gate semántico (botones de los 17 templates rutean)
- Harness gcold-e2e.sh (5 sims) + gcold-simc/simd standalone + gcold-templates.js (submit idempotente)
E2E: 54/54 efectivos (harness completo con presupuesto owner 6/60s) + regresión post-review SIM C 13/13 y SIM D 15/15; test-alias 8/8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…a no cuenta como respuesta - handleIa360ClienteActivoBetaLearning: la rama dry-run (IA360_MEMORY_EGRESS off) devolvía true sin egress real; el padre lo interpretaba como respondido y el contacto quedaba mudo (incidente Andrés 2026-06-11, 38 min sin respuesta, inbound 17:23 UTC). Ahora devuelve false. - handleIa360FreeText: si el handler de cliente activo/beta devuelve false, envía holding al contacto + alerta al owner + registra failure en ia360_bot_failures (nunca silencio). - handleIa360BotFailure: copy del fallback más ejecutivo y honesto. - Nuevo test de regresión backend/test/ia360NoSilenceRegression.test.js (PASS).
…e, invariante watchdog y guard del inyector QA Cliente activo/beta SIEMPRE recibe respuesta real (P0, incidente Andrés 38 min mudo): - Rama beta de handleIa360FreeText: captura de memoria en segundo plano (captureOnly, nunca cuenta como respuesta) + respuesta REAL vía callIa360Agent con memoria y perfil ejecutivo (roleHint viaja como role en el payload; el Normalize del workflow lo expone al modelo SIN tocar n8n publicado). Holding + alerta + failure SOLO si el agente falla. Datos vivos del portal => handoff explícito, nunca inventar listas. - Invariante estructural de CLASE (watchdog 75 s en el dispatcher): tras cada inbound de contacto activo/beta (o deal ganado), si no hay fila outgoing real en chat_history (excluyendo failed) => holding + alerta al owner + failure. Cubre texto, botones, audio y vCard; boot-rescan de 15 min cubre deploys/restarts. - Guard del inyector QA (incidente José Ramón): payloads sintéticos (wamid e2e./qa-*/ harness) hacia números fuera de 52199900* y distintos del owner se descartan antes del INSERT: sin fila, sin handlers, sin egress derivado. - Cierres de la auditoría adversarial (51 agentes, 7 confirmados): catch del dispatch con verificación en chat_history, holding+alerta en el catch del slot-confirm, ack de vCard al remitente no-owner (incluso parse-fail), guard owner-only del canary Brain v2 en código. - Tests: ia360NoSilenceRegression.test.js ampliado a 4 casos (PASS). E2E nuevo glive-e2e.sh 13/13 PASS (respuesta real, agente caído, guard, watchdog). Regresión cold-send G-COLD sin romper (54 PASS; los FAIL del SIM D son fixture caducado: aliado_criterios_fit ya APPROVED por Meta el 06-11). - Flags: NINGUNO activado. IA360_MEMORY_EGRESS sigue off; la respuesta real ya no depende de ese flag y queda acotada por código a la rama cliente activo/beta, conforme a la política de producción de Alek del 06-11 (egress real como respuesta a contactos reales que escriben; prohibido iniciar conversaciones o pitch a do_not_pitch).
…mico + sandbox QA total
- Dedupe: índice único parcial chat_history_ia360_handler_dedupe + ON CONFLICT
DO NOTHING en insertPendingRow (TOCTOU cerrado); candado anti-doble-ruta
enqueueIa360AgentReply (advisory xact lock por contacto) — dos inbound casi
simultáneos ya no generan dos respuestas (caso José Ramón ids 1651/1653).
- Estado conversacional ia360_conv_state en custom_fields + roleHint extendido:
presupuesto 4 preguntas/conversación (1 por turno), prohibido re-preguntar lo
respondido, correcciones respetadas, cierre con 2-3 opciones cada 3 turnos,
señal de compra => proponer, modo PROPONER desde "Dolor calificado"; facts de
memory-lookup inyectados al agente vía roleHint (n8n intacto).
- Sandbox QA: egress a 52199900XXXXX cortado en sendQueue antes de Meta (wamid
qa-sandbox, harness verde sin riesgo de calidad); tarjetas/readouts al owner
con origen wamid sintético quedan status=qa_sandboxed sin egress real; alertas
owner_bot_failure de contactos QA van a ia360_qa_evidence; deny
synthetic_approve_real_contact en approve-send. OJO review: patrón QA exacto,
NUNCA ^521999 (lada de Mérida).
- Render: message_body de templates persiste el body RENDERIZADO con vars (el
{{1}} literal del id 1612 era solo logging; el payload a Graph iba correcto).
- Deudas cerradas: dedupSuffix en enqueueIa360Text, post-filtro pitch
do_not_pitch, last_reply_kind no se escribe en captureOnly, beta con deal
lost recibe agente; sendIa360DirectText incluye label en el handler.
- DB: 9 duplicados históricos sufijados :dup-N, índice único, tabla
ia360_qa_evidence, constraint de status admite qa_sandboxed.
- E2E: gbrain-e2e.sh nuevo 16/16 (facts reflejados, corrección, cierre,
dedupe 2=>1, sandbox); regresión glive 14/14; gcold 62/62 con fixture
SUBMITTED + filtro temporal anti falsos PASS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e, jaulas por proyecto, round-trip) Identidad determinista por teléfono entre el vault de Obsidian y el RAG: - Tabla puente coexistence.ia360_vault_links: N notas por contacto, una nota vinculada apunta a UN solo contacto (índice parcial único) y los rechazos sellados no se re-preguntan. Auto-match SOLO por frontmatter telefono_wa (blocklist bot/owner/521999%); el nombre JAMÁS auto-matchea (homónimos). - Indexador y drenador en scripts/vault-bridge.js corriendo en el HOST (cron */10 con flock). Decisión de arquitectura: host-script en vez de bind mount read-only porque el round-trip NECESITA escribir el vault (un mount ro no alcanza y uno rw ampliaría la superficie del contenedor expuesto a Meta); el contenedor backend nunca toca el filesystem del vault — la DB es la única interfaz (ia360_vault_notes), lo que además deja todo testeable por SQL. - Enriquecimiento determinista a ia360_memory_facts con source=alekcontenido, fact_key=alekcontenido:<note_path>#<slot> (provenance reversible vía payload.note_path), al alta de contacto y con el comando del owner "sincroniza a <nombre|número>"; marca rag_enriched_at en el contacto. - Tarjeta de candidatos por nombre (fuzzy Levenshtein<=1, tipo Antúnez/Antunes) con taps owner_vlink/owner_vnone que sellan vínculo o rechazo; sin tap no hay sync. - JAULA por proyecto en lookupIa360MemoryContext (decisión B1 de Alek 06-11): con proyecto activo declarado (beta.project || custom_fields.project_name; account_name NO es proxy de proyecto) el agente recibe SOLO facts de ese proyecto + generales de persona; sin proyecto activo se conserva el comportamiento G-BRAIN para no esconder memoria legítima. - Round-trip: el drenador de ia360_docs_sync escribe sobre la nota VINCULADA (por vínculo, jamás por nombre) o crea nota nueva en Areas/CRM/contactos/ desde el template; idempotente por marcador de id; drenadas las 2 filas reales. Contención dura de path dentro del vault. - Test no-silencio actualizado: G-BRAIN compuso el roleHint como arreglo y el patrón estático viejo ya no existía (fallaba 3/4 ANTES de este cambio). Piloto real: JR vinculado por teléfono (4 facts Konforthome) y Andrés con sus 2 notas selladas por tap (5 facts Camiones-Selectos + 2 ArrendadoraMETA, cero fuga inter-proyecto). E2E grag-e2e.sh 43/43; regresiones glive-e2e 14/14, gbrain-e2e 16/16, no-silencio 4/4; revisión adversarial APROBADO CON CAMBIOS con los P1 aplicados (dq tag parcial, contención de path, llave de jaula). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…en en el fallback Los quick-reply de los templates frios del opener llegan con id=titulo visible y sin payload estable; handleRevenueOsButton y el resolver de alias seq_* los rutean solo bajo su estado gateado, asi que fuera de ese estado caian al fallback generico (log: unhandled interactive reply id=si, cuentame). - nuevo modulo puro src/routes/ia360OpenerReply.js: normalizeOpenerReplyId (minusculas+sin acentos+sin puntuacion+trim) y classifyOpenerReply. - getInteractiveReplyId delega en extractInteractiveReplyId del modulo. - handler de ultimo recurso ANTES del fallback: afirmativo -> REVENUE_OS_COPY.paso2 (demo/onboarding) + estado calificacion; negativo -> REVENUE_OS_COPY.ahoraNo (cierre cortes) + nutricion suave; ambos avisan al owner. - test/ia360OpenerButtons.test.js (5 casos, sin DB). - TODO: buildIa360OpenerInteractive debe emitir payload ESTABLE (no titulo). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hook de status - detecta status failed con codigos de pago/elegibilidad (131042 y familia) en el loop de statusRecords - marca cuenta bloqueada-por-pago y alerta al owner UNA vez (anti-spam por cuenta/dia) - auto-recuperacion solo con entrega facturable (sesion NO limpia el flag) - sendQueue: skipRetry para payment_blocked (no quema reintentos) - gate de pausa de templates NO activado (evita deadlock de auto-recuperacion), documentado TODO - test 7/7 (sin deps externas)
# Conflicts: # backend/src/routes/webhook.js
…Partners/Aliados id 6) - syncIa360Deal acepta pipelineName (default Revenue generico: no rompe lo existente) - ia360DealRouting.js: relationshipContext aliado_socio/referido_bni -> Partners/Aliados; mapea stages a los reales del pipeline 6 - callsites Revenue/100M intactos; test 8/8 sin deps externas - gaps P1 documentados: Fit identificado y Diagnostico compartido sin callsite (faltan secuencias Blueprint/Propuesta)
…o (quien_intro) Reanima la intro del referido BNI que estaba muerta (auditoria 2026-06-15, gap Forgemind-git#2 / P0-2): quien_intro=NULL en los BNI reales porque solo se capturaba via vCard de un no-owner, y el owner no tenia forma de teclearla. Sin el dato, referido_contexto moria en frio (cold_send_missing_quien_intro) y en caliente (placeholder bloquea). - Nuevo modulo puro src/routes/ia360ReferidoIntro.js (cero deps): parser del comando, sanitize, compact, buildIntroCustomFields, buildReferidoContextoDraft, deteccion de placeholder. webhook.js importa estas funciones en los DOS puntos de consumo. - Comando "intro <contacto>: <quien presenta>" (atajo "referido <contacto> de <quien>"), owner-only, antes del canary; persiste quien_intro y referido_por al ALIADO real (nunca el owner) via mergeContactIa360State. - Frio (gate del template) y caliente (draft) ya consumen custom_fields.quien_intro: con el dato dejan de bloquear y arman la intro real. - sanitizeIa360IntroName delega al modulo (fuente unica vCard+comando). - Test E2E test/ia360QuienIntroCommand.test.js (store en memoria que replica mergeContactIa360State + doble de resolve): simula owner teclea -> verifica persistencia -> verifica frio sin deny y caliente sin placeholder. 6/6, cero egress. - node --check OK. Doc: anexo G9 en la auditoria del vault. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts: # backend/src/routes/webhook.js
… sonda template-probe - AGENTS.md/CLAUDE.md: rutas, reglas (fish/bakeado/sandbox/no-egress), patron de trabajo, como correr tests, deploy (build+up, no install.sh), probar envio, consultar DB, estado G5/G6/G8/G9 desplegado y backlog (P1 test vivo, P2 Blueprint/Propuesta, deferred, push 403) - template-probe.js persistente en el repo
…+ Blueprint/Propuesta stub fail-closed
… al owner (re-scope record a targetContact)
…do, P2 código hecho, falta templates Meta)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Respalda y propone al canónico el trabajo IA360 G5–G10 hecho y desplegado en el VPS (vivía solo en
mainlocal del VPS por el bloqueo de permiso push 403 sobreForgemind-git/ForgeChat).Incluido (todo desplegado en producción y verificado con datos)
failed131042 → alerta owner anti-spam,skipRetry).intro <contacto>: <quien>→ pueblaquien_intro(verificado E2E: desbloquea gates COLD/HOT del referido).Fit identificado(pos 0) /Diagnóstico compartido(pos 3) + secuencias Blueprint/Propuesta como stub fail-closed detrás de flagIA360_PARTNER_BLUEPRINT(default OFF). Incluye bugfixd8f68ee(el deal Fit se atribuía al owner en vez del contacto partner; cazado por prueba viva).Notas para el merge
mainde upstream (upstream tiene commits que el VPS no, p. ej. chore: declare maintainer in package manifests #66). Puede requerir reconciliación de esos 10.ia360_partner_blueprint/ia360_partner_propuestay activar el flag.🤖 Generated with Claude Code