{
  "snapshot": {
    "date": "2026-10-09",
    "repos": [
      {
        "repo": "frontend",
        "branch": "dev",
        "revision": "5930f50c60bd73741c0656a3b20da689700c66cc",
        "previous_revision": "87a4cb82ff35a7738f43f4ff11d14f17b8ceb544",
        "changed": true,
        "integrated": true
      },
      {
        "repo": "backend",
        "branch": "dev",
        "revision": "1e56ffb9fa8fc344d111d001a79c04a79bbe40b2",
        "previous_revision": "d7865e44c82d4e219df529ba3b6b62088c6c6037",
        "changed": true,
        "integrated": true
      },
      {
        "repo": "infra",
        "branch": "main",
        "revision": "30825daaae38eb9777247248dca50e72907ebfbc",
        "previous_revision": "30825daaae38eb9777247248dca50e72907ebfbc",
        "changed": false,
        "integrated": true
      }
    ],
    "pending_prs": [
      {
        "baseRefName": "dev",
        "headRefName": "feat/dashboard-impact-totals",
        "number": 44,
        "title": "feat: dashboard impact totals",
        "updatedAt": "2026-10-09T14:10:09Z",
        "url": "https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Frontend/pull/44",
        "repo": "Frontend"
      },
      {
        "baseRefName": "dev",
        "headRefName": "feature/T2-23-profile-editing",
        "number": 42,
        "title": "feat: profile editing",
        "updatedAt": "2026-10-09T14:15:44Z",
        "url": "https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Frontend/pull/42",
        "repo": "Frontend"
      },
      {
        "baseRefName": "dev",
        "headRefName": "feat/e3-notifications-realtime",
        "number": 37,
        "title": "feat(notifications): wire real time notifications to the backend",
        "updatedAt": "2026-10-09T13:52:13Z",
        "url": "https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Frontend/pull/37",
        "repo": "Frontend"
      },
      {
        "baseRefName": "dev",
        "headRefName": "feat/profile-metrics-endpoint",
        "number": 146,
        "title": "feat(accounts): add ecological profile metrics endpoint",
        "updatedAt": "2026-10-09T14:12:22Z",
        "url": "https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Backend/pull/146",
        "repo": "Backend"
      },
      {
        "baseRefName": "dev",
        "headRefName": "feat/weekly-impact-trend-endpoint",
        "number": 143,
        "title": "feat(accounts): add weekly impact-trend endpoint for the dashboard",
        "updatedAt": "2026-10-09T01:59:03Z",
        "url": "https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Backend/pull/143",
        "repo": "Backend"
      },
      {
        "baseRefName": "dev",
        "headRefName": "feat/database-release-workflow",
        "number": 30,
        "title": "feat: migraciones antes del despliegue por digest",
        "updatedAt": "2026-10-09T13:39:23Z",
        "url": "https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Backend/pull/30",
        "repo": "Backend"
      }
    ],
    "baseline": "Latest pulled integrated dev/main; pending PRs not merged"
  },
  "rows": [
    {
      "id": "QA01",
      "title": "Compilación de producción del frontend",
      "layer": "Build",
      "role": "N/A",
      "status": "PASS",
      "expected": "npm run build termina con código 0",
      "actual": "Código 0",
      "evidence": "evidence/final-QA01.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA02A",
      "title": "Catálogo sin sesión",
      "layer": "API + PostgreSQL",
      "role": "ANONYMOUS",
      "status": "PASS",
      "expected": "HTTP 401",
      "actual": "HTTP 401",
      "method": "GET",
      "path": "/api/v1/actions/",
      "request": null,
      "response": {
        "detail": "Authentication credentials were not provided."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 0,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 0,
            "deleted_at": null
          }
        ],
        "logs": [],
        "missions": [],
        "participants": 1,
        "badges": [],
        "notifications": [],
        "posts": 1
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 0,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 0,
            "deleted_at": null
          }
        ],
        "logs": [],
        "missions": [],
        "participants": 1,
        "badges": [],
        "notifications": [],
        "posts": 1
      },
      "executedAt": "2026-10-09T14:18:49.737Z",
      "evidence": "evidence/final-QA02A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA03",
      "title": "Catálogo UI con backend real",
      "layer": "UI → API",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Muestra tres acciones sintéticas de PostgreSQL",
      "actual": "Bicicleta 10, limpieza 20, termo 5; validación y factores visibles",
      "evidence": "evidence/final-QA03.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA04",
      "title": "Registro UI persiste una acción",
      "layer": "UI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "FAIL",
      "expected": "POST de registro y nuevo ActionLog",
      "actual": "0 POST action-logs; 0 registros nuevos",
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 0,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 0,
            "deleted_at": null
          }
        ],
        "logs": [],
        "missions": [],
        "participants": 1,
        "badges": [],
        "notifications": [],
        "posts": 1
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 0,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 0,
            "deleted_at": null
          }
        ],
        "logs": [],
        "missions": [],
        "participants": 1,
        "badges": [],
        "notifications": [],
        "posts": 1
      },
      "evidence": "evidence/final-QA04.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA05A",
      "title": "Acción sin fotografía acredita puntos",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 201",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/action-logs/",
      "request": {
        "action_id": "8b1f0fa8-4ebe-4af2-98ba-16c8ff007304",
        "idempotency_key": "class-qa-bike-1",
        "is_shared_publicly": true
      },
      "response": {
        "message": "Action logged successfully.",
        "status": "APPROVED",
        "log_id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 0,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 0,
            "deleted_at": null
          }
        ],
        "logs": [],
        "missions": [],
        "participants": 1,
        "badges": [],
        "notifications": [],
        "posts": 1
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "executedAt": "2026-10-09T14:19:08.150Z",
      "evidence": "evidence/final-QA05A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA05B",
      "title": "Reintento idempotente de acción",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "Respuesta controlada y estado consistente",
      "actual": "HTTP 200",
      "method": "POST",
      "path": "/api/v1/action-logs/",
      "request": {
        "action_id": "8b1f0fa8-4ebe-4af2-98ba-16c8ff007304",
        "idempotency_key": "class-qa-bike-1",
        "is_shared_publicly": true
      },
      "response": {
        "message": "Action already logged.",
        "status": "APPROVED",
        "log_id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "executedAt": "2026-10-09T14:19:09.161Z",
      "evidence": "evidence/final-QA05B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA06A",
      "title": "Referencia PHOTO queda pendiente sin acreditar",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 201",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/action-logs/",
      "request": {
        "action_id": "2e63ace0-9d2f-424f-bc39-a6dbcedaa671",
        "idempotency_key": "class-qa-photo-1",
        "evidence_object_key": "synthetic-qa/no-real-upload.jpg"
      },
      "response": {
        "message": "Action logged successfully.",
        "status": "PENDING_AUDIT",
        "log_id": "825acd9b-ec51-4408-904c-b24a69e6666e"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "PENDING_AUDIT",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "executedAt": "2026-10-09T14:19:10.142Z",
      "evidence": "evidence/final-QA06A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA06B",
      "title": "Estudiante no puede auditar",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 403",
      "actual": "HTTP 403",
      "method": "PATCH",
      "path": "/api/v1/action-logs/825acd9b-ec51-4408-904c-b24a69e6666e/audit/",
      "request": {
        "status": "APPROVED"
      },
      "response": {
        "detail": "You do not have permission to perform this action."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "PENDING_AUDIT",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "PENDING_AUDIT",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "executedAt": "2026-10-09T14:19:11.374Z",
      "evidence": "evidence/final-QA06B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA06C",
      "title": "Bandeja UI de auditoría carga pendientes",
      "layer": "UI → API",
      "role": "ADMIN",
      "status": "FAIL",
      "expected": "Lista el registro PHOTO pendiente",
      "actual": "GET de pendientes → HTTP 405",
      "evidence": "evidence/final-QA06C.json",
      "response": {
        "detail": "Method \"GET\" not allowed."
      },
      "method": "GET",
      "path": "/api/v1/action-logs/?status=PENDING_AUDIT",
      "screenshot": "evidence/03-auditoria-ui.png",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA06D",
      "title": "Administrador aprueba PHOTO por API",
      "layer": "API + PostgreSQL",
      "role": "admin",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "PATCH",
      "path": "/api/v1/action-logs/825acd9b-ec51-4408-904c-b24a69e6666e/audit/",
      "request": {
        "status": "APPROVED"
      },
      "response": {
        "message": "Audit processed successfully."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "PENDING_AUDIT",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 30,
            "available_points": 30,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 30,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 30,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "APPROVED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 1,
            "is_completed": true
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "executedAt": "2026-10-09T14:19:19.207Z",
      "evidence": "evidence/final-QA06D.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA06E",
      "title": "Revocación revierte puntos y misión",
      "layer": "API + PostgreSQL",
      "role": "admin",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "PATCH",
      "path": "/api/v1/action-logs/825acd9b-ec51-4408-904c-b24a69e6666e/audit/",
      "request": {
        "status": "REJECTED",
        "rejection_reason": "Prueba QA: referencia sintética; no se cargó fotografía real."
      },
      "response": {
        "message": "Audit processed successfully."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 30,
            "available_points": 30,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 30,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 30,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "APPROVED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 1,
            "is_completed": true
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "executedAt": "2026-10-09T14:19:20.042Z",
      "evidence": "evidence/final-QA06E.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA07A",
      "title": "Progreso de misión derivado de acción aprobada",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/missions/682a9bd9-3593-476f-9697-8cf1b0b63a12/progress/",
      "request": null,
      "response": {
        "mission": "682a9bd9-3593-476f-9697-8cf1b0b63a12",
        "current_count": 1,
        "is_completed": false,
        "target_count": 2,
        "progress_percentage": 50
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 1,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "executedAt": "2026-10-09T14:19:20.850Z",
      "evidence": "evidence/final-QA07A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA07B",
      "title": "Inscripción a campaña desde UI",
      "layer": "UI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Una nueva participación persistida",
      "actual": "2 participaciones totales; inició con 1",
      "evidence": "evidence/final-QA07B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA08A",
      "title": "Ranking de usuarios",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/rankings/users/",
      "request": null,
      "response": {
        "count": 3,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "rank": 1,
            "display_name": "Ana QA",
            "total_points": 10
          },
          {
            "id": "2de121b7-da58-4810-9b9a-04b85c957258",
            "rank": 2,
            "display_name": "Diego QA",
            "total_points": 0
          },
          {
            "id": "6f36c219-9321-4a11-bba2-5862864dc913",
            "rank": 2,
            "display_name": "Laura QA",
            "total_points": 0
          }
        ]
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "executedAt": "2026-10-09T14:19:33.150Z",
      "evidence": "evidence/final-QA08A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA08B",
      "title": "Ranking de equipos disponible en UI",
      "layer": "UI → API",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Lista de clanes ordenados",
      "actual": "UI muestra Ingeniería QA y Ecoequipo QA desde GET /api/v1/rankings/?type=...",
      "evidence": "evidence/final-QA08B.json",
      "method": "GET",
      "path": "/api/v1/rankings/",
      "screenshot": "evidence/05-ranking.png",
      "response": {
        "type": "Must be INSTITUTIONAL or PRIVATE_CLAN."
      },
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA09A",
      "title": "Crear publicación propia en feed",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 201",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/feed/",
      "request": {
        "post_type": "SHARED_EVIDENCE",
        "content": "Prueba QA: reutilicé mi termo en el campus. Datos sintéticos."
      },
      "response": {
        "id": 3,
        "author": {
          "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
          "first_name": "Ana",
          "last_name": "QA"
        },
        "author_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "post_type": "SHARED_EVIDENCE",
        "content": "Prueba QA: reutilicé mi termo en el campus. Datos sintéticos.",
        "image_url": "",
        "badge_user": null,
        "badge_info": null,
        "relative_time": "hace un momento",
        "created_at": "2026-10-09T08:19:41.955062-06:00",
        "updated_at": "2026-10-09T08:19:41.955072-06:00"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:19:41.529Z",
      "evidence": "evidence/final-QA09A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA09B",
      "title": "Otro usuario no edita publicación ajena",
      "layer": "API + PostgreSQL",
      "role": "outsider",
      "status": "PASS",
      "expected": "HTTP 403",
      "actual": "HTTP 403",
      "method": "PATCH",
      "path": "/api/v1/feed/3/",
      "request": {
        "content": "Intento no autorizado QA"
      },
      "response": {
        "detail": "You do not have permission to perform this action."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:19:42.402Z",
      "evidence": "evidence/final-QA09B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA09C",
      "title": "Autor edita publicación por API",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "PATCH",
      "path": "/api/v1/feed/3/",
      "request": {
        "content": "Actualización QA: termo reutilizable. Datos sintéticos."
      },
      "response": {
        "id": 3,
        "author": {
          "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
          "first_name": "Ana",
          "last_name": "QA"
        },
        "author_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "post_type": "SHARED_EVIDENCE",
        "content": "Actualización QA: termo reutilizable. Datos sintéticos.",
        "image_url": "",
        "badge_user": null,
        "badge_info": null,
        "relative_time": "hace un momento",
        "created_at": "2026-10-09T08:19:41.955062-06:00",
        "updated_at": "2026-10-09T08:19:43.697960-06:00"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:19:43.231Z",
      "evidence": "evidence/final-QA09C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA09D",
      "title": "Autor dispone de controles de edición en UI",
      "layer": "UI ownership",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Controles editar/eliminar para su propia publicación",
      "actual": "Controles de edición: 2",
      "evidence": "evidence/final-QA09D.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA10A",
      "title": "Evento de insignia persistido y consultable",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/notifications/",
      "request": null,
      "response": {
        "count": 4,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "5ddcf168-79c0-4c32-a24d-55c200d1acb2",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "Evidencia Rechazada",
            "message": "Tu evidencia fue rechazada. Motivo: Prueba QA: referencia sintética; no se cargó fotografía real.",
            "notification_type": "AUDIT_REJECT",
            "notification_type_display": "Photo audit rejected",
            "is_read": false,
            "created_at": "2026-10-09T08:19:20.446358-06:00",
            "time_since_created": "0 minutes ago"
          },
          {
            "id": "48debd9b-46a9-47ca-95f1-d062c1b3afa6",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "Evidencia aprobada",
            "message": "Tu registro de Participé en limpieza fue validado. Ganaste 20 puntos.",
            "notification_type": "AUDIT_APPROVED",
            "notification_type_display": "Photo audit approved",
            "is_read": false,
            "created_at": "2026-10-09T08:19:19.654877-06:00",
            "time_since_created": "0 minutes ago"
          },
          {
            "id": "17d32f6a-f8ca-4246-b963-e1a7c579cfdd",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "¡Misión completada!",
            "message": "Completaste la misión 'Participé en limpieza' (1/1) de la campaña 'Semana sustentable QA'.",
            "notification_type": "MISSION_COMPLETED",
            "notification_type_display": "Mission completed",
            "is_read": false,
            "created_at": "2026-10-09T08:19:19.653039-06:00",
            "time_since_created": "0 minutes ago"
          },
          {
            "id": "2fee6ff5-c91b-445c-9145-c37b19101685",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "¡Nueva medalla desbloqueada!",
            "message": "Has obtenido el logro: Primer paso QA. ¡Sigue así!",
            "notification_type": "BADGE_EARNED",
            "notification_type_display": "Badge earned",
            "is_read": false,
            "created_at": "2026-10-09T08:19:08.753669-06:00",
            "time_since_created": "0 minutes ago"
          }
        ],
        "unread_count": 4
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:19:49.321Z",
      "evidence": "evidence/final-QA10A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA10B",
      "title": "UI refleja notificaciones reales",
      "layer": "UI → API",
      "role": "STUDENT",
      "status": "FAIL",
      "expected": "Muestra Primer paso QA y rechazo de la prueba",
      "actual": "0 solicitudes a API de notificaciones",
      "evidence": "evidence/final-QA10B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA11A",
      "title": "Perfil editable por propietario",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "PATCH",
      "path": "/api/v1/profile/me/",
      "request": {
        "bio": "Estudiante sintética para QA local",
        "visibility": "PRIVATE"
      },
      "response": {
        "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "email": "student@qa.example.test",
        "first_name": "Ana",
        "last_name": "QA",
        "role": "STUDENT",
        "visibility": "PRIVATE",
        "bio": "Estudiante sintética para QA local",
        "preferences": {},
        "unlocked_cosmetics": [],
        "avatar_url": "",
        "total_points": 10,
        "available_points": 10,
        "current_streak": 0,
        "level": null,
        "badges": [],
        "impact_metrics": {
          "co2_kg": "1.250",
          "water_liters": "0.000",
          "plastic_kg": "0.000"
        },
        "finished_campaigns": [],
        "institutional_clan": {
          "id": "79fe991e-ad41-4dec-884d-7e2b3d39c9c9",
          "name": "Ingeniería QA"
        },
        "active_private_clan": {
          "id": "8707d413-083f-454d-aae1-030b3ec80042",
          "name": "Ecoequipo QA"
        }
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:19:56.518Z",
      "evidence": "evidence/final-QA11A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA11B",
      "title": "Consulta del perfil e impacto aprobado",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/profile/me/",
      "request": null,
      "response": {
        "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "email": "student@qa.example.test",
        "first_name": "Ana",
        "last_name": "QA",
        "role": "STUDENT",
        "visibility": "PRIVATE",
        "bio": "Estudiante sintética para QA local",
        "preferences": {},
        "unlocked_cosmetics": [],
        "avatar_url": "",
        "total_points": 10,
        "available_points": 10,
        "current_streak": 0,
        "level": null,
        "badges": [],
        "impact_metrics": {
          "co2_kg": "1.250",
          "water_liters": "0.000",
          "plastic_kg": "0.000"
        },
        "finished_campaigns": [],
        "institutional_clan": {
          "id": "79fe991e-ad41-4dec-884d-7e2b3d39c9c9",
          "name": "Ingeniería QA"
        },
        "active_private_clan": {
          "id": "8707d413-083f-454d-aae1-030b3ec80042",
          "name": "Ecoequipo QA"
        }
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:19:57.284Z",
      "evidence": "evidence/final-QA11B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA11C",
      "title": "Límite de un liderazgo privado por usuario",
      "layer": "API + PostgreSQL",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 400: ya lidera Ecoequipo QA",
      "actual": "HTTP 400",
      "method": "POST",
      "path": "/api/v1/clans/",
      "request": {
        "name": "Clan temporal QA",
        "description": "Creado y eliminado en escenario QA"
      },
      "response": [
        "User already leads a clan; BR-04 allows a single leadership at a time."
      ],
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:19:58.033Z",
      "evidence": "evidence/final-QA11C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA12A",
      "title": "Administrador modifica catálogo y persiste",
      "layer": "API + PostgreSQL",
      "role": "admin",
      "status": "FAIL",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "PATCH",
      "path": "/api/v1/actions/cbedadf8-b766-422c-b97e-5315fed61997/",
      "request": {
        "name": "Termo QA actualizado"
      },
      "response": {
        "id": "cbedadf8-b766-422c-b97e-5315fed61997",
        "code": "QA_REFILL",
        "category": {
          "id": "667e7850-c249-4230-a7c4-ee5e8833423b",
          "code": "QA_MOVILIDAD",
          "name": "Movilidad y consumo",
          "description": "Catálogo sintético",
          "icon": "bike"
        },
        "name": "Rellené mi termo",
        "description": "Escenario de prueba local, sin impacto ambiental real medido.",
        "points": 5,
        "daily_limit": 3,
        "validation_type": "NONE",
        "co2_kg_factor": "0.050",
        "water_liters_factor": "0.000",
        "plastic_kg_factor": "0.000",
        "is_active": true
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:19:58.814Z",
      "evidence": "evidence/final-QA12A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA02B",
      "title": "Estudiante no accede a pantalla administrativa",
      "layer": "UI role guard",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Acceso Restringido",
      "actual": "Acceso Restringido; se mostró Error 403 · Prohibido",
      "evidence": "evidence/final-QA02B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA11D",
      "title": "Crear clan privado con usuario elegible",
      "role": "outsider",
      "layer": "API + PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 201",
      "actual": "HTTP 201",
      "path": "/api/v1/clans/",
      "method": "POST",
      "request": {
        "name": "Clan temporal QA",
        "description": "Creado y eliminado en QA"
      },
      "response": {
        "id": "37b73c87-8024-49dc-858d-cbe5bf0d7814",
        "name": "Clan temporal QA",
        "description": "Creado y eliminado en QA",
        "avatar_object_key": "",
        "type": "PRIVATE",
        "privacy": "PUBLIC",
        "total_points": 0,
        "created_at": "2026-10-09T08:21:01.530570-06:00"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:21:02.581Z",
      "evidence": "evidence/final-QA11D.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA11E",
      "title": "No propietario no elimina clan privado",
      "role": "student",
      "layer": "API + PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 403",
      "actual": "HTTP 403",
      "path": "/api/v1/clans/37b73c87-8024-49dc-858d-cbe5bf0d7814/",
      "method": "DELETE",
      "request": null,
      "response": {
        "detail": "Only the clan leader can dissolve the clan."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:21:04.296Z",
      "evidence": "evidence/final-QA11E.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA11F",
      "title": "Propietario elimina clan mediante borrado lógico",
      "role": "outsider",
      "layer": "API + PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 204",
      "actual": "HTTP 204",
      "path": "/api/v1/clans/37b73c87-8024-49dc-858d-cbe5bf0d7814/",
      "method": "DELETE",
      "request": null,
      "response": {
        "detail": "Respuesta sin JSON; HTTP 204"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 10,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "executedAt": "2026-10-09T14:21:06.479Z",
      "evidence": "evidence/final-QA11F.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA10C",
      "title": "Perfil muestra insignias ganadas",
      "layer": "Integración de dominios",
      "role": "STUDENT",
      "status": "FAIL",
      "expected": "Perfil incluye Primer paso QA",
      "actual": "Insignias retornadas: []",
      "evidence": "evidence/final-QA10C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA13",
      "title": "Despliegue real / infraestructura compartida",
      "layer": "Cloud",
      "role": "N/A",
      "status": "NOT RUN",
      "expected": "Migraciones y conectividad del entorno desplegado verificadas",
      "actual": "La grabación es local; no se aplicó Terraform ni se modificó Neon",
      "evidence": "evidence/final-QA13.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA14",
      "title": "Dashboard con sesión y backend real",
      "layer": "UI",
      "status": "PASS",
      "expected": "Campañas reales y progreso visible en dashboard",
      "actual": "Semana sustentable QA; bicicleta 1/2; GET campaigns HTTP 200",
      "evidence": "evidence/final-QA14.json",
      "executedAt": "2026-10-09T14:21:35.692Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA15",
      "title": "Perfil y recarga conservan biografía",
      "layer": "UI → API",
      "status": "PASS",
      "expected": "Biografía persistida visible tras recarga",
      "actual": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nVolver al inicio\nPERFIL ECOLÓGICO\nAQ\nAna QA\nEstudiante\n\nstudent@qa.example.test\n\nEstudiante sintética para QA local\n\nPerfil Privado\n\nConfiguración privada activa: tus métricas solo son visibles por ti.\n\nProgreso y Nivel\n\n10\n\nPUNTOS TOTALES\n\n10\n\nDISPONIBLES\n\n0\n\nDÍAS DE RACHA\n\n—\n\nSIN NIVEL\n\nImpacto Ambiental Acumulado\nCalculado a partir de tus acciones ecológicas aprobadas\n\nCO₂ Evitado\n\n1.25 kg\n\nAgua Ahorrada\n\n0 L\n\nPlástico Reciclado\n\n0 kg\n\nMis Clanes\nEquipos y colectivos a los que perteneces\nClan Institucional\nIngeniería QA\n\nAsignado automáticamente por carrera o departamento ITESO.\n\nClan Privado Activo\nEcoequipo QA\n\nClan privado seleccionado actualmente para sumar puntos en equipo.\n\nInsignias y Reconocimientos\nLogros otorgados por tu constancia y compromiso ecológico\nAún no tienes insignias\n\nParticipa en acciones sustentables, mantén tu racha y únete a campañas para desbloquear tus primeras insignias.\n\nHistorial de Campañas\nCampañas sostenibles en las que participast",
      "evidence": "evidence/final-QA15.json",
      "executedAt": "2026-10-09T14:21:40.738Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA16A",
      "title": "Ruta protegida sin sesión",
      "layer": "UI",
      "status": "PASS",
      "expected": "Redirige a login",
      "actual": "http://localhost:3001/login",
      "evidence": "evidence/final-QA16A.json",
      "executedAt": "2026-10-09T14:21:44.922Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA16B",
      "title": "Login institucional configurado",
      "layer": "UI",
      "status": "PASS",
      "expected": "Botón activo con configuración institucional",
      "actual": "Client ID y authority recuperados; botón activo",
      "evidence": "evidence/final-QA16B.json",
      "executedAt": "2026-10-09T14:21:44.945Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA16C",
      "title": "Backend Entra rechaza identidad mock",
      "layer": "API local mock",
      "status": "PASS",
      "expected": "HTTP 401 en modo Entra",
      "actual": "HTTP 401",
      "evidence": "evidence/final-QA16C.json",
      "executedAt": "2026-10-09T14:21:47.015Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA16G",
      "title": "Dos renovaciones consecutivas desde el cliente real",
      "layer": "Browser → API",
      "status": "FAIL",
      "expected": "Ambas renovaciones aceptadas, sesión conservada",
      "actual": "{\"first\":true,\"second\":false,\"sessionCleared\":true}",
      "evidence": "evidence/final-QA16G.json",
      "executedAt": "2026-10-09T14:21:48.388Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA17A",
      "title": "Listado de amistades",
      "layer": "API real",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 200 y efecto especificado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/friendships/",
      "request": null,
      "response": {
        "count": 0,
        "next": null,
        "previous": null,
        "results": []
      },
      "evidence": "evidence/final-QA17A.json",
      "executedAt": "2026-10-09T14:21:53.550Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA17B",
      "title": "Solicitud de amistad entre dos usuarios",
      "layer": "API real",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 201 y efecto especificado",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/friendships/",
      "request": {
        "addressee": "2de121b7-da58-4810-9b9a-04b85c957258"
      },
      "response": {
        "id": "f40545e0-b3c1-41fe-9642-9ad0bc172bdf",
        "requester": {
          "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
          "email": "student@qa.example.test",
          "first_name": "Ana",
          "last_name": "QA"
        },
        "addressee": {
          "id": "2de121b7-da58-4810-9b9a-04b85c957258",
          "email": "outsider@qa.example.test",
          "first_name": "Diego",
          "last_name": "QA"
        },
        "status": "PENDING",
        "created_at": "2026-10-09T08:21:53.568200-06:00",
        "responded_at": null
      },
      "evidence": "evidence/final-QA17B.json",
      "executedAt": "2026-10-09T14:21:53.574Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA17C",
      "title": "Solicitante no acepta su propia solicitud",
      "layer": "API real",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 403 o 404: solicitante no puede aceptar",
      "actual": "HTTP 404; operación rechazada según regla vigente",
      "method": "POST",
      "path": "/api/v1/friendships/f40545e0-b3c1-41fe-9642-9ad0bc172bdf/accept/",
      "request": {},
      "response": {
        "detail": "No pending friend request found."
      },
      "evidence": "evidence/final-QA17C.json",
      "executedAt": "2026-10-09T14:21:53.588Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA17D",
      "title": "Destinatario acepta amistad",
      "layer": "API real",
      "role": "outsider",
      "status": "PASS",
      "expected": "HTTP 200 y efecto especificado",
      "actual": "HTTP 200",
      "method": "POST",
      "path": "/api/v1/friendships/f40545e0-b3c1-41fe-9642-9ad0bc172bdf/accept/",
      "request": {},
      "response": {
        "id": "f40545e0-b3c1-41fe-9642-9ad0bc172bdf",
        "requester": {
          "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
          "email": "student@qa.example.test",
          "first_name": "Ana",
          "last_name": "QA"
        },
        "addressee": {
          "id": "2de121b7-da58-4810-9b9a-04b85c957258",
          "email": "outsider@qa.example.test",
          "first_name": "Diego",
          "last_name": "QA"
        },
        "status": "ACCEPTED",
        "created_at": "2026-10-09T08:21:53.568200-06:00",
        "responded_at": "2026-10-09T08:21:53.603865-06:00"
      },
      "evidence": "evidence/final-QA17D.json",
      "executedAt": "2026-10-09T14:21:53.609Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA17E",
      "title": "Amistad visible tras nueva lectura",
      "layer": "API real",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 200 y efecto especificado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/friendships/",
      "request": null,
      "response": {
        "count": 1,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "f40545e0-b3c1-41fe-9642-9ad0bc172bdf",
            "requester": {
              "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
              "email": "student@qa.example.test",
              "first_name": "Ana",
              "last_name": "QA"
            },
            "addressee": {
              "id": "2de121b7-da58-4810-9b9a-04b85c957258",
              "email": "outsider@qa.example.test",
              "first_name": "Diego",
              "last_name": "QA"
            },
            "status": "ACCEPTED",
            "created_at": "2026-10-09T08:21:53.568200-06:00",
            "responded_at": "2026-10-09T08:21:53.603865-06:00"
          }
        ]
      },
      "evidence": "evidence/final-QA17E.json",
      "executedAt": "2026-10-09T14:21:53.626Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA18A",
      "title": "Unirse a clan público",
      "layer": "API real",
      "role": "outsider",
      "status": "PASS",
      "expected": "HTTP 201 y efecto especificado",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/clans/8707d413-083f-454d-aae1-030b3ec80042/join/",
      "request": {},
      "response": {
        "id": "45e24467-8e58-43a8-9265-0b3f6e9a1dc4",
        "clan": "8707d413-083f-454d-aae1-030b3ec80042",
        "user": "2de121b7-da58-4810-9b9a-04b85c957258",
        "role": "MEMBER",
        "status": "ACCEPTED",
        "is_active_private": false,
        "joined_at": "2026-10-09T08:21:53.649826-06:00"
      },
      "evidence": "evidence/final-QA18A.json",
      "executedAt": "2026-10-09T14:21:53.655Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA18B",
      "title": "Membresía visible en detalle",
      "layer": "API real",
      "role": "outsider",
      "status": "PASS",
      "expected": "HTTP 200 y efecto especificado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/clans/8707d413-083f-454d-aae1-030b3ec80042/",
      "request": null,
      "response": {
        "id": "8707d413-083f-454d-aae1-030b3ec80042",
        "name": "Ecoequipo QA",
        "description": "Clan privado de prueba",
        "avatar_object_key": "",
        "type": "PRIVATE",
        "privacy": "PUBLIC",
        "total_points": 10,
        "created_at": "2026-10-09T08:16:34.560445-06:00",
        "members": [
          {
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "nickname": "Ana QA",
            "role": "LEADER",
            "joined_at": "2026-10-09T08:16:34.574994-06:00"
          },
          {
            "user_id": "2de121b7-da58-4810-9b9a-04b85c957258",
            "nickname": "Diego QA",
            "role": "MEMBER",
            "joined_at": "2026-10-09T08:21:53.649826-06:00"
          }
        ],
        "member_count": 2
      },
      "evidence": "evidence/final-QA18B.json",
      "executedAt": "2026-10-09T14:21:53.675Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA18C",
      "title": "Salir del clan",
      "layer": "API real",
      "role": "outsider",
      "status": "PASS",
      "expected": "HTTP 204 y efecto especificado",
      "actual": "HTTP 204",
      "method": "POST",
      "path": "/api/v1/clans/8707d413-083f-454d-aae1-030b3ec80042/leave/",
      "request": {},
      "response": {
        "detail": "Respuesta sin JSON; HTTP 204"
      },
      "evidence": "evidence/final-QA18C.json",
      "executedAt": "2026-10-09T14:21:53.699Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA18D",
      "title": "Líder no abandona sin transferencia",
      "layer": "API real",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 403: líder no puede abandonar sin transferencia",
      "actual": "HTTP 403; operación rechazada según regla vigente",
      "method": "POST",
      "path": "/api/v1/clans/8707d413-083f-454d-aae1-030b3ec80042/leave/",
      "request": {},
      "response": {
        "detail": "The clan's leader must transfer leadership or dissolve the clan before leaving."
      },
      "evidence": "evidence/final-QA18D.json",
      "executedAt": "2026-10-09T14:21:53.720Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA19A",
      "title": "Canje en tienda persiste inventario y saldo tras recarga",
      "layer": "UI → API → PostgreSQL",
      "status": "PASS",
      "expected": "Inventario qa-frame, saldo 5, total histórico 10",
      "actual": "{\"inventory\":{\"unlocked_cosmetics\":[\"qa-frame\"]},\"available\":5,\"total\":10}",
      "evidence": "evidence/final-QA19A.json",
      "executedAt": "2026-10-09T14:21:56.342Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA19B",
      "title": "Canje repetido no descuenta de nuevo",
      "layer": "API real",
      "role": "student",
      "status": "PASS",
      "expected": "HTTP 400 y efecto especificado",
      "actual": "HTTP 400",
      "method": "POST",
      "path": "/api/v1/exchangeables/redeem/",
      "request": {
        "item_key": "qa-frame"
      },
      "response": {
        "error": "Ya posees este cosmético en tu perfil."
      },
      "evidence": "evidence/final-QA19B.json",
      "executedAt": "2026-10-09T14:21:58.545Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA19C",
      "title": "Canje sin saldo suficiente",
      "layer": "API real",
      "role": "outsider",
      "status": "PASS",
      "expected": "HTTP 400 y efecto especificado",
      "actual": "HTTP 400",
      "method": "POST",
      "path": "/api/v1/exchangeables/redeem/",
      "request": {
        "item_key": "qa-expensive"
      },
      "response": {
        "error": "Puntos disponibles insuficientes para realizar este canje."
      },
      "evidence": "evidence/final-QA19C.json",
      "executedAt": "2026-10-09T14:21:58.561Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA20",
      "title": "Catálogo en móvil sin desborde horizontal",
      "layer": "UI móvil",
      "status": "PASS",
      "expected": "390 × 844 sin desborde",
      "actual": "Desborde horizontal: false",
      "evidence": "evidence/final-QA20.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA21A",
      "title": "Notificaciones persistidas consultables",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/notifications/",
      "request": null,
      "response": {
        "count": 4,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "5ddcf168-79c0-4c32-a24d-55c200d1acb2",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "Evidencia Rechazada",
            "message": "Tu evidencia fue rechazada. Motivo: Prueba QA: referencia sintética; no se cargó fotografía real.",
            "notification_type": "AUDIT_REJECT",
            "notification_type_display": "Photo audit rejected",
            "is_read": false,
            "created_at": "2026-10-09T08:19:20.446358-06:00",
            "time_since_created": "3 minutes ago"
          },
          {
            "id": "48debd9b-46a9-47ca-95f1-d062c1b3afa6",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "Evidencia aprobada",
            "message": "Tu registro de Participé en limpieza fue validado. Ganaste 20 puntos.",
            "notification_type": "AUDIT_APPROVED",
            "notification_type_display": "Photo audit approved",
            "is_read": false,
            "created_at": "2026-10-09T08:19:19.654877-06:00",
            "time_since_created": "3 minutes ago"
          },
          {
            "id": "17d32f6a-f8ca-4246-b963-e1a7c579cfdd",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "¡Misión completada!",
            "message": "Completaste la misión 'Participé en limpieza' (1/1) de la campaña 'Semana sustentable QA'.",
            "notification_type": "MISSION_COMPLETED",
            "notification_type_display": "Mission completed",
            "is_read": false,
            "created_at": "2026-10-09T08:19:19.653039-06:00",
            "time_since_created": "3 minutes ago"
          },
          {
            "id": "2fee6ff5-c91b-445c-9145-c37b19101685",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "¡Nueva medalla desbloqueada!",
            "message": "Has obtenido el logro: Primer paso QA. ¡Sigue así!",
            "notification_type": "BADGE_EARNED",
            "notification_type_display": "Badge earned",
            "is_read": false,
            "created_at": "2026-10-09T08:19:08.753669-06:00",
            "time_since_created": "3 minutes ago"
          }
        ],
        "unread_count": 4
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA21A.json",
      "executedAt": "2026-10-09T14:22:21.601Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA21B",
      "title": "Otro usuario no marca notificación ajena",
      "role": "outsider",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 404",
      "actual": "HTTP 404",
      "method": "PATCH",
      "path": "/api/v1/notifications/5ddcf168-79c0-4c32-a24d-55c200d1acb2/",
      "request": {
        "is_read": true
      },
      "response": {
        "detail": "No Notification matches the given query."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA21B.json",
      "executedAt": "2026-10-09T14:22:22.354Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA21C",
      "title": "Marcar notificación como leída",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "PATCH",
      "path": "/api/v1/notifications/5ddcf168-79c0-4c32-a24d-55c200d1acb2/",
      "request": {
        "is_read": true
      },
      "response": {
        "id": "5ddcf168-79c0-4c32-a24d-55c200d1acb2",
        "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "title": "Evidencia Rechazada",
        "message": "Tu evidencia fue rechazada. Motivo: Prueba QA: referencia sintética; no se cargó fotografía real.",
        "notification_type": "AUDIT_REJECT",
        "notification_type_display": "Photo audit rejected",
        "is_read": true,
        "created_at": "2026-10-09T08:19:20.446358-06:00",
        "time_since_created": "3 minutes ago"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": true
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA21C.json",
      "executedAt": "2026-10-09T14:22:23.109Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA21D",
      "title": "Eliminar notificación propia",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 204",
      "actual": "HTTP 204",
      "method": "DELETE",
      "path": "/api/v1/notifications/5ddcf168-79c0-4c32-a24d-55c200d1acb2/",
      "request": null,
      "response": {
        "detail": "HTTP 204"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia Rechazada",
            "notification_type": "AUDIT_REJECT",
            "is_read": true
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA21D.json",
      "executedAt": "2026-10-09T14:22:23.987Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA21E",
      "title": "Notificación eliminada excluida tras lectura",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/notifications/",
      "request": null,
      "response": {
        "count": 3,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "48debd9b-46a9-47ca-95f1-d062c1b3afa6",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "Evidencia aprobada",
            "message": "Tu registro de Participé en limpieza fue validado. Ganaste 20 puntos.",
            "notification_type": "AUDIT_APPROVED",
            "notification_type_display": "Photo audit approved",
            "is_read": false,
            "created_at": "2026-10-09T08:19:19.654877-06:00",
            "time_since_created": "3 minutes ago"
          },
          {
            "id": "17d32f6a-f8ca-4246-b963-e1a7c579cfdd",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "¡Misión completada!",
            "message": "Completaste la misión 'Participé en limpieza' (1/1) de la campaña 'Semana sustentable QA'.",
            "notification_type": "MISSION_COMPLETED",
            "notification_type_display": "Mission completed",
            "is_read": false,
            "created_at": "2026-10-09T08:19:19.653039-06:00",
            "time_since_created": "3 minutes ago"
          },
          {
            "id": "2fee6ff5-c91b-445c-9145-c37b19101685",
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "title": "¡Nueva medalla desbloqueada!",
            "message": "Has obtenido el logro: Primer paso QA. ¡Sigue así!",
            "notification_type": "BADGE_EARNED",
            "notification_type_display": "Badge earned",
            "is_read": false,
            "created_at": "2026-10-09T08:19:08.753669-06:00",
            "time_since_created": "3 minutes ago"
          }
        ],
        "unread_count": 3
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA21E.json",
      "executedAt": "2026-10-09T14:22:24.744Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA21F",
      "title": "Marcar todas las notificaciones",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "PATCH",
      "path": "/api/v1/notifications/mark-all-read/",
      "request": {},
      "response": {
        "marked_as_read": 3
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": false
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": false
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA21F.json",
      "executedAt": "2026-10-09T14:22:25.470Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA21G",
      "title": "Contador sin pendientes",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/notifications/unread-count/",
      "request": null,
      "response": {
        "unread_count": 0
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA21G.json",
      "executedAt": "2026-10-09T14:22:26.221Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA22",
      "title": "Catálogo de insignias",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/rankings/badges/",
      "request": null,
      "response": [
        {
          "id": "84b4a7a4-7b8c-47ad-a8af-70a972eac01c",
          "name": "Primer paso QA",
          "description": "Umbral sintético de 10 puntos",
          "points_required": 10,
          "icon_name": "leaf",
          "is_earned": true,
          "earned_at": "2026-10-09T08:19:08.752031-06:00"
        }
      ],
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA22.json",
      "executedAt": "2026-10-09T14:22:26.972Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA23",
      "title": "Estudiante no modifica catálogo administrativo",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 403",
      "actual": "HTTP 403",
      "method": "PATCH",
      "path": "/api/v1/actions/cbedadf8-b766-422c-b97e-5315fed61997/",
      "request": {
        "name": "Cambio no autorizado QA"
      },
      "response": {
        "detail": "You do not have permission to perform this action."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA23.json",
      "executedAt": "2026-10-09T14:22:27.728Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA24A",
      "title": "Otro usuario no elimina publicación ajena",
      "role": "outsider",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 403",
      "actual": "HTTP 403",
      "method": "DELETE",
      "path": "/api/v1/feed/3/",
      "request": null,
      "response": {
        "detail": "You do not have permission to perform this action."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "evidence": "evidence/final-QA24A.json",
      "executedAt": "2026-10-09T14:22:28.571Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA24B",
      "title": "Autor elimina publicación",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 204",
      "actual": "HTTP 204",
      "method": "DELETE",
      "path": "/api/v1/feed/3/",
      "request": null,
      "response": {
        "detail": "HTTP 204"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 3
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 2
      },
      "evidence": "evidence/final-QA24B.json",
      "executedAt": "2026-10-09T14:22:29.339Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA25A",
      "title": "Segundo registro dentro de cuota",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 201",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/action-logs/",
      "request": {
        "action_id": "8b1f0fa8-4ebe-4af2-98ba-16c8ff007304",
        "idempotency_key": "qa-current-quota-2"
      },
      "response": {
        "message": "Action logged successfully.",
        "status": "APPROVED",
        "log_id": "bf336541-1038-4234-a151-c55cff4a4b78"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 10,
            "available_points": 5,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Ingeniería QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 10,
            "deleted_at": null
          },
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 1,
            "is_completed": false
          },
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 20,
            "available_points": 15,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          },
          {
            "name": "Ingeniería QA",
            "total_points": 20,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 20,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          },
          {
            "id": "bf336541-1038-4234-a151-c55cff4a4b78",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "qa-current-quota-2"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          },
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 2,
            "is_completed": true
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 2
      },
      "evidence": "evidence/final-QA25A.json",
      "executedAt": "2026-10-09T14:22:30.117Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA25B",
      "title": "Tercer registro dentro de cuota",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 201",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/action-logs/",
      "request": {
        "action_id": "8b1f0fa8-4ebe-4af2-98ba-16c8ff007304",
        "idempotency_key": "qa-current-quota-3"
      },
      "response": {
        "message": "Action logged successfully.",
        "status": "APPROVED",
        "log_id": "0ebf3f17-5b86-4022-9dc1-39996a6b51f6"
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 20,
            "available_points": 15,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          },
          {
            "name": "Ingeniería QA",
            "total_points": 20,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 20,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          },
          {
            "id": "bf336541-1038-4234-a151-c55cff4a4b78",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "qa-current-quota-2"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          },
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 2,
            "is_completed": true
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 30,
            "available_points": 25,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          },
          {
            "name": "Ingeniería QA",
            "total_points": 30,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 30,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          },
          {
            "id": "bf336541-1038-4234-a151-c55cff4a4b78",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "qa-current-quota-2"
          },
          {
            "id": "0ebf3f17-5b86-4022-9dc1-39996a6b51f6",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "qa-current-quota-3"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          },
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 2,
            "is_completed": true
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 2
      },
      "evidence": "evidence/final-QA25B.json",
      "executedAt": "2026-10-09T14:22:31.057Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA25C",
      "title": "Cuarto registro excede límite diario de tres",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "Respuesta controlada y efecto esperado",
      "actual": "HTTP 429",
      "method": "POST",
      "path": "/api/v1/action-logs/",
      "request": {
        "action_id": "8b1f0fa8-4ebe-4af2-98ba-16c8ff007304",
        "idempotency_key": "qa-current-quota-4"
      },
      "response": {
        "error": "Daily limit reached for this action."
      },
      "before": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 30,
            "available_points": 25,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          },
          {
            "name": "Ingeniería QA",
            "total_points": 30,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 30,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          },
          {
            "id": "bf336541-1038-4234-a151-c55cff4a4b78",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "qa-current-quota-2"
          },
          {
            "id": "0ebf3f17-5b86-4022-9dc1-39996a6b51f6",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "qa-current-quota-3"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          },
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 2,
            "is_completed": true
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 2
      },
      "after": {
        "profiles": [
          {
            "user__first_name": "Ana",
            "total_points": 30,
            "available_points": 25,
            "bio": "Estudiante sintética para QA local",
            "visibility": "PRIVATE"
          },
          {
            "user__first_name": "Laura",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          },
          {
            "user__first_name": "Diego",
            "total_points": 0,
            "available_points": 0,
            "bio": "",
            "visibility": "PUBLIC"
          }
        ],
        "clans": [
          {
            "name": "Clan temporal QA",
            "total_points": 0,
            "deleted_at": "2026-10-09 14:21:05.380849+00:00"
          },
          {
            "name": "Ingeniería QA",
            "total_points": 30,
            "deleted_at": null
          },
          {
            "name": "Ecoequipo QA",
            "total_points": 30,
            "deleted_at": null
          }
        ],
        "logs": [
          {
            "id": "8bf46e0e-87e0-4eb8-8dc7-04af2a462976",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "class-qa-bike-1"
          },
          {
            "id": "825acd9b-ec51-4408-904c-b24a69e6666e",
            "status": "REJECTED",
            "points_awarded": 20,
            "co2_kg_factor_snapshot": "0.100",
            "idempotency_key": "class-qa-photo-1"
          },
          {
            "id": "bf336541-1038-4234-a151-c55cff4a4b78",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "qa-current-quota-2"
          },
          {
            "id": "0ebf3f17-5b86-4022-9dc1-39996a6b51f6",
            "status": "APPROVED",
            "points_awarded": 10,
            "co2_kg_factor_snapshot": "1.250",
            "idempotency_key": "qa-current-quota-3"
          }
        ],
        "missions": [
          {
            "mission__action__name": "Participé en limpieza",
            "current_count": 0,
            "is_completed": false
          },
          {
            "mission__action__name": "Llegué en bicicleta",
            "current_count": 2,
            "is_completed": true
          }
        ],
        "participants": 2,
        "badges": [
          {
            "user__first_name": "Ana",
            "badge__name": "Primer paso QA"
          }
        ],
        "notifications": [
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": false
          },
          {
            "title": "Evidencia aprobada",
            "notification_type": "AUDIT_APPROVED",
            "is_read": true
          },
          {
            "title": "¡Misión completada!",
            "notification_type": "MISSION_COMPLETED",
            "is_read": true
          },
          {
            "title": "¡Nueva medalla desbloqueada!",
            "notification_type": "BADGE_EARNED",
            "is_read": true
          }
        ],
        "posts": 2
      },
      "evidence": "evidence/final-QA25C.json",
      "executedAt": "2026-10-09T14:22:31.844Z",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA26A",
      "title": "Administrador crea campaña con misión desde UI",
      "layer": "UI → API → PostgreSQL",
      "role": "ADMIN",
      "status": "PASS",
      "expected": "HTTP 201 y campaña con una misión",
      "actual": "HTTP 201",
      "response": {
        "id": "428bd1b9-d34d-4086-ab00-6908c16b2e2b",
        "title": "Campaña creada desde pantalla QA",
        "description": "Demostración sintética de un flujo completo con una misión.",
        "scope": "GLOBAL",
        "status": "PROMOTION",
        "creator": "6f36c219-9321-4a11-bba2-5862864dc913",
        "target_clan": null,
        "start_date": "2026-10-11T00:00:00-06:00",
        "end_date": "2026-10-18T23:59:59-06:00",
        "created_at": "2026-10-09T08:23:16.460303-06:00",
        "missions": [
          {
            "id": "a7ae0e52-aeac-456d-a870-0739f335b16a",
            "campaign": "428bd1b9-d34d-4086-ab00-6908c16b2e2b",
            "action": {
              "code": "QA_REFILL",
              "name": "Rellené mi termo",
              "description": "Escenario de prueba local, sin impacto ambiental real medido.",
              "points": 5
            },
            "target_count": 2
          }
        ],
        "approval_status": "APPROVED",
        "is_participant": false,
        "can_manage": true
      },
      "requests": [
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/clans/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/actions/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/clans/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/actions/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 201,
          "method": "POST"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/428bd1b9-d34d-4086-ab00-6908c16b2e2b/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/428bd1b9-d34d-4086-ab00-6908c16b2e2b/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/428bd1b9-d34d-4086-ab00-6908c16b2e2b/",
          "status": 200,
          "method": "PATCH"
        },
        {
          "path": "/api/v1/campaigns/428bd1b9-d34d-4086-ab00-6908c16b2e2b/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        }
      ],
      "screenshot": "evidence/18-campana-admin.png",
      "executedAt": "2026-10-09T14:23:16.881Z",
      "evidence": "evidence/final-QA26A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA26B",
      "title": "Administrador edita campaña en promoción desde UI",
      "layer": "UI → API → PostgreSQL",
      "role": "ADMIN",
      "status": "PASS",
      "expected": "HTTP 200 y nuevo título visible",
      "actual": "HTTP 200",
      "response": {
        "id": "428bd1b9-d34d-4086-ab00-6908c16b2e2b",
        "title": "Campaña editada desde pantalla QA",
        "description": "Demostración sintética de un flujo completo con una misión.",
        "scope": "GLOBAL",
        "status": "PROMOTION",
        "creator": "6f36c219-9321-4a11-bba2-5862864dc913",
        "target_clan": null,
        "start_date": "2026-10-11T00:00:00-06:00",
        "end_date": "2026-10-18T23:59:59-06:00",
        "created_at": "2026-10-09T08:23:16.460303-06:00",
        "missions": [
          {
            "id": "a7ae0e52-aeac-456d-a870-0739f335b16a",
            "campaign": "428bd1b9-d34d-4086-ab00-6908c16b2e2b",
            "action": {
              "code": "QA_REFILL",
              "name": "Rellené mi termo",
              "description": "Escenario de prueba local, sin impacto ambiental real medido.",
              "points": 5
            },
            "target_count": 2
          }
        ],
        "approval_status": "APPROVED",
        "is_participant": false,
        "can_manage": true
      },
      "requests": [
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/clans/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/actions/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/clans/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/actions/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 201,
          "method": "POST"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/428bd1b9-d34d-4086-ab00-6908c16b2e2b/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/428bd1b9-d34d-4086-ab00-6908c16b2e2b/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/428bd1b9-d34d-4086-ab00-6908c16b2e2b/",
          "status": 200,
          "method": "PATCH"
        },
        {
          "path": "/api/v1/campaigns/428bd1b9-d34d-4086-ab00-6908c16b2e2b/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        }
      ],
      "screenshot": "evidence/18-campana-admin.png",
      "executedAt": "2026-10-09T14:23:17.614Z",
      "evidence": "evidence/final-QA26B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA27A",
      "title": "Estudiante envía propuesta global desde UI",
      "layer": "UI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Propuesta persistida pendiente de revisión",
      "actual": "HTTP 201",
      "response": {
        "id": "86eaa818-a39e-46b8-9a8d-7bf647fc2f68",
        "title": "Propuesta de comunidad QA",
        "description": "Demostración sintética de un flujo completo con una misión.",
        "scope": "GLOBAL",
        "status": "PROMOTION",
        "approval_status": "PENDING",
        "creator": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "start_date": "2026-10-11T00:00:00-06:00",
        "end_date": "2026-10-18T23:59:59-06:00",
        "created_at": "2026-10-09T08:23:21.878037-06:00",
        "missions": [
          {
            "id": "ebcef5a6-8734-476f-a7aa-50034f5bd180",
            "campaign": "86eaa818-a39e-46b8-9a8d-7bf647fc2f68",
            "action": {
              "code": "QA_REFILL",
              "name": "Rellené mi termo",
              "description": "Escenario de prueba local, sin impacto ambiental real medido.",
              "points": 5
            },
            "target_count": 2
          }
        ],
        "reviewed_by": null,
        "reviewed_at": null,
        "rejection_reason": ""
      },
      "requests": [
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/actions/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/actions/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 201,
          "method": "POST"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        }
      ],
      "screenshot": "evidence/19-propuesta-estudiante.png",
      "executedAt": "2026-10-09T14:23:21.946Z",
      "evidence": "evidence/final-QA27A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA27B",
      "title": "Administrador aprueba propuesta desde Auditoría",
      "layer": "UI → API → PostgreSQL",
      "role": "ADMIN",
      "status": "PASS",
      "expected": "HTTP 200, propuesta aprobada y publicada",
      "actual": "HTTP 200",
      "response": {
        "id": "86eaa818-a39e-46b8-9a8d-7bf647fc2f68",
        "title": "Propuesta de comunidad QA",
        "description": "Demostración sintética de un flujo completo con una misión.",
        "scope": "GLOBAL",
        "status": "PROMOTION",
        "approval_status": "APPROVED",
        "creator": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "start_date": "2026-10-11T00:00:00-06:00",
        "end_date": "2026-10-18T23:59:59-06:00",
        "created_at": "2026-10-09T08:23:21.878037-06:00",
        "missions": [
          {
            "id": "ebcef5a6-8734-476f-a7aa-50034f5bd180",
            "campaign": "86eaa818-a39e-46b8-9a8d-7bf647fc2f68",
            "action": {
              "code": "QA_REFILL",
              "name": "Rellené mi termo",
              "description": "Escenario de prueba local, sin impacto ambiental real medido.",
              "points": 5
            },
            "target_count": 2
          }
        ],
        "reviewed_by": "6f36c219-9321-4a11-bba2-5862864dc913",
        "reviewed_at": "2026-10-09T08:23:26.867500-06:00",
        "rejection_reason": ""
      },
      "requests": [
        {
          "path": "/api/v1/action-logs/",
          "status": 405,
          "method": "GET"
        },
        {
          "path": "/api/v1/action-logs/",
          "status": 405,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/86eaa818-a39e-46b8-9a8d-7bf647fc2f68/approve/",
          "status": 200,
          "method": "POST"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        }
      ],
      "screenshot": "evidence/20-aprobacion-propuesta.png",
      "executedAt": "2026-10-09T14:23:26.981Z",
      "evidence": "evidence/final-QA27B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA27C",
      "title": "Propuesta aprobada aparece como campaña pública",
      "layer": "UI → API",
      "role": "ADMIN",
      "status": "PASS",
      "expected": "Campaña visible en catálogo",
      "actual": "Título visible tras recargar catálogo",
      "requests": [
        {
          "path": "/api/v1/action-logs/",
          "status": 405,
          "method": "GET"
        },
        {
          "path": "/api/v1/action-logs/",
          "status": 405,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/86eaa818-a39e-46b8-9a8d-7bf647fc2f68/approve/",
          "status": 200,
          "method": "POST"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        }
      ],
      "executedAt": "2026-10-09T14:23:27.325Z",
      "evidence": "evidence/final-QA27C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA27D",
      "title": "Segunda propuesta para revisar rechazo",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 201 y efecto esperado",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/campaigns/proposals/",
      "request": {
        "title": "Propuesta rechazada QA",
        "description": "Caso sintético para revisar el motivo de rechazo",
        "scope": "GLOBAL",
        "start_date": "2026-10-11T12:00:00Z",
        "end_date": "2026-10-18T12:00:00Z",
        "missions": [
          {
            "action_id": "cbedadf8-b766-422c-b97e-5315fed61997",
            "target_count": 1
          }
        ]
      },
      "response": {
        "id": "66b85ec7-d54c-411c-82f1-94eded137231",
        "title": "Propuesta rechazada QA",
        "description": "Caso sintético para revisar el motivo de rechazo",
        "scope": "GLOBAL",
        "status": "PROMOTION",
        "approval_status": "PENDING",
        "creator": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "start_date": "2026-10-11T06:00:00-06:00",
        "end_date": "2026-10-18T06:00:00-06:00",
        "created_at": "2026-10-09T08:23:29.539149-06:00",
        "missions": [
          {
            "id": "98f18cde-28d6-4261-a528-d9563d302c53",
            "campaign": "66b85ec7-d54c-411c-82f1-94eded137231",
            "action": {
              "code": "QA_REFILL",
              "name": "Rellené mi termo",
              "description": "Escenario de prueba local, sin impacto ambiental real medido.",
              "points": 5
            },
            "target_count": 1
          }
        ],
        "reviewed_by": null,
        "reviewed_at": null,
        "rejection_reason": ""
      },
      "executedAt": "2026-10-09T14:23:29.551Z",
      "evidence": "evidence/final-QA27D.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA27E",
      "title": "Administrador rechaza propuesta con motivo desde UI",
      "layer": "UI → API → PostgreSQL",
      "role": "ADMIN",
      "status": "PASS",
      "expected": "HTTP 200 y motivo persistido",
      "actual": "HTTP 200",
      "response": {
        "id": "66b85ec7-d54c-411c-82f1-94eded137231",
        "title": "Propuesta rechazada QA",
        "description": "Caso sintético para revisar el motivo de rechazo",
        "scope": "GLOBAL",
        "status": "PROMOTION",
        "approval_status": "REJECTED",
        "creator": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "start_date": "2026-10-11T06:00:00-06:00",
        "end_date": "2026-10-18T06:00:00-06:00",
        "created_at": "2026-10-09T08:23:29.539149-06:00",
        "missions": [
          {
            "id": "98f18cde-28d6-4261-a528-d9563d302c53",
            "campaign": "66b85ec7-d54c-411c-82f1-94eded137231",
            "action": {
              "code": "QA_REFILL",
              "name": "Rellené mi termo",
              "description": "Escenario de prueba local, sin impacto ambiental real medido.",
              "points": 5
            },
            "target_count": 1
          }
        ],
        "reviewed_by": "6f36c219-9321-4a11-bba2-5862864dc913",
        "reviewed_at": "2026-10-09T08:23:30.820610-06:00",
        "rejection_reason": "Caso QA: precisar la meta antes de publicar."
      },
      "requests": [
        {
          "path": "/api/v1/action-logs/",
          "status": 405,
          "method": "GET"
        },
        {
          "path": "/api/v1/action-logs/",
          "status": 405,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/proposals/66b85ec7-d54c-411c-82f1-94eded137231/reject/",
          "status": 200,
          "method": "POST"
        },
        {
          "path": "/api/v1/campaigns/proposals/",
          "status": 200,
          "method": "GET"
        }
      ],
      "screenshot": "evidence/21-rechazo-propuesta.png",
      "executedAt": "2026-10-09T14:23:30.884Z",
      "evidence": "evidence/final-QA27E.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA27F",
      "title": "Proponente consulta el motivo de rechazo",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/campaigns/proposals/",
      "request": null,
      "response": {
        "count": 2,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "66b85ec7-d54c-411c-82f1-94eded137231",
            "title": "Propuesta rechazada QA",
            "description": "Caso sintético para revisar el motivo de rechazo",
            "scope": "GLOBAL",
            "status": "PROMOTION",
            "approval_status": "REJECTED",
            "creator": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "start_date": "2026-10-11T06:00:00-06:00",
            "end_date": "2026-10-18T06:00:00-06:00",
            "created_at": "2026-10-09T08:23:29.539149-06:00",
            "missions": [
              {
                "id": "98f18cde-28d6-4261-a528-d9563d302c53",
                "campaign": "66b85ec7-d54c-411c-82f1-94eded137231",
                "action": {
                  "code": "QA_REFILL",
                  "name": "Rellené mi termo",
                  "description": "Escenario de prueba local, sin impacto ambiental real medido.",
                  "points": 5
                },
                "target_count": 1
              }
            ],
            "reviewed_by": "6f36c219-9321-4a11-bba2-5862864dc913",
            "reviewed_at": "2026-10-09T08:23:30.820610-06:00",
            "rejection_reason": "Caso QA: precisar la meta antes de publicar."
          },
          {
            "id": "86eaa818-a39e-46b8-9a8d-7bf647fc2f68",
            "title": "Propuesta de comunidad QA",
            "description": "Demostración sintética de un flujo completo con una misión.",
            "scope": "GLOBAL",
            "status": "PROMOTION",
            "approval_status": "APPROVED",
            "creator": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "start_date": "2026-10-11T00:00:00-06:00",
            "end_date": "2026-10-18T23:59:59-06:00",
            "created_at": "2026-10-09T08:23:21.878037-06:00",
            "missions": [
              {
                "id": "ebcef5a6-8734-476f-a7aa-50034f5bd180",
                "campaign": "86eaa818-a39e-46b8-9a8d-7bf647fc2f68",
                "action": {
                  "code": "QA_REFILL",
                  "name": "Rellené mi termo",
                  "description": "Escenario de prueba local, sin impacto ambiental real medido.",
                  "points": 5
                },
                "target_count": 2
              }
            ],
            "reviewed_by": "6f36c219-9321-4a11-bba2-5862864dc913",
            "reviewed_at": "2026-10-09T08:23:26.867500-06:00",
            "rejection_reason": ""
          }
        ]
      },
      "executedAt": "2026-10-09T14:23:33.351Z",
      "evidence": "evidence/final-QA27F.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA27G",
      "title": "Estudiante no aprueba propuestas",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 403 y efecto esperado",
      "actual": "HTTP 403",
      "method": "POST",
      "path": "/api/v1/campaigns/proposals/66b85ec7-d54c-411c-82f1-94eded137231/approve/",
      "request": {},
      "response": {
        "detail": "You do not have permission to perform this action."
      },
      "executedAt": "2026-10-09T14:23:33.366Z",
      "evidence": "evidence/final-QA27G.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA28A",
      "title": "Feed evita publicar contenido vacío",
      "layer": "UI",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Botón deshabilitado sin contenido",
      "actual": "disabled=true",
      "executedAt": "2026-10-09T14:23:33.919Z",
      "evidence": "evidence/final-QA28A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA29A",
      "title": "Consultar cuenta autenticada",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/users/me/",
      "request": null,
      "response": {
        "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "email": "student@qa.example.test",
        "role": "STUDENT",
        "date_joined": "2026-10-09T08:16:34.539019-06:00"
      },
      "executedAt": "2026-10-09T14:23:36.474Z",
      "evidence": "evidence/final-QA29A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA29B",
      "title": "Directorio reservado al administrador",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 403 y efecto esperado",
      "actual": "HTTP 403",
      "method": "GET",
      "path": "/api/v1/users/",
      "request": null,
      "response": {
        "detail": "You do not have permission to perform this action."
      },
      "executedAt": "2026-10-09T14:23:36.489Z",
      "evidence": "evidence/final-QA29B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA29C",
      "title": "Administrador consulta directorio",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/users/",
      "request": null,
      "response": {
        "count": 3,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "6f36c219-9321-4a11-bba2-5862864dc913",
            "email": "admin@qa.example.test",
            "role": "ADMIN",
            "date_joined": "2026-10-09T08:16:34.555476-06:00"
          },
          {
            "id": "2de121b7-da58-4810-9b9a-04b85c957258",
            "email": "outsider@qa.example.test",
            "role": "STUDENT",
            "date_joined": "2026-10-09T08:16:34.556556-06:00"
          },
          {
            "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "email": "student@qa.example.test",
            "role": "STUDENT",
            "date_joined": "2026-10-09T08:16:34.539019-06:00"
          }
        ]
      },
      "executedAt": "2026-10-09T14:23:36.506Z",
      "evidence": "evidence/final-QA29C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA29D",
      "title": "Estudiante no cambia roles",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 403 y efecto esperado",
      "actual": "HTTP 403",
      "method": "PATCH",
      "path": "/api/v1/users/2de121b7-da58-4810-9b9a-04b85c957258/role/",
      "request": {
        "role": "STAFF"
      },
      "response": {
        "detail": "You do not have permission to perform this action."
      },
      "executedAt": "2026-10-09T14:23:36.525Z",
      "evidence": "evidence/final-QA29D.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA29E",
      "title": "Administrador cambia rol de cuenta sintética",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "PATCH",
      "path": "/api/v1/users/2de121b7-da58-4810-9b9a-04b85c957258/role/",
      "request": {
        "role": "STAFF"
      },
      "response": {
        "id": "2de121b7-da58-4810-9b9a-04b85c957258",
        "email": "outsider@qa.example.test",
        "role": "STAFF",
        "date_joined": "2026-10-09T08:16:34.556556-06:00"
      },
      "executedAt": "2026-10-09T14:23:36.553Z",
      "evidence": "evidence/final-QA29E.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA29F",
      "title": "Historial de cambio de rol consultable",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/users/2de121b7-da58-4810-9b9a-04b85c957258/role-history/",
      "request": null,
      "response": {
        "count": 1,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "834e4cb8-bae3-4bcb-a71d-12e01de40170",
            "user": "2de121b7-da58-4810-9b9a-04b85c957258",
            "changed_by": "6f36c219-9321-4a11-bba2-5862864dc913",
            "previous_role": "STUDENT",
            "new_role": "STAFF",
            "created_at": "2026-10-09T08:23:36.545548-06:00"
          }
        ]
      },
      "executedAt": "2026-10-09T14:23:36.578Z",
      "evidence": "evidence/final-QA29F.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA29G",
      "title": "No se elimina el último administrador",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 400 y efecto esperado",
      "actual": "HTTP 400",
      "method": "PATCH",
      "path": "/api/v1/users/6f36c219-9321-4a11-bba2-5862864dc913/role/",
      "request": {
        "role": "STUDENT"
      },
      "response": {
        "error": {
          "code": "VALIDATION_ERROR",
          "message": "Cannot demote the only active administrator."
        }
      },
      "executedAt": "2026-10-09T14:23:36.597Z",
      "evidence": "evidence/final-QA29G.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA29H",
      "title": "Restaurar rol de cuenta sintética",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "PATCH",
      "path": "/api/v1/users/2de121b7-da58-4810-9b9a-04b85c957258/role/",
      "request": {
        "role": "STUDENT"
      },
      "response": {
        "id": "2de121b7-da58-4810-9b9a-04b85c957258",
        "email": "outsider@qa.example.test",
        "role": "STUDENT",
        "date_joined": "2026-10-09T08:16:34.556556-06:00"
      },
      "executedAt": "2026-10-09T14:23:36.619Z",
      "evidence": "evidence/final-QA29H.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA30A",
      "title": "Consultar clan institucional asignado",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/clans/institutional-clan/",
      "request": null,
      "response": {
        "career": "Ingeniería",
        "institutional_clan": {
          "id": "79fe991e-ad41-4dec-884d-7e2b3d39c9c9",
          "name": "Ingeniería QA",
          "description": "Datos sintéticos para demostración",
          "avatar_object_key": "",
          "type": "INSTITUTIONAL",
          "privacy": "PUBLIC",
          "total_points": 30,
          "created_at": "2026-10-09T08:16:34.558419-06:00"
        },
        "onboarding_completed_at": "2026-10-09T08:16:34.562318-06:00"
      },
      "executedAt": "2026-10-09T14:23:36.641Z",
      "evidence": "evidence/final-QA30A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA30B",
      "title": "Carrera vacía rechazada en onboarding",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 400 y efecto esperado",
      "actual": "HTTP 400",
      "method": "POST",
      "path": "/api/v1/clans/institutional-clan/",
      "request": {
        "career": ""
      },
      "response": {
        "career": [
          "This field may not be blank."
        ]
      },
      "executedAt": "2026-10-09T14:23:36.655Z",
      "evidence": "evidence/final-QA30B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA30C",
      "title": "Detalle y roster de clan privado",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/clans/8707d413-083f-454d-aae1-030b3ec80042/",
      "request": null,
      "response": {
        "id": "8707d413-083f-454d-aae1-030b3ec80042",
        "name": "Ecoequipo QA",
        "description": "Clan privado de prueba",
        "avatar_object_key": "",
        "type": "PRIVATE",
        "privacy": "PUBLIC",
        "total_points": 30,
        "created_at": "2026-10-09T08:16:34.560445-06:00",
        "members": [
          {
            "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "nickname": "Ana QA",
            "role": "LEADER",
            "joined_at": "2026-10-09T08:16:34.574994-06:00"
          }
        ],
        "member_count": 1
      },
      "executedAt": "2026-10-09T14:23:36.673Z",
      "evidence": "evidence/final-QA30C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA31A",
      "title": "Líder crea campaña privada para su clan",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 201 y efecto esperado",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/campaigns/",
      "request": {
        "title": "Campaña privada del líder QA",
        "description": "Caso sintético para revisar el motivo de rechazo",
        "scope": "PRIVATE",
        "start_date": "2026-10-11T12:00:00Z",
        "end_date": "2026-10-18T12:00:00Z",
        "missions": [
          {
            "action_id": "cbedadf8-b766-422c-b97e-5315fed61997",
            "target_count": 1
          }
        ],
        "target_clan": "8707d413-083f-454d-aae1-030b3ec80042"
      },
      "response": {
        "id": "2798c046-ddbc-48c8-b1ed-98a93b5ba018",
        "title": "Campaña privada del líder QA",
        "description": "Caso sintético para revisar el motivo de rechazo",
        "scope": "PRIVATE",
        "status": "PROMOTION",
        "creator": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "target_clan": "8707d413-083f-454d-aae1-030b3ec80042",
        "start_date": "2026-10-11T06:00:00-06:00",
        "end_date": "2026-10-18T06:00:00-06:00",
        "created_at": "2026-10-09T08:23:36.705819-06:00",
        "missions": [
          {
            "id": "f1770ebf-8e61-4450-9ac7-6fe410e9ad2f",
            "campaign": "2798c046-ddbc-48c8-b1ed-98a93b5ba018",
            "action": {
              "code": "QA_REFILL",
              "name": "Rellené mi termo",
              "description": "Escenario de prueba local, sin impacto ambiental real medido.",
              "points": 5
            },
            "target_count": 1
          }
        ],
        "approval_status": "APPROVED",
        "is_participant": true,
        "can_manage": true
      },
      "executedAt": "2026-10-09T14:23:36.718Z",
      "evidence": "evidence/final-QA31A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA31B",
      "title": "No miembro no se inscribe a campaña privada",
      "role": "outsider",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 403 y efecto esperado",
      "actual": "HTTP 403",
      "method": "POST",
      "path": "/api/v1/campaigns/2798c046-ddbc-48c8-b1ed-98a93b5ba018/join/",
      "request": {},
      "response": {
        "detail": "User is not a member of this campaign's clan."
      },
      "executedAt": "2026-10-09T14:23:36.742Z",
      "evidence": "evidence/final-QA31B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA31D",
      "title": "Campaña sin misiones rechazada",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 400 y efecto esperado",
      "actual": "HTTP 400",
      "method": "POST",
      "path": "/api/v1/campaigns/",
      "request": {
        "title": "Propuesta rechazada QA",
        "description": "Caso sintético para revisar el motivo de rechazo",
        "scope": "GLOBAL",
        "start_date": "2026-10-11T12:00:00Z",
        "end_date": "2026-10-18T12:00:00Z",
        "missions": []
      },
      "response": {
        "missions": [
          "A campaign must have at least one mission."
        ]
      },
      "executedAt": "2026-10-09T14:23:36.794Z",
      "evidence": "evidence/final-QA31D.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA31E",
      "title": "Campaña con fechas invertidas rechazada",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 400 y efecto esperado",
      "actual": "HTTP 400",
      "method": "POST",
      "path": "/api/v1/campaigns/",
      "request": {
        "title": "Propuesta rechazada QA",
        "description": "Caso sintético para revisar el motivo de rechazo",
        "scope": "GLOBAL",
        "start_date": "2026-10-18T12:00:00Z",
        "end_date": "2026-10-11T12:00:00Z",
        "missions": [
          {
            "action_id": "cbedadf8-b766-422c-b97e-5315fed61997",
            "target_count": 1
          }
        ]
      },
      "response": {
        "end_date": [
          "End date must be after start date."
        ]
      },
      "executedAt": "2026-10-09T14:23:36.821Z",
      "evidence": "evidence/final-QA31E.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA31F",
      "title": "Participantes de campaña consultables",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/campaigns/919da940-9e94-4c76-8af4-c7add98c7c78/participants/",
      "request": null,
      "response": {
        "count": 1,
        "next": null,
        "previous": null,
        "results": [
          {
            "campaign": "919da940-9e94-4c76-8af4-c7add98c7c78",
            "user": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "joined_at": "2026-10-09T08:16:35.007343-06:00"
          }
        ]
      },
      "executedAt": "2026-10-09T14:23:36.841Z",
      "evidence": "evidence/final-QA31F.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA31G",
      "title": "Misiones de campaña consultables",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/campaigns/919da940-9e94-4c76-8af4-c7add98c7c78/missions/",
      "request": null,
      "response": {
        "count": 2,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "1ed3089c-8c5f-4cd9-bcb2-af4e6bed9f05",
            "campaign": "919da940-9e94-4c76-8af4-c7add98c7c78",
            "action": {
              "code": "QA_CLEANUP",
              "name": "Participé en limpieza",
              "description": "Escenario de prueba local, sin impacto ambiental real medido.",
              "points": 20
            },
            "target_count": 1
          },
          {
            "id": "682a9bd9-3593-476f-9697-8cf1b0b63a12",
            "campaign": "919da940-9e94-4c76-8af4-c7add98c7c78",
            "action": {
              "code": "QA_BICYCLE",
              "name": "Llegué en bicicleta",
              "description": "Escenario de prueba local, sin impacto ambiental real medido.",
              "points": 10
            },
            "target_count": 2
          }
        ]
      },
      "executedAt": "2026-10-09T14:23:36.864Z",
      "evidence": "evidence/final-QA31G.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA32A",
      "title": "Categorías de acciones consultables",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/action-categories/",
      "request": null,
      "response": {
        "count": 1,
        "next": null,
        "previous": null,
        "results": [
          {
            "id": "667e7850-c249-4230-a7c4-ee5e8833423b",
            "code": "QA_MOVILIDAD",
            "name": "Movilidad y consumo",
            "description": "Catálogo sintético",
            "icon": "bike"
          }
        ]
      },
      "executedAt": "2026-10-09T14:23:36.884Z",
      "evidence": "evidence/final-QA32A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA33home",
      "title": "Ruta auxiliar /home",
      "layer": "UI",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Página renderiza sin error fatal",
      "actual": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nGreenITESO\n\nEn Desarrollo\n\nPlataforma integral de sostenibilidad y gestión ambiental para la comunidad ITESO. Medimos, monitoreamos y maximizamos el impacto positivo en nuestro planeta.\n\nVer Dashboard\nIniciar sesión\nMi Perfil\nPróximamente\nDashboard\n\nVisualiza tu impacto ambiental ",
      "requests": [
        {
          "path": "/api/v1/exchangeables/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/profile/me/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/profile/me/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        }
      ],
      "executedAt": "2026-10-09T14:23:39.234Z",
      "evidence": "evidence/final-QA33home.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA33designsystem",
      "title": "Ruta auxiliar /design-system",
      "layer": "UI",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Página renderiza sin error fatal",
      "actual": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nGreenITESO\n\nSistema de Diseño\n\nTipografía\n\nDisplay / Hero\n\nPlus Jakarta Sans - ExtraBold (800)\n\nTítulo H1\n\nPlus Jakarta Sans - Bold (700)\n\nTítulo H2\n\nPlus Jakarta Sans - Bold (700)\n\nSubtítulo H3\n\nPlus Jakarta Sans - SemiBold (600)\n\nCuerpo Principal Regular\n\nPlus Jakarta Sans - Reg",
      "requests": [
        {
          "path": "/api/v1/exchangeables/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/profile/me/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/profile/me/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        }
      ],
      "executedAt": "2026-10-09T14:23:40.737Z",
      "evidence": "evidence/final-QA33designsystem.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA33shop",
      "title": "Ruta auxiliar /shop",
      "layer": "UI",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Página renderiza sin error fatal",
      "actual": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nTienda de canjeables\n\nCanjea tus puntos acumulados por marcos de avatar, fondos de perfil y cosméticos.\n\nSALDO DE PUNTOS\n\nPuntos disponibles para canjear\n\nLos puntos se descontarán de tu saldo disponible al confirmar un canje.\n\n25 pts\nTodos\nMarcos\nFondos\nOtros\nMarco\nObtenido\nMarco",
      "requests": [
        {
          "path": "/api/v1/exchangeables/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/profile/me/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/profile/me/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        }
      ],
      "executedAt": "2026-10-09T14:23:42.248Z",
      "evidence": "evidence/final-QA33shop.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA34A",
      "title": "Cerrar sesión desde menú elimina sesión y vuelve a login",
      "layer": "UI → API",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Sesión vacía y página de login",
      "actual": "cleared=true",
      "requests": [
        {
          "path": "/api/v1/exchangeables/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/profile/me/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/profile/me/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/campaigns/",
          "status": 200,
          "method": "GET"
        }
      ],
      "screenshot": "evidence/23-rutas-y-salida.png",
      "executedAt": "2026-10-09T14:23:42.600Z",
      "evidence": "evidence/final-QA34A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA35A",
      "title": "Microsoft institucional real: callback, intercambio y recarga",
      "layer": "Microsoft Entra → UI → API",
      "role": "STAFF",
      "status": "PRIOR VERIFIED",
      "expected": "Token Microsoft válido aceptado por backend Entra",
      "actual": "Exchange 200; reload=true",
      "response": {
        "completed": true,
        "provider": "Microsoft Entra real",
        "backendMode": "entra",
        "role": "STAFF",
        "credentialStepsRecorded": false,
        "reloadPreservesSession": true,
        "responses": [
          {
            "path": "/api/v1/campaigns/",
            "status": 200
          },
          {
            "path": "/api/v1/campaigns/",
            "status": 200
          },
          {
            "path": "/api/v1/actions/",
            "status": 200
          },
          {
            "path": "/api/v1/actions/",
            "status": 200
          },
          {
            "path": "/api/v1/actions/",
            "status": 200
          },
          {
            "path": "/api/v1/actions/",
            "status": 200
          }
        ],
        "exchange": [
          {
            "status": 200,
            "at": "2026-10-09T07:07:17.148Z"
          }
        ],
        "accountIdentifiersOmitted": true,
        "provenance": "Validated on previous frontend/backend revisions; current authentication code unchanged, not rerun against this database"
      },
      "executedAt": "2026-10-09T14:23:44.779Z",
      "evidence": "evidence/final-QA35A.json",
      "kind": "Login institucional · evidencia anterior",
      "provenance": "Grabación previa: frontend 87a4cb8 / backend d7865e4; autenticación sin cambios. No repetido en el nuevo entorno."
    },
    {
      "id": "QA31C",
      "title": "Creador de campaña privada inscrito automáticamente",
      "role": "student",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "GET",
      "path": "/api/v1/campaigns/2798c046-ddbc-48c8-b1ed-98a93b5ba018/participants/",
      "response": {
        "count": 1,
        "next": null,
        "previous": null,
        "results": [
          {
            "campaign": "2798c046-ddbc-48c8-b1ed-98a93b5ba018",
            "user": "efe5c170-055e-4c2e-8143-12fba58edb52",
            "joined_at": "2026-10-09T08:23:36.710844-06:00"
          }
        ]
      },
      "executedAt": "2026-10-09T14:23:45.686Z",
      "evidence": "evidence/final-QA31C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA30D",
      "title": "Declarar carrera asigna clan institucional",
      "role": "outsider",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "POST",
      "path": "/api/v1/clans/institutional-clan/",
      "response": {
        "career": "Ingeniería QA",
        "institutional_clan": {
          "id": "79fe991e-ad41-4dec-884d-7e2b3d39c9c9",
          "name": "Ingeniería QA",
          "description": "Datos sintéticos para demostración",
          "avatar_object_key": "",
          "type": "INSTITUTIONAL",
          "privacy": "PUBLIC",
          "total_points": 30,
          "created_at": "2026-10-09T08:16:34.558419-06:00"
        },
        "onboarding_completed_at": "2026-10-09T08:16:34.571180-06:00"
      },
      "executedAt": "2026-10-09T14:23:45.713Z",
      "evidence": "evidence/final-QA30D.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA30E",
      "title": "Repetir carrera conserva la asignación institucional",
      "role": "outsider",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "POST",
      "path": "/api/v1/clans/institutional-clan/",
      "response": {
        "career": "Ingeniería QA",
        "institutional_clan": {
          "id": "79fe991e-ad41-4dec-884d-7e2b3d39c9c9",
          "name": "Ingeniería QA",
          "description": "Datos sintéticos para demostración",
          "avatar_object_key": "",
          "type": "INSTITUTIONAL",
          "privacy": "PUBLIC",
          "total_points": 30,
          "created_at": "2026-10-09T08:16:34.558419-06:00"
        },
        "onboarding_completed_at": "2026-10-09T08:16:34.571180-06:00"
      },
      "executedAt": "2026-10-09T14:23:45.738Z",
      "evidence": "evidence/final-QA30E.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA36A",
      "title": "Crear clan con acceso por solicitud",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 201 y efecto esperado",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/clans/",
      "response": {
        "id": "6f497965-ed1c-44a1-844b-d35ea03a2cd2",
        "name": "Clan de solicitudes QA",
        "description": "Prueba local sintética",
        "avatar_object_key": "",
        "type": "PRIVATE",
        "privacy": "PRIVATE_INVITE",
        "total_points": 0,
        "created_at": "2026-10-09T08:23:45.759770-06:00"
      },
      "executedAt": "2026-10-09T14:23:45.764Z",
      "evidence": "evidence/final-QA36A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA36B",
      "title": "Solicitud de acceso queda pendiente",
      "role": "outsider",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 201 y efecto esperado",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/clans/6f497965-ed1c-44a1-844b-d35ea03a2cd2/join/",
      "response": {
        "id": "14607988-cff7-4da7-b9d2-87eaa5e508a7",
        "clan": "6f497965-ed1c-44a1-844b-d35ea03a2cd2",
        "user": "2de121b7-da58-4810-9b9a-04b85c957258",
        "role": "MEMBER",
        "status": "PENDING",
        "is_active_private": false,
        "joined_at": "2026-10-09T08:23:45.782477-06:00"
      },
      "executedAt": "2026-10-09T14:23:45.786Z",
      "evidence": "evidence/final-QA36B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA36C",
      "title": "Líder rechaza solicitud de acceso",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "POST",
      "path": "/api/v1/clans/6f497965-ed1c-44a1-844b-d35ea03a2cd2/reject-request/",
      "response": {
        "id": "14607988-cff7-4da7-b9d2-87eaa5e508a7",
        "clan": "6f497965-ed1c-44a1-844b-d35ea03a2cd2",
        "user": "2de121b7-da58-4810-9b9a-04b85c957258",
        "role": "MEMBER",
        "status": "REJECTED",
        "is_active_private": false,
        "joined_at": "2026-10-09T08:23:45.782477-06:00"
      },
      "executedAt": "2026-10-09T14:23:45.814Z",
      "evidence": "evidence/final-QA36C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA36D",
      "title": "Solicitante puede volver a pedir acceso",
      "role": "outsider",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 201 y efecto esperado",
      "actual": "HTTP 201",
      "method": "POST",
      "path": "/api/v1/clans/6f497965-ed1c-44a1-844b-d35ea03a2cd2/join/",
      "response": {
        "id": "14607988-cff7-4da7-b9d2-87eaa5e508a7",
        "clan": "6f497965-ed1c-44a1-844b-d35ea03a2cd2",
        "user": "2de121b7-da58-4810-9b9a-04b85c957258",
        "role": "MEMBER",
        "status": "PENDING",
        "is_active_private": false,
        "joined_at": "2026-10-09T08:23:45.782477-06:00"
      },
      "executedAt": "2026-10-09T14:23:45.836Z",
      "evidence": "evidence/final-QA36D.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA36E",
      "title": "Líder acepta solicitud y activa membresía",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "POST",
      "path": "/api/v1/clans/6f497965-ed1c-44a1-844b-d35ea03a2cd2/accept-request/",
      "response": {
        "id": "14607988-cff7-4da7-b9d2-87eaa5e508a7",
        "clan": "6f497965-ed1c-44a1-844b-d35ea03a2cd2",
        "user": "2de121b7-da58-4810-9b9a-04b85c957258",
        "role": "MEMBER",
        "status": "ACCEPTED",
        "is_active_private": false,
        "joined_at": "2026-10-09T08:23:45.782477-06:00"
      },
      "executedAt": "2026-10-09T14:23:45.861Z",
      "evidence": "evidence/final-QA36E.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA36F",
      "title": "Elegir clan privado activo",
      "role": "outsider",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "POST",
      "path": "/api/v1/clans/6f497965-ed1c-44a1-844b-d35ea03a2cd2/select-active/",
      "response": {
        "id": "14607988-cff7-4da7-b9d2-87eaa5e508a7",
        "clan": "6f497965-ed1c-44a1-844b-d35ea03a2cd2",
        "user": "2de121b7-da58-4810-9b9a-04b85c957258",
        "role": "MEMBER",
        "status": "ACCEPTED",
        "is_active_private": true,
        "joined_at": "2026-10-09T08:23:45.782477-06:00"
      },
      "executedAt": "2026-10-09T14:23:45.883Z",
      "evidence": "evidence/final-QA36F.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA36G",
      "title": "Transferir liderazgo a miembro aceptado",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 200 y efecto esperado",
      "actual": "HTTP 200",
      "method": "POST",
      "path": "/api/v1/clans/6f497965-ed1c-44a1-844b-d35ea03a2cd2/transfer-leadership/",
      "response": {
        "id": "14607988-cff7-4da7-b9d2-87eaa5e508a7",
        "clan": "6f497965-ed1c-44a1-844b-d35ea03a2cd2",
        "user": "2de121b7-da58-4810-9b9a-04b85c957258",
        "role": "LEADER",
        "status": "ACCEPTED",
        "is_active_private": true,
        "joined_at": "2026-10-09T08:23:45.782477-06:00"
      },
      "executedAt": "2026-10-09T14:23:45.913Z",
      "evidence": "evidence/final-QA36G.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA28B",
      "title": "Publicar desde feed y conservar tras recarga",
      "role": "STUDENT",
      "layer": "UI → API → PostgreSQL",
      "status": "PASS",
      "expected": "HTTP 201 y publicación visible tras recarga",
      "actual": "HTTP 201",
      "response": {
        "id": 5,
        "author": {
          "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
          "first_name": "Ana",
          "last_name": "QA"
        },
        "author_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "post_type": "SHARED_EVIDENCE",
        "content": "Publicación desde UI comprobada tras recarga. Datos sintéticos.",
        "image_url": "",
        "badge_user": null,
        "badge_info": null,
        "relative_time": "hace un momento",
        "created_at": "2026-10-09T08:23:46.518414-06:00",
        "updated_at": "2026-10-09T08:23:46.518424-06:00"
      },
      "requests": [
        {
          "path": "/api/v1/feed/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/feed/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/feed/",
          "status": 201,
          "method": "POST"
        },
        {
          "path": "/api/v1/feed/",
          "status": 200,
          "method": "GET"
        },
        {
          "path": "/api/v1/feed/",
          "status": 200,
          "method": "GET"
        }
      ],
      "screenshot": "evidence/22-publicacion-feed.png",
      "executedAt": "2026-10-09T14:23:51.558Z",
      "evidence": "evidence/final-QA28B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA34B",
      "title": "Logout invalida refresh token en backend",
      "role": "ADMIN",
      "layer": "API",
      "status": "PASS",
      "expected": "Logout 200 y refresh posterior 401",
      "actual": "Logout 200; refresh 401",
      "executedAt": "2026-10-09T14:23:52.071Z",
      "evidence": "evidence/final-QA34B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA37A",
      "title": "Autenticación WebSocket de student",
      "layer": "WebSocket ASGI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Comportamiento descrito en protocolo de notificaciones",
      "actual": "auth.ok con contador de no leídas",
      "response": {
        "type": "auth.ok",
        "unread_count": 2
      },
      "evidence": "evidence/final-QA37A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA37B",
      "title": "Autenticación WebSocket de outsider",
      "layer": "WebSocket ASGI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Comportamiento descrito en protocolo de notificaciones",
      "actual": "auth.ok con contador de no leídas",
      "response": {
        "type": "auth.ok",
        "unread_count": 2
      },
      "evidence": "evidence/final-QA37B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA37C",
      "title": "Ping del WebSocket responde pong",
      "layer": "WebSocket ASGI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Comportamiento descrito en protocolo de notificaciones",
      "actual": "{'type': 'pong'}",
      "response": {
        "type": "pong"
      },
      "evidence": "evidence/final-QA37C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA37D",
      "title": "Aprobar evidencia entrega notificación por WebSocket",
      "layer": "WebSocket ASGI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Comportamiento descrito en protocolo de notificaciones",
      "actual": "Registro 201; auditoría 200; evento notification.created",
      "response": {
        "type": "notification.created",
        "notification": {
          "id": "f8c8a7a7-cd9e-4058-a609-75116aba6e6e",
          "user_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
          "title": "Evidencia aprobada",
          "message": "Tu registro de Participé en limpieza fue validado. Ganaste 20 puntos.",
          "notification_type": "AUDIT_APPROVED",
          "notification_type_display": "Photo audit approved",
          "is_read": false,
          "created_at": "2026-10-09T08:23:52.444465-06:00",
          "time_since_created": "0 minutes ago"
        }
      },
      "evidence": "evidence/final-QA37D.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA37E",
      "title": "Usuario ajeno no recibe notificación del estudiante",
      "layer": "WebSocket ASGI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Comportamiento descrito en protocolo de notificaciones",
      "actual": "Sin evento ajeno durante ventana de observación",
      "response": null,
      "evidence": "evidence/final-QA37E.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA37F",
      "title": "Token inválido cierra WebSocket",
      "layer": "WebSocket ASGI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Comportamiento descrito en protocolo de notificaciones",
      "actual": "Código 4401",
      "response": null,
      "evidence": "evidence/final-QA37F.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA37G",
      "title": "Mensaje previo a autenticación cierra WebSocket",
      "layer": "WebSocket ASGI → API → PostgreSQL",
      "role": "STUDENT",
      "status": "PASS",
      "expected": "Comportamiento descrito en protocolo de notificaciones",
      "actual": "Código 4401",
      "response": null,
      "evidence": "evidence/final-QA37G.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "QA38A",
      "title": "Administrador crea una definición de acción",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "FAIL",
      "expected": "HTTP 201",
      "actual": "HTTP 500",
      "method": "POST",
      "path": "/api/v1/actions/",
      "response": {
        "detail": "HTTP 500 sin JSON; depuración excluida"
      },
      "executedAt": "2026-10-09T14:23:54.230Z",
      "evidence": "evidence/final-QA38A.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA38B",
      "title": "Eliminar acción referenciada responde con error controlado",
      "role": "admin",
      "layer": "API → PostgreSQL",
      "status": "FAIL",
      "expected": "HTTP 400/409",
      "actual": "HTTP 500",
      "method": "DELETE",
      "path": "/api/v1/actions/cbedadf8-b766-422c-b97e-5315fed61997/",
      "response": {
        "detail": "HTTP 500 sin JSON; depuración excluida"
      },
      "executedAt": "2026-10-09T14:23:54.310Z",
      "evidence": "evidence/final-QA38B.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "QA26C",
      "title": "Administrador agrega misión a campaña en promoción desde UI",
      "layer": "UI → API → PostgreSQL",
      "role": "ADMIN",
      "status": "PASS",
      "expected": "HTTP 201 y misión visible",
      "actual": "HTTP 201",
      "response": {
        "id": "c0e486cd-0aac-4844-90de-3a6deec24f64",
        "campaign": "428bd1b9-d34d-4086-ab00-6908c16b2e2b",
        "action": {
          "code": "QA_BICYCLE",
          "name": "Llegué en bicicleta",
          "description": "Escenario de prueba local, sin impacto ambiental real medido.",
          "points": 10
        },
        "target_count": 3
      },
      "screenshot": "evidence/25-mision-adicional.png",
      "executedAt": "2026-10-09T14:23:58.555Z",
      "evidence": "evidence/final-QA26C.json",
      "kind": "Funcional · integración real",
      "provenance": "Versión integrada actual · PostgreSQL local · datos sintéticos"
    },
    {
      "id": "CLAN-01",
      "title": "Crear clan valida nombre vacío",
      "status": "PASS",
      "actual": "No se envía POST sin nombre",
      "role": "clanleader",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:27:54.297Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-01.png",
      "video": "scenarios/current-clan-create.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-01.json"
    },
    {
      "id": "CLAN-02",
      "title": "Crear clan público desde pantalla",
      "status": "PASS",
      "actual": "HTTP 201",
      "response": {
        "id": "628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f",
        "name": "Guardianes del campus",
        "description": "Equipo de demostración para participar en acciones sustentables.",
        "avatar_object_key": "",
        "type": "PRIVATE",
        "privacy": "PUBLIC",
        "total_points": 0,
        "created_at": "2026-10-09T08:27:58.683202-06:00"
      },
      "role": "clanleader",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:27:58.836Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/",
          "status": 201
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-02.png",
      "video": "scenarios/current-clan-create.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-02.json"
    },
    {
      "id": "CLAN-03",
      "title": "Copiar invitación del clan",
      "status": "PASS",
      "actual": "http://localhost:3001/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f",
      "role": "clanleader",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:28:00.749Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/",
          "status": 201
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-03.png",
      "video": "scenarios/current-clan-create.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-03.json"
    },
    {
      "id": "CLAN-04",
      "title": "Buscar y unirse al clan público",
      "status": "PASS",
      "actual": "HTTP 201",
      "response": {
        "id": "818bdca9-08ef-4753-aacb-1d7f5c6767e9",
        "clan": "628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f",
        "user": "366fd0f1-7ff1-4ce7-b7cb-c483d808bed7",
        "role": "MEMBER",
        "status": "ACCEPTED",
        "is_active_private": false,
        "joined_at": "2026-10-09T08:28:07.388801-06:00"
      },
      "role": "clanmember",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:28:07.473Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/join/",
          "status": 201
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-04.png",
      "video": "scenarios/current-clan-join.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-04.json"
    },
    {
      "id": "CLAN-05",
      "title": "Seleccionar clan activo conserva estado tras recarga",
      "status": "PASS",
      "actual": "HTTP 200",
      "response": {
        "id": "818bdca9-08ef-4753-aacb-1d7f5c6767e9",
        "clan": "628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f",
        "user": "366fd0f1-7ff1-4ce7-b7cb-c483d808bed7",
        "role": "MEMBER",
        "status": "ACCEPTED",
        "is_active_private": true,
        "joined_at": "2026-10-09T08:28:07.388801-06:00"
      },
      "role": "clanmember",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:28:09.656Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/join/",
          "status": 201
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/select-active/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-05.png",
      "video": "scenarios/current-clan-join.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-05.json"
    },
    {
      "id": "CLAN-06",
      "title": "Transferir liderazgo desde pantalla",
      "status": "PASS",
      "actual": "HTTP 200",
      "response": {
        "id": "818bdca9-08ef-4753-aacb-1d7f5c6767e9",
        "clan": "628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f",
        "user": "366fd0f1-7ff1-4ce7-b7cb-c483d808bed7",
        "role": "LEADER",
        "status": "ACCEPTED",
        "is_active_private": true,
        "joined_at": "2026-10-09T08:28:07.388801-06:00"
      },
      "role": "clanleader",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:28:15.214Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/transfer-leadership/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-06.png",
      "video": "scenarios/current-clan-transfer.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-06.json"
    },
    {
      "id": "CLAN-07",
      "title": "Cancelar salida conserva membresía",
      "status": "PASS",
      "actual": "Se mantiene la pertenencia",
      "role": "clanleader",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:28:17.184Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/transfer-leadership/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-07.png",
      "video": "scenarios/current-clan-transfer.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-07.json"
    },
    {
      "id": "CLAN-08",
      "title": "Salir del clan tras transferir liderazgo",
      "status": "PASS",
      "actual": "HTTP 204",
      "response": null,
      "role": "clanleader",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:28:19.196Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/transfer-leadership/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/leave/",
          "status": 204
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-08.png",
      "video": "scenarios/current-clan-transfer.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-08.json"
    },
    {
      "id": "CLAN-09",
      "title": "Disolver clan con confirmación",
      "status": "PASS",
      "actual": "HTTP 204",
      "response": null,
      "role": "clanmember",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:28:24.012Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "DELETE",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 204
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-09.png",
      "video": "scenarios/current-clan-dissolve.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-09.json"
    },
    {
      "id": "CLAN-10",
      "title": "Clan disuelto muestra estado no disponible",
      "status": "PASS",
      "actual": "HTTP 404 y mensaje controlado",
      "role": "clanmember",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:28:26.093Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "DELETE",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 204
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 404
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/628dc949-f4b6-4aa4-9c6a-6aa4c2b09f2f/",
          "status": 404
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-10.png",
      "video": "scenarios/current-clan-dissolve.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-10.json"
    },
    {
      "id": "FEED-01",
      "title": "Publicar desde el feed",
      "status": "PASS",
      "actual": "HTTP 201",
      "response": {
        "id": 9,
        "author": {
          "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
          "first_name": "Ana",
          "last_name": "QA"
        },
        "author_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "post_type": "SHARED_EVIDENCE",
        "content": "Compartimos una ruta segura al campus en bicicleta.",
        "image_url": "",
        "badge_user": null,
        "badge_info": null,
        "relative_time": "hace un momento",
        "created_at": "2026-10-09T08:29:43.813235-06:00",
        "updated_at": "2026-10-09T08:29:43.813257-06:00"
      },
      "role": "student",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:29:44.310Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/feed/",
          "status": 201
        }
      ],
      "screenshot": "evidence/FEED-01.png",
      "video": "scenarios/current-feed-edit.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/FEED-01.json"
    },
    {
      "id": "FEED-02",
      "title": "Editar publicación propia y recargar",
      "status": "PASS",
      "actual": "HTTP 200",
      "response": {
        "id": 9,
        "author": {
          "id": "efe5c170-055e-4c2e-8143-12fba58edb52",
          "first_name": "Ana",
          "last_name": "QA"
        },
        "author_id": "efe5c170-055e-4c2e-8143-12fba58edb52",
        "post_type": "SHARED_EVIDENCE",
        "content": "Compartimos una ruta segura en bicicleta y evitamos usar el auto.",
        "image_url": "",
        "badge_user": null,
        "badge_info": null,
        "relative_time": "hace un momento",
        "created_at": "2026-10-09T08:29:43.813235-06:00",
        "updated_at": "2026-10-09T08:29:48.395905-06:00"
      },
      "role": "student",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:29:48.700Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/feed/",
          "status": 201
        },
        {
          "method": "PATCH",
          "path": "/api/v1/feed/9/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        }
      ],
      "screenshot": "evidence/FEED-02.png",
      "video": "scenarios/current-feed-edit.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/FEED-02.json"
    },
    {
      "id": "FEED-03",
      "title": "Eliminar publicación propia",
      "status": "PASS",
      "actual": "HTTP 204",
      "response": null,
      "role": "student",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:29:50.907Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/feed/",
          "status": 201
        },
        {
          "method": "PATCH",
          "path": "/api/v1/feed/9/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 304
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "DELETE",
          "path": "/api/v1/feed/9/",
          "status": 204
        }
      ],
      "screenshot": "evidence/FEED-03.png",
      "video": "scenarios/current-feed-edit.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/FEED-03.json"
    },
    {
      "id": "CLAN-11",
      "title": "Invitación inválida muestra explicación",
      "status": "PASS",
      "actual": "No navega ni envía una solicitud inválida",
      "role": "claninvite",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:39:24.741Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "screenshot": "evidence/CLAN-11.png",
      "video": "scenarios/current-clan-invitation.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-11.json"
    },
    {
      "id": "CLAN-12",
      "title": "Invitación privada genera solicitud pendiente desde UI",
      "status": "PASS",
      "actual": "HTTP 201",
      "response": {
        "id": "b5a7fdb4-8329-4d98-bafe-4add7c17a696",
        "clan": "6f497965-ed1c-44a1-844b-d35ea03a2cd2",
        "user": "462d543b-a8b2-4be6-8284-2e839b4b4787",
        "role": "MEMBER",
        "status": "PENDING",
        "is_active_private": false,
        "joined_at": "2026-10-09T08:39:28.802482-06:00"
      },
      "role": "claninvite",
      "layer": "UI → API → PostgreSQL",
      "expected": "Operación persistida y estado visible coherente",
      "executedAt": "2026-10-09T14:39:28.846Z",
      "network": [
        {
          "method": "GET",
          "path": "/src/lib/api/auth.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/feed.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/client.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-catalog.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/clans.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/leaderboard.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/errors.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/action-audit.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/ecological-profile.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/exchangeables.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/src/lib/api/campaigns.ts",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/6f497965-ed1c-44a1-844b-d35ea03a2cd2/",
          "status": 404
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/6f497965-ed1c-44a1-844b-d35ea03a2cd2/",
          "status": 404
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "POST",
          "path": "/api/v1/clans/6f497965-ed1c-44a1-844b-d35ea03a2cd2/join/",
          "status": 201
        }
      ],
      "screenshot": "evidence/CLAN-12.png",
      "video": "scenarios/current-clan-invitation.webm",
      "kind": "Funcional · UI real",
      "provenance": "Versión integrada actual · UI → API → PostgreSQL",
      "evidence": "evidence/CLAN-12.json"
    },
    {
      "id": "ROUTE-01-D",
      "title": "Ruta /login · escritorio",
      "route": "/login",
      "resolvedRoute": "/login",
      "role": "ANONYMOUS",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [],
      "overflow": false,
      "screenshot": "evidence/ROUTE-01-D.png",
      "text": "GREENITESO\n\nInicia sesión\n\nAccede con tu cuenta institucional para registrar y consultar tu impacto ambiental.\n\nIniciar sesión con @iteso.mx\n\nUsa exclusivamente tu cuenta institucional @iteso.mx.",
      "video": "scenarios/ROUTE-01-D.webm",
      "executedAt": "2026-10-09T14:20:28.657Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-01-D.json"
    },
    {
      "id": "ROUTE-02-D",
      "title": "Ruta / · escritorio",
      "route": "/",
      "resolvedRoute": "/",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-02-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\n\nDashboard Impact\n\nMis campañas\nTodas\nEn promoción\nActivas\nFinalizadas\nTodas\nGlobales\nPrivadas\n\nGLOBAL\n\nReto del termo QA\nEn promoción\n\nCampaña sintética para verificar integración\n\n10 oct – 17 oct\nProgreso de misiones\n0/1\nx\n\nGLOBAL\n\nSemana sustentable QA\nActiva\n\nCampaña sintética para verificar integración\n\n8 oct – 16 oct\nProgreso de misiones\n0/2\nx\nMisiones activas\nSemana sustentable QA\n\nLlegué en bicicleta\n\nMeta: 2 veces\n\nx\n+10 pts\n1/2\n\nParticipé en limpieza\n\nMeta: 1 veces\n\nx\n+20 pts\n0/1\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-02-D.webm",
      "executedAt": "2026-10-09T14:20:34.167Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-02-D.json"
    },
    {
      "id": "ROUTE-03-D",
      "title": "Ruta /home · escritorio",
      "route": "/home",
      "resolvedRoute": "/home",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [],
      "overflow": false,
      "screenshot": "evidence/ROUTE-03-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nGreenITESO\n\nEn Desarrollo\n\nPlataforma integral de sostenibilidad y gestión ambiental para la comunidad ITESO. Medimos, monitoreamos y maximizamos el impacto positivo en nuestro planeta.\n\nVer Dashboard\nIniciar sesión\nMi Perfil\nPróximamente\nDashboard\n\nVisualiza tu impacto ambiental en tiempo real\n\nMisiones\n\nParticipa en retos sostenibles y gana puntos\n\nLeaderboard\n\nCompite y colabora con tu comunidad\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-03-D.webm",
      "executedAt": "2026-10-09T14:20:40.248Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-03-D.json"
    },
    {
      "id": "ROUTE-04-D",
      "title": "Ruta /design-system · escritorio",
      "route": "/design-system",
      "resolvedRoute": "/design-system",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [],
      "overflow": false,
      "screenshot": "evidence/ROUTE-04-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nGreenITESO\n\nSistema de Diseño\n\nTipografía\n\nDisplay / Hero\n\nPlus Jakarta Sans - ExtraBold (800)\n\nTítulo H1\n\nPlus Jakarta Sans - Bold (700)\n\nTítulo H2\n\nPlus Jakarta Sans - Bold (700)\n\nSubtítulo H3\n\nPlus Jakarta Sans - SemiBold (600)\n\nCuerpo Principal Regular\n\nPlus Jakarta Sans - Regular (400)\n\nCuerpo Secundario\n\nPlus Jakarta Sans - Regular (400)\n\nPaleta Primaria - Verde Ecológico\n\n-50\n\n-100\n\n-200\n\n-300\n\n-400\n\n-500\n\n-600\n\n-700\n\n-800\n\n-900\n\nPaleta Secundaria - Gris Salvia\n\n-50\n\n-100\n\n-200\n\n-300\n\n-400\n\n-500\n\n-600\n\n-700\n\n-800\n\n-900\n\nEstados Semánticos\n\nAprobado / Exitoso\n\nRegistro aprobado, misión completada\n\nPendiente de Auditoría\n\nEvidencia en revisión\n\nRechazado / Alerta\n\nEvidencia rechazada, error\n\nInformación / Neutral\n\nAvisos generales, tutoriales\n\nIdentidad Visual de Impacto\n\nCO₂ Evitado\n\n128 kg\n\nAgua Ahorrada\n\n2,450 L\n\nPlástico Reciclado\n\n45 kg\n\nBotones\n\nPrimario - Estados\n\nNormal\nHover\nActive\nDisabled\n\nSecundario / Outlined\n\nNormal\nHover\nDisabled\nFormularios e Inputs\nNombre\nEmail\nMensaje\nTarjetas (Cards)\nMisión Principal\n\nReduce tu huella de carbono en esta semana\n\nVer Detalles\nTu Impacto\n\n2,450 L\n\nAgua ahorrada este mes\n\nBadges y Tags\nAPROBADO\nPENDIENTE\nRECHAZADO\nINFORMACIÓN\n\nBadges con estados semánticos y colores de alto contraste\n\nInicio\nExplorar\nPerfil\nConfig\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-04-D.webm",
      "executedAt": "2026-10-09T14:20:47.662Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-04-D.json"
    },
    {
      "id": "ROUTE-05-D",
      "title": "Ruta /missions · escritorio",
      "route": "/missions",
      "resolvedRoute": "/missions",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/campaigns/proposals/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/proposals/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-05-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nMisiones y campañas\n\nParticipa en campañas activas y completa misiones para sumar puntos e impacto ambiental.\n\nCrear campaña de clan\nTodas las campañas\nTodas\nEn promoción\nActivas\nFinalizadas\nTodas\nGlobales\nPrivadas\n\nGLOBAL\n\nReto del termo QA\nEn promoción\n\nCampaña sintética para verificar integración\n\n10 oct – 17 oct\nProgreso de misiones\n0/1\nx\n\nGLOBAL\n\nSemana sustentable QA\nActiva\n\nCampaña sintética para verificar integración\n\n8 oct – 16 oct\nProgreso de misiones\n0/2\nx\nMis propuestas\nProponer campaña\nTodas\nPendientes\nAprobadas\nRechazadas\nAún no has propuesto campañas\n\nUsa \"Proponer campaña\" para enviar una idea a los administradores.\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-05-D.webm",
      "executedAt": "2026-10-09T14:20:53.137Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-05-D.json"
    },
    {
      "id": "ROUTE-06-D",
      "title": "Ruta /store · escritorio",
      "route": "/store",
      "resolvedRoute": "/store",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-06-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nTienda de canjeables\n\nCanjea tus puntos acumulados por marcos de avatar, fondos de perfil y cosméticos.\n\nSALDO DE PUNTOS\n\nPuntos disponibles para canjear\n\nLos puntos se descontarán de tu saldo disponible al confirmar un canje.\n\n10 pts\nTodos\nMarcos\nFondos\nOtros\nMarco\nMarco QA\n\nSin descripción disponible.\n\nCanjear • 5 pts\nFondo\nFondo Ecologico\n\nCosmético de fondo verde.\n\nCanjear • 10 pts\nFondo\nFondo QA\n\nSin descripción disponible.\n\nCanjear • 100 pts\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-06-D.webm",
      "executedAt": "2026-10-09T14:20:59.449Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-06-D.json"
    },
    {
      "id": "ROUTE-07-D",
      "title": "Ruta /shop · escritorio",
      "route": "/shop",
      "resolvedRoute": "/shop",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-07-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nTienda de canjeables\n\nCanjea tus puntos acumulados por marcos de avatar, fondos de perfil y cosméticos.\n\nSALDO DE PUNTOS\n\nPuntos disponibles para canjear\n\nLos puntos se descontarán de tu saldo disponible al confirmar un canje.\n\n10 pts\nTodos\nMarcos\nFondos\nOtros\nMarco\nMarco QA\n\nSin descripción disponible.\n\nCanjear • 5 pts\nFondo\nFondo Ecologico\n\nCosmético de fondo verde.\n\nCanjear • 10 pts\nFondo\nFondo QA\n\nSin descripción disponible.\n\nCanjear • 100 pts\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-07-D.webm",
      "executedAt": "2026-10-09T14:21:05.640Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-07-D.json"
    },
    {
      "id": "ROUTE-08-D",
      "title": "Ruta /feed · escritorio",
      "route": "/feed",
      "resolvedRoute": "/feed",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-08-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nMuro Social\n\nLo que la comunidad GreenITESO está logrando en este momento.\n\nAñadir imagen\nPublicar\nA\nAna QA\nhace 1 minuto\n(Editado)\nEvidencia Compartida\n\nActualización QA: termo reutilizable. Datos sintéticos.\n\nA\nAna QA\nhace 1 minuto\n(Editado)\nEvidencia Compartida\n\nNueva acción registrada: Llegué en bicicleta (+10 puntos).\n\nD\nDiego QA\nhace 4 minutos\n(Editado)\nEvidencia Compartida\n\nHoy probamos una ruta segura para llegar al campus. Publicación sintética de QA.\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-08-D.webm",
      "executedAt": "2026-10-09T14:21:12.718Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-08-D.json"
    },
    {
      "id": "ROUTE-09-D",
      "title": "Ruta /notifications · escritorio",
      "route": "/notifications",
      "resolvedRoute": "/notifications",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [],
      "overflow": false,
      "screenshot": "evidence/ROUTE-09-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nNotificaciones\n\nTienes 3 notificaciones sin leer.\n\nMarcar todo\n\nNueva misión disponible\n\nSe agregó \"Rechaza un popote o bolsa de plástico\" a Semana sin plásticos.\n\nhace 20 minutos\n\nMarcar como leída\n\nEvidencia aprobada\n\nTu registro de reciclaje fue validado por un administrador.\n\nhace 5 horas\n\nMarcar como leída\n\n¡Nueva insignia desbloqueada!\n\nObtuviste la insignia \"Guardián del agua\".\n\nayer\n\nMarcar como leída\n\nNuevo seguidor\n\ncarlos.iteso ahora sigue tu actividad.\n\nanteayer\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-09-D.webm",
      "executedAt": "2026-10-09T14:21:19.081Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-09-D.json"
    },
    {
      "id": "ROUTE-10-D",
      "title": "Ruta /actions · escritorio",
      "route": "/actions",
      "resolvedRoute": "/actions",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/actions/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/actions/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-10-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\n\nEQUIPO 1\n\nCatálogo de acciones\n\nAcciones sustentables disponibles y su valor en puntos.\n\nMOVILIDAD Y CONSUMO\n\nLlegué en bicicleta\n10 pts\n\nEscenario de prueba local, sin impacto ambiental real medido.\n\nSIN EVIDENCIA\nLímite 3/día\n\n1.25 kg\n\nCO₂\n\nMOVILIDAD Y CONSUMO\n\nParticipé en limpieza\n20 pts\n\nEscenario de prueba local, sin impacto ambiental real medido.\n\nFOTO\nLímite 3/día\n\n0.1 kg\n\nCO₂\n\nMOVILIDAD Y CONSUMO\n\nRellené mi termo\n5 pts\n\nEscenario de prueba local, sin impacto ambiental real medido.\n\nSIN EVIDENCIA\nLímite 3/día\n\n0.05 kg\n\nCO₂\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-10-D.webm",
      "executedAt": "2026-10-09T14:21:24.770Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-10-D.json"
    },
    {
      "id": "ROUTE-11-D",
      "title": "Ruta /actions/register · escritorio",
      "route": "/actions/register",
      "resolvedRoute": "/actions/register",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/actions/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/actions/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-11-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\n\nREGISTRO\n\nRegistrar acción\n\nElige una acción del catálogo y, si aplica, adjunta la evidencia fotográfica.\n\nAcción\nSelecciona una acción\nLlegué en bicicleta · 10 pts\nParticipé en limpieza · 20 pts\nRellené mi termo · 5 pts\nEvidencia fotográfica\n\nJPG, PNG o WEBP. Máximo 5.0 MB. Opcional si la acción no pide evidencia.\n\nRegistrar\nLimpiar\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-11-D.webm",
      "executedAt": "2026-10-09T14:21:30.517Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-11-D.json"
    },
    {
      "id": "ROUTE-12-D",
      "title": "Ruta /audit · escritorio",
      "route": "/audit",
      "resolvedRoute": "/audit",
      "role": "admin",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/action-logs/",
          "status": 405
        },
        {
          "method": "GET",
          "path": "/api/v1/action-logs/",
          "status": 405
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-12-D.png",
      "text": "GreenITESO\n3\nLQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\n\nAUDITORÍA\n\nPanel de revisión\n\nEvidencias fotográficas en PENDING_AUDIT. Aprobar o rechazar no calcula puntos en el cliente.\n\nEvidencias\nPropuestas de campañas\nNo se pudo cargar la cola de auditoría\n\nNo fue posible obtener las evidencias pendientes. Intenta de nuevo cuando el servicio esté disponible.\n\nFailed to load audit queue (405)\n\nReintentar\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-12-D.webm",
      "executedAt": "2026-10-09T14:21:36.110Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-12-D.json"
    },
    {
      "id": "ROUTE-13-D",
      "title": "Ruta /clans · escritorio",
      "route": "/clans",
      "resolvedRoute": "/clans",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-13-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\n\nCOMUNIDAD\n\nClanes\n\nÚnete a un clan o crea el tuyo para sumar puntos en equipo.\n\nTengo una invitación\nCrear clan\nMis clanes\n\nINSTITUCIONAL\n\nIngeniería QA\n\nCLAN ACTIVO\n\nEcoequipo QA\n\nExplorar clanes\n\nPRIVADO\n\nEcoequipo QA\nPública\n\nClan privado de prueba\n\n10 puntos\n\nINSTITUCIONAL\n\nIngeniería QA\n\nDatos sintéticos para demostración\n\n10 puntos\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-13-D.webm",
      "executedAt": "2026-10-09T14:21:41.545Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-13-D.json"
    },
    {
      "id": "ROUTE-14-D",
      "title": "Ruta /clans/:clanId · escritorio",
      "route": "/clans/:clanId",
      "resolvedRoute": "/clans/8707d413-083f-454d-aae1-030b3ec80042",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/clans/8707d413-083f-454d-aae1-030b3ec80042/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/8707d413-083f-454d-aae1-030b3ec80042/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-14-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nVolver a clanes\nEQ\nPrivado\nPública\nEcoequipo QA\n\nClan privado de prueba\n\nPuntos\n10 puntos\nMiembros\n1 miembro\nCreado\nDesde octubre de 2026\nEs tu clan activo\nCopiar enlace de invitación\nTransferir liderazgo\nDisolver clan\n\nPara transferir el liderazgo, el clan necesita al menos otro miembro.\n\nMiembros (1)\nAQ\n\nAna QA(tú)\n\nDesde octubre de 2026\n\nLíder\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-14-D.webm",
      "executedAt": "2026-10-09T14:21:46.962Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-14-D.json"
    },
    {
      "id": "ROUTE-15-D",
      "title": "Ruta /leaderboard · escritorio",
      "route": "/leaderboard",
      "resolvedRoute": "/leaderboard",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/rankings/users/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/rankings/users/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-15-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\n\nRANKINGS\n\nTablas de clasificación\nClasificación Global\nRanking institucional\nClanes privados\nClasificación global\nPOS.\tPARTICIPANTE\tPUNTOS\n1\tDiego QA\t0\n1\tLaura QA\t0\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-15-D.webm",
      "executedAt": "2026-10-09T14:21:52.561Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-15-D.json"
    },
    {
      "id": "ROUTE-16-D",
      "title": "Ruta /profile · escritorio",
      "route": "/profile",
      "resolvedRoute": "/profile",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-16-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\nVolver al inicio\nPERFIL ECOLÓGICO\nAQ\nAna QA\nEstudiante\n\nstudent@qa.example.test\n\nEstudiante sintética para QA local\n\nPerfil Privado\n\nConfiguración privada activa: tus métricas solo son visibles por ti.\n\nProgreso y Nivel\n\n10\n\nPUNTOS TOTALES\n\n10\n\nDISPONIBLES\n\n0\n\nDÍAS DE RACHA\n\n—\n\nSIN NIVEL\n\nImpacto Ambiental Acumulado\nCalculado a partir de tus acciones ecológicas aprobadas\n\nCO₂ Evitado\n\n1.25 kg\n\nAgua Ahorrada\n\n0 L\n\nPlástico Reciclado\n\n0 kg\n\nMis Clanes\nEquipos y colectivos a los que perteneces\nClan Institucional\nIngeniería QA\n\nAsignado automáticamente por carrera o departamento ITESO.\n\nClan Privado Activo\nEcoequipo QA\n\nClan privado seleccionado actualmente para sumar puntos en equipo.\n\nInsignias y Reconocimientos\nLogros otorgados por tu constancia y compromiso ecológico\nAún no tienes insignias\n\nParticipa en acciones sustentables, mantén tu racha y únete a campañas para desbloquear tus primeras insignias.\n\nHistorial de Campañas\nCampañas sostenibles en las que participaste y han concluido\nSin campañas finalizadas\n\nCuando concluyan las campañas ecológicas en las que te inscribas, aparecerán listadas en este historial de participación.\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-16-D.webm",
      "executedAt": "2026-10-09T14:21:58.090Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-16-D.json"
    },
    {
      "id": "ROUTE-17-D",
      "title": "Ruta * · escritorio",
      "route": "*",
      "resolvedRoute": "/ruta-inexistente",
      "role": "student",
      "layer": "Render real 1600×900",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-17-D.png",
      "text": "GreenITESO\n3\nAQ\nInicio\nMisiones\nTienda\nFeed\nNotificaciones\nMi perfil\nCatálogo de acciones\nClanes\nLeaderboard\nAuditoría\n\nDashboard Impact\n\nMis campañas\nTodas\nEn promoción\nActivas\nFinalizadas\nTodas\nGlobales\nPrivadas\n\nGLOBAL\n\nReto del termo QA\nEn promoción\n\nCampaña sintética para verificar integración\n\n10 oct – 17 oct\nProgreso de misiones\n0/1\nx\n\nGLOBAL\n\nSemana sustentable QA\nActiva\n\nCampaña sintética para verificar integración\n\n8 oct – 16 oct\nProgreso de misiones\n0/2\nx\nMisiones activas\nSemana sustentable QA\n\nLlegué en bicicleta\n\nMeta: 2 veces\n\nx\n+10 pts\n1/2\n\nParticipé en limpieza\n\nMeta: 1 veces\n\nx\n+20 pts\n0/1\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible",
      "video": "scenarios/ROUTE-17-D.webm",
      "executedAt": "2026-10-09T14:22:05.273Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-17-D.json"
    },
    {
      "id": "ROUTE-01-M",
      "title": "Ruta /login · móvil",
      "route": "/login",
      "resolvedRoute": "/login",
      "role": "ANONYMOUS",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [],
      "overflow": false,
      "screenshot": "evidence/ROUTE-01-M.png",
      "text": "GREENITESO\n\nInicia sesión\n\nAccede con tu cuenta institucional para registrar y consultar tu impacto ambiental.\n\nIniciar sesión con @iteso.mx\n\nUsa exclusivamente tu cuenta institucional @iteso.mx.",
      "video": null,
      "executedAt": "2026-10-09T14:22:07.818Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-01-M.json"
    },
    {
      "id": "ROUTE-02-M",
      "title": "Ruta / · móvil",
      "route": "/",
      "resolvedRoute": "/",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-02-M.png",
      "text": "3\nAQ\n\nDashboard Impact\n\nMis campañas\nTodas\nEn promoción\nActivas\nFinalizadas\nTodas\nGlobales\nPrivadas\n\nGLOBAL\n\nReto del termo QA\nEn promoción\n\nCampaña sintética para verificar integración\n\n10 oct – 17 oct\nProgreso de misiones\n0/1\nx\n\nGLOBAL\n\nSemana sustentable QA\nActiva\n\nCampaña sintética para verificar integración\n\n8 oct – 16 oct\nProgreso de misiones\n0/2\nx\nMisiones activas\nSemana sustentable QA\n\nLlegué en bicicleta\n\nMeta: 2 veces\n\nx\n+10 pts\n1/2\n\nParticipé en limpieza\n\nMeta: 1 veces\n\nx\n+20 pts\n0/1\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:09.902Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-02-M.json"
    },
    {
      "id": "ROUTE-03-M",
      "title": "Ruta /home · móvil",
      "route": "/home",
      "resolvedRoute": "/home",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [],
      "overflow": false,
      "screenshot": "evidence/ROUTE-03-M.png",
      "text": "3\nAQ\nGreenITESO\n\nEn Desarrollo\n\nPlataforma integral de sostenibilidad y gestión ambiental para la comunidad ITESO. Medimos, monitoreamos y maximizamos el impacto positivo en nuestro planeta.\n\nVer Dashboard\nIniciar sesión\nMi Perfil\nPróximamente\nDashboard\n\nVisualiza tu impacto ambiental en tiempo real\n\nMisiones\n\nParticipa en retos sostenibles y gana puntos\n\nLeaderboard\n\nCompite y colabora con tu comunidad\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:14.471Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-03-M.json"
    },
    {
      "id": "ROUTE-04-M",
      "title": "Ruta /design-system · móvil",
      "route": "/design-system",
      "resolvedRoute": "/design-system",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [],
      "overflow": false,
      "screenshot": "evidence/ROUTE-04-M.png",
      "text": "3\nAQ\nGreenITESO\n\nSistema de Diseño\n\nTipografía\n\nDisplay / Hero\n\nPlus Jakarta Sans - ExtraBold (800)\n\nTítulo H1\n\nPlus Jakarta Sans - Bold (700)\n\nTítulo H2\n\nPlus Jakarta Sans - Bold (700)\n\nSubtítulo H3\n\nPlus Jakarta Sans - SemiBold (600)\n\nCuerpo Principal Regular\n\nPlus Jakarta Sans - Regular (400)\n\nCuerpo Secundario\n\nPlus Jakarta Sans - Regular (400)\n\nPaleta Primaria - Verde Ecológico\n\n-50\n\n-100\n\n-200\n\n-300\n\n-400\n\n-500\n\n-600\n\n-700\n\n-800\n\n-900\n\nPaleta Secundaria - Gris Salvia\n\n-50\n\n-100\n\n-200\n\n-300\n\n-400\n\n-500\n\n-600\n\n-700\n\n-800\n\n-900\n\nEstados Semánticos\n\nAprobado / Exitoso\n\nRegistro aprobado, misión completada\n\nPendiente de Auditoría\n\nEvidencia en revisión\n\nRechazado / Alerta\n\nEvidencia rechazada, error\n\nInformación / Neutral\n\nAvisos generales, tutoriales\n\nIdentidad Visual de Impacto\n\nCO₂ Evitado\n\n128 kg\n\nAgua Ahorrada\n\n2,450 L\n\nPlástico Reciclado\n\n45 kg\n\nBotones\n\nPrimario - Estados\n\nNormal\nHover\nActive\nDisabled\n\nSecundario / Outlined\n\nNormal\nHover\nDisabled\nFormularios e Inputs\nNombre\nEmail\nMensaje\nTarjetas (Cards)\nMisión Principal\n\nReduce tu huella de carbono en esta semana\n\nVer Detalles\nTu Impacto\n\n2,450 L\n\nAgua ahorrada este mes\n\nBadges y Tags\nAPROBADO\nPENDIENTE\nRECHAZADO\nINFORMACIÓN\n\nBadges con estados semánticos y colores de alto contraste\n\nInicio\nExplorar\nPerfil\nConfig\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:17.293Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-04-M.json"
    },
    {
      "id": "ROUTE-05-M",
      "title": "Ruta /missions · móvil",
      "route": "/missions",
      "resolvedRoute": "/missions",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/campaigns/proposals/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/proposals/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-05-M.png",
      "text": "3\nAQ\nMisiones y campañas\n\nParticipa en campañas activas y completa misiones para sumar puntos e impacto ambiental.\n\nCrear campaña de clan\nTodas las campañas\nTodas\nEn promoción\nActivas\nFinalizadas\nTodas\nGlobales\nPrivadas\n\nGLOBAL\n\nReto del termo QA\nEn promoción\n\nCampaña sintética para verificar integración\n\n10 oct – 17 oct\nProgreso de misiones\n0/1\nx\n\nGLOBAL\n\nSemana sustentable QA\nActiva\n\nCampaña sintética para verificar integración\n\n8 oct – 16 oct\nProgreso de misiones\n0/2\nx\nMis propuestas\nProponer campaña\nTodas\nPendientes\nAprobadas\nRechazadas\nAún no has propuesto campañas\n\nUsa \"Proponer campaña\" para enviar una idea a los administradores.\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:20.559Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-05-M.json"
    },
    {
      "id": "ROUTE-06-M",
      "title": "Ruta /store · móvil",
      "route": "/store",
      "resolvedRoute": "/store",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-06-M.png",
      "text": "3\nAQ\nTienda de canjeables\n\nCanjea tus puntos acumulados por marcos de avatar, fondos de perfil y cosméticos.\n\nSALDO DE PUNTOS\n\nPuntos disponibles para canjear\n\nLos puntos se descontarán de tu saldo disponible al confirmar un canje.\n\n5 pts\nTodos\nMarcos\nFondos\nOtros\nMarco\nObtenido\nMarco QA\n\nSin descripción disponible.\n\nCanjeado\nFondo\nFondo Ecologico\n\nCosmético de fondo verde.\n\nCanjear • 10 pts\nFondo\nFondo QA\n\nSin descripción disponible.\n\nCanjear • 100 pts\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:23.365Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-06-M.json"
    },
    {
      "id": "ROUTE-07-M",
      "title": "Ruta /shop · móvil",
      "route": "/shop",
      "resolvedRoute": "/shop",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/my-inventory/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/exchangeables/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-07-M.png",
      "text": "3\nAQ\nTienda de canjeables\n\nCanjea tus puntos acumulados por marcos de avatar, fondos de perfil y cosméticos.\n\nSALDO DE PUNTOS\n\nPuntos disponibles para canjear\n\nLos puntos se descontarán de tu saldo disponible al confirmar un canje.\n\n5 pts\nTodos\nMarcos\nFondos\nOtros\nMarco\nObtenido\nMarco QA\n\nSin descripción disponible.\n\nCanjeado\nFondo\nFondo Ecologico\n\nCosmético de fondo verde.\n\nCanjear • 10 pts\nFondo\nFondo QA\n\nSin descripción disponible.\n\nCanjear • 100 pts\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:28.311Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-07-M.json"
    },
    {
      "id": "ROUTE-08-M",
      "title": "Ruta /feed · móvil",
      "route": "/feed",
      "resolvedRoute": "/feed",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/feed/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-08-M.png",
      "text": "3\nAQ\nMuro Social\n\nLo que la comunidad GreenITESO está logrando en este momento.\n\nPublicar\nA\nAna QA\nhace 2 minutos\n(Editado)\n\nActualización QA: termo reutilizable. Datos sintéticos.\n\nA\nAna QA\nhace 3 minutos\n(Editado)\n\nNueva acción registrada: Llegué en bicicleta (+10 puntos).\n\nD\nDiego QA\nhace 5 minutos\n(Editado)\n\nHoy probamos una ruta segura para llegar al campus. Publicación sintética de QA.\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:30.422Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-08-M.json"
    },
    {
      "id": "ROUTE-09-M",
      "title": "Ruta /notifications · móvil",
      "route": "/notifications",
      "resolvedRoute": "/notifications",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [],
      "overflow": false,
      "screenshot": "evidence/ROUTE-09-M.png",
      "text": "3\nAQ\nNotificaciones\n\nTienes 3 notificaciones sin leer.\n\nMarcar todo\n\nNueva misión disponible\n\nSe agregó \"Rechaza un popote o bolsa de plástico\" a Semana sin plásticos.\n\nhace 20 minutos\n\nMarcar como leída\n\nEvidencia aprobada\n\nTu registro de reciclaje fue validado por un administrador.\n\nhace 5 horas\n\nMarcar como leída\n\n¡Nueva insignia desbloqueada!\n\nObtuviste la insignia \"Guardián del agua\".\n\nayer\n\nMarcar como leída\n\nNuevo seguidor\n\ncarlos.iteso ahora sigue tu actividad.\n\nanteayer\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:33.157Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-09-M.json"
    },
    {
      "id": "ROUTE-10-M",
      "title": "Ruta /actions · móvil",
      "route": "/actions",
      "resolvedRoute": "/actions",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/actions/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/actions/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-10-M.png",
      "text": "3\nAQ\n\nEQUIPO 1\n\nCatálogo de acciones\n\nAcciones sustentables disponibles y su valor en puntos.\n\nMOVILIDAD Y CONSUMO\n\nLlegué en bicicleta\n10 pts\n\nEscenario de prueba local, sin impacto ambiental real medido.\n\nSIN EVIDENCIA\nLímite 3/día\n\n1.25 kg\n\nCO₂\n\nMOVILIDAD Y CONSUMO\n\nParticipé en limpieza\n20 pts\n\nEscenario de prueba local, sin impacto ambiental real medido.\n\nFOTO\nLímite 3/día\n\n0.1 kg\n\nCO₂\n\nMOVILIDAD Y CONSUMO\n\nRellené mi termo\n5 pts\n\nEscenario de prueba local, sin impacto ambiental real medido.\n\nSIN EVIDENCIA\nLímite 3/día\n\n0.05 kg\n\nCO₂\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:35.942Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-10-M.json"
    },
    {
      "id": "ROUTE-11-M",
      "title": "Ruta /actions/register · móvil",
      "route": "/actions/register",
      "resolvedRoute": "/actions/register",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/actions/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/actions/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-11-M.png",
      "text": "3\nAQ\n\nREGISTRO\n\nRegistrar acción\n\nElige una acción del catálogo y, si aplica, adjunta la evidencia fotográfica.\n\nAcción\nSelecciona una acción\nLlegué en bicicleta · 10 pts\nParticipé en limpieza · 20 pts\nRellené mi termo · 5 pts\nEvidencia fotográfica\n\nJPG, PNG o WEBP. Máximo 5.0 MB. Opcional si la acción no pide evidencia.\n\nRegistrar\nLimpiar\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:39.304Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-11-M.json"
    },
    {
      "id": "ROUTE-12-M",
      "title": "Ruta /audit · móvil",
      "route": "/audit",
      "resolvedRoute": "/audit",
      "role": "admin",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/action-logs/",
          "status": 405
        },
        {
          "method": "GET",
          "path": "/api/v1/action-logs/",
          "status": 405
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-12-M.png",
      "text": "3\nLQ\n\nAUDITORÍA\n\nPanel de revisión\n\nEvidencias fotográficas en PENDING_AUDIT. Aprobar o rechazar no calcula puntos en el cliente.\n\nEvidencias\nPropuestas de campañas\nNo se pudo cargar la cola de auditoría\n\nNo fue posible obtener las evidencias pendientes. Intenta de nuevo cuando el servicio esté disponible.\n\nFailed to load audit queue (405)\n\nReintentar\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:41.451Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-12-M.json"
    },
    {
      "id": "ROUTE-13-M",
      "title": "Ruta /clans · móvil",
      "route": "/clans",
      "resolvedRoute": "/clans",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-13-M.png",
      "text": "3\nAQ\n\nCOMUNIDAD\n\nClanes\n\nÚnete a un clan o crea el tuyo para sumar puntos en equipo.\n\nTengo una invitación\nCrear clan\nMis clanes\n\nINSTITUCIONAL\n\nIngeniería QA\n\nCLAN ACTIVO\n\nEcoequipo QA\n\nExplorar clanes\n\nPRIVADO\n\nEcoequipo QA\nPública\n\nClan privado de prueba\n\n30 puntos\n\nINSTITUCIONAL\n\nIngeniería QA\n\nDatos sintéticos para demostración\n\n30 puntos\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:43.893Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-13-M.json"
    },
    {
      "id": "ROUTE-14-M",
      "title": "Ruta /clans/:clanId · móvil",
      "route": "/clans/:clanId",
      "resolvedRoute": "/clans/8707d413-083f-454d-aae1-030b3ec80042",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/clans/8707d413-083f-454d-aae1-030b3ec80042/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/clans/8707d413-083f-454d-aae1-030b3ec80042/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-14-M.png",
      "text": "3\nAQ\nVolver a clanes\nEQ\nPrivado\nPública\nEcoequipo QA\n\nClan privado de prueba\n\nPuntos\n30 puntos\nMiembros\n1 miembro\nCreado\nDesde octubre de 2026\nEs tu clan activo\nCopiar enlace de invitación\nTransferir liderazgo\nDisolver clan\n\nPara transferir el liderazgo, el clan necesita al menos otro miembro.\n\nMiembros (1)\nAQ\n\nAna QA(tú)\n\nDesde octubre de 2026\n\nLíder\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:47.255Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-14-M.json"
    },
    {
      "id": "ROUTE-15-M",
      "title": "Ruta /leaderboard · móvil",
      "route": "/leaderboard",
      "resolvedRoute": "/leaderboard",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/rankings/users/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/rankings/users/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-15-M.png",
      "text": "3\nAQ\n\nRANKINGS\n\nTablas de clasificación\nClasificación Global\nRanking institucional\nClanes privados\nClasificación global\nPOS.\tPARTICIPANTE\tPUNTOS\n1\tDiego QA\t0\n1\tLaura QA\t0\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:50.012Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-15-M.json"
    },
    {
      "id": "ROUTE-16-M",
      "title": "Ruta /profile · móvil",
      "route": "/profile",
      "resolvedRoute": "/profile",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/profile/me/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-16-M.png",
      "text": "3\nAQ\nVolver al inicio\nPERFIL ECOLÓGICO\nAQ\nAna QA\nEstudiante\n\nstudent@qa.example.test\n\nEstudiante sintética para QA local\n\nPerfil Privado\n\nConfiguración privada activa: tus métricas solo son visibles por ti.\n\nProgreso y Nivel\n\n30\n\nPUNTOS TOTALES\n\n25\n\nDISPONIBLES\n\n0\n\nDÍAS DE RACHA\n\n—\n\nSIN NIVEL\n\nImpacto Ambiental Acumulado\nCalculado a partir de tus acciones ecológicas aprobadas\n\nCO₂ Evitado\n\n3.75 kg\n\nAgua Ahorrada\n\n0 L\n\nPlástico Reciclado\n\n0 kg\n\nMis Clanes\nEquipos y colectivos a los que perteneces\nClan Institucional\nIngeniería QA\n\nAsignado automáticamente por carrera o departamento ITESO.\n\nClan Privado Activo\nEcoequipo QA\n\nClan privado seleccionado actualmente para sumar puntos en equipo.\n\nInsignias y Reconocimientos\nLogros otorgados por tu constancia y compromiso ecológico\nAún no tienes insignias\n\nParticipa en acciones sustentables, mantén tu racha y únete a campañas para desbloquear tus primeras insignias.\n\nHistorial de Campañas\nCampañas sostenibles en las que participaste y han concluido\nSin campañas finalizadas\n\nCuando concluyan las campañas ecológicas en las que te inscribas, aparecerán listadas en este historial de participación.\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:52.887Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-16-M.json"
    },
    {
      "id": "ROUTE-17-M",
      "title": "Ruta * · móvil",
      "route": "*",
      "resolvedRoute": "/ruta-inexistente",
      "role": "student",
      "layer": "Render real 390×844",
      "status": "PASS",
      "expected": "Render sin excepción ni desborde horizontal; no equivale a validar todos los controles",
      "actual": "Texto visible; errores JS 0; desborde false",
      "pageErrors": [],
      "network": [
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        },
        {
          "method": "GET",
          "path": "/api/v1/campaigns/",
          "status": 200
        }
      ],
      "overflow": false,
      "screenshot": "evidence/ROUTE-17-M.png",
      "text": "3\nAQ\n\nDashboard Impact\n\nMis campañas\nTodas\nEn promoción\nActivas\nFinalizadas\nTodas\nGlobales\nPrivadas\n\nGLOBAL\n\nReto del termo QA\nEn promoción\n\nCampaña sintética para verificar integración\n\n10 oct – 17 oct\nProgreso de misiones\n0/1\nx\n\nGLOBAL\n\nSemana sustentable QA\nActiva\n\nCampaña sintética para verificar integración\n\n8 oct – 16 oct\nProgreso de misiones\n1/2\nx\nMisiones activas\nSemana sustentable QA\n\nLlegué en bicicleta\n\nMeta: 2 veces\n\nx\n+10 pts\n2/2\n\nParticipé en limpieza\n\nMeta: 1 veces\n\nx\n+20 pts\n0/1\n\nGreenITESO © 2026 | Desarrollando un futuro sostenible\n\nInicio\nMisiones\nTienda\nFeed\n3\nNotificaciones\nMás",
      "video": null,
      "executedAt": "2026-10-09T14:22:58.463Z",
      "kind": "Render de página",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/ROUTE-17-M.json"
    },
    {
      "id": "GUARD-02",
      "title": "Sin sesión: /",
      "route": "/",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:00.363Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-02.json"
    },
    {
      "id": "GUARD-03",
      "title": "Sin sesión: /home",
      "route": "/home",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:02.332Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-03.json"
    },
    {
      "id": "GUARD-04",
      "title": "Sin sesión: /design-system",
      "route": "/design-system",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:03.210Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-04.json"
    },
    {
      "id": "GUARD-05",
      "title": "Sin sesión: /missions",
      "route": "/missions",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:04.150Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-05.json"
    },
    {
      "id": "GUARD-06",
      "title": "Sin sesión: /store",
      "route": "/store",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:05.949Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-06.json"
    },
    {
      "id": "GUARD-07",
      "title": "Sin sesión: /shop",
      "route": "/shop",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:08.328Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-07.json"
    },
    {
      "id": "GUARD-08",
      "title": "Sin sesión: /feed",
      "route": "/feed",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:10.015Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-08.json"
    },
    {
      "id": "GUARD-09",
      "title": "Sin sesión: /notifications",
      "route": "/notifications",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:10.953Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-09.json"
    },
    {
      "id": "GUARD-10",
      "title": "Sin sesión: /actions",
      "route": "/actions",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:13.232Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-10.json"
    },
    {
      "id": "GUARD-11",
      "title": "Sin sesión: /actions/register",
      "route": "/actions/register",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:15.064Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-11.json"
    },
    {
      "id": "GUARD-12",
      "title": "Sin sesión: /audit",
      "route": "/audit",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:16.314Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-12.json"
    },
    {
      "id": "GUARD-13",
      "title": "Sin sesión: /clans",
      "route": "/clans",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:18.460Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-13.json"
    },
    {
      "id": "GUARD-14",
      "title": "Sin sesión: /clans/:clanId",
      "route": "/clans/:clanId",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:21.206Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-14.json"
    },
    {
      "id": "GUARD-15",
      "title": "Sin sesión: /leaderboard",
      "route": "/leaderboard",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:23.158Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-15.json"
    },
    {
      "id": "GUARD-16",
      "title": "Sin sesión: /profile",
      "route": "/profile",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:24.280Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-16.json"
    },
    {
      "id": "GUARD-17",
      "title": "Sin sesión: *",
      "route": "*",
      "role": "ANONYMOUS",
      "layer": "Guard de autenticación",
      "status": "PASS",
      "expected": "Redirección a /login",
      "actual": "http://localhost:3001/login",
      "executedAt": "2026-10-09T14:23:25.345Z",
      "kind": "Acceso sin sesión",
      "provenance": "Chromium · no demuestra funcionamiento de todos los controles",
      "evidence": "evidence/GUARD-17.json"
    },
    {
      "id": "FE-TEST-001",
      "title": "should render sustainable action cards from the catalog endpoint",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeVisible\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('heading', { name: 'Catálogo de acciones' })\nExpected: visible\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeVisible\" getByRole('heading', { name: 'Catálogo de acciones' }) with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for getByRole('heading', { name: 'Catálogo de acciones' })\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/action-catalog.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-002",
      "title": "should show an error when the catalog endpoint fails",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeVisible\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('heading', { name: 'No se pudo cargar el catálogo' })\nExpected: visible\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeVisible\" getByRole('heading', { name: 'No se pudo cargar el catálogo' }) with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for getByRole('heading', { name: 'No se pudo cargar el catálogo' })\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/action-catalog.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-003",
      "title": "should show an error when the catalog payload is malformed",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeVisible\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('heading', { name: 'No se pudo cargar el catálogo' })\nExpected: visible\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeVisible\" getByRole('heading', { name: 'No se pudo cargar el catálogo' }) with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for getByRole('heading', { name: 'No se pudo cargar el catálogo' })\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/action-catalog.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-004",
      "title": "should load catalog cards after retry reaches a valid response",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeVisible\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('heading', { name: 'No se pudo cargar el catálogo' })\nExpected: visible\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeVisible\" getByRole('heading', { name: 'No se pudo cargar el catálogo' }) with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for getByRole('heading', { name: 'No se pudo cargar el catálogo' })\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/action-catalog.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-005",
      "title": "should require an action before submitting the registration form",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeVisible\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('heading', { name: 'Registrar acción' })\nExpected: visible\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeVisible\" getByRole('heading', { name: 'Registrar acción' }) with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for getByRole('heading', { name: 'Registrar acción' })\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/action-log-form.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-006",
      "title": "should reject photographic evidence larger than 5MB",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeAttached\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('option', { name: /Llegar en bicicleta/ })\nExpected: attached\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeAttached\" getByRole('option', { name: /Llegar en bicicleta/ }) with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for getByRole('option', { name: /Llegar en bicicleta/ })\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/action-log-form.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-007",
      "title": "should require a photo when the selected action uses PHOTO validation",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeAttached\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('option', { name: /Usar termo reutilizable/ })\nExpected: attached\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeAttached\" getByRole('option', { name: /Usar termo reutilizable/ }) with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for getByRole('option', { name: /Usar termo reutilizable/ })\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/action-log-form.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-008",
      "title": "should show an error when the catalog GET fails",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeVisible\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('heading', { name: 'No se pudo cargar el catálogo' })\nExpected: visible\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeVisible\" getByRole('heading', { name: 'No se pudo cargar el catálogo' }) with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for getByRole('heading', { name: 'No se pudo cargar el catálogo' })\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/action-log-form.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-009",
      "title": "should list pending evidence with approve and reject controls",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/audit-review.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-010",
      "title": "should show an error when the audit queue GET fails",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/audit-review.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-011",
      "title": "should require a rejection reason before rejecting evidence",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/audit-review.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-012",
      "title": "should remove an item after a successful approve request",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/audit-review.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-013",
      "title": "should switch to the campaign proposals tab and reflect it in the URL",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/audit-review.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-014",
      "title": "should open the proposals tab directly from ?tab=propuestas",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/audit-review.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-015",
      "title": "should list campaigns and open the detail of one",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-016",
      "title": "should filter campaigns by status and scope",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-017",
      "title": "should join a campaign in promotion",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-018",
      "title": "should show the progress of their missions in the dashboard",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-019",
      "title": "should propose a campaign and list it as pending",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-020",
      "title": "should create a private campaign for a clan",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-021",
      "title": "should show the backend error when the user does not lead the clan",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-022",
      "title": "should create a global campaign with a mission",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-023",
      "title": "should approve a pending proposal",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-024",
      "title": "should reject a pending proposal with a reason",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-025",
      "title": "should edit a campaign in promotion",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-026",
      "title": "should not offer editing once the campaign left promotion",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-027",
      "title": "should not let an admin join a campaign",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-028",
      "title": "should show an error and recover on retry when campaigns fail to load",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-029",
      "title": "should show the empty state when there are no campaigns",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-030",
      "title": "should show the empty states of the dashboard when the user has no campaigns",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-031",
      "title": "should show an error when the campaign detail fails to load",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-032",
      "title": "should show an error when joining fails",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-033",
      "title": "should validate the required fields of the campaign form",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-034",
      "title": "should show the empty state when there are no pending proposals",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-035",
      "title": "should show an error when proposals fail to load",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-036",
      "title": "should show an error when approving a proposal fails",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/campaigns.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-037",
      "title": "should list clans and filter them with the search box",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-038",
      "title": "should show an empty state when the search has no results",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-039",
      "title": "should show an error with retry when the clan list fails",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-040",
      "title": "should show the clan profile with its members and member actions",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-041",
      "title": "should set the clan as active",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-042",
      "title": "should leave a clan after confirming and go back to the list",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-043",
      "title": "should show leader actions and transfer leadership",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-044",
      "title": "should dissolve the clan after confirming",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-045",
      "title": "should create a clan and open its profile",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-046",
      "title": "should translate a duplicate clan name error",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-047",
      "title": "should require a name before creating a clan",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-048",
      "title": "should join a public clan from its profile",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-049",
      "title": "should request to join an invite-only clan from an invite link",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-050",
      "title": "should reject an invite link without a clan id",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-051",
      "title": "should show the clans link in the sidebar navigation",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-052",
      "title": "should not show the leave notice again after reloading the list",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-053",
      "title": "should send a single create request when submit is double clicked",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-054",
      "title": "should keep the profile when a background refresh fails",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-055",
      "title": "should not reload the clan when copying the invite link",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-056",
      "title": "should keep the confirm dialog open while the request is in flight",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/clans.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-057",
      "title": "should display welcome message",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoContainText\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m failed\n\nLocator: locator('h1')\nExpected substring: \u001b[32m\"GreenITESO\"\u001b[39m\nReceived string:    \u001b[31m\"Inicia sesión\"\u001b[39m\nTimeout: 5000ms\n\nCall log:\n\u001b[2m  - Expect \"toContainText\" locator('h1') with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('h1')\u001b[22m\n\u001b[2m    14 × locator resolved to <h1 class=\"mt-2 text-2xl font-bold text-secondary-500\">Inicia sesión</h1>\u001b[22m\n\u001b[2m       - unexpected value \"Inicia sesión\"\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/example.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-058",
      "title": "should display tech stack",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeVisible\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: locator('text=React 18')\nExpected: visible\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeVisible\" locator('text=React 18') with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for locator('text=React 18')\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · prueba sin sesión para una ruta protegida; requiere actualizar la preparación/expectativas",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/example.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-059",
      "title": "should show the global ranking table by default",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/leaderboard.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-060",
      "title": "should load the institutional clan ranking from GET /rankings/?type=",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/leaderboard.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-061",
      "title": "should load private clan ranking rows using clan_name",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/leaderboard.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-062",
      "title": "should request the next rankings page with limit and offset",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/leaderboard.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-063",
      "title": "should return to the first page when the ranking count no longer fills page two",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/leaderboard.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-064",
      "title": "should show an error when the global ranking GET fails",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/leaderboard.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-065",
      "title": "should render the Microsoft login screen",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/login.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-066",
      "title": "should redirect unauthenticated users to /login",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/profile.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-067",
      "title": "should display full ecological profile with all sections and metrics",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/profile.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-068",
      "title": "should gracefully handle empty states for badges, clans, and campaigns",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/profile.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-069",
      "title": "should show error banner when profile request fails and recover on retry",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/profile.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-070",
      "title": "should navigate back to home using the back button",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/profile.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-071",
      "title": "should navigate to profile from the navbar user dropdown",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/profile.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-072",
      "title": "should redirect unauthenticated users from /audit to /login",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/role-guards.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-073",
      "title": "should block STUDENT from accessing /audit and show 403 Access Denied",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/role-guards.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-074",
      "title": "should block STAFF from accessing /audit and show 403 Access Denied",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/role-guards.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-075",
      "title": "should grant ADMIN access to /audit review panel",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/role-guards.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-076",
      "title": "should allow STUDENT to access standard protected routes like /actions",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/role-guards.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-077",
      "title": "should allow STAFF to access standard protected routes like /actions",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/role-guards.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-078",
      "title": "should not render admin UI controls on Home for STUDENT users",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/role-guards.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-079",
      "title": "should not render admin UI controls on Home for STAFF users",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "PASS",
      "expected": "Aserción del test del repositorio",
      "actual": "expected",
      "provenance": "Mocks de API; no comprueba la integración real",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/role-guards.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "FE-TEST-080",
      "title": "should conditionally render admin UI controls exclusively for ADMIN users",
      "kind": "Repositorio · UI con mocks",
      "layer": "Chromium Playwright",
      "status": "FAIL",
      "expected": "Aserción del test del repositorio",
      "actual": "unexpected · Error: \u001b[2mexpect(\u001b[22m\u001b[31mlocator\u001b[39m\u001b[2m).\u001b[22mtoBeVisible\u001b[2m(\u001b[22m\u001b[2m)\u001b[22m failed\n\nLocator: getByRole('button', { name: 'Panel de Auditoría' })\nExpected: visible\nTimeout: 5000ms\nError: element(s) not found\n\nCall log:\n\u001b[2m  - Expect \"toBeVisible\" getByRole('button', { name: 'Panel de Auditoría' }) with timeout 5000ms\u001b[22m\n\u001b[2m  - waiting for getByRole('button', { name: 'Panel de Auditoría' })\u001b[22m\n",
      "provenance": "Mocks de API; no comprueba la integración real · espera el botón de /home en /; el dashboard sustituyó esa ruta",
      "evidence": "evidence/frontend-tests.json",
      "source": "../../../../private/tmp/greeniteso-qa-latest-20261009/frontend/tests/role-guards.spec.ts",
      "executedAt": "2026-10-09T14:20:23.905Z"
    },
    {
      "id": "BE-SUITE",
      "title": "Suite completa del backend",
      "kind": "Repositorio · backend",
      "status": "PASS",
      "expected": "Suite completa",
      "actual": "697 passed; 2 warnings; 165.01 s",
      "provenance": "Pytest local; no equivale a cobertura de líneas ni prueba en producción",
      "evidence": "logs/backend-tests.log",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "FE-BUILD",
      "title": "Compilación de producción del frontend",
      "kind": "Build",
      "status": "PASS",
      "expected": "Build sin errores",
      "actual": "Exit code 0",
      "evidence": "build-result.json",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-01",
      "title": "Login institucional en la revisión actual",
      "status": "NOT RUN",
      "actual": "El retorno real grabado corresponde a las revisiones anteriores; no se completó una nueva autenticación/MFA en localhost:3001.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-02",
      "title": "Despliegue compartido y migraciones del release",
      "status": "NOT RUN",
      "actual": "No se comprobó un despliegue en GCP/Neon ni se aplicó infraestructura.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-03",
      "title": "Carga real de fotografía a almacenamiento",
      "status": "NOT RUN",
      "actual": "Se usaron claves de evidencia sintéticas; falta comprobar imagen real de extremo a extremo.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-04",
      "title": "Registro por QR dinámico",
      "status": "NOT RUN",
      "actual": "El contrato lo contempla para Beta; no se ejecutó escaneo/token temporal desde una pantalla.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-05",
      "title": "Instalación PWA y funcionamiento del shell offline",
      "status": "NOT RUN",
      "actual": "No se probó instalación iOS/Android ni caché offline.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-06",
      "title": "Safari/Firefox y dispositivos físicos",
      "status": "NOT RUN",
      "actual": "Pruebas en Chromium con viewport de escritorio/móvil; sin navegadores adicionales ni teléfonos físicos.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-07",
      "title": "Rendimiento P95 y carga del sistema",
      "status": "NOT RUN",
      "actual": "No se ejecutó ensayo de carga/P95; las pruebas concurrentes del backend no prueban capacidad del despliegue.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-08",
      "title": "Accesibilidad completa y navegación por teclado",
      "status": "NOT RUN",
      "actual": "Sin auditoría exhaustiva WCAG/lector de pantalla/teclado.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-09",
      "title": "Avatar de clan y expulsión/gestión de solicitudes desde UI",
      "status": "NOT RUN",
      "actual": "Ciclo público probado y aceptación por API; aún faltan controles de solicitudes y expulsión en la pantalla.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-10",
      "title": "Todas las variantes cosméticas/equipamiento de la tienda",
      "status": "NOT RUN",
      "actual": "Se comprobó el canje; no todas las variantes ni el equipamiento visual.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-11",
      "title": "Alta institucional de una cuenta nueva / onboarding Microsoft",
      "status": "NOT RUN",
      "actual": "Fixtures sintéticas tienen onboarding; no se creó una nueva cuenta institucional real.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-12",
      "title": "Bloqueo/desbloqueo y panel completo de usuarios",
      "status": "NOT RUN",
      "actual": "Roles probados por API; administración completa de usuarios no recorrida desde una pantalla.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    },
    {
      "id": "GAP-13",
      "title": "Dashboard de impacto de todo el campus",
      "status": "NOT RUN",
      "actual": "No se ha demostrado un consolidado institucional dinámico desde frontend; PRs de métricas/impacto siguen abiertos.",
      "expected": "Recorrido completo comprobado",
      "kind": "Alcance pendiente",
      "provenance": "Requisito no verificado en esta ejecución",
      "executedAt": "2026-10-09 · ejecución local; hora individual no registrada"
    }
  ],
  "requirements": [
    {
      "id": "FR-AUTH-01",
      "title": "Autenticación Institucional",
      "status": "PARTIAL",
      "evidence_cases": [
        "QA35A",
        "GAP-01",
        "GAP-11"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-AUTH-02",
      "title": "Perfil Ecológico",
      "status": "GAPS FOUND",
      "evidence_cases": [
        "QA10C",
        "QA11A",
        "GAP-13"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-AUTH-03",
      "title": "Gestión de Roles Globales vs. Contextuales",
      "status": "PARTIAL",
      "evidence_cases": [
        "QA29D",
        "QA29E",
        "QA29G",
        "GAP-12"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-CLAN-01",
      "title": "Clanes Institucionales / Facciones",
      "status": "PARTIAL",
      "evidence_cases": [
        "QA30A",
        "QA30B",
        "GAP-11"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-CLAN-02",
      "title": "Creación de Clanes Privados",
      "status": "PARTIAL",
      "evidence_cases": [
        "CLAN-02",
        "QA36B",
        "GAP-09"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-CLAN-03",
      "title": "Administración de Miembros y Borrado Lógico",
      "status": "PARTIAL",
      "evidence_cases": [
        "CLAN-05",
        "CLAN-06",
        "CLAN-08",
        "CLAN-09",
        "QA36E",
        "GAP-09"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-ACT-01",
      "title": "Catálogo Maestro de Acciones",
      "status": "GAPS FOUND",
      "evidence_cases": [
        "QA12A",
        "QA38A",
        "QA38B"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-ACT-02",
      "title": "Reglas Anti-Fraude por Frecuencia",
      "status": "PARTIAL",
      "evidence_cases": [
        "QA25C",
        "BE-SUITE"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-VAL-01",
      "title": "Registro Libre y Hábitos Diarios",
      "status": "GAPS FOUND",
      "evidence_cases": [
        "QA04"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-VAL-02",
      "title": "Registro con Foto Evidencia y Auditoría de Rechazo",
      "status": "GAPS FOUND",
      "evidence_cases": [
        "QA06C",
        "GAP-03"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-VAL-03",
      "title": "Registro por Código QR Dinámico",
      "status": "PARTIAL",
      "evidence_cases": [
        "GAP-04"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-GAM-01",
      "title": "Motor de Acreditación y Reversión de Puntos",
      "status": "PASS",
      "evidence_cases": [
        "QA05A",
        "QA06D",
        "QA06E"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-GAM-02",
      "title": "Tablas de Rankings / Leaderboards",
      "status": "PASS",
      "evidence_cases": [
        "QA08A",
        "QA08B"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-GAM-03",
      "title": "Badges e Insignias",
      "status": "GAPS FOUND",
      "evidence_cases": [
        "QA10C"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-CAMP-01",
      "title": "Estructuración de Misiones",
      "status": "PASS",
      "evidence_cases": [
        "QA26A",
        "QA31D"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-CAMP-02",
      "title": "Campañas Globales",
      "status": "PASS",
      "evidence_cases": [
        "QA26A",
        "QA26B"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-CAMP-03",
      "title": "Propuestas de Campañas Globales",
      "status": "PASS",
      "evidence_cases": [
        "QA27A",
        "QA27B",
        "QA27E",
        "QA27F"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-CAMP-04",
      "title": "Campañas Privadas / de Clan",
      "status": "PASS",
      "evidence_cases": [
        "QA31A",
        "QA31B"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-CAMP-05",
      "title": "Ciclo de Vida Automático",
      "status": "PARTIAL",
      "evidence_cases": [
        "BE-SUITE"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-COMM-01",
      "title": "Feed Social Dinámico",
      "status": "PARTIAL",
      "evidence_cases": [
        "FEED-01",
        "FEED-02",
        "FEED-03"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-DASH-01",
      "title": "Dashboard Resumen del Usuario",
      "status": "PARTIAL",
      "evidence_cases": [
        "ROUTE-02-D"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-DASH-02",
      "title": "Dashboard ITESO Impact",
      "status": "PARTIAL",
      "evidence_cases": [
        "GAP-13"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "FR-DASH-03",
      "title": "Panel de Administración y Moderación",
      "status": "GAPS FOUND",
      "evidence_cases": [
        "QA27B",
        "QA27E",
        "QA06C",
        "GAP-12"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "NFR-STACK-01",
      "title": "Backend Python / Django",
      "status": "PASS",
      "evidence_cases": [
        "BE-SUITE"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "NFR-STACK-02",
      "title": "Frontend React / Vite SPA",
      "status": "PASS",
      "evidence_cases": [
        "FE-BUILD"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "NFR-PWA-01",
      "title": "PWA Mobile-First & Alcance Conectado",
      "status": "PARTIAL",
      "evidence_cases": [
        "GAP-05",
        "GAP-06"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "NFR-SEC-01",
      "title": "Seguridad y Autenticación",
      "status": "PARTIAL",
      "evidence_cases": [
        "GAP-02",
        "QA35A"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "NFR-SEC-02",
      "title": "Control de Acceso RBAC",
      "status": "PASS",
      "evidence_cases": [
        "QA29D",
        "QA29G",
        "GUARD-12"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "NFR-PERF-01",
      "title": "Rendimiento de APIs",
      "status": "PARTIAL",
      "evidence_cases": [
        "GAP-07"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "NFR-RELI-01",
      "title": "Consistencia Transaccional",
      "status": "PARTIAL",
      "evidence_cases": [
        "BE-SUITE"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    },
    {
      "id": "NFR-ARCH-01",
      "title": "Integración de Módulos",
      "status": "PARTIAL",
      "evidence_cases": [
        "GAP-02"
      ],
      "source": "evidence/requirements-source.md",
      "scope_note": "Trazabilidad de evidencia; no aprobación de todos los criterios del requisito"
    }
  ],
  "counts": {
    "PASS": 245,
    "FAIL": 19,
    "NOT RUN": 14,
    "PRIOR VERIFIED": 1
  },
  "missing_links": [],
  "scope": "17 rutas × escritorio/móvil + 16 guards. La visita no prueba todos los controles. UI con sesiones sintéticas salvo login anterior."
}