{
  "feature_id": "F-152",
  "agent": "qa",
  "stage": "qa_gate",
  "verdict": "APPROVED",
  "summary": "F-152 verificado: welcome email se envía al email registrado (account_created) de forma best-effort con warning logueado si SMTP falla o no está configurado; el registro sigue retornando 2xx. La confirmación de orden se dispara en PaymentSucceeded con outcome.kind==='processed' (idempotente ante duplicados) y la orden pasa a PAID. Suite tsc/prettier/eslint/boundaries/vitest(197) y verify.sh verdes.",
  "evidence": [
    "SettingsWelcomeMailer.test.ts: nodemailer mockeado -> sendMail llamado una sola vez con to==email registrado y subject=='¡Bienvenido a Mercado de Vida!' (plantilla account_created)",
    "SettingsWelcomeMailer.test.ts: readSmtpOptions lanza 'SMTP is not configured' cuando falta SMTP; sendWelcome no propaga -> register handler no falla",
    "identity.routes register: welcome dispatch es fire-and-forget .catch(request.log.warn) -> warning logueado y respuesta 201 con payload de usuario",
    "payments.routes webhook: gate event.type==='PaymentSucceeded' && outcome.kind==='processed' -> sendOrderStatusEmail({state:'PAID'}); PaymentsService.test cubre transición a PAID",
    "outcome.kind==='processed' garantiza un solo email ante webhooks duplicados (PaymentsService devuelve kind:'duplicate' antes de transición)",
    "order-status-mailer.test.ts cubre buildOrderStatusEmail/PAID (preexistente, sin tocar)",
    "orders-index.test.ts verifica barrel re-exporta sendOrderStatusEmail/ORDER_STATE_LABELS/buildOrderStatusEmail",
    "Regresión: verify.sh exit 0; tsc 0 errors; prettier+eslint clean; lint:boundaries sin nuevas violaciones; 197 tests pass; git diff --check clean"
  ],
  "checks": [
    {"item": "AC: welcome email enviado al email registrado", "ok": true, "evidence": "SettingsWelcomeMailer.test.ts: mail.to === 'ada@example.com' (input email), subject === account_created"},
    {"item": "AC: registro responde 2xx aunque SMTP falle/no-config", "ok": true, "evidence": "dispatch fire-and-forget .catch(request.log.warn); RegisterUser sin depender de email"},
    {"item": "AC: warning logueado ante fallo SMTP welcome", "ok": true, "evidence": ".catch(request.log.warn) en identity.routes register handler"},
    {"item": "AC: confirmación enviada en PaymentSucceeded", "ok": true, "evidence": "payments.routes: sendOrderStatusEmail({state:'PAID'}) tras outcome.kind==='processed'"},
    {"item": "AC: orden pasa a PAID", "ok": true, "evidence": "PaymentsService.handleWebhook transition + payments-service.test.ts (existente)"},
    {"item": "AC: webhook responde 2xx", "ok": true, "evidence": "reply.send sin propagar error de email; try/catch + warn"},
    {"item": "AC: webhook duplicado -> un solo email", "ok": true, "evidence": "gate outcome.kind==='processed'"},
    {"item": "AC: email falla/no-config -> orden PAID + 2xx + warn (no excepción)", "ok": true, "evidence": "try/catch en payments.routes -> request.log.warn (o console.warn)"},
    {"item": "Regresión: verify.sh/tsc/prettier/eslint/boundaries/tests", "ok": true, "evidence": "verify.sh exit 0; tsc 0; prettier+eslint clean; 197 tests pass; git diff --check clean"},
    {"item": "Regresión: password-reset + admin dispatch intactos", "ok": true, "evidence": "solo se añade account_created; no se removen plantillas ni routes"}
  ],
  "issues": [],
  "notes": "No hay endpoint HTTP nuevo para validar en vivo más allá de los tests unitarios; la cobertura email está cubierta por SettingsWelcomeMailer.test.ts (nodemailer mockeado) y el gate de dedup outcome.kind. El order-confirmation wiring es difícil de unit-testear sin app full; se valida por tipo + gate lógico + transición PAID preexistente.",
  "timestamp": "2026-08-22T05:05:50Z"
}
