{
  "catalog_version": "v1",
  "generated_at": "2026-05-14T06:00:48+00:00",
  "snapshot_date": "2026-05-14",
  "summary": {
    "sources_total": 46,
    "desired_total": 46,
    "in_db_total": 44,
    "active_total": 44,
    "with_network_total": 25,
    "with_any_data_total": 37,
    "sample_backed_total": 45,
    "blocked_total": 3,
    "tracker_done_total": 19,
    "sql_done_total": 25,
    "ops_ok_total": 29,
    "available_total": 27,
    "stale_total": 9,
    "missing_total": 7,
    "under_threshold_total": 10,
    "done_zero_real_total": 0,
    "mismatch_total": 18,
    "missing_source_ids_total": 2,
    "legal_status_counts": {
      "pending_review": 24,
      "verified": 18,
      "partially_verified": 3,
      "not_verified": 1
    },
    "by_domain": [
      {
        "key": "infoelectoral",
        "sources_total": 2,
        "desired_total": 2,
        "in_db_total": 0,
        "active_total": 0,
        "with_network_total": 0,
        "tracker_done_total": 0,
        "sql_done_total": 0,
        "blocked_total": 0,
        "mismatch_total": 2
      },
      {
        "key": "parlamentario",
        "sources_total": 7,
        "desired_total": 7,
        "in_db_total": 7,
        "active_total": 7,
        "with_network_total": 2,
        "tracker_done_total": 2,
        "sql_done_total": 2,
        "blocked_total": 0,
        "mismatch_total": 7
      },
      {
        "key": "politicos",
        "sources_total": 37,
        "desired_total": 37,
        "in_db_total": 37,
        "active_total": 37,
        "with_network_total": 23,
        "tracker_done_total": 17,
        "sql_done_total": 23,
        "blocked_total": 3,
        "mismatch_total": 9
      }
    ],
    "by_scope": [
      {
        "key": "autonomico",
        "sources_total": 19,
        "desired_total": 19,
        "in_db_total": 19,
        "active_total": 19,
        "with_network_total": 14,
        "tracker_done_total": 11,
        "sql_done_total": 14,
        "blocked_total": 1,
        "mismatch_total": 3
      },
      {
        "key": "dinero",
        "sources_total": 6,
        "desired_total": 6,
        "in_db_total": 6,
        "active_total": 6,
        "with_network_total": 2,
        "tracker_done_total": 2,
        "sql_done_total": 2,
        "blocked_total": 0,
        "mismatch_total": 2
      },
      {
        "key": "ejecutivo",
        "sources_total": 2,
        "desired_total": 2,
        "in_db_total": 2,
        "active_total": 2,
        "with_network_total": 2,
        "tracker_done_total": 0,
        "sql_done_total": 2,
        "blocked_total": 0,
        "mismatch_total": 2
      },
      {
        "key": "electoral",
        "sources_total": 2,
        "desired_total": 2,
        "in_db_total": 0,
        "active_total": 0,
        "with_network_total": 0,
        "tracker_done_total": 0,
        "sql_done_total": 0,
        "blocked_total": 0,
        "mismatch_total": 2
      },
      {
        "key": "europeo",
        "sources_total": 1,
        "desired_total": 1,
        "in_db_total": 1,
        "active_total": 1,
        "with_network_total": 1,
        "tracker_done_total": 1,
        "sql_done_total": 1,
        "blocked_total": 0,
        "mismatch_total": 0
      },
      {
        "key": "legal",
        "sources_total": 1,
        "desired_total": 1,
        "in_db_total": 1,
        "active_total": 1,
        "with_network_total": 1,
        "tracker_done_total": 0,
        "sql_done_total": 1,
        "blocked_total": 0,
        "mismatch_total": 1
      },
      {
        "key": "municipal",
        "sources_total": 1,
        "desired_total": 1,
        "in_db_total": 1,
        "active_total": 1,
        "with_network_total": 1,
        "tracker_done_total": 1,
        "sql_done_total": 1,
        "blocked_total": 0,
        "mismatch_total": 0
      },
      {
        "key": "nacional",
        "sources_total": 9,
        "desired_total": 9,
        "in_db_total": 9,
        "active_total": 9,
        "with_network_total": 3,
        "tracker_done_total": 3,
        "sql_done_total": 3,
        "blocked_total": 0,
        "mismatch_total": 7
      },
      {
        "key": "organigrama",
        "sources_total": 1,
        "desired_total": 1,
        "in_db_total": 1,
        "active_total": 1,
        "with_network_total": 0,
        "tracker_done_total": 0,
        "sql_done_total": 0,
        "blocked_total": 0,
        "mismatch_total": 1
      },
      {
        "key": "outcomes",
        "sources_total": 4,
        "desired_total": 4,
        "in_db_total": 4,
        "active_total": 4,
        "with_network_total": 1,
        "tracker_done_total": 1,
        "sql_done_total": 1,
        "blocked_total": 2,
        "mismatch_total": 0
      }
    ],
    "tracker": {
      "items_total": 300,
      "unmapped": 254,
      "todo": 28,
      "partial": 42,
      "done": 229,
      "mismatch": 10,
      "waived_mismatch": 0,
      "done_zero_real": 0,
      "untracked_sources": 8,
      "waivers_active": 0,
      "waivers_expired": 0,
      "waivers_error": ""
    }
  },
  "ops": {
    "ingestion_runs_total": 39,
    "ingestion_runs_ok": 39,
    "ingestion_runs_error": 0,
    "ingestion_runs_retry": 0,
    "ingestion_runs_ok_pct": 1.0,
    "avg_run_seconds": 35.384614307146805,
    "last_run_seconds": 0.0,
    "retry_rate": 0.0,
    "published_recommendation_artifacts": 0,
    "autonomico_sources_ok": 15,
    "europeo_sources_ok": 1
  },
  "roadmap": {
    "path": "docs/roadmap.md",
    "exists": true,
    "phases": [
      {
        "id": "phase_0",
        "phase": 0,
        "title": "Fase 0: base metodol\u00f3gica y de datos",
        "points_eng": 3,
        "points_hum": 13,
        "progress": {
          "done": 5,
          "partial": 0,
          "todo": 0,
          "untracked": 1,
          "tracked_total": 5,
          "overall_total": 6,
          "tracked_percent": 100,
          "overall_percent": 83
        },
        "items": [
          {
            "kind": "tracker",
            "id": "referencias_territoriales",
            "label": "Referencias territoriales",
            "status": "MISSING",
            "dominio": "",
            "scope": "",
            "bloque": "No existe fila en e2e-scrape-load-tracker",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "taxonomia_de_temas_alto_impacto_por_scope",
            "label": "Taxonomia de temas (alto impacto por scope)",
            "status": "DONE",
            "dominio": "Analitica",
            "scope": "territorial",
            "bloque": "Seed/versionado: `etl/data/seeds/topic_taxonomy_es.json`. Build: `python3 scripts/ingestar_parlamentario_es.py backfill-topic-analytics --db <db> --as-of-date <YYYY-MM-DD> --taxonomy-seed etl/data/seeds/topic_taxonomy_es.json`",
            "source_ids": []
          },
          {
            "kind": "manual",
            "id": "taxonomy_v1",
            "label": "Taxonom\u00eda (Tier 1/2) definida y versionada",
            "status": "DONE",
            "path": "docs/domain_taxonomy_es.md"
          },
          {
            "kind": "manual",
            "id": "codebook_v1",
            "label": "Codebook Tier 1 (ejes por dominio) versionado",
            "status": "DONE",
            "path": "docs/codebook_tier1_es.md"
          },
          {
            "kind": "manual",
            "id": "annotation_protocol",
            "label": "Protocolo de anotaci\u00f3n (doble entrada, acuerdo, arbitraje)",
            "status": "DONE",
            "path": "docs/annotation_protocol_es.md"
          },
          {
            "kind": "manual",
            "id": "interventions_template",
            "label": "Plantilla de intervenci\u00f3n (definici\u00f3n de tratamiento)",
            "status": "DONE",
            "path": "docs/intervention_template_es.md"
          }
        ],
        "next": [
          {
            "id": "referencias_territoriales",
            "label": "Referencias territoriales",
            "status": "MISSING",
            "path": null
          }
        ]
      },
      {
        "id": "phase_1",
        "phase": 1,
        "title": "Fase 1: MVP \"acci\u00f3n verificable\" a nivel Estado",
        "points_eng": 21,
        "points_hum": 8,
        "progress": {
          "done": 4,
          "partial": 4,
          "todo": 0,
          "untracked": 8,
          "tracked_total": 8,
          "overall_total": 16,
          "tracked_percent": 75,
          "overall_percent": 38
        },
        "items": [
          {
            "kind": "tracker",
            "id": "votaciones_congreso",
            "label": "Votaciones Congreso",
            "status": "MISSING",
            "dominio": "",
            "scope": "",
            "bloque": "No existe fila en e2e-scrape-load-tracker",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "iniciativas_congreso",
            "label": "Iniciativas Congreso",
            "status": "MISSING",
            "dominio": "",
            "scope": "",
            "bloque": "No existe fila en e2e-scrape-load-tracker",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "votaciones_senado_y_mociones",
            "label": "Votaciones Senado y mociones",
            "status": "MISSING",
            "dominio": "",
            "scope": "",
            "bloque": "No existe fila en e2e-scrape-load-tracker",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "intervenciones_congreso",
            "label": "Intervenciones Congreso",
            "status": "MISSING",
            "dominio": "",
            "scope": "",
            "bloque": "No existe fila en e2e-scrape-load-tracker",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "marco_legal_electoral",
            "label": "Marco legal electoral",
            "status": "PARTIAL",
            "dominio": "Legal",
            "scope": "legal",
            "bloque": "Done now: NO para live-clean en GitHub Actions. La ingesta historica BOE (`boe_api_legal`) existe (`records_loaded=298`, `policy_events_boe=298`), pero PR gate `25687905013` fallo en `--strict-network` con `urllib.error.URLError: <urlopen error timed out>`. Mantener como parcial hasta recuperar run reproducible de red real vigente. Evidencia: `docs/etl/sprints/AI-OPS-08/reports/waiver-burndown-apply-recompute.md`, `docs/etl/sprints/AI-OPS-08/evidence/waiver-burndown-apply-recompute-boe-ingest-replay.log`, `docs/etl/sprints/AI-OPS-08/evidence/waiver-burndown-apply-recompute-boe-policy-events-backfill.log`, `docs/etl/sprints/AI-OPS-08/reports/boe-tracker-mapping-hardening.md` y `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source boe_api_legal --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
            "source_ids": [
              "boe_api_legal"
            ]
          },
          {
            "kind": "tracker",
            "id": "accion_ejecutiva_consejo_de_ministros",
            "label": "Accion ejecutiva (Consejo de Ministros)",
            "status": "PARTIAL",
            "dominio": "Ejecutivo",
            "scope": "ejecutivo",
            "bloque": "Done now: NO para live-clean actual. La evidencia hist\u00f3rica existe, pero el DB operativo actual no conserva runs de red para `moncloa_referencias` y `moncloa_rss_referencias`; repetir strict-network o documentar bloqueo antes de `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-07/reports/dual-entry-apply-recompute.md`, `docs/etl/sprints/AI-OPS-07/reports/boe-policy-events-mapping.md` y `docs/etl/sprints/AI-OPS-07/evidence/post_apply_waiveraware_checker_final.log`.",
            "source_ids": [
              "moncloa_referencias",
              "moncloa_rss_referencias"
            ]
          },
          {
            "kind": "tracker",
            "id": "contratacion_publica_espana",
            "label": "Contratacion publica (Espana)",
            "status": "PARTIAL",
            "dominio": "Dinero",
            "scope": "dinero",
            "bloque": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `placsp_sindicacion` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-11/evidence/placsp-strict-refresh.log`, `docs/etl/sprints/AI-OPS-11/evidence/post-strict-status.log`, `docs/etl/sprints/AI-OPS-11/evidence/post-strict-gate.log`, `docs/etl/sprints/AI-OPS-11/exports/placsp_waiver_decision.csv`.",
            "source_ids": [
              "placsp_sindicacion"
            ]
          },
          {
            "kind": "tracker",
            "id": "subvenciones_y_ayudas_espana",
            "label": "Subvenciones y ayudas (Espana)",
            "status": "PARTIAL",
            "dominio": "Dinero",
            "scope": "dinero",
            "bloque": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `bdns_api_subvenciones` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-13/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-13/evidence/bdns-api-discovery.log`, `docs/etl/sprints/AI-OPS-13/exports/unblock_feasibility_matrix.csv`.",
            "source_ids": [
              "bdns_api_subvenciones"
            ]
          },
          {
            "kind": "tracker",
            "id": "transparencia_agendas_altos_cargos",
            "label": "Transparencia: agendas altos cargos",
            "status": "MISSING",
            "dominio": "",
            "scope": "",
            "bloque": "No existe fila en e2e-scrape-load-tracker",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "transparencia_declaraciones_intereses",
            "label": "Transparencia: declaraciones/intereses",
            "status": "MISSING",
            "dominio": "",
            "scope": "",
            "bloque": "No existe fila en e2e-scrape-load-tracker",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "taxonomia_de_temas_alto_impacto_por_scope",
            "label": "Taxonomia de temas (alto impacto por scope)",
            "status": "DONE",
            "dominio": "Analitica",
            "scope": "territorial",
            "bloque": "Seed/versionado: `etl/data/seeds/topic_taxonomy_es.json`. Build: `python3 scripts/ingestar_parlamentario_es.py backfill-topic-analytics --db <db> --as-of-date <YYYY-MM-DD> --taxonomy-seed etl/data/seeds/topic_taxonomy_es.json`",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "evidencia_textual_para_posiciones_declaradas",
            "label": "Evidencia textual (para posiciones declaradas)",
            "status": "DONE",
            "dominio": "Analitica",
            "scope": "nacional",
            "bloque": "Modelo can\u00f3nico: `text_documents` (metadata + excerpt) enlazado por `source_record_pk` de `topic_evidence`. Backfill: `python3 scripts/ingestar_parlamentario_es.py backfill-text-documents --db <db> --source-id congreso_intervenciones --only-missing` (o `just parl-backfill-text-documents`). Adem\u00e1s, copia un snippet a `topic_evidence.excerpt` para que `/explorer-temas` sea auditable sin joins. Nota: stance classification sigue siendo otro paso (ver filas de \u201cIntervenciones\u201d/\u201cPosiciones\u201d).",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "clasificacion_evidencia_tema_trazable",
            "label": "Clasificacion evidencia -> tema (trazable)",
            "status": "DONE",
            "dominio": "Analitica",
            "scope": "",
            "bloque": "MVP (votos + intervenciones): evidencia se etiqueta a `topic_id` (votos via `parl_vote_event_initiatives`; intervenciones via `initiative_id`/expediente). KPIs en `/explorer-sources`: `topic_evidence_with_topic_pct` + breakdown por `topic_method`/`stance_method`.",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "posiciones_por_tema_politico_x_scope",
            "label": "Posiciones por tema (politico x scope)",
            "status": "DONE",
            "dominio": "Analitica",
            "scope": "nacional",
            "bloque": "Done now: YES. `backfill-topic-analytics` en `as_of_date=2026-02-16` dej\u00f3 ambos sets en latest alineado y cerr\u00f3 el blocker de cobertura en Congreso: `topic_set_id=1` pas\u00f3 de `12/60 (20.0%)` a `60/60 (100.0%)`, mientras `topic_set_id=2` qued\u00f3 en `23/24 (95.83%)` con latest tambi\u00e9n en `2026-02-16`; adem\u00e1s, `topic_positions_total` subi\u00f3 de `137379` a `205907` y `computed_method_votes` de `68528` a `137056` (`combined=68612`, `declared=239`). Evidencia: `docs/etl/sprints/AI-OPS-15/exports/topic_positions_kpi_baseline.csv`, `docs/etl/sprints/AI-OPS-15/exports/topic_positions_kpi_post.csv`, `docs/etl/sprints/AI-OPS-15/evidence/topic_positions_baseline.log`, `docs/etl/sprints/AI-OPS-15/evidence/topic_positions_recompute.log`, `docs/etl/sprints/AI-OPS-15/reports/topic_positions_reconciliation.md`. Siguiente comando: `just etl-tracker-gate`.",
            "source_ids": []
          },
          {
            "kind": "manual",
            "id": "action_vectors_v1",
            "label": "Action vectors Tier 1 (vectorial + incertidumbre) con drill-down",
            "status": "UNTRACKED",
            "path": ""
          },
          {
            "kind": "manual",
            "id": "incoherence_v1",
            "label": "Se\u00f1al de incoherencia v1 (intra-dominio y dicho vs hecho)",
            "status": "UNTRACKED",
            "path": ""
          }
        ],
        "next": [
          {
            "id": "accion_ejecutiva_consejo_de_ministros",
            "label": "Accion ejecutiva (Consejo de Ministros)",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "contratacion_publica_espana",
            "label": "Contratacion publica (Espana)",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "marco_legal_electoral",
            "label": "Marco legal electoral",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "subvenciones_y_ayudas_espana",
            "label": "Subvenciones y ayudas (Espana)",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "action_vectors_v1",
            "label": "Action vectors Tier 1 (vectorial + incertidumbre) con drill-down",
            "status": "UNTRACKED",
            "path": ""
          }
        ]
      },
      {
        "id": "phase_2",
        "phase": 2,
        "title": "Fase 2: multinivel (3 CCAA piloto)",
        "points_eng": 21,
        "points_hum": 8,
        "progress": {
          "done": 2,
          "partial": 3,
          "todo": 2,
          "untracked": 1,
          "tracked_total": 7,
          "overall_total": 8,
          "tracked_percent": 50,
          "overall_percent": 44
        },
        "items": [
          {
            "kind": "tracker",
            "id": "representantes_y_mandatos_asamblea_de_madrid",
            "label": "Representantes y mandatos (Asamblea de Madrid)",
            "status": "DONE",
            "dominio": "Autonomico",
            "scope": "autonomico",
            "bloque": "Definir umbral minimo y aclarar semantica de `is_active`",
            "source_ids": [
              "asamblea_madrid_ocupaciones"
            ]
          },
          {
            "kind": "tracker",
            "id": "representantes_y_mandatos_parlament_de_catalunya",
            "label": "Representantes y mandatos (Parlament de Catalunya)",
            "status": "DONE",
            "dominio": "Autonomico",
            "scope": "autonomico",
            "bloque": "Hardening de parsing y umbral minimo",
            "source_ids": [
              "parlament_catalunya_diputats"
            ]
          },
          {
            "kind": "tracker",
            "id": "representantes_y_mandatos_parlamento_de_andalucia",
            "label": "Representantes y mandatos (Parlamento de Andalucia)",
            "status": "PARTIAL",
            "dominio": "Autonomico",
            "scope": "autonomico",
            "bloque": "GitHub Actions strict-network ya no encuentra diputados actuales (`codmie/nlegis`); requiere reparar parser o endpoint antes de volver a `DONE`.",
            "source_ids": [
              "parlamento_andalucia_diputados"
            ]
          },
          {
            "kind": "tracker",
            "id": "normativa_autonomica_piloto_3_ccaa",
            "label": "Normativa auton\u00f3mica (piloto 3 CCAA)",
            "status": "TODO",
            "dominio": "Legal",
            "scope": "autonomico",
            "bloque": "Falta conector y modelo can\u00f3nico de normas auton\u00f3micas (con efectos) con trazabilidad y dedupe por versi\u00f3n",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "contratacion_autonomica_piloto_3_ccaa",
            "label": "Contrataci\u00f3n auton\u00f3mica (piloto 3 CCAA)",
            "status": "PARTIAL",
            "dominio": "Dinero",
            "scope": "dinero",
            "bloque": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `placsp_autonomico` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-11/evidence/placsp-strict-refresh.log`, `docs/etl/sprints/AI-OPS-11/evidence/post-strict-status.log`, `docs/etl/sprints/AI-OPS-11/evidence/post-strict-gate.log`, `docs/etl/sprints/AI-OPS-11/exports/placsp_waiver_decision.csv`.",
            "source_ids": [
              "placsp_autonomico"
            ]
          },
          {
            "kind": "tracker",
            "id": "subvenciones_autonomicas_piloto_3_ccaa",
            "label": "Subvenciones auton\u00f3micas (piloto 3 CCAA)",
            "status": "PARTIAL",
            "dominio": "Dinero",
            "scope": "dinero",
            "bloque": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `bdns_autonomico` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-13/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-13/evidence/bdns-api-discovery.log`, `docs/etl/sprints/AI-OPS-13/exports/unblock_feasibility_matrix.csv`.",
            "source_ids": [
              "bdns_autonomico"
            ]
          },
          {
            "kind": "tracker",
            "id": "presupuesto_ejecucion_autonomica_piloto_3_ccaa",
            "label": "Presupuesto + ejecuci\u00f3n auton\u00f3mica (piloto 3 CCAA)",
            "status": "TODO",
            "dominio": "Dinero",
            "scope": "autonomico",
            "bloque": "Falta conector y crosswalk de clasificaciones; preferir ejecuci\u00f3n cuando exista",
            "source_ids": []
          },
          {
            "kind": "manual",
            "id": "ccaa_vectors",
            "label": "Action vectors Tier 1 para 3 CCAA (comparables con Estado)",
            "status": "UNTRACKED",
            "path": ""
          }
        ],
        "next": [
          {
            "id": "contratacion_autonomica_piloto_3_ccaa",
            "label": "Contrataci\u00f3n auton\u00f3mica (piloto 3 CCAA)",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "representantes_y_mandatos_parlamento_de_andalucia",
            "label": "Representantes y mandatos (Parlamento de Andalucia)",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "subvenciones_autonomicas_piloto_3_ccaa",
            "label": "Subvenciones auton\u00f3micas (piloto 3 CCAA)",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "normativa_autonomica_piloto_3_ccaa",
            "label": "Normativa auton\u00f3mica (piloto 3 CCAA)",
            "status": "TODO",
            "path": null
          },
          {
            "id": "presupuesto_ejecucion_autonomica_piloto_3_ccaa",
            "label": "Presupuesto + ejecuci\u00f3n auton\u00f3mica (piloto 3 CCAA)",
            "status": "TODO",
            "path": null
          }
        ]
      },
      {
        "id": "phase_3",
        "phase": 3,
        "title": "Fase 3: producto p\u00fablico v1 (trazabilidad total)",
        "points_eng": 13,
        "points_hum": 5,
        "progress": {
          "done": 1,
          "partial": 1,
          "todo": 2,
          "untracked": 3,
          "tracked_total": 4,
          "overall_total": 7,
          "tracked_percent": 38,
          "overall_percent": 21
        },
        "items": [
          {
            "kind": "tracker",
            "id": "procesos_electorales_y_resultados",
            "label": "Procesos electorales y resultados",
            "status": "PARTIAL",
            "dominio": "Electoral",
            "scope": "electoral",
            "bloque": "`infoelectoral_descargas` tiene evidencia de red en snapshot rico, pero `infoelectoral_procesos` no tiene run live-clean en el DB operativo actual. Cerrar solo cuando ambos source_id tengan `records_loaded > 0` o bloqueo documentado.",
            "source_ids": [
              "infoelectoral_descargas",
              "infoelectoral_procesos"
            ]
          },
          {
            "kind": "tracker",
            "id": "convocatorias_y_estado_electoral",
            "label": "Convocatorias y estado electoral",
            "status": "TODO",
            "dominio": "Electoral",
            "scope": "nacional",
            "bloque": "Falta scraper y normalizacion",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "posiciones_declaradas_programas",
            "label": "Posiciones declaradas (programas)",
            "status": "TODO",
            "dominio": "Editorial",
            "scope": "nacional",
            "bloque": "No hay run live-clean de `programas_partidos` en el DB operativo actual; repetir pipeline con manifest HTTP y `records_loaded > 0` antes de `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-239/reports/programas-network-contract-closure-20260228.md`, `docs/etl/sprints/AI-OPS-239/evidence/programas_ingest_http_sample_20260228.json`, `docs/etl/sprints/AI-OPS-239/evidence/tracker_status_post_programas_network_contract_20260228.log`.",
            "source_ids": [
              "programas_partidos"
            ]
          },
          {
            "kind": "tracker",
            "id": "posiciones_por_tema_politico_x_scope",
            "label": "Posiciones por tema (politico x scope)",
            "status": "DONE",
            "dominio": "Analitica",
            "scope": "nacional",
            "bloque": "Done now: YES. `backfill-topic-analytics` en `as_of_date=2026-02-16` dej\u00f3 ambos sets en latest alineado y cerr\u00f3 el blocker de cobertura en Congreso: `topic_set_id=1` pas\u00f3 de `12/60 (20.0%)` a `60/60 (100.0%)`, mientras `topic_set_id=2` qued\u00f3 en `23/24 (95.83%)` con latest tambi\u00e9n en `2026-02-16`; adem\u00e1s, `topic_positions_total` subi\u00f3 de `137379` a `205907` y `computed_method_votes` de `68528` a `137056` (`combined=68612`, `declared=239`). Evidencia: `docs/etl/sprints/AI-OPS-15/exports/topic_positions_kpi_baseline.csv`, `docs/etl/sprints/AI-OPS-15/exports/topic_positions_kpi_post.csv`, `docs/etl/sprints/AI-OPS-15/evidence/topic_positions_baseline.log`, `docs/etl/sprints/AI-OPS-15/evidence/topic_positions_recompute.log`, `docs/etl/sprints/AI-OPS-15/reports/topic_positions_reconciliation.md`. Siguiente comando: `just etl-tracker-gate`.",
            "source_ids": []
          },
          {
            "kind": "manual",
            "id": "dashboard_public_v1",
            "label": "Dashboard p\u00fablico v1 (trazabilidad total, modo auditor)",
            "status": "UNTRACKED",
            "path": ""
          },
          {
            "kind": "manual",
            "id": "weights_scenarios",
            "label": "Escenarios de pesos + sensibilidad (sin ranking \u00fanico por defecto)",
            "status": "UNTRACKED",
            "path": ""
          },
          {
            "kind": "manual",
            "id": "replica_mode",
            "label": "Modo r\u00e9plica: export dataset procesado + script/consulta reproducible",
            "status": "UNTRACKED",
            "path": ""
          }
        ],
        "next": [
          {
            "id": "procesos_electorales_y_resultados",
            "label": "Procesos electorales y resultados",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "convocatorias_y_estado_electoral",
            "label": "Convocatorias y estado electoral",
            "status": "TODO",
            "path": null
          },
          {
            "id": "posiciones_declaradas_programas",
            "label": "Posiciones declaradas (programas)",
            "status": "TODO",
            "path": null
          },
          {
            "id": "dashboard_public_v1",
            "label": "Dashboard p\u00fablico v1 (trazabilidad total, modo auditor)",
            "status": "UNTRACKED",
            "path": ""
          },
          {
            "id": "weights_scenarios",
            "label": "Escenarios de pesos + sensibilidad (sin ranking \u00fanico por defecto)",
            "status": "UNTRACKED",
            "path": ""
          }
        ]
      },
      {
        "id": "phase_4",
        "phase": 4,
        "title": "Fase 4: impacto (causalidad) en 1-2 dominios",
        "points_eng": 13,
        "points_hum": 13,
        "progress": {
          "done": 1,
          "partial": 3,
          "todo": 0,
          "untracked": 3,
          "tracked_total": 4,
          "overall_total": 7,
          "tracked_percent": 62,
          "overall_percent": 36
        },
        "items": [
          {
            "kind": "tracker",
            "id": "indicadores_outcomes_ine",
            "label": "Indicadores (outcomes): INE",
            "status": "MISSING",
            "dominio": "",
            "scope": "",
            "bloque": "No existe fila en e2e-scrape-load-tracker",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "indicadores_outcomes_eurostat",
            "label": "Indicadores (outcomes): Eurostat",
            "status": "PARTIAL",
            "dominio": "Outcomes",
            "scope": "outcomes",
            "bloque": "Done now: NO para live-clean. Live ETL `2026-05-11` carg\u00f3 solo fallback (`2/2`) tras `HTTP 404` en red real (`max_net=0`, `net/fallback_fetches=0/1`), as\u00ed que queda `PARTIAL` hasta corregir endpoint/query o confirmar contrato alternativo. Evidencia: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source eurostat_sdmx --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
            "source_ids": [
              "eurostat_sdmx"
            ]
          },
          {
            "kind": "tracker",
            "id": "indicadores_confusores_banco_de_espana",
            "label": "Indicadores (confusores): Banco de Espana",
            "status": "DONE",
            "dominio": "Outcomes",
            "scope": "outcomes",
            "bloque": "Done now: YES. Live ETL `2026-05-11` carg\u00f3 `58/58` registros con red real, y verificaci\u00f3n local `--strict-network` sobre DB limpia confirm\u00f3 `58/58 registros validos` contra BIEREST `listaSeries`. Evidencia: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`; cobertura ampliada: fila `Cobertura BDE multi-serie`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source bde_series_api --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30 && python3 scripts/ingestar_politicos_es.py backfill-indicators --db <db> --source-ids bde_series_api`.",
            "source_ids": [
              "bde_series_api"
            ]
          },
          {
            "kind": "tracker",
            "id": "indicadores_confusores_aemet",
            "label": "Indicadores (confusores): AEMET",
            "status": "PARTIAL",
            "dominio": "Outcomes",
            "scope": "outcomes",
            "bloque": "Done now: NO. Blocker: `aemet_opendata_series` en `strict-network` sigue bloqueado por contrato (`aemet_blocker=contract`, JSON invalido con payload vac\u00edo `payload_sig=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`, `run_id=263`, `run_records_loaded=0`), por lo que la fila permanece `PARTIAL`. Evidencia: `docs/etl/sprints/AI-OPS-14/evidence/blocker-probe-refresh.log`, `docs/etl/sprints/AI-OPS-14/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-14/exports/unblock_feasibility_matrix.csv`. Siguiente comando: `AEMET_API_KEY=<token> python3 scripts/ingestar_politicos_es.py ingest --db etl/data/staging/politicos-es.db --source aemet_opendata_series --url https://opendata.aemet.es/opendata/api/observacion/convencional/todas --snapshot-date 2026-02-17 --strict-network --timeout 30`.",
            "source_ids": [
              "aemet_opendata_series"
            ]
          },
          {
            "kind": "tracker",
            "id": "indicadores_confusores_esios_ree",
            "label": "Indicadores (confusores): ESIOS/REE",
            "status": "PARTIAL",
            "dominio": "Outcomes",
            "scope": "outcomes",
            "bloque": "Done now: PARTIAL. AI-OPS-296 cierra el gap de conector con `ree_esios_indicators` (config/registry + parser de payload REE `included[].attributes.values` + soporte de contenedor serializado `records` + rechazo de snapshots legacy `metric,value` + fallback sample reproducible) y lo integra en `backfill-indicators`/mapeo tracker. Corrida reproducible en DB principal desde muestra (`--from-file`) deja `status=ok`, `records_loaded=2`, `source_records_total=2`; el probe `--strict-network` al endpoint oficial sigue bloqueado de forma reproducible con `HTTP 500`, body HTML y cabecera `x-cdn: Imperva`, por lo que no aplica `DONE` en red real. Evidencia: `docs/etl/sprints/AI-OPS-296/reports/ree-esios-indicators-connector-partial-closure-20260228.md`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_ingest_status_latest.json`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_curl_headers_latest.txt`, `docs/etl/sprints/AI-OPS-296/evidence/e2e_tracker_status_main_db_latest.txt`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_main_db_ingestion_runs_latest.txt`. Siguiente comando: `ESIOS_API_TOKEN=<token> python3 scripts/ingestar_politicos_es.py ingest --db <db> --source ree_esios_indicators --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30 && python3 scripts/ingestar_politicos_es.py backfill-indicators --db <db> --source-ids ree_esios_indicators`.",
            "source_ids": [
              "ree_esios_indicators"
            ]
          },
          {
            "kind": "manual",
            "id": "impact_cards",
            "label": "Impact cards (efecto + incertidumbre + supuestos + enlaces)",
            "status": "UNTRACKED",
            "path": ""
          },
          {
            "kind": "manual",
            "id": "causal_eval_pack",
            "label": "Evaluaciones causales (dise\u00f1o + diagn\u00f3sticos + credibilidad)",
            "status": "UNTRACKED",
            "path": ""
          }
        ],
        "next": [
          {
            "id": "indicadores_confusores_aemet",
            "label": "Indicadores (confusores): AEMET",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "indicadores_confusores_esios_ree",
            "label": "Indicadores (confusores): ESIOS/REE",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "indicadores_outcomes_eurostat",
            "label": "Indicadores (outcomes): Eurostat",
            "status": "PARTIAL",
            "path": null
          },
          {
            "id": "causal_eval_pack",
            "label": "Evaluaciones causales (dise\u00f1o + diagn\u00f3sticos + credibilidad)",
            "status": "UNTRACKED",
            "path": ""
          },
          {
            "id": "impact_cards",
            "label": "Impact cards (efecto + incertidumbre + supuestos + enlaces)",
            "status": "UNTRACKED",
            "path": ""
          }
        ]
      },
      {
        "id": "phase_5",
        "phase": 5,
        "title": "Fase 5: expansi\u00f3n operativa (10-12 CCAA + municipios grandes)",
        "points_eng": 34,
        "points_hum": 13,
        "progress": {
          "done": 0,
          "partial": 0,
          "todo": 4,
          "untracked": 2,
          "tracked_total": 4,
          "overall_total": 6,
          "tracked_percent": 0,
          "overall_percent": 0
        },
        "items": [
          {
            "kind": "tracker",
            "id": "ue_legislacion_y_documentos",
            "label": "UE: legislacion y documentos",
            "status": "TODO",
            "dominio": "UE",
            "scope": "europeo",
            "bloque": "Falta conector UE legal; linking a expedientes y textos vigentes",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "ue_votaciones_roll_call",
            "label": "UE: votaciones (roll-call)",
            "status": "TODO",
            "dominio": "UE",
            "scope": "europeo",
            "bloque": "Falta ingesta de votos + mapeo a MEPs; KPI: % con actor resuelto",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "ue_contratacion_publica",
            "label": "UE: contratacion publica",
            "status": "TODO",
            "dominio": "UE",
            "scope": "europeo",
            "bloque": "Falta ingesta; KPI: cobertura y trazabilidad por notice",
            "source_ids": []
          },
          {
            "kind": "tracker",
            "id": "ue_lobbying_influencia",
            "label": "UE: lobbying/influencia",
            "status": "TODO",
            "dominio": "UE",
            "scope": "europeo",
            "bloque": "Falta ingesta y modelo de entidades; linking cuando existan meetings/agendas publicas",
            "source_ids": []
          },
          {
            "kind": "manual",
            "id": "multilevel_scale",
            "label": "Escalado multinivel (10-12 CCAA + municipios grandes) sin caer en PDFs por defecto",
            "status": "UNTRACKED",
            "path": ""
          },
          {
            "kind": "manual",
            "id": "money_sampling",
            "label": "Estrategia de muestreo/agregaci\u00f3n en contrataci\u00f3n/subvenciones (no 'leerlo todo')",
            "status": "UNTRACKED",
            "path": ""
          }
        ],
        "next": [
          {
            "id": "ue_contratacion_publica",
            "label": "UE: contratacion publica",
            "status": "TODO",
            "path": null
          },
          {
            "id": "ue_legislacion_y_documentos",
            "label": "UE: legislacion y documentos",
            "status": "TODO",
            "path": null
          },
          {
            "id": "ue_lobbying_influencia",
            "label": "UE: lobbying/influencia",
            "status": "TODO",
            "path": null
          },
          {
            "id": "ue_votaciones_roll_call",
            "label": "UE: votaciones (roll-call)",
            "status": "TODO",
            "path": null
          },
          {
            "id": "multilevel_scale",
            "label": "Escalado multinivel (10-12 CCAA + municipios grandes) sin caer en PDFs por defecto",
            "status": "UNTRACKED",
            "path": ""
          }
        ]
      }
    ],
    "summary": {
      "done": 13,
      "partial": 11,
      "todo": 8,
      "untracked": 18,
      "tracked_total": 32,
      "overall_total": 50,
      "tracked_percent": 58,
      "overall_percent": 37
    }
  },
  "roadmap_technical": {
    "path": "docs/roadmap-tecnico.md",
    "exists": true,
    "phases": [
      {
        "id": "tech_phase_0",
        "phase": 0,
        "title": "Fase 0: Reforzar base de datos y calidad",
        "points_eng": 8,
        "points_eng_raw": "8",
        "progress": {
          "done": 5,
          "partial": 1,
          "todo": 1,
          "untracked": 3,
          "tracked_total": 7,
          "overall_total": 10,
          "tracked_percent": 79,
          "overall_percent": 55
        },
        "checks": [
          {
            "kind": "tracker",
            "id": "votaciones_congreso",
            "label": "Votaciones Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "iniciativas_congreso",
            "label": "Iniciativas Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "votaciones_senado_y_mociones",
            "label": "Votaciones Senado y mociones",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "taxonomia_de_temas_alto_impacto_por_scope",
            "label": "Taxonomia de temas (alto impacto por scope)",
            "status": "DONE",
            "actual_display": "DONE",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "clasificacion_evidencia_tema_trazable",
            "label": "Clasificacion evidencia -> tema (trazable)",
            "status": "DONE",
            "actual_display": "DONE",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "posiciones_por_tema_politico_x_scope",
            "label": "Posiciones por tema (politico x scope)",
            "status": "DONE",
            "actual_display": "DONE",
            "target_display": "DONE"
          },
          {
            "kind": "metric",
            "id": "fk_check_clean",
            "label": "PRAGMA foreign_key_check sin filas",
            "status": "DONE",
            "metric": "fk_violations",
            "actual": 0,
            "target": 0,
            "format": "int",
            "actual_display": "0",
            "target_display": "0"
          },
          {
            "kind": "metric",
            "id": "votes_quality_gate",
            "label": "Gate de calidad de votaciones (enforce-gate)",
            "status": "DONE",
            "metric": "vote_gate_passed",
            "actual": true,
            "target": null,
            "format": "bool",
            "actual_display": "true",
            "target_display": "\u2014"
          },
          {
            "kind": "metric",
            "id": "initiatives_quality_gate",
            "label": "Gate de calidad de iniciativas",
            "status": "TODO",
            "metric": "initiative_gate_passed",
            "actual": false,
            "target": null,
            "format": "bool",
            "actual_display": "false",
            "target_display": "\u2014"
          },
          {
            "kind": "metric",
            "id": "done_sources_with_network",
            "label": "Fuentes tracker=DONE con evidencia de red",
            "status": "PARTIAL",
            "metric": "done_sources_with_network_pct",
            "actual": 0.8947368421052632,
            "target": 1.0,
            "format": "pct",
            "actual_display": "89%",
            "target_display": "100%"
          }
        ],
        "next": [
          {
            "id": "done_sources_with_network",
            "label": "Fuentes tracker=DONE con evidencia de red",
            "status": "PARTIAL",
            "actual_display": "89%",
            "target_display": "100%"
          },
          {
            "id": "initiatives_quality_gate",
            "label": "Gate de calidad de iniciativas",
            "status": "TODO",
            "actual_display": "false",
            "target_display": "\u2014"
          },
          {
            "id": "iniciativas_congreso",
            "label": "Iniciativas Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "id": "votaciones_congreso",
            "label": "Votaciones Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "id": "votaciones_senado_y_mociones",
            "label": "Votaciones Senado y mociones",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          }
        ]
      },
      {
        "id": "tech_phase_1",
        "phase": 1,
        "title": "Fase 1: Cerrar loop de \u201clo que hacen\u201d",
        "points_eng": 8,
        "points_eng_raw": "8",
        "progress": {
          "done": 3,
          "partial": 0,
          "todo": 1,
          "untracked": 4,
          "tracked_total": 4,
          "overall_total": 8,
          "tracked_percent": 75,
          "overall_percent": 38
        },
        "checks": [
          {
            "kind": "tracker",
            "id": "votaciones_congreso",
            "label": "Votaciones Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "iniciativas_congreso",
            "label": "Iniciativas Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "votaciones_senado_y_mociones",
            "label": "Votaciones Senado y mociones",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "intervenciones_congreso",
            "label": "Intervenciones Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "kind": "metric",
            "id": "events_with_date_pct",
            "label": "Eventos con fecha",
            "status": "DONE",
            "metric": "events_with_date_pct",
            "actual": 1.0,
            "target": 0.95,
            "format": "pct",
            "actual_display": "100%",
            "target_display": "95%"
          },
          {
            "kind": "metric",
            "id": "events_with_initiative_link_pct",
            "label": "Eventos con iniciativa enlazada",
            "status": "DONE",
            "metric": "events_with_initiative_link_pct",
            "actual": 1.0,
            "target": 0.95,
            "format": "pct",
            "actual_display": "100%",
            "target_display": "95%"
          },
          {
            "kind": "metric",
            "id": "member_votes_with_person_id_pct",
            "label": "Votos nominales con person_id",
            "status": "DONE",
            "metric": "member_votes_with_person_id_pct",
            "actual": 1.0,
            "target": 0.9,
            "format": "pct",
            "actual_display": "100%",
            "target_display": "90%"
          },
          {
            "kind": "metric",
            "id": "latest_events_with_topic_evidence_pct",
            "label": "Eventos latest con topic_evidence",
            "status": "TODO",
            "metric": "latest_events_with_topic_evidence_pct",
            "actual": 0.0,
            "target": 0.5,
            "format": "pct",
            "actual_display": "0%",
            "target_display": "50%"
          }
        ],
        "next": [
          {
            "id": "latest_events_with_topic_evidence_pct",
            "label": "Eventos latest con topic_evidence",
            "status": "TODO",
            "actual_display": "0%",
            "target_display": "50%"
          },
          {
            "id": "iniciativas_congreso",
            "label": "Iniciativas Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "id": "intervenciones_congreso",
            "label": "Intervenciones Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "id": "votaciones_congreso",
            "label": "Votaciones Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "id": "votaciones_senado_y_mociones",
            "label": "Votaciones Senado y mociones",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          }
        ]
      },
      {
        "id": "tech_phase_2",
        "phase": 2,
        "title": "Fase 2: Posiciones p\u00fablicas y se\u00f1al de coherencia",
        "points_eng": 13,
        "points_eng_raw": "13",
        "progress": {
          "done": 3,
          "partial": 0,
          "todo": 4,
          "untracked": 1,
          "tracked_total": 7,
          "overall_total": 8,
          "tracked_percent": 43,
          "overall_percent": 38
        },
        "checks": [
          {
            "kind": "tracker",
            "id": "intervenciones_congreso",
            "label": "Intervenciones Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "evidencia_textual_para_posiciones_declaradas",
            "label": "Evidencia textual (para posiciones declaradas)",
            "status": "DONE",
            "actual_display": "DONE",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "clasificacion_evidencia_tema_trazable",
            "label": "Clasificacion evidencia -> tema (trazable)",
            "status": "DONE",
            "actual_display": "DONE",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "posiciones_por_tema_politico_x_scope",
            "label": "Posiciones por tema (politico x scope)",
            "status": "DONE",
            "actual_display": "DONE",
            "target_display": "DONE"
          },
          {
            "kind": "metric",
            "id": "topic_evidence_declared_total",
            "label": "Evidencia declarada extraida",
            "status": "TODO",
            "metric": "topic_evidence_declared_total",
            "actual": 0,
            "target": 1,
            "format": "int",
            "actual_display": "0",
            "target_display": "1"
          },
          {
            "kind": "metric",
            "id": "topic_evidence_declared_with_signal_pct",
            "label": "Evidencia declarada con stance util",
            "status": "TODO",
            "metric": "topic_evidence_declared_with_signal_pct",
            "actual": 0.0,
            "target": 0.5,
            "format": "pct",
            "actual_display": "0%",
            "target_display": "50%"
          },
          {
            "kind": "metric",
            "id": "topic_evidence_with_topic_pct",
            "label": "Evidencia con topic_id",
            "status": "TODO",
            "metric": "topic_evidence_with_topic_pct",
            "actual": 0.0,
            "target": 0.95,
            "format": "pct",
            "actual_display": "0%",
            "target_display": "95%"
          },
          {
            "kind": "metric",
            "id": "topic_evidence_with_source_url_pct",
            "label": "Trazabilidad en topic_evidence (source_url)",
            "status": "TODO",
            "metric": "topic_evidence_with_source_url_pct",
            "actual": 0.0,
            "target": 1.0,
            "format": "pct",
            "actual_display": "0%",
            "target_display": "100%"
          }
        ],
        "next": [
          {
            "id": "topic_evidence_with_topic_pct",
            "label": "Evidencia con topic_id",
            "status": "TODO",
            "actual_display": "0%",
            "target_display": "95%"
          },
          {
            "id": "topic_evidence_declared_with_signal_pct",
            "label": "Evidencia declarada con stance util",
            "status": "TODO",
            "actual_display": "0%",
            "target_display": "50%"
          },
          {
            "id": "topic_evidence_declared_total",
            "label": "Evidencia declarada extraida",
            "status": "TODO",
            "actual_display": "0",
            "target_display": "1"
          },
          {
            "id": "topic_evidence_with_source_url_pct",
            "label": "Trazabilidad en topic_evidence (source_url)",
            "status": "TODO",
            "actual_display": "0%",
            "target_display": "100%"
          },
          {
            "id": "intervenciones_congreso",
            "label": "Intervenciones Congreso",
            "status": "MISSING",
            "actual_display": "MISSING",
            "target_display": "DONE"
          }
        ]
      },
      {
        "id": "tech_phase_3",
        "phase": 3,
        "title": "Fase 3: Motor de recomendaci\u00f3n y fiabilidad",
        "points_eng": 13,
        "points_eng_raw": "13",
        "progress": {
          "done": 1,
          "partial": 0,
          "todo": 4,
          "untracked": 0,
          "tracked_total": 5,
          "overall_total": 5,
          "tracked_percent": 20,
          "overall_percent": 20
        },
        "checks": [
          {
            "kind": "tracker",
            "id": "posiciones_por_tema_politico_x_scope",
            "label": "Posiciones por tema (politico x scope)",
            "status": "DONE",
            "actual_display": "DONE",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "posiciones_declaradas_programas",
            "label": "Posiciones declaradas (programas)",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "kind": "metric",
            "id": "topic_positions_total",
            "label": "Posiciones agregadas disponibles",
            "status": "TODO",
            "metric": "topic_positions_total",
            "actual": 0,
            "target": 1,
            "format": "int",
            "actual_display": "0",
            "target_display": "1"
          },
          {
            "kind": "metric",
            "id": "topic_positions_with_evidence_pct",
            "label": "Posiciones con evidencia suficiente",
            "status": "TODO",
            "metric": "topic_positions_with_evidence_pct",
            "actual": 0.0,
            "target": 0.9,
            "format": "pct",
            "actual_display": "0%",
            "target_display": "90%"
          },
          {
            "kind": "metric",
            "id": "coherence_explicit_total",
            "label": "Comparaciones explicitas says/does",
            "status": "TODO",
            "metric": "coherence_explicit_total",
            "actual": 0,
            "target": 1,
            "format": "int",
            "actual_display": "0",
            "target_display": "1"
          }
        ],
        "next": [
          {
            "id": "coherence_explicit_total",
            "label": "Comparaciones explicitas says/does",
            "status": "TODO",
            "actual_display": "0",
            "target_display": "1"
          },
          {
            "id": "topic_positions_total",
            "label": "Posiciones agregadas disponibles",
            "status": "TODO",
            "actual_display": "0",
            "target_display": "1"
          },
          {
            "id": "topic_positions_with_evidence_pct",
            "label": "Posiciones con evidencia suficiente",
            "status": "TODO",
            "actual_display": "0%",
            "target_display": "90%"
          },
          {
            "id": "posiciones_declaradas_programas",
            "label": "Posiciones declaradas (programas)",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          }
        ]
      },
      {
        "id": "tech_phase_4",
        "phase": 4,
        "title": "Fase 4: UX + comunidad + operaciones",
        "points_eng": 8,
        "points_eng_raw": "8",
        "progress": {
          "done": 1,
          "partial": 1,
          "todo": 3,
          "untracked": 0,
          "tracked_total": 5,
          "overall_total": 5,
          "tracked_percent": 30,
          "overall_percent": 30
        },
        "checks": [
          {
            "kind": "tracker",
            "id": "procesos_electorales_y_resultados",
            "label": "Procesos electorales y resultados",
            "status": "PARTIAL",
            "actual_display": "PARTIAL",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "convocatorias_y_estado_electoral",
            "label": "Convocatorias y estado electoral",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "posiciones_declaradas_programas",
            "label": "Posiciones declaradas (programas)",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "kind": "metric",
            "id": "review_queue_pending_ratio",
            "label": "Review queue pendiente / declaradas",
            "status": "DONE",
            "metric": "review_queue_pending_ratio",
            "actual": 0.0,
            "target": 0.25,
            "format": "pct",
            "actual_display": "0%",
            "target_display": "25%"
          },
          {
            "kind": "metric",
            "id": "published_recommendation_artifacts",
            "label": "Artefactos publicados (topics/claims/recommendation-kpis)",
            "status": "TODO",
            "metric": "published_recommendation_artifacts",
            "actual": 0,
            "target": 3,
            "format": "int",
            "actual_display": "0",
            "target_display": "3"
          }
        ],
        "next": [
          {
            "id": "procesos_electorales_y_resultados",
            "label": "Procesos electorales y resultados",
            "status": "PARTIAL",
            "actual_display": "PARTIAL",
            "target_display": "DONE"
          },
          {
            "id": "published_recommendation_artifacts",
            "label": "Artefactos publicados (topics/claims/recommendation-kpis)",
            "status": "TODO",
            "actual_display": "0",
            "target_display": "3"
          },
          {
            "id": "convocatorias_y_estado_electoral",
            "label": "Convocatorias y estado electoral",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "id": "posiciones_declaradas_programas",
            "label": "Posiciones declaradas (programas)",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          }
        ]
      },
      {
        "id": "tech_phase_5",
        "phase": 5,
        "title": "Fase 5: Cobertura multinivel",
        "points_eng": 21,
        "points_eng_raw": "21+",
        "progress": {
          "done": 2,
          "partial": 2,
          "todo": 6,
          "untracked": 0,
          "tracked_total": 10,
          "overall_total": 10,
          "tracked_percent": 30,
          "overall_percent": 30
        },
        "checks": [
          {
            "kind": "tracker",
            "id": "normativa_autonomica_piloto_3_ccaa",
            "label": "Normativa auton\u00f3mica (piloto 3 CCAA)",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "contratacion_autonomica_piloto_3_ccaa",
            "label": "Contrataci\u00f3n auton\u00f3mica (piloto 3 CCAA)",
            "status": "PARTIAL",
            "actual_display": "PARTIAL",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "subvenciones_autonomicas_piloto_3_ccaa",
            "label": "Subvenciones auton\u00f3micas (piloto 3 CCAA)",
            "status": "PARTIAL",
            "actual_display": "PARTIAL",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "presupuesto_ejecucion_autonomica_piloto_3_ccaa",
            "label": "Presupuesto + ejecuci\u00f3n auton\u00f3mica (piloto 3 CCAA)",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "ue_legislacion_y_documentos",
            "label": "UE: legislacion y documentos",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "ue_votaciones_roll_call",
            "label": "UE: votaciones (roll-call)",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "ue_contratacion_publica",
            "label": "UE: contratacion publica",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "kind": "tracker",
            "id": "ue_lobbying_influencia",
            "label": "UE: lobbying/influencia",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "kind": "metric",
            "id": "autonomico_sources_ok",
            "label": "Fuentes autonomicas en estado ok",
            "status": "DONE",
            "metric": "autonomico_sources_ok",
            "actual": 15,
            "target": 1,
            "format": "int",
            "actual_display": "15",
            "target_display": "1"
          },
          {
            "kind": "metric",
            "id": "europeo_sources_ok",
            "label": "Fuentes europeas en estado ok",
            "status": "DONE",
            "metric": "europeo_sources_ok",
            "actual": 1,
            "target": 1,
            "format": "int",
            "actual_display": "1",
            "target_display": "1"
          }
        ],
        "next": [
          {
            "id": "contratacion_autonomica_piloto_3_ccaa",
            "label": "Contrataci\u00f3n auton\u00f3mica (piloto 3 CCAA)",
            "status": "PARTIAL",
            "actual_display": "PARTIAL",
            "target_display": "DONE"
          },
          {
            "id": "subvenciones_autonomicas_piloto_3_ccaa",
            "label": "Subvenciones auton\u00f3micas (piloto 3 CCAA)",
            "status": "PARTIAL",
            "actual_display": "PARTIAL",
            "target_display": "DONE"
          },
          {
            "id": "normativa_autonomica_piloto_3_ccaa",
            "label": "Normativa auton\u00f3mica (piloto 3 CCAA)",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "id": "presupuesto_ejecucion_autonomica_piloto_3_ccaa",
            "label": "Presupuesto + ejecuci\u00f3n auton\u00f3mica (piloto 3 CCAA)",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "id": "ue_contratacion_publica",
            "label": "UE: contratacion publica",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          },
          {
            "id": "ue_legislacion_y_documentos",
            "label": "UE: legislacion y documentos",
            "status": "TODO",
            "actual_display": "TODO",
            "target_display": "DONE"
          }
        ]
      }
    ],
    "program_kpis": [
      {
        "id": "tracking_sources_ok_pct",
        "label": "Fuentes objetivo en estado ok",
        "status": "PARTIAL",
        "metric": "desired_sources_ok_pct",
        "actual": 0.6304347826086957,
        "target": 0.8,
        "format": "pct",
        "actual_display": "63%",
        "target_display": "80%"
      },
      {
        "id": "events_with_initiative_link_pct",
        "label": "Eventos con iniciativa enlazada",
        "status": "DONE",
        "metric": "events_with_initiative_link_pct",
        "actual": 1.0,
        "target": 0.95,
        "format": "pct",
        "actual_display": "100%",
        "target_display": "95%"
      },
      {
        "id": "member_votes_with_person_id_pct",
        "label": "Votos nominales con person_id",
        "status": "DONE",
        "metric": "member_votes_with_person_id_pct",
        "actual": 1.0,
        "target": 0.9,
        "format": "pct",
        "actual_display": "100%",
        "target_display": "90%"
      },
      {
        "id": "latest_events_with_topic_evidence_pct",
        "label": "Eventos latest con topic_evidence",
        "status": "TODO",
        "metric": "latest_events_with_topic_evidence_pct",
        "actual": 0.0,
        "target": 0.5,
        "format": "pct",
        "actual_display": "0%",
        "target_display": "50%"
      },
      {
        "id": "topic_positions_with_evidence_pct",
        "label": "Posiciones con evidencia suficiente",
        "status": "TODO",
        "metric": "topic_positions_with_evidence_pct",
        "actual": 0.0,
        "target": 0.9,
        "format": "pct",
        "actual_display": "0%",
        "target_display": "90%"
      },
      {
        "id": "ingestion_runs_ok_pct",
        "label": "Runs ETL en estado ok",
        "status": "DONE",
        "metric": "ingestion_runs_ok_pct",
        "actual": 1.0,
        "target": 0.8,
        "format": "pct",
        "actual_display": "100%",
        "target_display": "80%"
      },
      {
        "id": "retry_rate",
        "label": "Costo de reintentos ETL",
        "status": "DONE",
        "metric": "retry_rate",
        "actual": 0.0,
        "target": 0.2,
        "format": "pct",
        "actual_display": "0%",
        "target_display": "20%"
      },
      {
        "id": "avg_run_seconds",
        "label": "Duraci\u00f3n media por run ETL",
        "status": "DONE",
        "metric": "avg_run_seconds",
        "actual": 35.384614307146805,
        "target": null,
        "format": "seconds",
        "actual_display": "35.4s",
        "target_display": "\u2014"
      }
    ],
    "summary": {
      "done": 15,
      "partial": 4,
      "todo": 19,
      "untracked": 8,
      "tracked_total": 38,
      "overall_total": 46,
      "tracked_percent": 45,
      "overall_percent": 37
    },
    "notes": [
      "Los checks de fase combinan tracker operativo y KPIs cuantificables.",
      "Cuando no existe medicion directa, el estado se marca como UNTRACKED."
    ]
  },
  "actions": [
    {
      "kind": "missing_source",
      "priority": "P0",
      "scope": "",
      "title": "Fuente deseada no existe en BD: infoelectoral_descargas",
      "details": "Dominio=infoelectoral \u00b7 scope=electoral",
      "source_ids": [
        "infoelectoral_descargas"
      ],
      "commands": [
        "python3 scripts/ingestar_infoelectoral_es.py ingest --db <db> --source infoelectoral_descargas --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "missing_source",
      "priority": "P0",
      "scope": "",
      "title": "Fuente deseada no existe en BD: infoelectoral_procesos",
      "details": "Dominio=infoelectoral \u00b7 scope=electoral",
      "source_ids": [
        "infoelectoral_procesos"
      ],
      "commands": [
        "python3 scripts/ingestar_infoelectoral_es.py ingest --db <db> --source infoelectoral_procesos --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: AEAT/TGSS/DGT/CCAA/ayuntamientos (sedes electr\u00f3nicas y procedimientos)",
      "details": "Falta cat\u00e1logo de obligaciones digitales por perfil ciudadano/pyme (`plazo`, `canal`, `sanci\u00f3n/recargo`) y medici\u00f3n de fricci\u00f3n por complejidad y tasa de error",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: BOCM (Madrid) + DOGC (Catalunya) + BOJA (Andaluc\u00eda)",
      "details": "Falta conector y modelo can\u00f3nico de normas auton\u00f3micas (con efectos) con trazabilidad y dedupe por versi\u00f3n",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "nacional",
      "title": "TODO: BOE (peajes/cargos/PVPC/TUR) + CNMC + MITECO",
      "details": "Falta descomponer factura en componentes normativos y atribuir variaciones de coste por norma/fecha/territorio, separando energ\u00eda de mercado vs parte regulada",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "europeo",
      "title": "TODO: BOE + EUR-Lex + MAPA/MITECO + OPA (ASAJA/COAG/UPA)",
      "details": "Falta modelo reproducible para ranking `top_regulaciones_mas_gravosas` por agricultura/ganaderia (coste de cumplimiento, sanciones, horas administrativas, alcance territorial, litigios) con metodolog\u00eda y pesos expl\u00edcitos",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "nacional",
      "title": "TODO: Banco de Espa\u00f1a (reclamaciones/memorias) + BOE cr\u00e9dito inmobiliario/servicios de pago",
      "details": "Falta mapa normativo + dataset de costes/reclamaciones por entidad y tipolog\u00eda de cobro para detectar fricci\u00f3n masiva y accountability regulatoria",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: CCAA + ayuntamientos (escuelas infantiles, comedor, actividades) + convocatorias de becas",
      "details": "Falta comparador territorial de precios p\u00fablicos y elegibilidad de ayudas (`umbrales`, `baremos`, `plazos`) con impacto neto por hogar",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: CCAA + entes locales + operadores p\u00fablicos/mixtos + BOE/boletines auton\u00f3micos",
      "details": "Falta mapa regulatorio y comparador de factura de agua por municipio (`cuota fija`, `bloques`, `canon`, `depuraci\u00f3n`) con trazabilidad de cambios normativos y \u00f3rgano decisor",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: CNMC + Consumo + CCAA (OMIC/Juntas Arbitrales) + operadores",
      "details": "Falta modelo unificado de reclamaciones/sanciones por cl\u00e1usula/pr\u00e1ctica para identificar qu\u00e9 marcos generan m\u00e1s conflicto ciudadano recurrente",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "nacional",
      "title": "TODO: DGSFP + BOE (responsabilidad civil obligatoria y normativa de mediaci\u00f3n/contrato) + supervisores",
      "details": "Falta mapa de obligaciones m\u00ednimas y costes recurrentes asociados por perfil de hogar, con trazabilidad normativa y v\u00edas de reclamaci\u00f3n",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "europeo",
      "title": "TODO: EU Transparency Register",
      "details": "Falta ingesta y modelo de entidades; linking cuando existan meetings/agendas publicas",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "europeo",
      "title": "TODO: EUR-Lex / Cellar (SPARQL/REST)",
      "details": "Falta conector UE legal; linking a expedientes y textos vigentes",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "nacional",
      "title": "TODO: Junta Electoral Central",
      "details": "Falta scraper y normalizacion",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "",
      "title": "TODO: Ley 12/2023 + normativa auton\u00f3mica de zonas tensionadas + fiscalidad asociada",
      "details": "Falta evaluaci\u00f3n trazable de impacto en oferta nueva (visados/inicios/terminadas por tipolog\u00eda y provincia) y cadena de decisi\u00f3n por norma/fragmento",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: Ley de presupuestos + acuerdos de gobierno CCAA + nombramientos + expedientes de gasto",
      "details": "Falta cadena reproducible `presupuesto -> centro gestor -> cargo designado -> expediente -> pago -> resultado asistencial` para atribuir qui\u00e9n propuso, aprob\u00f3, ejecut\u00f3 y fiscaliz\u00f3",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: Ley/BOE + SNS/CCAA (cartera y aportaci\u00f3n farmac\u00e9utica) + ministerio/servicios de salud",
      "details": "Falta vincular reglas de aportaci\u00f3n y financiaci\u00f3n a coste de bolsillo por perfil (renta, cronicidad, pensionista) y a variaciones territoriales",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: MITMA/Ministerio Transportes + CCAA + ayuntamientos/consorcios + operadores",
      "details": "Falta modelo reproducible por ciudad/\u00e1rea para medir impacto de reglas tarifarias/bonificaciones en coste mensual real por perfil de usuario",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: Ministerio/CCAA (listas de espera, plantilla, AP/hospitalaria) + presupuestos",
      "details": "Falta unir decisiones de gasto con outcomes (`espera`, `cobertura de plantilla`, `actividad`) para separar mala gesti\u00f3n de shocks de demanda",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "nacional",
      "title": "TODO: PLACSP + portales auton\u00f3micos + OCEX/Tribunal de Cuentas",
      "details": "Falta pipeline para detectar expedientes sanitarios con modificados, pr\u00f3rrogas, revisiones de precio y retrasos, con trazabilidad `organo -> mesa -> adjudicatario -> ejecuci\u00f3n`",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "europeo",
      "title": "TODO: Parlamento Europeo: votes XML/PDF + Open Data Portal",
      "details": "Falta ingesta de votos + mapeo a MEPs; KPI: % con actor resuelto",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: Portales presupuestarios auton\u00f3micos / IGAE cuando aplique",
      "details": "Falta conector y crosswalk de clasificaciones; preferir ejecuci\u00f3n cuando exista",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: Presupuestos y liquidaciones CCAA + Ministerio de Sanidad + IGAE",
      "details": "Falta modelo comparable por CCAA y programa para medir sustituci\u00f3n de gasto asistencial de plantilla por cap\u00edtulos de capital/externos, con series temporales y notas metodol\u00f3gicas",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "",
      "title": "TODO: SIEX/CUE + PAC + nitratos/suelos + planes hidrol\u00f3gicos + LESPRE lobo + medicamentos veterinarios",
      "details": "Falta publicar fichas comparables por norma (qu\u00e9 exige, a qui\u00e9n afecta, qu\u00e9 sanciona, qu\u00e9 alivios posteriores hubo, qui\u00e9n decidi\u00f3 cada cambio) con drill-down a evidencia primaria",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "nacional",
      "title": "TODO: Septuag\u00e9sima tercera pasada `status=403` con `packet5` + ejecuci\u00f3n serial por URL (`timeout 120`)",
      "details": "Estado base post AI-OPS-498: `missing_doc_links_actionable=2994`, `status404=563`, `status500=1337`, `status403=1078`, `status200=16`, `zero_doc_initiatives=890`. Palanca siguiente: repetir lane `status=403` con el mismo perfil nano-packet y ejecuci\u00f3n `serial_per_url_recovery` para sostener conversi\u00f3n incremental sin cuelgues. DoD: `retry_output_json_size_bytes > 0` y `candidate_urls > 0`; adem\u00e1s `downloaded_doc_links +1` o `missing_doc_links_actionable -1`. Siguiente comando: repetir la receta de `AI-OPS-498` (export `limit 60` + `packet5` + replay por URL + backfill limitado de excerpts/extractions).",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "",
      "title": "TODO: Suelo/urbanismo + evaluaci\u00f3n ambiental + CTE + reservas VPO + informes sectoriales",
      "details": "Falta publicar ranking `top_normas_cuello_botella_vivienda` con metodolog\u00eda expl\u00edcita (plazo, coste, litigiosidad, incertidumbre) y drill-down a art\u00edculos concretos",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "europeo",
      "title": "TODO: TED API (notices)",
      "details": "Falta ingesta; KPI: cobertura y trazabilidad por notice",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "municipal",
      "title": "TODO: TRLRHL + ordenanzas fiscales municipales + catastros/ayuntamientos",
      "details": "Falta comparador reproducible por municipio y perfil de hogar con trazabilidad `ordenanza -> pleno/alcald\u00eda -> liquidaci\u00f3n`",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "autonomico",
      "title": "TODO: TRLSRU + leyes urban\u00edsticas CCAA + ordenanzas municipales + Ley 21/2013",
      "details": "Falta mapa reproducible de plazos y bloqueos por fase (`planeamiento -> urbanizaci\u00f3n -> licencia -> obra`) con evidencia normativa y administrativa por territorio",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P0",
      "scope": "nacional",
      "title": "TODO: Webs/programas de partidos",
      "details": "No hay run live-clean de `programas_partidos` en el DB operativo actual; repetir pipeline con manifest HTTP y `records_loaded > 0` antes de `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-239/reports/programas-network-contract-closure-20260228.md`, `docs/etl/sprints/AI-OPS-239/evidence/programas_ingest_http_sample_20260228.json`, `docs/etl/sprints/AI-OPS-239/evidence/tracker_status_post_programas_network_contract_20260228.log`.",
      "source_ids": [
        "programas_partidos"
      ],
      "commands": [
        "python3 scripts/ingestar_parlamentario_es.py ingest --db <db> --source programas_partidos --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "outcomes",
      "title": "PARTIAL: AEMET OpenData",
      "details": "Done now: NO. Blocker: `aemet_opendata_series` en `strict-network` sigue bloqueado por contrato (`aemet_blocker=contract`, JSON invalido con payload vac\u00edo `payload_sig=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`, `run_id=263`, `run_records_loaded=0`), por lo que la fila permanece `PARTIAL`. Evidencia: `docs/etl/sprints/AI-OPS-14/evidence/blocker-probe-refresh.log`, `docs/etl/sprints/AI-OPS-14/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-14/exports/unblock_feasibility_matrix.csv`. Siguiente comando: `AEMET_API_KEY=<token> python3 scripts/ingestar_politicos_es.py ingest --db etl/data/staging/politicos-es.db --source aemet_opendata_series --url https://opendata.aemet.es/opendata/api/observacion/convencional/todas --snapshot-date 2026-02-17 --strict-network --timeout 30`.",
      "source_ids": [
        "aemet_opendata_series"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source aemet_opendata_series --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: AIR/Memoria normativa + evaluaciones ex post + \u00f3rganos consultivos + datos de outcomes",
      "details": "Done now: PARTIAL. Slice AI-OPS-119 abre pipeline reproducible de proporcionalidad (`liberty_proportionality_methodologies/liberty_proportionality_reviews`) con semilla versionada `liberty_proportionality_seed_v1.json`, validaci\u00f3n/import idempotente y gate ejecutable (`just parl-check-liberty-proportionality-gate`). Resultado actual: `reviews_total=8`, `target_fragments_coverage_pct=1.0`, `objective_defined_pct=1.0`, `indicator_defined_pct=0.75`, `alternatives_considered_pct=0.5`, `gate.passed=true` y `reviews_below_threshold_total=2` para priorizaci\u00f3n de revisi\u00f3n. Evidencia: `docs/etl/sprints/AI-OPS-119/reports/liberty-proportionality-direct-accountability-lane.md`, `docs/etl/sprints/AI-OPS-119/evidence/liberty_proportionality_import_20260223T182117Z.json`, `docs/etl/sprints/AI-OPS-119/evidence/liberty_proportionality_status_20260223T182117Z.json`, `docs/etl/sprints/AI-OPS-119/evidence/just_parl_liberty_restrictions_pipeline_20260223T182117Z.txt`. Falta sustituir semilla por ingesta continua AIR/ex-post y a\u00f1adir evidencia de eficacia observada fuera del piloto. Siguiente comando: `DB_PATH=<db> just parl-report-liberty-proportionality-status`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: Asamblea de Extremadura (dipslegis + paginacion)",
      "details": "Done now: NO para live-clean en GitHub Actions. PR gate `25687905013` fallo en `--strict-network` con `urllib.error.URLError: <urlopen error timed out>` para `asamblea_extremadura_diputados`; mantener evidencia previa como parcial hasta recuperar run reproducible. Evidencia: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source asamblea_extremadura_diputados --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "source_ids": [
        "asamblea_extremadura_diputados"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source asamblea_extremadura_diputados --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: Asamblea de Melilla: diputados (2023/2027)",
      "details": "Done now: NO para live-clean en GitHub Actions. Live ETL `25715374667` (`2026-05-12`) carg\u00f3 `26/26` solo por fallback (`max_net=0`, `max_any=26`) tras `network-error-fallback: RuntimeError: No se encontr\u00f3 dataset_PTS2_MIEMBROS en la p\u00e1gina`; por tanto no puede mantenerse como `DONE` hasta recuperar red real reproducible. Evidencia previa `2026-05-11` queda como hist\u00f3rica, no como verdad vigente. Evidencia actual: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260512.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source asamblea_melilla_diputados --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "source_ids": [
        "asamblea_melilla_diputados"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source asamblea_melilla_diputados --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "dinero",
      "title": "PARTIAL: BDNS/SNPSAP (filtrado por \u00f3rgano convocante/territorio)",
      "details": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `bdns_autonomico` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-13/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-13/evidence/bdns-api-discovery.log`, `docs/etl/sprints/AI-OPS-13/exports/unblock_feasibility_matrix.csv`.",
      "source_ids": [
        "bdns_autonomico"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source bdns_autonomico --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "dinero",
      "title": "PARTIAL: BDNS/SNPSAP: API",
      "details": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `bdns_api_subvenciones` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-13/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-13/evidence/bdns-api-discovery.log`, `docs/etl/sprints/AI-OPS-13/exports/unblock_feasibility_matrix.csv`.",
      "source_ids": [
        "bdns_api_subvenciones"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source bdns_api_subvenciones --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: BOCG + Diario de Sesiones (v\u00eda links en iniciativas Congreso/Senado)",
      "details": "Done now: PARTIAL. AI-OPS-380 consolid\u00f3 avance global fuera de `linked_to_votes` con dos pasadas `status=403` (`downloaded_doc_links +5`, `missing_doc_links_actionable -5`), AI-OPS-381/382 cerraron iteraciones sin delta neta, AI-OPS-383/384 drenaron/cerraron `unknown` (`downloaded_doc_links +114`, `missing_doc_links_actionable -114`, `unknown_status_urls 114->0`), AI-OPS-385/386 cerraron lanes globales `status=403/500` como `NO_DELTA_WITH_EVIDENCE`, AI-OPS-387 convirti\u00f3 `status=404` (`+42/-42`), AI-OPS-389 reactiv\u00f3 conversi\u00f3n por cohortes WAF (`+25/-25`), AI-OPS-390 cerr\u00f3 `status=500 + zero-doc` sin candidates, AI-OPS-391/392/393 mantuvieron conversi\u00f3n iterativa en lane `status=500` general (`+38/-38`, `+31/-31`, `+16/-16`), AI-OPS-394 confirm\u00f3 no-conversi\u00f3n en lane `status=404` general, AI-OPS-395/396 cerraron lanes `status=403/404 + zero-doc` sin delta, AI-OPS-397 convirti\u00f3 `status=429 + zero-doc` (`+12/-12`), AI-OPS-398 dren\u00f3 la lane `status=429` general (`+60/-60`), AI-OPS-399 dren\u00f3 la lane `status=599` general (`+8/-8`), AI-OPS-400 ejecut\u00f3 lane `status=500` timeboxed sin delta neta (`rc=124`, `packet20`), AI-OPS-401 cerr\u00f3 `status=403` timeboxed como `NO_DELTA_WITH_EVIDENCE`, AI-OPS-402 cerr\u00f3 `status=500` timeboxed como `NO_DELTA_WITH_EVIDENCE` (`rc=124`, salida retry vac\u00eda), AI-OPS-403 cerr\u00f3 `status=404` timeboxed como `NO_DELTA_WITH_EVIDENCE`, AI-OPS-404 cerr\u00f3 `status=403` multi-URL como `NO_DELTA_WITH_EVIDENCE`, AI-OPS-405 cerr\u00f3 `status=500` multi-URL como `NO_DELTA_WITH_EVIDENCE` (`rc=124`, salida retry vac\u00eda), AI-OPS-406 cerr\u00f3 `status=404` multi-URL como `NO_DELTA_WITH_EVIDENCE` (`rc=124`, salida retry vac\u00eda) y AI-OPS-407 cerr\u00f3 micro-packet `status=403` sin delta neta de cobertura (`rc=0`, `candidate_urls=10`, `fetched_ok=0`) con reclasificaci\u00f3n interna `status403->status404` (`-10/+10`). Estado actual (`etl/data/staging/politicos-es.db`, `2026-03-02`): `total_doc_links=9553`, `downloaded_doc_links=5946`, `missing_doc_links=3607`, `missing_doc_links_actionable=3416`, `doc_links_missing_fetch_status=0`, cobertura linkeada a voto `751/751` (`100%`). Congreso se mantiene cerrado (`812/812`) y el residual global sigue concentrado en Senado no linkeado (`3607/8741` faltantes; `downloaded_doc_links_pct=62.24%`, buckets accionables dominantes `status403=1475`, `status500=1345`, `status404=596`, `status200=0`, `status429=0`, `status599=0`, `unknown=0`). Evidencia: `docs/etl/sprints/AI-OPS-407/reports/senado-status403-general-micro-packet10-timebox-20260302.md`, `docs/etl/sprints/AI-OPS-407/evidence/senado_status403_general_conversion_delta_ai_ops_407_20260302T015128Z.json`, `docs/etl/sprints/AI-OPS-407/evidence/quality_initiatives_after_pass1_20260302T015128Z.json`. Siguiente comando: `python3 scripts/export_missing_initiative_doc_urls.py --db etl/data/staging/politicos-es.db --initiative-source-ids senado_iniciativas --only-actionable-missing --only-status 500 --max-urls-per-initiative 3 --limit 120 --format csv --out docs/etl/sprints/<SPRINT>/exports/senado_status500_general_actionable_multiurl_packet_<TS>.csv && sed -n \"1,11p\" docs/etl/sprints/<SPRINT>/exports/senado_status500_general_actionable_multiurl_packet_<TS>.csv > docs/etl/sprints/<SPRINT>/exports/senado_status500_general_actionable_multiurl_packet10_effective_<TS>.csv && timeout 180 python3 scripts/ingestar_parlamentario_es.py backfill-initiative-documents --db etl/data/staging/politicos-es.db --initiative-source-ids senado_iniciativas --include-unlinked --skip-link-backfill --doc-urls-file docs/etl/sprints/<SPRINT>/exports/senado_status500_general_actionable_multiurl_packet10_effective_<TS>.csv --archive-fallback --archive-fallback-http-statuses 403,404,429,500 --archive-timeout 3 --retry-http-statuses 500 --refetch-existing --timeout 8 --snapshot-date 2026-03-02`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: BOE (texto consolidado + versiones)",
      "details": "Done now: PARTIAL. Slice AI-OPS-115 cre\u00f3 la base reproducible `legal_norms` + `legal_norm_fragments` (`8` normas, `8` fragmentos). Slice AI-OPS-155 a\u00f1ade lineage normativo por versi\u00f3n/fecha con `legal_norm_lineage_edges` (`lineage_hints_total=8`, `lineage_edges_total=8`, `norms_with_lineage=8/8`, `lineage_primary_evidence_coverage_pct=1.0`), incluyendo alta autom\u00e1tica de `4` normas relacionadas referenciadas (`legal_norms_total=12`) en DB real (`status=ok`, `fk_violations_total=0`). Evidencia: `docs/etl/sprints/AI-OPS-155/reports/sanction-norms-lineage-seed-lane.md`, `docs/etl/sprints/AI-OPS-155/evidence/sanction_norms_seed_import_20260224T000517Z.json`, `docs/etl/sprints/AI-OPS-155/evidence/sanction_norms_seed_status_20260224T000517Z.json`, `docs/etl/sprints/AI-OPS-155/evidence/sqlite_fk_check_20260224T000533Z.json`. Falta backfill BOE continuo a cobertura completa por `articulo/disposicion/anexo` y lineage hist\u00f3rico multi-versi\u00f3n (sin dependencia de semilla cerrada). Siguiente comando: `DB_PATH=<db> SNAPSHOT_DATE=2026-02-24 just parl-sanction-norms-seed-pipeline`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: BOE + CCAA + ordenanzas + resoluciones administrativas/judiciales p\u00fablicas",
      "details": "Done now: PARTIAL. Slice AI-OPS-118 a\u00f1ade taxonom\u00eda reproducible `liberty_right_categories` (`6` derechos) y mapa operativo `restriction_map_by_right`; Slice AI-OPS-130 cierra el gap de categor\u00edas vac\u00edas y deja cobertura `6/6` (`right_categories_with_data_total=6`, `right_categories_with_data_pct=1.0`) con guardrail expl\u00edcito `rights_with_data_gate` en `report_liberty_restrictions_status.py` (`LIBERTY_RESTRICTIONS_RIGHTS_WITH_DATA_MIN`, default `1.0`). Evidencia: `docs/etl/sprints/AI-OPS-130/reports/liberty-right-map-coverage-gate.md`, `docs/etl/sprints/AI-OPS-130/evidence/liberty_restrictions_status_20260223T202028Z.json`, `docs/etl/sprints/AI-OPS-130/evidence/just_parl_check_liberty_focus_gate_20260223T202028Z.txt`, `docs/etl/sprints/AI-OPS-130/evidence/just_parl_check_liberty_focus_gate_fail_rc_20260223T202028Z.txt`. Falta extender alcance territorial (Estado+CCAA+municipal) y densidad de evidencia primaria multi-fuente. Siguiente comando: `DB_PATH=<db> just parl-report-liberty-restrictions-status`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: BOE + boletines auton\u00f3micos + BOP/ordenanzas + reglamentos sectoriales",
      "details": "Done now: PARTIAL. Slice AI-OPS-118 habilita censo base versionable para restricciones sobre el cat\u00e1logo legal ya cargado (`legal_norms/legal_norm_fragments`) y lo enlaza con `liberty_restriction_assessments` (`norms_with_irlc_total=8`, `fragments_with_irlc_total=8`). Evidencia: `docs/etl/sprints/AI-OPS-118/evidence/liberty_restrictions_status_20260223T181035Z.json`, `docs/etl/sprints/AI-OPS-118/reports/liberty-restrictions-foundation-lane.md`. Falta cobertura integral Estado+CCAA+municipal y rutina de refresh por bolet\u00edn/versiones. Siguiente comando: `DB_PATH=<db> SNAPSHOT_DATE=2026-02-23 just parl-liberty-restrictions-pipeline`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: BOE + normativa CCAA + ordenanzas municipales + jurisprudencia relevante",
      "details": "Done now: PARTIAL. Slice AI-OPS-118 publica metodolog\u00eda IRLC auditable (`irlc_v1`) con pesos expl\u00edcitos (`reach/intensity/due_process_risk/reversibility_risk/discretionality/compliance_cost`) y scoring reproducible por `fragment_id` en `liberty_restriction_assessments`; Slice AI-OPS-130 ampl\u00eda la semilla a `11` assessments manteniendo `8` fragmentos base, con gate de cobertura por derecho integrado en `focus_gate`. Evidencia: `docs/etl/sprints/AI-OPS-118/reports/liberty-restrictions-foundation-lane.md`, `docs/etl/sprints/AI-OPS-130/reports/liberty-right-map-coverage-gate.md`, `docs/etl/sprints/AI-OPS-130/evidence/liberty_restrictions_import_20260223T202028Z.json`, `docs/etl/sprints/AI-OPS-130/evidence/liberty_restrictions_status_20260223T202028Z.json`, `docs/etl/sprints/AI-OPS-130/evidence/just_parl_check_liberty_focus_gate_20260223T202028Z.txt`. Falta ampliar cobertura fuera del seed sancionador (CCAA/municipal/jurisprudencia) y pasar de semilla a ingesta continua. Siguiente comando: `DB_PATH=<db> SNAPSHOT_DATE=2026-02-23 just parl-liberty-restrictions-pipeline`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "legal",
      "title": "PARTIAL: BOE API",
      "details": "Done now: NO para live-clean en GitHub Actions. La ingesta historica BOE (`boe_api_legal`) existe (`records_loaded=298`, `policy_events_boe=298`), pero PR gate `25687905013` fallo en `--strict-network` con `urllib.error.URLError: <urlopen error timed out>`. Mantener como parcial hasta recuperar run reproducible de red real vigente. Evidencia: `docs/etl/sprints/AI-OPS-08/reports/waiver-burndown-apply-recompute.md`, `docs/etl/sprints/AI-OPS-08/evidence/waiver-burndown-apply-recompute-boe-ingest-replay.log`, `docs/etl/sprints/AI-OPS-08/evidence/waiver-burndown-apply-recompute-boe-policy-events-backfill.log`, `docs/etl/sprints/AI-OPS-08/reports/boe-tracker-mapping-hardening.md` y `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source boe_api_legal --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "source_ids": [
        "boe_api_legal"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source boe_api_legal --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "municipal",
      "title": "PARTIAL: BOP/portales municipales (movilidad, ORA/ZBE, civismo, residuos, ruido)",
      "details": "Done now: PARTIAL. Slice AI-OPS-117 a\u00f1ade tablas `sanction_municipal_ordinances` + `sanction_municipal_ordinance_fragments` y carga piloto reproducible con `20` ordenanzas (`normalized=3`, `identified=17`) y `3` fragmentos normalizados (`mapped_fragment_total=2`). Evidencia: `docs/etl/sprints/AI-OPS-117/reports/sanction-volume-pilot-lane.md`, `docs/etl/sprints/AI-OPS-117/evidence/sanction_volume_pilot_import_20260223T180041Z.json`, `docs/etl/sprints/AI-OPS-117/evidence/sanction_volume_pilot_status_20260223T180041Z.json`, `docs/etl/sprints/AI-OPS-117/evidence/sqlite_fk_check_20260223T180041Z.txt`. Falta completar normalizaci\u00f3n `20/20` a unidad sancionable (`articulo/conducta/rango/organo/recurso`) y elevar mappings municipales a cobertura operativa. Siguiente comando: `DB_PATH=<db> SNAPSHOT_DATE=2026-02-23 just parl-sanction-volume-pilot-pipeline`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: CCAA/ayuntamientos + organismos sancionadores + recursos estimados/desestimados",
      "details": "Done now: PARTIAL. Slice AI-OPS-120 abre lane reproducible de variaci\u00f3n territorial con `liberty_enforcement_methodologies/liberty_enforcement_observations` y reporte operativo `report_liberty_enforcement_variation_status.py` (m\u00e9tricas por `fragment_id`: `sanction_rate_per_1000`, `annulment_rate`, `resolution_delay_p90_days`). Resultado actual: `observations_total=16`, `fragments_with_multi_territory_total=8/8`, `high_variation_fragments_total=3`, `target_fragment_coverage_pct=1.0`, `gate.passed=true`. Evidencia: `docs/etl/sprints/AI-OPS-120/reports/liberty-territorial-variation-indirect-accountability-lane.md`, `docs/etl/sprints/AI-OPS-120/evidence/liberty_enforcement_import_20260223T183508Z.json`, `docs/etl/sprints/AI-OPS-120/evidence/liberty_enforcement_status_20260223T183508Z.json`, `docs/etl/sprints/AI-OPS-120/evidence/just_parl_liberty_restrictions_pipeline_20260223T183508Z.txt`. Falta sustituir piloto semilla por ingesta territorial continua y ampliar cobertura fuera de territorios de arranque. Siguiente comando: `DB_PATH=<db> just parl-report-liberty-enforcement-variation-status`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: Censo normativo + metadatos de publicaci\u00f3n + control de versiones",
      "details": "Done now: PARTIAL. Slice AI-OPS-118 public\u00f3 KPIs base y Slice AI-OPS-123 activ\u00f3 heartbeat append-only + ventana strict; Slice AI-OPS-131 a\u00f1adi\u00f3 `rights_with_data`; Slice AI-OPS-132 a\u00f1adi\u00f3 representatividad fuente/scope; Slice AI-OPS-133 a\u00f1adi\u00f3 doble cobertura (`IRLC + accountability`) por fuente/scope; Slice AI-OPS-134 a\u00f1adi\u00f3 quality-gate de evidencia primaria en accountability (`source_url + evidence_date + evidence_quote`) en status/heartbeat/window. Slice AI-OPS-135 cierra el hueco operativo del seed sancionador: `sanction_norms_seed_v1` exige y carga evidencia primaria por `responsibility_hint` (`source_url`, `evidence_date`, `evidence_quote`) en `legal_fragment_responsibilities`, se endurece el contrato default del foco (`LIBERTY_RESTRICTIONS_ACCOUNTABILITY_PRIMARY_EVIDENCE_MIN_PCT=1.0`, `LIBERTY_RESTRICTIONS_MIN_ACCOUNTABILITY_PRIMARY_EVIDENCE_EDGES=1`) y se extiende la observabilidad de estado sancionador con cobertura de evidencia primaria (`responsibility_primary_evidence_coverage_pct`). Corrida AI-OPS-135 (`20260223T210908Z`): `sanction_norms_seed_status` `ok` con `responsibilities_with_primary_evidence_total=15/15` y `responsibility_primary_evidence_coverage_pct=1.0`; `liberty_restrictions_status` `ok` con `accountability_edges_with_primary_evidence_total=15/15`, `accountability_edges_with_primary_evidence_pct=1.0`, `focus_gate.passed=true`; ventana strict pass `ok`; fail-path de foco con umbral imposible (`min_pct=1.1`, `min_edges=20`) devuelve `status=degraded` y `exit=2`. Evidencia: `docs/etl/sprints/AI-OPS-135/reports/liberty-accountability-primary-evidence-seed-hardening.md`, `docs/etl/sprints/AI-OPS-135/evidence/sanction_norms_seed_status_20260223T210908Z.json`, `docs/etl/sprints/AI-OPS-135/evidence/liberty_restrictions_status_20260223T210908Z.json`, `docs/etl/sprints/AI-OPS-135/evidence/liberty_restrictions_focus_gate_accountability_primary_evidence_fail_20260223T210908Z.json`, `docs/etl/sprints/AI-OPS-135/evidence/just_parl_check_liberty_focus_gate_accountability_primary_evidence_fail_rc_20260223T210908Z.txt`, `docs/etl/sprints/AI-OPS-135/evidence/liberty_restrictions_status_heartbeat_window_20260223T210908Z.json`, `docs/etl/sprints/AI-OPS-135/evidence/just_parl_test_sanction_norms_seed_20260223T210908Z.txt`, `docs/etl/sprints/AI-OPS-135/evidence/just_parl_test_liberty_restrictions_20260223T210908Z.txt`. Falta cobertura real fuera de seed inicial (State+CCAA+municipal) y sustituci\u00f3n progresiva de hints por evidencia primaria multi-fuente fuera del seed. Siguiente comando: `DB_PATH=<db> SNAPSHOT_DATE=2026-02-23 just parl-liberty-restrictions-pipeline`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: Congreso/Senado (iniciativas+enmiendas+votos) + BOE (firma/promulgacion)",
      "details": "Done now: PARTIAL. Cadena base por fragmento activada (`15` responsabilidades/`8` fragmentos), migraci\u00f3n documental `seed->non-seed` cerrada (`queue_rows_total=0`) y evidencia multipista operativa (`boe_publicacion`, `senado_diario`, `congreso_vote`, `senado_vote`, `other`). AI-OPS-167 cerr\u00f3 ejecuci\u00f3n al `100%` (`responsibilities_with_execution_evidence_total=15/15`). AI-OPS-168/169/170 elevaron cobertura parlamentaria-voto hasta `13/15`; AI-OPS-171 a\u00f1adi\u00f3 fallback conservador de t\u00edtulo LISOS (`title_rule:lisos_orden_social`) en `scripts/backfill_sanction_norms_parliamentary_evidence.py` y cerr\u00f3 cobertura parlamentaria a `15/15`, manteniendo voto en `13/15` (`responsibility_parliamentary_coverage_pct=1.0`, `responsibility_parliamentary_vote_coverage_pct=0.866667`, `responsibility_evidence_items_total=99`) con `execution=15/15`, `queue_rows_total=0` y `fk_violations_total=0`. Evidencia: `docs/etl/sprints/AI-OPS-170/reports/sanction-norms-vote-lineage-mixed-bridge-closure.md`, `docs/etl/sprints/AI-OPS-171/reports/sanction-norms-parliamentary-title-rule-closure.md`, `docs/etl/sprints/AI-OPS-171/evidence/sanction_norms_parliamentary_evidence_backfill_20260224T094041Z.json`, `docs/etl/sprints/AI-OPS-171/evidence/sanction_norms_vote_evidence_backfill_20260224T094041Z.json`, `docs/etl/sprints/AI-OPS-171/evidence/sanction_norms_seed_status_20260224T094041Z.json`, `docs/etl/sprints/AI-OPS-171/evidence/responsibility_parliamentary_vote_gap_20260224T094041Z.csv`, `docs/etl/sprints/AI-OPS-171/evidence/sqlite_fk_check_20260224T094041Z.txt`, `docs/etl/sprints/AI-OPS-171/evidence/just_parl_test_sanction_norms_seed_20260224T094041Z.txt`, `docs/etl/sprints/AI-OPS-171/evidence/just_parl_test_liberty_restrictions_20260224T094041Z.txt`. Gap residual: voto en `2` responsabilidades (`BOE-A-2000-15060`: `approve/enforce`, con `has_parliamentary_any=1` y `has_vote=0`). Falta adem\u00e1s escalar se\u00f1ales procedimentales desde piloto semilla a datos revisores oficiales (TEAR/TEAC/contencioso/defensores). Siguiente comando: `DB_PATH=<db> SANCTION_NORMS_VOTE_EVIDENCE_ROLES=approve,propose,enforce,delegate just parl-backfill-sanction-norms-vote-evidence && DB_PATH=<db> just parl-report-sanction-norms-seed-status`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: Congreso/Senado (votos y firmas) + BOE (promulgaci\u00f3n) + resoluciones/actos de enforcement",
      "details": "Done now: PARTIAL. Slice AI-OPS-119 activa cadena directa auditable por `fragment_id` mediante `report_liberty_direct_accountability_scores.py` (roles directos `propose/approve/enforce`) sobre responsabilidades legales cargadas. Slice AI-OPS-136 endurece ese contrato con quality-gate de evidencia primaria directa: m\u00e9tricas `direct_edges_with_primary_evidence_total/direct_edges_with_primary_evidence_pct` y gate `direct_primary_evidence_gate` (umbrales configurables en `justfile`: `LIBERTY_DIRECT_ACCOUNTABILITY_PRIMARY_EVIDENCE_MIN_PCT`, `LIBERTY_DIRECT_ACCOUNTABILITY_MIN_PRIMARY_EVIDENCE_EDGES`). Corrida AI-OPS-136 (`20260223T211623Z`): `fragments_with_direct_chain_total=8/8`, `direct_edges_total=19`, `direct_edges_with_primary_evidence_total=19`, `direct_edges_with_primary_evidence_pct=1.0`, `gate.passed=true`; fail-path con umbral imposible (`min_pct=1.1`, `min_edges=20`) devuelve `status=degraded`, `direct_primary_evidence_gate=false`, `exit=2`. Evidencia: `docs/etl/sprints/AI-OPS-136/reports/liberty-direct-accountability-primary-evidence-gate.md`, `docs/etl/sprints/AI-OPS-136/evidence/liberty_direct_accountability_scores_20260223T211623Z.json`, `docs/etl/sprints/AI-OPS-136/evidence/liberty_direct_accountability_gate_primary_evidence_fail_20260223T211623Z.json`, `docs/etl/sprints/AI-OPS-136/evidence/just_parl_check_liberty_direct_accountability_gate_primary_evidence_fail_rc_20260223T211623Z.txt`, `docs/etl/sprints/AI-OPS-136/evidence/just_parl_test_liberty_restrictions_20260223T211623Z.txt`. Falta enlazar actos directos de voto/firma/resoluci\u00f3n con evidencia primaria multi-fuente fechada y validaci\u00f3n temporal de cargo por persona. Siguiente comando: `DB_PATH=<db> SNAPSHOT_DATE=2026-02-23 just parl-report-liberty-direct-accountability-scores`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: Cortes de Aragon: diputados (XI)",
      "details": "GitHub Actions strict-network devuelve `HTTP 403`; mantener datos previos como evidencia parcial, pero no marcar `DONE` hasta recuperar run reproducible live-clean.",
      "source_ids": [
        "cortes_aragon_diputados"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source cortes_aragon_diputados --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "municipal",
      "title": "PARTIAL: DGT + AEAT + TGSS/ITSS + Interior + ayuntamientos",
      "details": "Done now: PARTIAL. Slice AI-OPS-116 crea cat\u00e1logo transversal en `sanction_infraction_types` (`10` tipolog\u00edas) y mapeo inicial en `sanction_infraction_type_mappings` (`10` mappings, cobertura a `fragment_id=8/10`, incluyendo lanes municipales `source_only` en espera de ordenanzas normalizadas). Evidencia: `docs/etl/sprints/AI-OPS-116/reports/sanction-data-catalog-lane.md`, `docs/etl/sprints/AI-OPS-116/evidence/sanction_data_catalog_import_20260223T174656Z.json`, `docs/etl/sprints/AI-OPS-116/evidence/sanction_data_catalog_status_20260223T174656Z.json`. Falta completar mappings municipales a `norma_fragmento_id` y a\u00f1adir m\u00e9tricas de volumen por tipolog\u00eda. Siguiente comando: `DB_PATH=<db> just parl-report-sanction-data-catalog-status`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "municipal",
      "title": "PARTIAL: DGT + ayuntamientos (movilidad/ORA/ZBE) + AEAT + TGSS + Interior (LO 4/2015)",
      "details": "Done now: PARTIAL. Slice AI-OPS-117 publica ranking reproducible `top_normas_sancion_ciudadana` desde `sanction_volume_observations` con metodolog\u00eda expl\u00edcita (`expediente_count` + `importe_total_eur`, proxy `incidence_per_1000_observed_cases`) y `status=ok` en reporte operativo. Evidencia: `docs/etl/sprints/AI-OPS-117/reports/sanction-volume-pilot-lane.md`, `docs/etl/sprints/AI-OPS-117/evidence/sanction_volume_pilot_import_20260223T180041Z.json`, `docs/etl/sprints/AI-OPS-117/evidence/sanction_volume_pilot_status_20260223T180041Z.json`, `docs/etl/sprints/AI-OPS-117/evidence/just_parl_sanction_citizen_pilot_pipeline_20260223T180041Z.txt`. Falta pasar de datos piloto a series reales por territorio y completar incidencia por `1.000 habitantes` (denominador poblacional). Siguiente comando: `DB_PATH=<db> SNAPSHOT_DATE=2026-02-23 just parl-sanction-volume-pilot-pipeline`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "municipal",
      "title": "PARTIAL: DGT anuarios + AEAT memorias sancionadoras + TGSS/ITSS + Interior (LO 4/2015) + ayuntamientos open data",
      "details": "Done now: PARTIAL. Slice AI-OPS-116 publica cat\u00e1logo operativo de fuentes en `sanction_volume_sources` (5 lanes: DGT/AEAT/TGSS-ITSS/Interior/municipal piloto), junto con contrato com\u00fan de m\u00e9tricas y tablas destino (`sanction_volume_observations`) para ingestas comparables. Evidencia: `docs/etl/sprints/AI-OPS-116/reports/sanction-data-catalog-lane.md`, `docs/etl/sprints/AI-OPS-116/evidence/sanction_data_catalog_import_20260223T174656Z.json`, `docs/etl/sprints/AI-OPS-116/evidence/sanction_data_catalog_status_20260223T174656Z.json`. Falta cargar observaciones reales por organismo/periodo (`expediente_count`, `importe_total`, `importe_medio`, `recurso_estado`). Siguiente comando: `DB_PATH=<db> SNAPSHOT_DATE=2026-02-23 just parl-sanction-data-catalog-pipeline`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "outcomes",
      "title": "PARTIAL: ESIOS/REE API (token)",
      "details": "Done now: PARTIAL. AI-OPS-296 cierra el gap de conector con `ree_esios_indicators` (config/registry + parser de payload REE `included[].attributes.values` + soporte de contenedor serializado `records` + rechazo de snapshots legacy `metric,value` + fallback sample reproducible) y lo integra en `backfill-indicators`/mapeo tracker. Corrida reproducible en DB principal desde muestra (`--from-file`) deja `status=ok`, `records_loaded=2`, `source_records_total=2`; el probe `--strict-network` al endpoint oficial sigue bloqueado de forma reproducible con `HTTP 500`, body HTML y cabecera `x-cdn: Imperva`, por lo que no aplica `DONE` en red real. Evidencia: `docs/etl/sprints/AI-OPS-296/reports/ree-esios-indicators-connector-partial-closure-20260228.md`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_ingest_status_latest.json`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_curl_headers_latest.txt`, `docs/etl/sprints/AI-OPS-296/evidence/e2e_tracker_status_main_db_latest.txt`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_main_db_ingestion_runs_latest.txt`. Siguiente comando: `ESIOS_API_TOKEN=<token> python3 scripts/ingestar_politicos_es.py ingest --db <db> --source ree_esios_indicators --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30 && python3 scripts/ingestar_politicos_es.py backfill-indicators --db <db> --source-ids ree_esios_indicators`.",
      "source_ids": [
        "ree_esios_indicators"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source ree_esios_indicators --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: Enriquecimiento de candidatos de replay (Wayback/Memento seeds) para URLs sin historial",
      "details": "AI-OPS-351 no reabre capacidad en `status=404` (`fresh_rows_total=0`) y mantiene estable el bloque residual de `no snapshot candidates` en consolidado hist\u00f3rico. Cola residual consolidada reciente (evidencia acumulada `AI-OPS-*`): `archive_no_snapshot_failures_total=441`, `unique_urls_total=316`; la lane sigue `PARTIAL` y requiere seed/captura alterna para URLs sin historial p\u00fablico. Evidencia: `docs/etl/sprints/AI-OPS-351/evidence/senado_status404_recent-window_packet_summary_20260301T074257Z.json`, `docs/etl/sprints/AI-OPS-351/evidence/senado_archive_gap_urls_20260301T074257Z.json`, `docs/etl/sprints/AI-OPS-351/exports/senado_archive_gap_urls_20260301T074257Z.csv`, `docs/etl/sprints/AI-OPS-340/reports/senado-status404-archive-family-probes-and-gap-export-20260301.md`. Siguiente comando: `python3 scripts/report_senado_cookie_lever_status.py --cookie-file <fresh_cookie_file> --strict --out docs/etl/sprints/<SPRINT>/evidence/senado_cookie_lever_status_<TS>.json && python3 scripts/export_senado_manual_capture_pending_targets.py --validity-json docs/etl/sprints/<SPRINT>/evidence/senado_manual_capture_validity_<TS>.json --out docs/etl/sprints/<SPRINT>/exports/senado_manual_capture_pending_targets_<TS>.csv --commands-out docs/etl/sprints/<SPRINT>/exports/senado_manual_capture_pending_targets_commands_<TS>.sh && bash docs/etl/sprints/<SPRINT>/exports/senado_manual_capture_pending_targets_commands_<TS>.sh`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "outcomes",
      "title": "PARTIAL: Eurostat (API/SDMX)",
      "details": "Done now: NO para live-clean. Live ETL `2026-05-11` carg\u00f3 solo fallback (`2/2`) tras `HTTP 404` en red real (`max_net=0`, `net/fallback_fetches=0/1`), as\u00ed que queda `PARTIAL` hasta corregir endpoint/query o confirmar contrato alternativo. Evidencia: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source eurostat_sdmx --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "source_ids": [
        "eurostat_sdmx"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source eurostat_sdmx --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "electoral",
      "title": "PARTIAL: Infoelectoral descargas/procesos",
      "details": "`infoelectoral_descargas` tiene evidencia de red en snapshot rico, pero `infoelectoral_procesos` no tiene run live-clean en el DB operativo actual. Cerrar solo cuando ambos source_id tengan `records_loaded > 0` o bloqueo documentado.",
      "source_ids": [
        "infoelectoral_descargas",
        "infoelectoral_procesos"
      ],
      "commands": [
        "python3 scripts/ingestar_infoelectoral_es.py ingest --db <db> --source infoelectoral_descargas --strict-network",
        "python3 scripts/ingestar_infoelectoral_es.py ingest --db <db> --source infoelectoral_procesos --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "ejecutivo",
      "title": "PARTIAL: La Moncloa: referencias + RSS",
      "details": "Done now: NO para live-clean actual. La evidencia hist\u00f3rica existe, pero el DB operativo actual no conserva runs de red para `moncloa_referencias` y `moncloa_rss_referencias`; repetir strict-network o documentar bloqueo antes de `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-07/reports/dual-entry-apply-recompute.md`, `docs/etl/sprints/AI-OPS-07/reports/boe-policy-events-mapping.md` y `docs/etl/sprints/AI-OPS-07/evidence/post_apply_waiveraware_checker_final.log`.",
      "source_ids": [
        "moncloa_referencias",
        "moncloa_rss_referencias"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source moncloa_referencias --strict-network",
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source moncloa_rss_referencias --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "territorial",
      "title": "PARTIAL: Nombramientos y estructura org\u00e1nica + reglamentos de delegaci\u00f3n + disciplina de grupo/partido + \u00f3rganos consultivos",
      "details": "Done now: PARTIAL. Slice AI-OPS-120 activa modelo causal de segundo orden con `liberty_indirect_methodologies/liberty_indirect_responsibility_edges` (roles `delegate/appoint/instruct/design`) y filtros expl\u00edcitos de atribuci\u00f3n (`attributable_confidence_min`, `attributable_max_causal_distance`) en `report_liberty_indirect_accountability_status.py`. Slice AI-OPS-137 endurece este lane con contrato expl\u00edcito persona/cargo + ventana temporal: `liberty_indirect_responsibility_edges` incorpora `actor_person_name`, `actor_role_title`, `appointment_start_date`, `appointment_end_date`; `validate_liberty_indirect_accountability_seed.py` exige coherencia de ventana (`appointment_end_date>=appointment_start_date`) y consistencia temporal con `evidence_date`; y `report_liberty_indirect_accountability_status.py` a\u00f1ade m\u00e9tricas `attributable_edges_with_actor_person_total`, `attributable_edges_with_valid_person_window_total`, `attributable_edges_with_valid_person_window_pct` y gate `indirect_person_window_gate` (umbrales configurables en `justfile`: `LIBERTY_INDIRECT_PERSON_WINDOW_MIN`, `LIBERTY_INDIRECT_MIN_PERSON_WINDOW_EDGES`). Corrida AI-OPS-137 (`20260223T212645Z`): `edges_total=12`, `attributable_edges_total=9`, `fragments_with_attributable_edges_total=7/8`, `attributable_edges_with_actor_person_total=9`, `attributable_edges_with_valid_person_window_total=9`, `attributable_edges_with_valid_person_window_pct=1.0`, `gate.passed=true`; fail-path contractual (`person_window_min=1.1`, `min_edges=20`) devuelve `status=degraded`, `indirect_person_window_gate=false`, `exit=2`. Evidencia: `docs/etl/sprints/AI-OPS-137/reports/liberty-indirect-accountability-person-window-gate.md`, `docs/etl/sprints/AI-OPS-137/evidence/liberty_indirect_import_20260223T212645Z.json`, `docs/etl/sprints/AI-OPS-137/evidence/liberty_indirect_status_20260223T212645Z.json`, `docs/etl/sprints/AI-OPS-137/evidence/liberty_indirect_gate_person_window_fail_20260223T212645Z.json`, `docs/etl/sprints/AI-OPS-137/evidence/liberty_indirect_gate_person_window_fail_rc_20260223T212645Z.txt`, `docs/etl/sprints/AI-OPS-137/evidence/liberty_restrictions_snapshot_20260223_ai_ops_137_20260223T212645Z.json`, `docs/etl/sprints/AI-OPS-137/evidence/just_parl_test_liberty_restrictions_20260223T212645Z.txt`. Falta sustituir seed por cobertura multi-fuente real (nombramientos/resoluciones oficiales) y resolver identidad persona/cargo fuera del piloto. Siguiente comando: `DB_PATH=<db> just parl-report-liberty-indirect-accountability-status`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: Norma habilitante + organismo instructor/resolutor + recaudaci\u00f3n + recursos",
      "details": "Done now: PARTIAL. Slice AI-OPS-115 abre trazabilidad `norma -> fragmento -> responsabilidad`; AI-OPS-156 a\u00f1ade evidencia multipista; AI-OPS-158/159/160/161 cierran cobertura documental y migraci\u00f3n `seed -> non-seed` (`seed=0`, `non-seed=15`, cola vac\u00eda). Slice AI-OPS-162 incorpora primera se\u00f1al parlamentaria reproducible (`senado_diario=2`) ligada a normas sancionadoras (`BOE-A-2003-23186`, `BOE-A-2015-3442`) con status lane `ok` y nuevos KPIs de cobertura parlamentaria (`responsibility_evidence_items_parliamentary_total=2`, `responsibility_parliamentary_coverage_pct=0.133333`). Evidencia: `docs/etl/sprints/AI-OPS-161/reports/sanction-norms-seed-source-record-upgrade-apply.md`, `docs/etl/sprints/AI-OPS-162/reports/sanction-norms-parliamentary-evidence-backfill.md`, `docs/etl/sprints/AI-OPS-162/evidence/sanction_norms_parliamentary_evidence_backfill_20260224T010415Z.json`, `docs/etl/sprints/AI-OPS-162/evidence/sanction_norms_seed_status_20260224T010415Z.json`, `docs/etl/sprints/AI-OPS-162/evidence/sanction_norms_seed_source_record_upgrade_queue_20260224T010415Z.json`. Falta integrar niveles `acto sancionador -> cobro -> recurso/resultado` por expediente y elevar cobertura parlamentaria por rol/acto (votos + enmiendas + ejecuci\u00f3n). Siguiente comando: `DB_PATH=<db> just parl-report-sanction-norms-seed-status`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "dinero",
      "title": "PARTIAL: PLACSP (filtrado por \u00f3rganos auton\u00f3micos)",
      "details": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `placsp_autonomico` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-11/evidence/placsp-strict-refresh.log`, `docs/etl/sprints/AI-OPS-11/evidence/post-strict-status.log`, `docs/etl/sprints/AI-OPS-11/evidence/post-strict-gate.log`, `docs/etl/sprints/AI-OPS-11/exports/placsp_waiver_decision.csv`.",
      "source_ids": [
        "placsp_autonomico"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source placsp_autonomico --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "dinero",
      "title": "PARTIAL: PLACSP: sindicaci\u00f3n/ATOM (CODICE)",
      "details": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `placsp_sindicacion` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-11/evidence/placsp-strict-refresh.log`, `docs/etl/sprints/AI-OPS-11/evidence/post-strict-status.log`, `docs/etl/sprints/AI-OPS-11/evidence/post-strict-gate.log`, `docs/etl/sprints/AI-OPS-11/exports/placsp_waiver_decision.csv`.",
      "source_ids": [
        "placsp_sindicacion"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source placsp_sindicacion --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: Parlament de les Illes Balears: diputats (listado + fichas via webGTP)",
      "details": "Done now: NO para live-clean en GitHub Actions. PR gate `25687905013` fallo en `--strict-network` con `urllib.error.URLError: <urlopen error timed out>` para `parlament_balears_diputats`; mantener evidencia previa como parcial hasta recuperar run reproducible. Evidencia: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlament_balears_diputats --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "source_ids": [
        "parlament_balears_diputats"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlament_balears_diputats --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: Parlamento Vasco (listado ACT)",
      "details": "GitHub Actions strict-network agota tiempo en `parlamento_vasco_parlamentarios`; requiere retry reproducible o hardening de timeout/endpoints antes de volver a `DONE`.",
      "source_ids": [
        "parlamento_vasco_parlamentarios"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlamento_vasco_parlamentarios --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: Parlamento de Andalucia (listado + fichas)",
      "details": "GitHub Actions strict-network ya no encuentra diputados actuales (`codmie/nlegis`); requiere reparar parser o endpoint antes de volver a `DONE`.",
      "source_ids": [
        "parlamento_andalucia_diputados"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlamento_andalucia_diputados --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: Parlamento de Galicia: deputados (fichas HTML)",
      "details": "Done now: NO. Blocker: `parlamento_galicia_deputados` en `strict-network` sigue bloqueado con HTTP 403 (`run_id=265`, `run_records_loaded=0`), por lo que la fila permanece `PARTIAL`. Evidencia: `docs/etl/sprints/AI-OPS-14/evidence/blocker-probe-refresh.log`, `docs/etl/sprints/AI-OPS-14/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-14/exports/unblock_feasibility_matrix.csv`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db etl/data/staging/politicos-es.db --source parlamento_galicia_deputados --snapshot-date 2026-02-17 --strict-network --timeout 30`.",
      "source_ids": [
        "parlamento_galicia_deputados"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlamento_galicia_deputados --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "autonomico",
      "title": "PARTIAL: Parlamento de Navarra: parlamentarios forales (fichas HTML)",
      "details": "Done now: NO para live-clean. Existe replay manual `from-file` (`50/50 registros validos`), pero falta run de red real vigente o bloqueo reproducible actualizado antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-14/evidence/blocker-probe-refresh.log`, `docs/etl/sprints/AI-OPS-14/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-14/exports/unblock_feasibility_matrix.csv`.",
      "source_ids": [
        "parlamento_navarra_parlamentarios_forales"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlamento_navarra_parlamentarios_forales --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: RDL 6/2015 (Tr\u00e1fico) + RD 320/1994 + LGT 58/2003 + RD 2063/2004 + LGSS/LISOS + LO 4/2015 + ordenanzas municipales",
      "details": "Done now: PARTIAL. Slice AI-OPS-115 publica cat\u00e1logo operativo en `sanction_norm_catalog` + `sanction_norm_fragment_links` con `8` marcos iniciales (BOE IDs semilla), `organismo_competente`, hip\u00f3tesis de incidencia y `evidence_required_json`; import reproducible y validado con tests. Evidencia: `docs/etl/sprints/AI-OPS-115/reports/sanction-norms-seed-lane.md`, `docs/etl/sprints/AI-OPS-115/evidence/sanction_norms_seed_import_20260223T173448Z.json`, `docs/etl/sprints/AI-OPS-115/evidence/just_parl_test_sanction_norms_seed_20260223T173633Z.txt`. Falta ampliar cobertura (ordenanzas municipales y fragmentaci\u00f3n completa por norma/territorio). Siguiente comando: `DB_PATH=<db> just parl-import-sanction-norms-seed`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: Retry acotado + lever de cookie fresca + fallback alternativo",
      "details": "Gap actualizado: la lane queda operativamente cerrada en t\u00e9rminos de conversi\u00f3n de packet (`AI-OPS-355`: `candidate_urls=24`, `fetched_ok=24`, `runtime=6.64s`, `failures=0`) y habilita los avances posteriores en `403` y `status=0` hasta AI-OPS-360. El residual global persiste fuera de `404`, pero el riesgo de throughput/runtime de esta lane queda resuelto. Evidencia: `docs/etl/sprints/AI-OPS-355/reports/senado-manual-cookie-packet25-runtime-and-delta-20260301.md`, `docs/etl/sprints/AI-OPS-355/evidence/senado_status404_manual_cookie_archive_retry_packet25_20260301T084757Z.json`, `docs/etl/sprints/AI-OPS-357/evidence/senado_status403_packet50_conversion_delta_ai_ops_357_20260301T085854Z.json`, `docs/etl/sprints/AI-OPS-360/evidence/senado_status0_packet50_refetch_third_pass_delta_ai_ops_360_20260301T091018Z.json`. Siguiente comando: `python3 scripts/export_missing_initiative_doc_urls.py --db etl/data/staging/politicos-es.db --initiative-source-ids senado_iniciativas --only-actionable-missing --only-linked-to-votes --only-status 403 --limit 50 --format csv --out docs/etl/sprints/<SPRINT>/exports/senado_status403_linked_packet50_<TS>.csv && python3 scripts/ingestar_parlamentario_es.py backfill-initiative-documents --db etl/data/staging/politicos-es.db --initiative-source-ids senado_iniciativas --skip-link-backfill --doc-urls-file docs/etl/sprints/<SPRINT>/exports/senado_status403_linked_packet50_<TS>.csv --archive-fallback --archive-fallback-http-statuses 403,404 --retry-forbidden --refetch-existing --cookie-file <fresh_cookie_file> --limit-initiatives 50 --max-docs-per-initiative 1 --timeout 12`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: Senado OpenData XML (grupos + fichas)",
      "details": "GitHub Actions strict-network devuelve `HTTP 403` en `senado_senadores`; mantener datos previos como evidencia parcial, pero no marcar `DONE` hasta recuperar run reproducible live-clean.",
      "source_ids": [
        "senado_senadores"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source senado_senadores --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "nacional",
      "title": "PARTIAL: Sesi\u00f3n renovada + cookie file sanitizado y versionado",
      "details": "Gap actualizado (AI-OPS-235 + AI-OPS-236 + AI-OPS-299 + AI-OPS-300 + AI-OPS-301 + AI-OPS-302 + AI-OPS-303 + AI-OPS-304): la lane ya cubre (a) cola reproducible de captura (`scripts/export_senado_manual_capture_targets.py`), (b) gate de progreso (`scripts/report_senado_manual_capture_target_progress.py`), (c) runner condicional de retry (`scripts/run_senado_manual_capture_retry_cycle.py`), (d) paquetizaci\u00f3n operativa de pendientes (`scripts/export_senado_manual_capture_pending_targets.py`) y (e) ciclo unificado de iteraci\u00f3n con delta (`scripts/run_senado_manual_capture_iteration_cycle.py`). AI-OPS-304 a\u00f1ade una palanca controlable de scraping (`manual_capture_playwright --headless`) sobre los 2 targets `unmatched`, cerrando el hueco estructural de cobertura: `matched_targets_total 6->8`, `unmatched_targets_total 2->0`, `coverage_pct 0.75->1.0`, `capture_files_total 2->4` (baseline AI-OPS-301 -> AI-OPS-304). Estado actual en DB principal (`2026-02-28`): `usable_targets_total=0`; cola pendiente sigue en `pending_targets_total=8`, ahora `pending_unmatched_total=0` y `pending_access_denied_total=8`; check estricto de iteraci\u00f3n `rc=4`. El bloqueo externo persiste: sin captura usable no procede retry de descarga. Evidencia: `docs/etl/sprints/AI-OPS-304/reports/senado-manual-capture-headless-probe-coverage-lane-20260228.md`, `docs/etl/sprints/AI-OPS-304/evidence/senado_manual_capture_target_progress_latest.json`, `docs/etl/sprints/AI-OPS-304/evidence/senado_manual_capture_target_progress_delta_latest.json`, `docs/etl/sprints/AI-OPS-304/evidence/senado_manual_capture_headless_probe_summary_latest.json`, `docs/etl/sprints/AI-OPS-304/evidence/senado_manual_capture_iteration_cycle_latest.json`, `docs/etl/sprints/AI-OPS-304/evidence/just_parl_check_senado_manual_capture_iteration_cycle_rc_latest.txt`, `docs/etl/sprints/AI-OPS-304/evidence/tracker_status_latest.log`. Siguiente comando: `bash docs/etl/sprints/AI-OPS-304/exports/senado_manual_capture_pending_targets_commands_latest.sh && just parl-run-senado-manual-capture-iteration-cycle && just parl-check-senado-manual-capture-iteration-cycle`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "territorial",
      "title": "PARTIAL: Tablas de responsabilidades + nombramientos + trazas de expediente/recurso",
      "details": "Done now: PARTIAL. Slice AI-OPS-119 publica score auditable institucional `responsibility_score` (normalizado 0-100) con pesos por rol. Slice AI-OPS-138 abre scoring personal reproducible con `scripts/report_liberty_personal_accountability_scores.py`, combinando edges directos con `person_id` y cadena indirecta atribuible con contexto persona/cargo+ventana temporal (`actor_person_name`, `actor_role_title`, `appointment_start_date/end_date`) y fuerza probatoria expl\u00edcita (`edge_confidence * primary_evidence_factor`). Slice AI-OPS-139 endurece el contrato para eliminar sesgo por visualizaci\u00f3n (`top_n` no altera `persons_scored_total`). Slice AI-OPS-140 a\u00f1ade observabilidad/gate de resoluci\u00f3n de identidad indirecta (`indirect_identity_resolution_pct`, `indirect_identity_resolution_gate`) con muestra de no resueltos (`indirect_identity_unresolved_sample`). Slice AI-OPS-141 convierte ese backlog en cola operativa reproducible (`report_liberty_person_identity_resolution_queue.py`). Slice AI-OPS-142 cierra el loop con aplicaci\u00f3n reproducible de alias en DB (`person_name_aliases`) v\u00eda seed validado/importado. Slice AI-OPS-143 a\u00f1ade contrato expl\u00edcito de procedencia (`source_kind`, `evidence_date`, `evidence_quote`) y separa alias `manual_seed` vs `official_*` en scoring/queue. Slice AI-OPS-144 a\u00f1ade backlog accionable de migraci\u00f3n `manual -> official` (manual-upgrade queue + CSV), gate de `manual_alias_share` en la cola, y guardrail de no-downgrade de procedencia en import. Slice AI-OPS-145 endurece el guardrail para impedir retarget manual sobre alias ya `official_*` (`aliases_retarget_downgrade_prevented`) y alinea scoring personal con la cola a\u00f1adiendo m\u00e9tricas/gate de `manual_alias_share`. Slice AI-OPS-146 a\u00f1ade gate expl\u00edcito de evidencia oficial para alias `official_*` en scoring/queue (`official_alias_rows_with_evidence_total`, `official_alias_rows_missing_evidence_total`, `official_alias_evidence_coverage_pct`, `official_alias_evidence_gate`) con umbrales dedicados en `justfile`. Slice AI-OPS-147 a\u00f1ade gate expl\u00edcito de cuota oficial (`official_alias_share_pct`, `official_alias_share_gate`) para hacer exigible la migraci\u00f3n `manual_seed -> official_*` en ambas lanes. Slice AI-OPS-148 a\u00f1ade trazabilidad de `official_*` a `source_records` (`source_record_pk`) en schema/import y gate expl\u00edcito en scoring/queue (`official_alias_source_record_coverage_pct`, `official_alias_source_record_gate`). Slice AI-OPS-149 operacionaliza la remediaci\u00f3n de gaps `official_*` con colas accionables dedicadas (`official_alias_evidence_upgrade_queue_rows`, `official_alias_source_record_upgrade_queue_rows`) y checks de visibilidad de backlog (`official_alias_evidence_backlog_visible`, `official_alias_source_record_backlog_visible`) exportables a CSV desde `justfile`. Slice AI-OPS-150 cierra el loop review/apply con `scripts/export_liberty_person_identity_official_upgrade_review_queue.py` y `scripts/apply_liberty_person_identity_official_upgrade_reviews.py` (CSV de decisiones reproducible + guardrail anti-downgrade). Slice AI-OPS-151 endurece el apply con autoresoluci\u00f3n de `source_record_pk` v\u00eda lookup en `source_records` usando `--db`, m\u00e9tricas expl\u00edcitas de resoluci\u00f3n (`source_record_pk_auto_resolved`, `source_record_pk_auto_resolve_missed`) y wiring en `justfile`. Corrida AI-OPS-149 (`20260223T231638Z`): pass observabilidad (`official_alias_rows_total=0`, colas `0/0`) y fail-path contractual (`official_alias_rows_total=1`, `official_alias_rows_missing_evidence_total=1`, `official_alias_rows_missing_source_record_total=1`) con colas `1/1`, checks de visibilidad `true` y `exit=2`; suites en verde (`Ran 8`, `Ran 89`). Corrida AI-OPS-150 (`20260223T232635Z`): loop review/apply operativo con `rows_total=9`, `approved_rows=1`, `updated_rows=1`, reducci\u00f3n de cola manual `9 -> 8`, `official_alias_rows_total=1`, `official_alias_rows_missing_source_record_total=1`; suites en verde (`Ran 3`, `Ran 92`). Corrida AI-OPS-151 (`20260223T232954Z`): dry-run contractual de autoresoluci\u00f3n con lookup real (`source_record_lookup.rows_total=173070`, `source_record_pk_auto_resolved=1`, `validation.valid=true`); suites en verde (`Ran 4`, `Ran 93`). Evidencia: `docs/etl/sprints/AI-OPS-138/reports/liberty-personal-accountability-scoring-lane.md`, `docs/etl/sprints/AI-OPS-139/reports/liberty-personal-accountability-topn-contract.md`, `docs/etl/sprints/AI-OPS-140/reports/liberty-personal-identity-resolution-gate.md`, `docs/etl/sprints/AI-OPS-141/reports/liberty-person-identity-resolution-queue-lane.md`, `docs/etl/sprints/AI-OPS-142/reports/liberty-person-identity-apply-lane.md`, `docs/etl/sprints/AI-OPS-143/reports/liberty-person-identity-provenance-gate.md`, `docs/etl/sprints/AI-OPS-144/reports/liberty-person-identity-manual-upgrade-backlog-gate.md`, `docs/etl/sprints/AI-OPS-145/reports/liberty-person-identity-source-guard-personal-gate.md`, `docs/etl/sprints/AI-OPS-146/reports/liberty-person-identity-official-evidence-gate.md`, `docs/etl/sprints/AI-OPS-147/reports/liberty-person-identity-official-alias-share-gate.md`, `docs/etl/sprints/AI-OPS-148/reports/liberty-person-identity-official-source-record-gate.md`, `docs/etl/sprints/AI-OPS-149/reports/liberty-person-identity-official-gap-actionable-queues.md`, `docs/etl/sprints/AI-OPS-150/reports/liberty-person-identity-official-upgrade-review-apply-loop.md`, `docs/etl/sprints/AI-OPS-151/reports/liberty-person-identity-source-record-autoresolve.md`, `docs/etl/sprints/AI-OPS-149/evidence/liberty_person_identity_resolution_queue_20260223T231638Z.json`, `docs/etl/sprints/AI-OPS-149/evidence/liberty_person_identity_resolution_queue_official_gap_fail_20260223T231638Z.json`, `docs/etl/sprints/AI-OPS-149/evidence/liberty_person_identity_official_gap_queue_contract_summary_20260223T231638Z.json`, `docs/etl/sprints/AI-OPS-149/evidence/liberty_person_identity_resolution_queue_official_gap_fail_rc_20260223T231638Z.txt`, `docs/etl/sprints/AI-OPS-149/evidence/unittest_liberty_person_identity_resolution_queue_20260223T231638Z.txt`, `docs/etl/sprints/AI-OPS-149/evidence/just_parl_test_liberty_restrictions_20260223T231638Z.txt`, `docs/etl/sprints/AI-OPS-149/exports/liberty_person_identity_official_alias_evidence_upgrade_queue_20260223T231638Z.csv`, `docs/etl/sprints/AI-OPS-149/exports/liberty_person_identity_official_alias_source_record_upgrade_queue_20260223T231638Z.csv`, `docs/etl/sprints/AI-OPS-150/evidence/liberty_person_identity_official_upgrade_review_apply_contract_summary_20260223T232635Z.json`, `docs/etl/sprints/AI-OPS-151/evidence/liberty_person_identity_official_upgrade_apply_autoresolve_20260223T232954Z.json`, `docs/etl/sprints/AI-OPS-151/evidence/liberty_person_identity_official_upgrade_source_record_autoresolve_contract_summary_20260223T232954Z.json`. Falta reemplazar progresivamente alias `manual_seed` por alias `official_*` (nombramientos/resoluciones/expedientes) y ampliar cobertura fuera del piloto. Siguiente comando: `DB_PATH=<db> just parl-export-liberty-person-identity-official-upgrade-review-queue && DB_PATH=<db> LIBERTY_PERSON_IDENTITY_OFFICIAL_UPGRADE_REVIEWS_IN=<review_csv> LIBERTY_PERSON_IDENTITY_SEED_REVIEW_OUT=<seed_out_json> just parl-apply-liberty-person-identity-official-upgrade-reviews && DB_PATH=<db> LIBERTY_PERSONAL_MANUAL_ALIAS_SHARE_MAX=<target> LIBERTY_PERSONAL_INDIRECT_NON_MANUAL_ALIAS_RESOLUTION_MIN_PCT=<target> LIBERTY_PERSONAL_OFFICIAL_ALIAS_SHARE_MIN_PCT=<target> LIBERTY_PERSONAL_MIN_ALIAS_ROWS_FOR_OFFICIAL_SHARE_GATE=<target> LIBERTY_PERSONAL_OFFICIAL_ALIAS_EVIDENCE_MIN_PCT=<target> LIBERTY_PERSONAL_MIN_OFFICIAL_ALIAS_ROWS_FOR_EVIDENCE_GATE=<target> LIBERTY_PERSONAL_OFFICIAL_ALIAS_SOURCE_RECORD_MIN_PCT=<target> LIBERTY_PERSONAL_MIN_OFFICIAL_ALIAS_ROWS_FOR_SOURCE_RECORD_GATE=<target> just parl-check-liberty-personal-accountability-gate && DB_PATH=<db> LIBERTY_PERSON_IDENTITY_MANUAL_ALIAS_SHARE_MAX=<target> LIBERTY_PERSON_IDENTITY_NON_MANUAL_ALIAS_RESOLUTION_MIN_PCT=<target> LIBERTY_PERSON_IDENTITY_OFFICIAL_ALIAS_SHARE_MIN_PCT=<target> LIBERTY_PERSON_IDENTITY_MIN_ALIAS_ROWS_FOR_OFFICIAL_SHARE_GATE=<target> LIBERTY_PERSON_IDENTITY_OFFICIAL_ALIAS_EVIDENCE_MIN_PCT=<target> LIBERTY_PERSON_IDENTITY_MIN_OFFICIAL_ALIAS_ROWS_FOR_EVIDENCE_GATE=<target> LIBERTY_PERSON_IDENTITY_OFFICIAL_ALIAS_SOURCE_RECORD_MIN_PCT=<target> LIBERTY_PERSON_IDENTITY_MIN_OFFICIAL_ALIAS_ROWS_FOR_SOURCE_RECORD_GATE=<target> just parl-check-liberty-person-identity-resolution-gate`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "municipal",
      "title": "PARTIAL: Tr\u00e1fico/movilidad + tributario/SS + seguridad ciudadana + ordenanzas c\u00edvicas/residuos",
      "details": "Done now: PARTIAL. Slice AI-OPS-117 publica `norm_dossiers` (`5` fichas) con `conducta` (tipolog\u00edas), `volumen`, `importe`, `base legal` (`norma -> fragmentos`) y lanes de evidencia (`source_lanes`/enlaces municipales) en `report_sanction_volume_pilot_status.py`. Evidencia: `docs/etl/sprints/AI-OPS-117/reports/sanction-volume-pilot-lane.md`, `docs/etl/sprints/AI-OPS-117/evidence/sanction_volume_pilot_status_20260223T180041Z.json`, `docs/etl/sprints/AI-OPS-117/evidence/just_parl_sanction_citizen_pilot_pipeline_20260223T180041Z.txt`. Falta enriquecer perfil afectado y sustituir valores piloto por observaciones oficiales recurrentes por fuente/periodo. Siguiente comando: `DB_PATH=<db> just parl-report-sanction-volume-pilot-status`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "tracker_item",
      "priority": "P1",
      "scope": "",
      "title": "PARTIAL: \u00d3rganos revisores (TEAR/TEAC, contencioso, defensores) + datos de estimaci\u00f3n/anulaci\u00f3n",
      "details": "Done now: PARTIAL. Slice AI-OPS-116 publica contrato KPI de justicia procedimental en `sanction_procedural_kpi_definitions` (`3` KPIs: recurso estimado, anulaci\u00f3n formal, retraso p90) y tabla operativa `sanction_procedural_metrics` para series observadas. Evidencia: `docs/etl/sprints/AI-OPS-116/reports/sanction-data-catalog-lane.md`, `docs/etl/sprints/AI-OPS-116/evidence/sanction_data_catalog_import_20260223T174656Z.json`, `docs/etl/sprints/AI-OPS-116/evidence/sanction_data_catalog_status_20260223T174656Z.json`. Falta ingesta de datos revisores (TEAR/TEAC/contencioso/defensores) para poblar m\u00e9tricas y pasar de contrato a resultados. Siguiente comando: `DB_PATH=<db> just parl-report-sanction-data-catalog-status`.",
      "source_ids": [],
      "commands": []
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: bdns_api_subvenciones",
      "details": "loaded=3 target=10",
      "source_ids": [
        "bdns_api_subvenciones"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source bdns_api_subvenciones --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: bdns_autonomico",
      "details": "loaded=2 target=3",
      "source_ids": [
        "bdns_autonomico"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source bdns_autonomico --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: dir3_unidades_age",
      "details": "loaded=3 target=1000",
      "source_ids": [
        "dir3_unidades_age"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source dir3_unidades_age --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: parlamento_andalucia_diputados",
      "details": "loaded=2 target=90",
      "source_ids": [
        "parlamento_andalucia_diputados"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlamento_andalucia_diputados --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: parlamento_galicia_deputados",
      "details": "loaded=3 target=50",
      "source_ids": [
        "parlamento_galicia_deputados"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlamento_galicia_deputados --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: parlamento_navarra_parlamentarios_forales",
      "details": "loaded=3 target=30",
      "source_ids": [
        "parlamento_navarra_parlamentarios_forales"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlamento_navarra_parlamentarios_forales --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: parlamento_vasco_parlamentarios",
      "details": "loaded=2 target=60",
      "source_ids": [
        "parlamento_vasco_parlamentarios"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlamento_vasco_parlamentarios --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: senado_iniciativas",
      "details": "loaded=0 target=1",
      "source_ids": [
        "senado_iniciativas"
      ],
      "commands": [
        "python3 scripts/ingestar_parlamentario_es.py ingest --db <db> --source senado_iniciativas --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: senado_senadores",
      "details": "loaded=2 target=250",
      "source_ids": [
        "senado_senadores"
      ],
      "commands": [
        "python3 scripts/ingestar_politicos_es.py ingest --db <db> --source senado_senadores --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    },
    {
      "kind": "under_threshold",
      "priority": "P1",
      "scope": "",
      "title": "Por debajo del umbral minimo: senado_votaciones",
      "details": "loaded=0 target=1",
      "source_ids": [
        "senado_votaciones"
      ],
      "commands": [
        "python3 scripts/ingestar_parlamentario_es.py ingest --db <db> --source senado_votaciones --strict-network",
        "python3 scripts/e2e_tracker_status.py --db <db> --tracker docs/etl/e2e-scrape-load-tracker.md"
      ]
    }
  ],
  "missing_source_ids": [
    "infoelectoral_descargas",
    "infoelectoral_procesos"
  ],
  "sources": [
    {
      "source_id": "asamblea_ceuta_diputados",
      "source_name": "Asamblea de Ceuta - Miembros (Legislatura 2023/2027)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Asamblea de Ceuta",
      "role_title": "Diputado/a",
      "format": "json",
      "default_url": "https://www.ceuta.es/gobiernodeceuta/index.php/el-gobierno/la-asamblea",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Asamblea de Ceuta)",
      "tracker_fuentes_objetivo": "Asamblea de Ceuta: miembros (2023/2027)",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 25,
      "max_loaded_any": 25,
      "max_loaded_network": 25,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:35:01+00:00",
      "latest_snapshot": "2026-05-14T05:35:01+00:00",
      "last_message": "Ingesta completada: 25/25 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 25,
        "target": 20,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 25,
        "counts": {
          "mandates": 25,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 20,
        "fallback_file": "etl/data/raw/samples/asamblea_ceuta_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/asamblea_ceuta_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.ceuta.es/gobiernodeceuta/index.php/el-gobierno/la-asamblea",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "asamblea_extremadura_diputados",
      "source_name": "Asamblea de Extremadura - Diputadas/os (XII Legislatura)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Asamblea de Extremadura",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://www.asambleaex.es/dipslegis",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Representantes y mandatos (Asamblea de Extremadura)",
      "tracker_fuentes_objetivo": "Asamblea de Extremadura (dipslegis + paginacion)",
      "tracker_block_note": "Done now: NO para live-clean en GitHub Actions. PR gate `25687905013` fallo en `--strict-network` con `urllib.error.URLError: <urlopen error timed out>` para `asamblea_extremadura_diputados`; mantener evidencia previa como parcial hasta recuperar run reproducible. Evidencia: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source asamblea_extremadura_diputados --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 65,
      "max_loaded_any": 65,
      "max_loaded_network": 65,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:35:06+00:00",
      "latest_snapshot": "2026-05-14T05:35:06+00:00",
      "last_message": "Ingesta completada: 65/65 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 65,
        "target": 50,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 65,
        "counts": {
          "mandates": 65,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 50,
        "fallback_file": "etl/data/raw/samples/asamblea_extremadura_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/asamblea_extremadura_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.asambleaex.es/dipslegis",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "asamblea_madrid_ocupaciones",
      "source_name": "Asamblea de Madrid - Ocupaciones (cargos, incluidos diputados)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Asamblea de Madrid",
      "role_title": "Cargo",
      "format": "csv",
      "default_url": "https://ctyp.asambleamadrid.es/static/doc/opendata/SGP_ADMIN.OPENDATA_OCUPACIONES_ASAMBLEA.csv",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Asamblea de Madrid)",
      "tracker_fuentes_objetivo": "Asamblea de Madrid OpenData Ocupaciones",
      "tracker_block_note": "Definir umbral minimo y aclarar semantica de `is_active`",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 9249,
      "max_loaded_any": 9249,
      "max_loaded_network": 9249,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:35:14+00:00",
      "latest_snapshot": "2026-05-14T05:35:14+00:00",
      "last_message": "Ingesta completada: 9249/9345 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 9249,
        "target": 5000,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 9249,
        "counts": {
          "mandates": 9249,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 5000,
        "fallback_file": "etl/data/raw/samples/asamblea_madrid_ocupaciones_sample.csv",
        "sample_url": "etl/data/raw/samples/asamblea_madrid_ocupaciones_sample.csv",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "CC BY 3.0 ES (Asamblea de Madrid, salvo indicaci\u00f3n en contrario)",
        "terms_url": "https://www.asambleamadrid.es/datos-abiertos",
        "obligations": [
          "Atribuir la fuente conforme a CC BY 3.0 ES.",
          "Indicar p\u00fablicamente cambios/adaptaciones cuando existan."
        ],
        "notes": "Atribuir expl\u00edcitamente a Asamblea de Madrid.",
        "personal_data_notes": "No publicar campos personales innecesarios.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "asamblea_melilla_diputados",
      "source_name": "Asamblea de Melilla - Miembros (Legislatura 2023/2027)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Asamblea de Melilla",
      "role_title": "Diputado/a",
      "format": "json",
      "default_url": "https://sede.melilla.es/sta/CarpetaPublic/doEvent?APP_CODE=STA&PAGE_CODE=PTS2_MIEMBROS",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Representantes y mandatos (Asamblea de Melilla)",
      "tracker_fuentes_objetivo": "Asamblea de Melilla: diputados (2023/2027)",
      "tracker_block_note": "Done now: NO para live-clean en GitHub Actions. Live ETL `25715374667` (`2026-05-12`) carg\u00f3 `26/26` solo por fallback (`max_net=0`, `max_any=26`) tras `network-error-fallback: RuntimeError: No se encontr\u00f3 dataset_PTS2_MIEMBROS en la p\u00e1gina`; por tanto no puede mantenerse como `DONE` hasta recuperar red real reproducible. Evidencia previa `2026-05-11` queda como hist\u00f3rica, no como verdad vigente. Evidencia actual: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260512.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source asamblea_melilla_diputados --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 26,
      "max_loaded_any": 26,
      "max_loaded_network": 26,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:35:17+00:00",
      "latest_snapshot": "2026-05-14T05:35:17+00:00",
      "last_message": "Ingesta completada: 26/26 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 26,
        "target": 20,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 26,
        "counts": {
          "mandates": 26,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 20,
        "fallback_file": "etl/data/raw/samples/asamblea_melilla_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/asamblea_melilla_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://sede.melilla.es/sta/CarpetaPublic/doEvent?APP_CODE=STA&PAGE_CODE=PTS2_MIEMBROS",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "asamblea_murcia_diputados",
      "source_name": "Asamblea Regional de Murcia - Diputados",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Asamblea Regional de Murcia",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://www.asambleamurcia.es/diputados",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Asamblea Murcia)",
      "tracker_fuentes_objetivo": "Asamblea Regional de Murcia: diputados (listado + fichas)",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 54,
      "max_loaded_any": 54,
      "max_loaded_network": 54,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:37:14+00:00",
      "latest_snapshot": "2026-05-14T05:37:14+00:00",
      "last_message": "Ingesta completada: 54/54 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 54,
        "target": 35,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 54,
        "counts": {
          "mandates": 54,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 35,
        "fallback_file": "etl/data/raw/samples/asamblea_murcia_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/asamblea_murcia_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.asambleamurcia.es/diputados",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "cortes_aragon_diputados",
      "source_name": "Cortes de Aragon - Diputados (XI Legislatura)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Cortes de Aragon",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://www.cortesaragon.es/Quienes-somos.2250.0.html?no_cache=1&tx_t3comunicacion_pi3%5Bnumleg%5D=11&tx_t3comunicacion_pi3%5Btipinf%5D=3&tx_t3comunicacion_pi3%5Buidcom%5D=-2#verContenido",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Representantes y mandatos (Cortes de Aragon)",
      "tracker_fuentes_objetivo": "Cortes de Aragon: diputados (XI)",
      "tracker_block_note": "GitHub Actions strict-network devuelve `HTTP 403`; mantener datos previos como evidencia parcial, pero no marcar `DONE` hasta recuperar run reproducible live-clean.",
      "sql_status": "PARTIAL",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 75,
      "max_loaded_any": 75,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:37:22+00:00",
      "latest_snapshot": "2026-05-14T05:37:22+00:00",
      "last_message": "Ingesta completada: 75/75 registros validos (network-error-fallback: HTTPError: HTTP Error 403: Forbidden)",
      "blocker_reason": "",
      "progress": {
        "loaded": 75,
        "target": 50,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 75,
        "counts": {
          "mandates": 75,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 50,
        "fallback_file": "etl/data/raw/samples/cortes_aragon_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/cortes_aragon_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.cortesaragon.es/Quienes-somos.2250.0.html?no_cache=1&tx_t3comunicacion_pi3%5Bnumleg%5D=11&tx_t3comunicacion_pi3%5Btipinf%5D=3&tx_t3comunicacion_pi3%5Buidcom%5D=-2#verContenido",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "cortes_cyl_procuradores",
      "source_name": "Cortes de Castilla y Leon - Procuradores y Procuradoras (XI Legislatura)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Cortes de Castilla y Leon",
      "role_title": "Procurador/a autonomico",
      "format": "json",
      "default_url": "https://www.ccyl.es/Organizacion/PlenoAlfabetico",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Cortes CyL)",
      "tracker_fuentes_objetivo": "Cortes de Castilla y Leon (PlenoAlfabetico)",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 82,
      "max_loaded_any": 82,
      "max_loaded_network": 82,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:38:07+00:00",
      "latest_snapshot": "2026-05-14T05:38:07+00:00",
      "last_message": "Ingesta completada: 82/82 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 82,
        "target": 70,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 82,
        "counts": {
          "mandates": 82,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 70,
        "fallback_file": "etl/data/raw/samples/cortes_cyl_procuradores_sample.json",
        "sample_url": "etl/data/raw/samples/cortes_cyl_procuradores_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.ccyl.es/Organizacion/PlenoAlfabetico",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "cortes_clm_diputados",
      "source_name": "Cortes de Castilla-La Mancha - Diputados (XI Legislatura)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Cortes de Castilla-La Mancha",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://www.cortesclm.es/web2/paginas/resul_diputados.php?legislatura=11",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Cortes CLM)",
      "tracker_fuentes_objetivo": "Cortes de Castilla-La Mancha (listado + fichas)",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 33,
      "max_loaded_any": 33,
      "max_loaded_network": 33,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:38:06+00:00",
      "latest_snapshot": "2026-05-14T05:38:06+00:00",
      "last_message": "Ingesta completada: 33/33 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 33,
        "target": 25,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 33,
        "counts": {
          "mandates": 33,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 25,
        "fallback_file": "etl/data/raw/samples/cortes_clm_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/cortes_clm_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.cortesclm.es/web2/paginas/resul_diputados.php?legislatura=11",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "jgpa_diputados",
      "source_name": "Junta General del Principado de Asturias - Diputados y diputadas",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Junta General del Principado de Asturias",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://www.jgpa.es/diputados-y-diputadas",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (JGPA Asturias)",
      "tracker_fuentes_objetivo": "Junta General del Principado de Asturias (diputados)",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 45,
      "max_loaded_any": 45,
      "max_loaded_network": 45,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:40:42+00:00",
      "latest_snapshot": "2026-05-14T05:40:42+00:00",
      "last_message": "Ingesta completada: 45/45 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 45,
        "target": 35,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 45,
        "counts": {
          "mandates": 45,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 35,
        "fallback_file": "etl/data/raw/samples/jgpa_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/jgpa_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.jgpa.es/diputados-y-diputadas",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "corts_valencianes_diputats",
      "source_name": "Les Corts Valencianes - Diputados (fichas HTML)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Les Corts Valencianes",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://www.cortsvalencianes.es/es/composicion/diputados",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Corts Valencianes)",
      "tracker_fuentes_objetivo": "Corts Valencianes (listado + fichas)",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 99,
      "max_loaded_any": 99,
      "max_loaded_network": 99,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:40:35+00:00",
      "latest_snapshot": "2026-05-14T05:40:35+00:00",
      "last_message": "Ingesta completada: 99/99 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 99,
        "target": 70,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 99,
        "counts": {
          "mandates": 99,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 70,
        "fallback_file": "etl/data/raw/samples/corts_valencianes_diputats_sample.json",
        "sample_url": "etl/data/raw/samples/corts_valencianes_diputats_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.cortsvalencianes.es/es/composicion/diputados",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parlament_catalunya_diputats",
      "source_name": "Parlament de Catalunya - Diputats (composicio actual)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Parlament de Catalunya",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://www.parlament.cat/web/composicio/ple-parlament/composicio-actual/index.html",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Parlament de Catalunya)",
      "tracker_fuentes_objetivo": "Parlament de Catalunya (composicio actual + fichas)",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 135,
      "max_loaded_any": 135,
      "max_loaded_network": 135,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:47:29+00:00",
      "latest_snapshot": "2026-05-14T05:47:29+00:00",
      "last_message": "Ingesta completada: 135/135 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 135,
        "target": 100,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 135,
        "counts": {
          "mandates": 135,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 100,
        "fallback_file": "etl/data/raw/samples/parlament_catalunya_diputats_sample.json",
        "sample_url": "etl/data/raw/samples/parlament_catalunya_diputats_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.parlament.cat/web/composicio/ple-parlament/composicio-actual/index.html",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parlament_balears_diputats",
      "source_name": "Parlament de les Illes Balears - Diputats (webGTP)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Parlament de les Illes Balears",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://www.parlamentib.es/Representants/Diputats.aspx?criteria=0",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Representantes y mandatos (Parlament IB)",
      "tracker_fuentes_objetivo": "Parlament de les Illes Balears: diputats (listado + fichas via webGTP)",
      "tracker_block_note": "Done now: NO para live-clean en GitHub Actions. PR gate `25687905013` fallo en `--strict-network` con `urllib.error.URLError: <urlopen error timed out>` para `parlament_balears_diputats`; mantener evidencia previa como parcial hasta recuperar run reproducible. Evidencia: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source parlament_balears_diputats --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 59,
      "max_loaded_any": 59,
      "max_loaded_network": 59,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:44:46+00:00",
      "latest_snapshot": "2026-05-14T05:44:46+00:00",
      "last_message": "Ingesta completada: 59/59 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 59,
        "target": 45,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 59,
        "counts": {
          "mandates": 59,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 45,
        "fallback_file": "etl/data/raw/samples/parlament_balears_diputats_sample.json",
        "sample_url": "etl/data/raw/samples/parlament_balears_diputats_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.parlamentib.es/Representants/Diputats.aspx?criteria=0",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parlamento_andalucia_diputados",
      "source_name": "Parlamento de Andalucia - Diputados (fichas HTML)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Parlamento de Andalucia",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://www.parlamentodeandalucia.es/webdinamica/portal-web-parlamento/composicionyfuncionamiento/diputadosysenadores.do",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Representantes y mandatos (Parlamento de Andalucia)",
      "tracker_fuentes_objetivo": "Parlamento de Andalucia (listado + fichas)",
      "tracker_block_note": "GitHub Actions strict-network ya no encuentra diputados actuales (`codmie/nlegis`); requiere reparar parser o endpoint antes de volver a `DONE`.",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "stale",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 2,
      "max_loaded_any": 2,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:47:30+00:00",
      "latest_snapshot": "2026-05-14T05:47:30+00:00",
      "last_message": "Ingesta completada: 2/2 registros validos (network-error-fallback: RuntimeError: No se encontraron diputados actuales (codmie/nlegis) en Parlamento de Andalucia)",
      "blocker_reason": "",
      "progress": {
        "loaded": 2,
        "target": 90,
        "percent": 2
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 2,
        "counts": {
          "mandates": 2,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 90,
        "fallback_file": "etl/data/raw/samples/parlamento_andalucia_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/parlamento_andalucia_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.parlamentodeandalucia.es/webdinamica/portal-web-parlamento/composicionyfuncionamiento/diputadosysenadores.do",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parlamento_canarias_diputados",
      "source_name": "Parlamento de Canarias - Diputados (API)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Parlamento de Canarias",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://parcan.es/api/diputados/por_legislatura/11/?format=json",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Parlamento de Canarias)",
      "tracker_fuentes_objetivo": "Parlamento de Canarias: diputados + grupos (API oficial)",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 79,
      "max_loaded_any": 79,
      "max_loaded_network": 79,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:47:32+00:00",
      "latest_snapshot": "2026-05-14T05:47:32+00:00",
      "last_message": "Ingesta completada: 79/79 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 79,
        "target": 60,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 79,
        "counts": {
          "mandates": 79,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 60,
        "fallback_file": "etl/data/raw/samples/parlamento_canarias_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/parlamento_canarias_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://parcan.es/api/diputados/por_legislatura/11/?format=json",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parlamento_cantabria_diputados",
      "source_name": "Parlamento de Cantabria - Diputados (XI Legislatura)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Parlamento de Cantabria",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://parlamento-cantabria.es/informacion-general/composicion/11l-pleno-del-parlamento-de-cantabria",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Parlamento de Cantabria)",
      "tracker_fuentes_objetivo": "Parlamento de Cantabria",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 35,
      "max_loaded_any": 35,
      "max_loaded_network": 35,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:49:41+00:00",
      "latest_snapshot": "2026-05-14T05:49:41+00:00",
      "last_message": "Ingesta completada: 35/35 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 35,
        "target": 25,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 35,
        "counts": {
          "mandates": 35,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 25,
        "fallback_file": "etl/data/raw/samples/parlamento_cantabria_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/parlamento_cantabria_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://parlamento-cantabria.es/informacion-general/composicion/11l-pleno-del-parlamento-de-cantabria",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parlamento_galicia_deputados",
      "source_name": "Parlamento de Galicia - Deputados (fichas HTML)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Parlamento de Galicia",
      "role_title": "Deputado/a autonomico",
      "format": "json",
      "default_url": "https://www.parlamentodegalicia.gal/Composicion/Deputados",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Representantes y mandatos (Parlamento de Galicia)",
      "tracker_fuentes_objetivo": "Parlamento de Galicia: deputados (fichas HTML)",
      "tracker_block_note": "Done now: NO. Blocker: `parlamento_galicia_deputados` en `strict-network` sigue bloqueado con HTTP 403 (`run_id=265`, `run_records_loaded=0`), por lo que la fila permanece `PARTIAL`. Evidencia: `docs/etl/sprints/AI-OPS-14/evidence/blocker-probe-refresh.log`, `docs/etl/sprints/AI-OPS-14/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-14/exports/unblock_feasibility_matrix.csv`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db etl/data/staging/politicos-es.db --source parlamento_galicia_deputados --snapshot-date 2026-02-17 --strict-network --timeout 30`.",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "blocked",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 3,
      "max_loaded_any": 3,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:49:41+00:00",
      "latest_snapshot": "2026-05-14T05:49:41+00:00",
      "last_message": "Ingesta completada: 3/3 registros validos (network-error-fallback: HTTPError: HTTP Error 403: Forbidden)",
      "blocker_reason": "Done now: NO. Blocker: `parlamento_galicia_deputados` en `strict-network` sigue bloqueado con HTTP 403 (`run_id=265`, `run_records_loaded=0`), por lo que la fila permanece `PARTIAL`. Evidencia: `docs/etl/sprints/AI-OPS-14/evidence/blocker-probe-refresh.log`, `docs/etl/sprints/AI-OPS-14/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-14/exports/unblock_feasibility_matrix.csv`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db etl/data/staging/politicos-es.db --source parlamento_galicia_deputados --snapshot-date 2026-02-17 --strict-network --timeout 30`.",
      "progress": {
        "loaded": 3,
        "target": 50,
        "percent": 6
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 3,
        "counts": {
          "mandates": 3,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 50,
        "fallback_file": "etl/data/raw/samples/parlamento_galicia_deputados_sample.json",
        "sample_url": "etl/data/raw/samples/parlamento_galicia_deputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": true
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.parlamentodegalicia.gal/Composicion/Deputados",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parlamento_larioja_diputados",
      "source_name": "Parlamento de La Rioja - Diputados (XI Legislatura)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Parlamento de La Rioja",
      "role_title": "Diputado/a autonomico",
      "format": "json",
      "default_url": "https://adminweb.parlamento-larioja.org/composicion-y-organos/diputados",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Parlamento de La Rioja)",
      "tracker_fuentes_objetivo": "Parlamento de La Rioja: diputados (listado + fichas)",
      "tracker_block_note": "Hardening de parsing y umbral minimo",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 33,
      "max_loaded_any": 33,
      "max_loaded_network": 33,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:49:43+00:00",
      "latest_snapshot": "2026-05-14T05:49:43+00:00",
      "last_message": "Ingesta completada: 33/33 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 33,
        "target": 25,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 33,
        "counts": {
          "mandates": 33,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 25,
        "fallback_file": "etl/data/raw/samples/parlamento_larioja_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/parlamento_larioja_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://adminweb.parlamento-larioja.org/composicion-y-organos/diputados",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parlamento_navarra_parlamentarios_forales",
      "source_name": "Parlamento de Navarra - Parlamentarios Forales (fichas HTML)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Parlamento de Navarra",
      "role_title": "Parlamentario/a foral",
      "format": "json",
      "default_url": "https://parlamentodenavarra.es/es/composicion-organos/parlamentarios-forales",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Representantes y mandatos (Parlamento de Navarra)",
      "tracker_fuentes_objetivo": "Parlamento de Navarra: parlamentarios forales (fichas HTML)",
      "tracker_block_note": "Done now: NO para live-clean. Existe replay manual `from-file` (`50/50 registros validos`), pero falta run de red real vigente o bloqueo reproducible actualizado antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-14/evidence/blocker-probe-refresh.log`, `docs/etl/sprints/AI-OPS-14/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-14/exports/unblock_feasibility_matrix.csv`.",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "stale",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 3,
      "max_loaded_any": 3,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:49:43+00:00",
      "latest_snapshot": "2026-05-14T05:49:43+00:00",
      "last_message": "Ingesta completada: 3/3 registros validos (network-error-fallback: HTTPError: HTTP Error 403: Forbidden)",
      "blocker_reason": "",
      "progress": {
        "loaded": 3,
        "target": 30,
        "percent": 10
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 3,
        "counts": {
          "mandates": 3,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 30,
        "fallback_file": "etl/data/raw/samples/parlamento_navarra_parlamentarios_forales_sample.json",
        "sample_url": "etl/data/raw/samples/parlamento_navarra_parlamentarios_forales_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://parlamentodenavarra.es/es/composicion-organos/parlamentarios-forales",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parlamento_vasco_parlamentarios",
      "source_name": "Parlamento Vasco - Parlamentarios (listado ACT)",
      "domain": "politicos",
      "scope": "autonomico",
      "level": "autonomico",
      "institution_name": "Parlamento Vasco",
      "role_title": "Parlamentario/a autonomico",
      "format": "json",
      "default_url": "https://www.legebiltzarra.eus/comparla/c_comparla_alf_ACT.html",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Representantes y mandatos (Parlamento Vasco)",
      "tracker_fuentes_objetivo": "Parlamento Vasco (listado ACT)",
      "tracker_block_note": "GitHub Actions strict-network agota tiempo en `parlamento_vasco_parlamentarios`; requiere retry reproducible o hardening de timeout/endpoints antes de volver a `DONE`.",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "stale",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 2,
      "max_loaded_any": 2,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:56:28+00:00",
      "latest_snapshot": "2026-05-14T05:56:28+00:00",
      "last_message": "Ingesta completada: 2/2 registros validos (network-error-fallback: URLError: <urlopen error [Errno 110] Connection timed out>)",
      "blocker_reason": "",
      "progress": {
        "loaded": 2,
        "target": 60,
        "percent": 3
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 2,
        "counts": {
          "mandates": 2,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 60,
        "fallback_file": "etl/data/raw/samples/parlamento_vasco_parlamentarios_sample.json",
        "sample_url": "etl/data/raw/samples/parlamento_vasco_parlamentarios_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.legebiltzarra.eus/comparla/c_comparla_alf_ACT.html",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "bdns_autonomico",
      "source_name": "BDNS/SNPSAP - Subvenciones autonomicas (piloto 3 CCAA)",
      "domain": "politicos",
      "scope": "dinero",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://www.pap.hacienda.gob.es/bdnstrans/GE/es/convocatorias",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Subvenciones auton\u00f3micas (piloto 3 CCAA)",
      "tracker_fuentes_objetivo": "BDNS/SNPSAP (filtrado por \u00f3rgano convocante/territorio)",
      "tracker_block_note": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `bdns_autonomico` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-13/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-13/evidence/bdns-api-discovery.log`, `docs/etl/sprints/AI-OPS-13/exports/unblock_feasibility_matrix.csv`.",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "stale",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 2,
      "max_loaded_any": 2,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:37:16+00:00",
      "latest_snapshot": "2026-05-14T05:37:16+00:00",
      "last_message": "Ingesta completada: 2/2 registros validos (network-error-fallback: RuntimeError: Respuesta HTML inesperada para BDNS feed (payload_sig=31d51dfeea8d6e27917ede290381f8d1e17b63c712bd007d2857d0b3e9474b5b))",
      "blocker_reason": "",
      "progress": {
        "loaded": 2,
        "target": 3,
        "percent": 67
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 3,
        "fallback_file": "etl/data/raw/samples/bdns_autonomico_sample.json",
        "sample_url": "etl/data/raw/samples/bdns_autonomico_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Aviso legal tipo AGE/Hacienda (reutilizaci\u00f3n abierta con condiciones)",
        "terms_url": "https://datos.gob.es/es/aviso-legal",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "Riesgo adicional GDPR cuando haya beneficiarios personas f\u00edsicas.",
        "personal_data_notes": "Aplicar minimizaci\u00f3n; considerar segregaci\u00f3n/anonimizaci\u00f3n de beneficiarios personas f\u00edsicas.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "bdns_api_subvenciones",
      "source_name": "BDNS/SNPSAP - Subvenciones y ayudas Espana (API)",
      "domain": "politicos",
      "scope": "dinero",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://www.pap.hacienda.gob.es/bdnstrans/GE/es/convocatorias",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Subvenciones y ayudas (Espana)",
      "tracker_fuentes_objetivo": "BDNS/SNPSAP: API",
      "tracker_block_note": "Done now: NO para live-clean actual. El snapshot operativo conserva fallback/local replay para `bdns_api_subvenciones` (`max_net=0`), as\u00ed que falta repetir strict-network con red real o documentar bloqueo antes de cerrar como `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-13/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-13/evidence/bdns-api-discovery.log`, `docs/etl/sprints/AI-OPS-13/exports/unblock_feasibility_matrix.csv`.",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "stale",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 3,
      "max_loaded_any": 3,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:37:16+00:00",
      "latest_snapshot": "2026-05-14T05:37:16+00:00",
      "last_message": "Ingesta completada: 3/3 registros validos (network-error-fallback: RuntimeError: Respuesta HTML inesperada para BDNS feed (payload_sig=31d51dfeea8d6e27917ede290381f8d1e17b63c712bd007d2857d0b3e9474b5b))",
      "blocker_reason": "",
      "progress": {
        "loaded": 3,
        "target": 10,
        "percent": 30
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 10,
        "fallback_file": "etl/data/raw/samples/bdns_api_subvenciones_sample.json",
        "sample_url": "etl/data/raw/samples/bdns_api_subvenciones_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Aviso legal tipo AGE/Hacienda (reutilizaci\u00f3n abierta con condiciones)",
        "terms_url": "https://datos.gob.es/es/aviso-legal",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "Riesgo adicional GDPR cuando haya beneficiarios personas f\u00edsicas.",
        "personal_data_notes": "Aplicar minimizaci\u00f3n; considerar segregaci\u00f3n/anonimizaci\u00f3n de beneficiarios personas f\u00edsicas.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "placsp_contratacion",
      "source_name": "Contratacion publica (canonico policy_events)",
      "domain": "politicos",
      "scope": "dinero",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://contrataciondelestado.es/",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "",
      "tracker_tipo_dato": "",
      "tracker_fuentes_objetivo": "",
      "tracker_block_note": "",
      "sql_status": "TODO",
      "ops_state": "not_run",
      "catalog_state": "missing",
      "mismatch_state": "UNTRACKED",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 0,
      "runs_ok": 0,
      "last_status": "",
      "last_loaded": 0,
      "max_loaded_any": 0,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 0,
      "last_seen_at": "",
      "latest_snapshot": "",
      "last_message": "",
      "blocker_reason": "",
      "progress": {
        "loaded": 0,
        "target": 0,
        "percent": null
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "",
        "strict_target": 0,
        "fallback_file": "etl/data/raw/samples/placsp_sindicacion_sample.xml",
        "sample_url": "etl/data/raw/samples/placsp_sindicacion_sample.xml",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": false,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://contrataciondelestado.es/",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "placsp_autonomico",
      "source_name": "PLACSP - Contratacion autonomica (piloto 3 CCAA)",
      "domain": "politicos",
      "scope": "dinero",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "xml",
      "default_url": "https://contrataciondelestado.es/sindicacion/sindicacion_643/licitacionesPerfilesContratanteCompleto3.atom",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Contratacion detalle y documentacion de licitaciones (PLACSP)",
      "tracker_fuentes_objetivo": "PLACSP: `url_detalle` desde `placsp_sindicacion`/`placsp_autonomico`",
      "tracker_block_note": "Done now: YES. Paso 1 sigue estable sin nuevos faltantes (`backfill-placsp-contract-details` `source_records_seen=0`). Paso 2 y 2.5 completados: `backfill-money-contract-records` (`1985` contratos mapeados/actualizados) y `backfill-policy-events-money` (`1985` `policy_events` upserted en `placsp_contratacion`, todos con `source_record_pk`; totals `policy_events_by_source['placsp_contratacion']=1985`). Cierres SQL reproducibles: `placsp_contract_detail_records` `992`+`993`, `placsp_contract_detail_documents` `8144`+`8144`, `money_contract_records` `992`+`993`, `policy_events` `placsp_contratacion=1985`; evidencia en `docs/etl/sprints/AI-OPS-152/evidence/placsp_linkage_checks.log` y `docs/etl/sprints/AI-OPS-152/evidence/tracker_status_after_placsp_money_policy_events.log`.",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 65,
      "max_loaded_any": 65,
      "max_loaded_network": 65,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:56:31+00:00",
      "latest_snapshot": "2026-05-14T05:56:31+00:00",
      "last_message": "Ingesta completada: 65/65 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 65,
        "target": 3,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 3,
        "fallback_file": "etl/data/raw/samples/placsp_autonomico_sample.xml",
        "sample_url": "etl/data/raw/samples/placsp_autonomico_sample.xml",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "PLACSP: reproducci\u00f3n autorizada con cita de origen; datasets vinculados a datos abiertos de Hacienda",
        "terms_url": "https://datos.gob.es/es/aviso-legal",
        "obligations": [
          "Citar el origen de la informaci\u00f3n.",
          "No desnaturalizar el contenido de origen.",
          "Conservar metadatos/condiciones de reutilizaci\u00f3n cuando existan."
        ],
        "notes": "Si se mezcla con datasets de Hacienda, aplican adem\u00e1s condiciones del aviso legal tipo.",
        "personal_data_notes": "No publicar campos personales innecesarios.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "placsp_sindicacion",
      "source_name": "PLACSP - Contratacion publica Espana (ATOM/CODICE)",
      "domain": "politicos",
      "scope": "dinero",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "xml",
      "default_url": "https://contrataciondelestado.es/sindicacion/sindicacion_643/licitacionesPerfilesContratanteCompleto3.atom",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Contratacion detalle y documentacion de licitaciones (PLACSP)",
      "tracker_fuentes_objetivo": "PLACSP: `url_detalle` desde `placsp_sindicacion`/`placsp_autonomico`",
      "tracker_block_note": "Done now: YES. Paso 1 sigue estable sin nuevos faltantes (`backfill-placsp-contract-details` `source_records_seen=0`). Paso 2 y 2.5 completados: `backfill-money-contract-records` (`1985` contratos mapeados/actualizados) y `backfill-policy-events-money` (`1985` `policy_events` upserted en `placsp_contratacion`, todos con `source_record_pk`; totals `policy_events_by_source['placsp_contratacion']=1985`). Cierres SQL reproducibles: `placsp_contract_detail_records` `992`+`993`, `placsp_contract_detail_documents` `8144`+`8144`, `money_contract_records` `992`+`993`, `policy_events` `placsp_contratacion=1985`; evidencia en `docs/etl/sprints/AI-OPS-152/evidence/placsp_linkage_checks.log` y `docs/etl/sprints/AI-OPS-152/evidence/tracker_status_after_placsp_money_policy_events.log`.",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 65,
      "max_loaded_any": 65,
      "max_loaded_network": 65,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:56:34+00:00",
      "latest_snapshot": "2026-05-14T05:56:34+00:00",
      "last_message": "Ingesta completada: 65/65 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 65,
        "target": 10,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 10,
        "fallback_file": "etl/data/raw/samples/placsp_sindicacion_sample.xml",
        "sample_url": "etl/data/raw/samples/placsp_sindicacion_sample.xml",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "PLACSP: reproducci\u00f3n autorizada con cita de origen; datasets vinculados a datos abiertos de Hacienda",
        "terms_url": "https://datos.gob.es/es/aviso-legal",
        "obligations": [
          "Citar el origen de la informaci\u00f3n.",
          "No desnaturalizar el contenido de origen.",
          "Conservar metadatos/condiciones de reutilizaci\u00f3n cuando existan."
        ],
        "notes": "Si se mezcla con datasets de Hacienda, aplican adem\u00e1s condiciones del aviso legal tipo.",
        "personal_data_notes": "No publicar campos personales innecesarios.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "bdns_subvenciones",
      "source_name": "Subvenciones publicas (canonico policy_events)",
      "domain": "politicos",
      "scope": "dinero",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://www.pap.hacienda.gob.es/bdnstrans/GE/es/convocatorias",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "",
      "tracker_tipo_dato": "",
      "tracker_fuentes_objetivo": "",
      "tracker_block_note": "",
      "sql_status": "TODO",
      "ops_state": "not_run",
      "catalog_state": "missing",
      "mismatch_state": "UNTRACKED",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 0,
      "runs_ok": 0,
      "last_status": "",
      "last_loaded": 0,
      "max_loaded_any": 0,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 0,
      "last_seen_at": "",
      "latest_snapshot": "",
      "last_message": "",
      "blocker_reason": "",
      "progress": {
        "loaded": 0,
        "target": 0,
        "percent": null
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "",
        "strict_target": 0,
        "fallback_file": "etl/data/raw/samples/bdns_api_subvenciones_sample.json",
        "sample_url": "etl/data/raw/samples/bdns_api_subvenciones_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": false,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://www.pap.hacienda.gob.es/bdnstrans/GE/es/convocatorias",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "moncloa_referencias",
      "source_name": "La Moncloa - Referencias del Consejo de Ministros",
      "domain": "politicos",
      "scope": "ejecutivo",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "html",
      "default_url": "https://www.lamoncloa.gob.es/consejodeministros/referencias/paginas/index.aspx",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Accion ejecutiva (Consejo de Ministros)",
      "tracker_fuentes_objetivo": "La Moncloa: referencias + RSS",
      "tracker_block_note": "Done now: NO para live-clean actual. La evidencia hist\u00f3rica existe, pero el DB operativo actual no conserva runs de red para `moncloa_referencias` y `moncloa_rss_referencias`; repetir strict-network o documentar bloqueo antes de `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-07/reports/dual-entry-apply-recompute.md`, `docs/etl/sprints/AI-OPS-07/reports/boe-policy-events-mapping.md` y `docs/etl/sprints/AI-OPS-07/evidence/post_apply_waiveraware_checker_final.log`.",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 2,
      "max_loaded_any": 2,
      "max_loaded_network": 2,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:40:48+00:00",
      "latest_snapshot": "2026-05-14T05:40:48+00:00",
      "last_message": "Ingesta completada: 2/2 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 2,
        "target": 2,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 2,
        "fallback_file": "etl/data/raw/samples/moncloa_referencias_sample.html",
        "sample_url": "etl/data/raw/samples/moncloa_referencias_sample.html",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Aviso legal La Moncloa (reproducci\u00f3n/modificaci\u00f3n/distribuci\u00f3n autorizadas)",
        "terms_url": "https://www.lamoncloa.gob.es/Paginas/avisolegal.aspx",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "Atribuci\u00f3n expl\u00edcita a La Moncloa/Ministerio de la Presidencia.",
        "personal_data_notes": "No publicar campos personales innecesarios.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "moncloa_rss_referencias",
      "source_name": "La Moncloa - RSS Referencias/Resumenes del Consejo de Ministros",
      "domain": "politicos",
      "scope": "ejecutivo",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "xml",
      "default_url": "https://www.lamoncloa.gob.es/Paginas/rss.aspx?tipo=16",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Accion ejecutiva (Consejo de Ministros)",
      "tracker_fuentes_objetivo": "La Moncloa: referencias + RSS",
      "tracker_block_note": "Done now: NO para live-clean actual. La evidencia hist\u00f3rica existe, pero el DB operativo actual no conserva runs de red para `moncloa_referencias` y `moncloa_rss_referencias`; repetir strict-network o documentar bloqueo antes de `DONE`. Evidencia hist\u00f3rica: `docs/etl/sprints/AI-OPS-07/reports/dual-entry-apply-recompute.md`, `docs/etl/sprints/AI-OPS-07/reports/boe-policy-events-mapping.md` y `docs/etl/sprints/AI-OPS-07/evidence/post_apply_waiveraware_checker_final.log`.",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 8,
      "max_loaded_any": 8,
      "max_loaded_network": 8,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:40:49+00:00",
      "latest_snapshot": "2026-05-14T05:40:49+00:00",
      "last_message": "Ingesta completada: 8/8 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 8,
        "target": 2,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 2,
        "fallback_file": "etl/data/raw/samples/moncloa_rss_referencias_sample.xml",
        "sample_url": "etl/data/raw/samples/moncloa_rss_referencias_sample.xml",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Aviso legal La Moncloa (reproducci\u00f3n/modificaci\u00f3n/distribuci\u00f3n autorizadas)",
        "terms_url": "https://www.lamoncloa.gob.es/Paginas/avisolegal.aspx",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "Atribuci\u00f3n expl\u00edcita a La Moncloa/Ministerio de la Presidencia.",
        "personal_data_notes": "No publicar campos personales innecesarios.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "infoelectoral_descargas",
      "source_name": "Infoelectoral - Area de descargas (convocatorias + archivos)",
      "domain": "infoelectoral",
      "scope": "electoral",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://infoelectoral.interior.gob.es/min/convocatorias/tipos/",
      "desired": true,
      "in_db": false,
      "active": false,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Procesos electorales y resultados",
      "tracker_fuentes_objetivo": "Infoelectoral descargas/procesos",
      "tracker_block_note": "`infoelectoral_descargas` tiene evidencia de red en snapshot rico, pero `infoelectoral_procesos` no tiene run live-clean en el DB operativo actual. Cerrar solo cuando ambos source_id tengan `records_loaded > 0` o bloqueo documentado.",
      "sql_status": "TODO",
      "ops_state": "missing",
      "catalog_state": "missing",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 0,
      "runs_ok": 0,
      "last_status": "",
      "last_loaded": 0,
      "max_loaded_any": 0,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 0,
      "last_seen_at": "",
      "latest_snapshot": "",
      "last_message": "",
      "blocker_reason": "",
      "progress": {
        "loaded": 0,
        "target": 3,
        "percent": 0
      },
      "warehouse": {
        "primary_table": "infoelectoral_convocatoria_tipos",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_infoelectoral_es.py",
        "strict_target": 3,
        "fallback_file": "etl/data/raw/samples/infoelectoral_descargas_sample.json",
        "sample_url": "etl/data/raw/samples/infoelectoral_descargas_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": false,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "partially_verified",
        "reuse_basis": "Indicio fuerte de adopci\u00f3n de aviso legal tipo AGE (datos.gob.es/aviso-legal)",
        "terms_url": "https://datos.gob.es/es/aviso-legal",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "No se pudo abrir el aviso legal del portal en este entorno; confirmar en pr\u00f3xima revisi\u00f3n.",
        "personal_data_notes": "No publicar campos personales innecesarios.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "infoelectoral_procesos",
      "source_name": "Infoelectoral - Procesos electorales celebrados (datos/resultados)",
      "domain": "infoelectoral",
      "scope": "electoral",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://infoelectoral.interior.gob.es/min/procesos/",
      "desired": true,
      "in_db": false,
      "active": false,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Procesos electorales y resultados",
      "tracker_fuentes_objetivo": "Infoelectoral descargas/procesos",
      "tracker_block_note": "`infoelectoral_descargas` tiene evidencia de red en snapshot rico, pero `infoelectoral_procesos` no tiene run live-clean en el DB operativo actual. Cerrar solo cuando ambos source_id tengan `records_loaded > 0` o bloqueo documentado.",
      "sql_status": "TODO",
      "ops_state": "missing",
      "catalog_state": "missing",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 0,
      "runs_ok": 0,
      "last_status": "",
      "last_loaded": 0,
      "max_loaded_any": 0,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 0,
      "last_seen_at": "",
      "latest_snapshot": "",
      "last_message": "",
      "blocker_reason": "",
      "progress": {
        "loaded": 0,
        "target": 1,
        "percent": 0
      },
      "warehouse": {
        "primary_table": "infoelectoral_procesos",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_infoelectoral_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/infoelectoral_procesos_sample.json",
        "sample_url": "etl/data/raw/samples/infoelectoral_procesos_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": false,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "partially_verified",
        "reuse_basis": "Indicio fuerte de adopci\u00f3n de aviso legal tipo AGE (datos.gob.es/aviso-legal)",
        "terms_url": "https://datos.gob.es/es/aviso-legal",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "No se pudo abrir el aviso legal del portal en este entorno; confirmar en pr\u00f3xima revisi\u00f3n.",
        "personal_data_notes": "No publicar campos personales innecesarios.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "europarl_meps",
      "source_name": "Parlamento Europeo - MEPs",
      "domain": "politicos",
      "scope": "europeo",
      "level": "europeo",
      "institution_name": "Parlamento Europeo",
      "role_title": "Eurodiputado/a",
      "format": "xml",
      "default_url": "https://www.europarl.europa.eu/meps/es/full-list/xml",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Europarl)",
      "tracker_fuentes_objetivo": "Europarl MEP XML",
      "tracker_block_note": "Mejorar completitud de fechas/metadatos",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 60,
      "max_loaded_any": 60,
      "max_loaded_network": 60,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:40:40+00:00",
      "latest_snapshot": "2026-05-14T05:40:40+00:00",
      "last_message": "Ingesta completada: 60/60 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 60,
        "target": 40,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 60,
        "counts": {
          "mandates": 60,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 40,
        "fallback_file": "etl/data/raw/samples/europarl_meps_sample.xml",
        "sample_url": "etl/data/raw/samples/europarl_meps_sample.xml",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "not_verified",
        "reuse_basis": "No verificado: falta evidencia documental espec\u00edfica del recurso XML de MEPs",
        "terms_url": "https://www.europarl.europa.eu/legal-notice/es/",
        "obligations": [
          "No asumir reutilizaci\u00f3n comercial hasta verificar licencia espec\u00edfica del recurso.",
          "Conservar evidencia de la revisi\u00f3n legal cuando se confirme."
        ],
        "notes": "Estado no confirmado en esta revisi\u00f3n.",
        "personal_data_notes": "Aplicar minimizaci\u00f3n al redistribuir datos personales de representantes.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "boe_api_legal",
      "source_name": "BOE API - Marco legal (RSS diario)",
      "domain": "politicos",
      "scope": "legal",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "xml",
      "default_url": "https://www.boe.es/rss/boe.php",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Marco legal electoral",
      "tracker_fuentes_objetivo": "BOE API",
      "tracker_block_note": "Done now: NO para live-clean en GitHub Actions. La ingesta historica BOE (`boe_api_legal`) existe (`records_loaded=298`, `policy_events_boe=298`), pero PR gate `25687905013` fallo en `--strict-network` con `urllib.error.URLError: <urlopen error timed out>`. Mantener como parcial hasta recuperar run reproducible de red real vigente. Evidencia: `docs/etl/sprints/AI-OPS-08/reports/waiver-burndown-apply-recompute.md`, `docs/etl/sprints/AI-OPS-08/evidence/waiver-burndown-apply-recompute-boe-ingest-replay.log`, `docs/etl/sprints/AI-OPS-08/evidence/waiver-burndown-apply-recompute-boe-policy-events-backfill.log`, `docs/etl/sprints/AI-OPS-08/reports/boe-tracker-mapping-hardening.md` y `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source boe_api_legal --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 179,
      "max_loaded_any": 179,
      "max_loaded_network": 179,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:37:17+00:00",
      "latest_snapshot": "2026-05-14T05:37:17+00:00",
      "last_message": "Ingesta completada: 179/179 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 179,
        "target": 5,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 5,
        "fallback_file": "etl/data/raw/samples/boe_api_legal_sample.xml",
        "sample_url": "etl/data/raw/samples/boe_api_legal_sample.xml",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Aviso legal BOE (reutilizaci\u00f3n autorizada con condiciones y excepciones de terceros)",
        "terms_url": "https://www.boe.es",
        "obligations": [
          "Atribuir la fuente BOE y enlazar al origen cuando sea posible.",
          "Indicar cambios/adaptaciones cuando existan.",
          "Excluir o segregar materiales con restricciones de terceros (p. ej. NC/ND)."
        ],
        "notes": "Aplicar exclusiones de terceros cuando correspondan.",
        "personal_data_notes": "No publicar campos personales innecesarios.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "municipal_concejales",
      "source_name": "Ambito municipal - Concejales y cargos locales",
      "domain": "politicos",
      "scope": "municipal",
      "level": "municipal",
      "institution_name": "Ayuntamiento",
      "role_title": "Cargo municipal",
      "format": "xlsx",
      "default_url": "https://concejales.redsara.es/consulta/getConcejalesLegislatura",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y cargos locales",
      "tracker_fuentes_objetivo": "RED SARA Concejales",
      "tracker_block_note": "Definir umbral minimo y criterio de cobertura",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 66907,
      "max_loaded_any": 66907,
      "max_loaded_network": 66907,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:43:02+00:00",
      "latest_snapshot": "2026-05-14T05:43:02+00:00",
      "last_message": "Ingesta completada: 66907/66907 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 66907,
        "target": 50000,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 66907,
        "counts": {
          "mandates": 66907,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 50000,
        "fallback_file": "etl/data/raw/samples/municipal_concejales_sample.csv",
        "sample_url": "etl/data/raw/samples/municipal_concejales_sample.csv",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Portal concejales.redsara: condiciones alineadas con aviso legal tipo AGE",
        "terms_url": "https://concejales.redsara.es",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "Datos de cargos electos con finalidad de transparencia.",
        "personal_data_notes": "Minimizar campos no necesarios y evitar exposici\u00f3n de datos de contacto personal.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "congreso_iniciativas",
      "source_name": "Congreso - Iniciativas (OpenData)",
      "domain": "parlamentario",
      "scope": "nacional",
      "level": "nacional",
      "institution_name": "Congreso de los Diputados",
      "role_title": "",
      "format": "html",
      "default_url": "https://www.congreso.es/es/opendata/iniciativas",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "",
      "tracker_tipo_dato": "",
      "tracker_fuentes_objetivo": "",
      "tracker_block_note": "",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "UNTRACKED",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 500,
      "max_loaded_any": 500,
      "max_loaded_network": 500,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:58:07+00:00",
      "latest_snapshot": "2026-05-14T05:58:07+00:00",
      "last_message": "{\"initiatives_loaded\": 500, \"note\": \"network\"}",
      "blocker_reason": "",
      "progress": {
        "loaded": 500,
        "target": 1,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "parl_initiatives",
        "primary_rows": 422,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 422,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_parlamentario_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/congreso_iniciativas_sample.json",
        "sample_url": "etl/data/raw/samples/congreso_iniciativas_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Aviso legal del Congreso (reutilizaci\u00f3n autorizada con condiciones)",
        "terms_url": "https://www.congreso.es/es/avisoLegal",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "Para mirror, conservar integridad/atribuci\u00f3n; para derivados, marcar elaboraci\u00f3n propia.",
        "personal_data_notes": "Datos de representantes: publicar solo campos necesarios para transparencia.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "congreso_intervenciones",
      "source_name": "Congreso - Intervenciones (OpenData)",
      "domain": "parlamentario",
      "scope": "nacional",
      "level": "nacional",
      "institution_name": "Congreso de los Diputados",
      "role_title": "",
      "format": "html",
      "default_url": "https://www.congreso.es/es/opendata/intervenciones",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "",
      "tracker_tipo_dato": "",
      "tracker_fuentes_objetivo": "",
      "tracker_block_note": "",
      "sql_status": "TODO",
      "ops_state": "not_run",
      "catalog_state": "missing",
      "mismatch_state": "UNTRACKED",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 0,
      "runs_ok": 0,
      "last_status": "",
      "last_loaded": 0,
      "max_loaded_any": 0,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 0,
      "last_seen_at": "",
      "latest_snapshot": "",
      "last_message": "",
      "blocker_reason": "",
      "progress": {
        "loaded": 0,
        "target": 1,
        "percent": 0
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_parlamentario_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/congreso_intervenciones_sample.json",
        "sample_url": "etl/data/raw/samples/congreso_intervenciones_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": false,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Aviso legal del Congreso (reutilizaci\u00f3n autorizada con condiciones)",
        "terms_url": "https://www.congreso.es/es/avisoLegal",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "Para mirror, conservar integridad/atribuci\u00f3n; para derivados, marcar elaboraci\u00f3n propia.",
        "personal_data_notes": "Datos de representantes: publicar solo campos necesarios para transparencia.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "congreso_votaciones",
      "source_name": "Congreso - Votaciones (pleno, OpenData)",
      "domain": "parlamentario",
      "scope": "nacional",
      "level": "nacional",
      "institution_name": "Congreso de los Diputados",
      "role_title": "",
      "format": "html",
      "default_url": "https://www.congreso.es/es/opendata/votaciones",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "",
      "tracker_tipo_dato": "",
      "tracker_fuentes_objetivo": "",
      "tracker_block_note": "",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "UNTRACKED",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 80,
      "max_loaded_any": 80,
      "max_loaded_network": 80,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:57:57+00:00",
      "latest_snapshot": "2026-05-14T05:57:57+00:00",
      "last_message": "{\"events_loaded\": 80, \"member_votes_loaded\": 28000, \"note\": \"network\"}",
      "blocker_reason": "",
      "progress": {
        "loaded": 80,
        "target": 1,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "parl_vote_events",
        "primary_rows": 80,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 80,
          "parl_initiatives": 21,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_parlamentario_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/congreso_votaciones_sample.json",
        "sample_url": "etl/data/raw/samples/congreso_votaciones_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Aviso legal del Congreso (reutilizaci\u00f3n autorizada con condiciones)",
        "terms_url": "https://www.congreso.es/es/avisoLegal",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "Para mirror, conservar integridad/atribuci\u00f3n; para derivados, marcar elaboraci\u00f3n propia.",
        "personal_data_notes": "Datos de representantes: publicar solo campos necesarios para transparencia.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "parl_initiative_docs",
      "source_name": "Parlamento - Documentos de iniciativas (BOCG/Diario de Sesiones)",
      "domain": "parlamentario",
      "scope": "nacional",
      "level": "nacional",
      "institution_name": "Cortes Generales",
      "role_title": "",
      "format": "bin",
      "default_url": "manifest://parl_initiative_docs",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "",
      "tracker_tipo_dato": "",
      "tracker_fuentes_objetivo": "",
      "tracker_block_note": "",
      "sql_status": "TODO",
      "ops_state": "not_run",
      "catalog_state": "missing",
      "mismatch_state": "UNTRACKED",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 0,
      "runs_ok": 0,
      "last_status": "",
      "last_loaded": 0,
      "max_loaded_any": 0,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 0,
      "last_seen_at": "",
      "latest_snapshot": "",
      "last_message": "",
      "blocker_reason": "",
      "progress": {
        "loaded": 0,
        "target": 1,
        "percent": 0
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "",
        "strict_target": 1,
        "fallback_file": "",
        "sample_url": "",
        "sample_available": false
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": false,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "manifest://parl_initiative_docs",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "programas_partidos",
      "source_name": "Programas de partidos (manifest-driven)",
      "domain": "parlamentario",
      "scope": "nacional",
      "level": "nacional",
      "institution_name": "Programas de partidos",
      "role_title": "",
      "format": "csv",
      "default_url": "manifest://programas_partidos",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Refinamiento ratio dedupe en `BNG europeas 2024`",
      "tracker_fuentes_objetivo": "`programas_partidos` (`24_bng_programa_europeas_2.pdf`)",
      "tracker_block_note": "Done now: YES. AI-OPS-270 cierra el objetivo con dedupe `near-duplicate` reproducible en `scripts/report_programas_support_unclear_unique_ratio.py` (Jaccard/containment + guard por n-grama), conservando contrato strict y fail-path exact-only. Resultado real en staging (`PROGRAMAS_UNCLEAR_RATIO_PARTIES='BNG'`, `MIN=2.0`): `BNG europeas 2024` pasa de `support_to_unclear_unique_ratio=1.428571` (`unclear_unique=7`) a `2.0` (`unclear_unique=5`, `collapsed=2`) sin degradar gates declared (`declared.gate.passed=true`, `review_pending=0`) ni tracker (`mismatches=0`, `done_zero_real=0`). Guardrail de precisi\u00f3n en muestra revisada vigente: `precision_by_required_party={BNG:0.8571, VOX:1.0, FORO:1.0, PP:1.0}` (`min_party_precision=0.85`, `reviewed_total=28`). Evidencia: `docs/etl/sprints/AI-OPS-270/reports/programas-bng-europeas-near-duplicate-ratio-closure-20260228.md`, `docs/etl/sprints/AI-OPS-270/evidence/programas_support_unclear_unique_ratio_bng_latest.json`, `docs/etl/sprints/AI-OPS-270/exports/programas_support_unclear_unique_ratio_bng_latest.csv`, `docs/etl/sprints/AI-OPS-270/evidence/programas_support_unclear_unique_ratio_bng_exact_fail_latest.json`, `docs/etl/sprints/AI-OPS-270/evidence/programas_support_unclear_unique_ratio_bng_exact_fail_rc_latest.txt`, `docs/etl/sprints/AI-OPS-270/evidence/programas_support_unclear_unique_ratio_bng_delta_vs_ai_ops_269_latest.json`, `docs/etl/sprints/AI-OPS-270/evidence/quality_declared_programas_enforce_latest.json`, `docs/etl/sprints/AI-OPS-270/evidence/tracker_status_post_latest.log`, `docs/etl/sprints/AI-OPS-270/evidence/programas_support_precision_audit_latest.json`.",
      "sql_status": "TODO",
      "ops_state": "not_run",
      "catalog_state": "missing",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 0,
      "runs_ok": 0,
      "last_status": "",
      "last_loaded": 0,
      "max_loaded_any": 0,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 0,
      "last_seen_at": "",
      "latest_snapshot": "",
      "last_message": "",
      "blocker_reason": "",
      "progress": {
        "loaded": 0,
        "target": 1,
        "percent": 0
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_parlamentario_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/programas_partidos_sample.csv",
        "sample_url": "etl/data/raw/samples/programas_partidos_sample.csv",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": false,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "manifest://programas_partidos",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "senado_iniciativas",
      "source_name": "Senado - Iniciativas y mociones (OpenData)",
      "domain": "parlamentario",
      "scope": "nacional",
      "level": "nacional",
      "institution_name": "Senado de Espana",
      "role_title": "",
      "format": "xml",
      "default_url": "https://www.senado.es/web/ficopendataservlet?tipoFich=9&legis=15",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Conversi\u00f3n iterativa adicional del residual global Senado `status=404` tras primer delta material",
      "tracker_fuentes_objetivo": "Packet global `status=404` (`senado_iniciativas`) con replay acotado + cierre anti-loop",
      "tracker_block_note": "Done now: NO_DELTA_WITH_EVIDENCE. AI-OPS-388 ejecuta dos pasadas `packet50` con `--include-unlinked` y postproceso completo (`excerpts` + `extractions --only-missing`) sin conversi\u00f3n neta: pass1 `candidate_urls=50`, `fetched_ok=0`, `failures=30`; pass2 `candidate_urls=50`, `fetched_ok=0`, `failures=30`; delta acumulada `downloaded_doc_links=0`, `missing_doc_links_actionable=0`, `missing_urls=0`, `status404=0`, con `status403/status500` estables. Se registra `no_new_lever` y se cierra por anti-loop. Evidencia: `docs/etl/sprints/AI-OPS-388/reports/senado-status404-global-two-pass-no-delta-20260301.md`, `docs/etl/sprints/AI-OPS-388/evidence/senado_status404_global_conversion_delta_ai_ops_388_20260301T174503Z.json`, `docs/etl/sprints/AI-OPS-388/evidence/senado_status404_global_no_new_lever_ai_ops_388_20260301T174503Z.json`, `docs/etl/sprints/AI-OPS-388/evidence/senado_status404_global_retry_packet50_effective_pass1_20260301T172903Z.json`, `docs/etl/sprints/AI-OPS-388/evidence/senado_status404_global_retry_packet50_effective_pass2_20260301T174503Z.json`.",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "stale",
      "mismatch_state": "MISMATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 0,
      "max_loaded_any": 0,
      "max_loaded_network": 0,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:58:11+00:00",
      "latest_snapshot": "2026-05-14T05:58:11+00:00",
      "last_message": "{\"initiatives_loaded\": 0, \"note\": \"network-partial\"}",
      "blocker_reason": "",
      "progress": {
        "loaded": 0,
        "target": 1,
        "percent": 0
      },
      "warehouse": {
        "primary_table": "parl_initiatives",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_parlamentario_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/senado_iniciativas_sample.xml",
        "sample_url": "etl/data/raw/samples/senado_iniciativas_sample.xml",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": false,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "CC BY 4.0 (datos abiertos del Senado)",
        "terms_url": "https://www.senado.es/web/relacionesciudadanos/datosabiertos/catalogodatos/index.html",
        "obligations": [
          "Atribuir la fuente conforme a CC BY 4.0.",
          "Indicar si hubo cambios, transformaciones o elaboraci\u00f3n propia."
        ],
        "notes": "Redistribuci\u00f3n y transformaci\u00f3n permitidas con atribuci\u00f3n.",
        "personal_data_notes": "Datos de representantes: publicar solo campos necesarios para transparencia.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "senado_votaciones",
      "source_name": "Senado - Votaciones (OpenData)",
      "domain": "parlamentario",
      "scope": "nacional",
      "level": "nacional",
      "institution_name": "Senado de Espana",
      "role_title": "",
      "format": "html",
      "default_url": "https://www.senado.es/web/relacionesciudadanos/datosabiertos/catalogodatos/votaciones/index.html?legis=15",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "",
      "tracker_tipo_dato": "",
      "tracker_fuentes_objetivo": "",
      "tracker_block_note": "",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "stale",
      "mismatch_state": "UNTRACKED",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 0,
      "max_loaded_any": 0,
      "max_loaded_network": 0,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:58:09+00:00",
      "latest_snapshot": "2026-05-14T05:58:09+00:00",
      "last_message": "{\"events_loaded\": 0, \"member_votes_loaded\": 0, \"note\": \"network-partial\"}",
      "blocker_reason": "",
      "progress": {
        "loaded": 0,
        "target": 1,
        "percent": 0
      },
      "warehouse": {
        "primary_table": "parl_vote_events",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_parlamentario_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/senado_votaciones_sample.xml",
        "sample_url": "etl/data/raw/samples/senado_votaciones_sample.xml",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": false,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "CC BY 4.0 (datos abiertos del Senado)",
        "terms_url": "https://www.senado.es/web/relacionesciudadanos/datosabiertos/catalogodatos/index.html",
        "obligations": [
          "Atribuir la fuente conforme a CC BY 4.0.",
          "Indicar si hubo cambios, transformaciones o elaboraci\u00f3n propia."
        ],
        "notes": "Redistribuci\u00f3n y transformaci\u00f3n permitidas con atribuci\u00f3n.",
        "personal_data_notes": "Datos de representantes: publicar solo campos necesarios para transparencia.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "congreso_diputados",
      "source_name": "Congreso - Diputados Activos",
      "domain": "politicos",
      "scope": "nacional",
      "level": "nacional",
      "institution_name": "Congreso de los Diputados",
      "role_title": "Diputado/a",
      "format": "json",
      "default_url": "https://www.congreso.es/es/opendata/diputados",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Representantes y mandatos (Congreso)",
      "tracker_fuentes_objetivo": "Congreso OpenData Diputados",
      "tracker_block_note": "Mejorar calidad de campos opcionales",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 350,
      "max_loaded_any": 350,
      "max_loaded_network": 350,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:37:20+00:00",
      "latest_snapshot": "2026-05-14T05:37:20+00:00",
      "last_message": "Ingesta completada: 350/350 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 350,
        "target": 300,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 350,
        "counts": {
          "mandates": 350,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 300,
        "fallback_file": "etl/data/raw/samples/congreso_diputados_sample.json",
        "sample_url": "etl/data/raw/samples/congreso_diputados_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "Aviso legal del Congreso (reutilizaci\u00f3n autorizada con condiciones)",
        "terms_url": "https://www.congreso.es/es/avisoLegal",
        "obligations": [
          "No desnaturalizar ni tergiversar la informaci\u00f3n de origen.",
          "Citar la fuente institucional de forma visible.",
          "Indicar fecha de \u00faltima actualizaci\u00f3n/extracci\u00f3n cuando conste.",
          "No sugerir patrocinio o respaldo institucional.",
          "Conservar metadatos relevantes de actualizaci\u00f3n y condiciones de reutilizaci\u00f3n."
        ],
        "notes": "Para mirror, conservar integridad/atribuci\u00f3n; para derivados, marcar elaboraci\u00f3n propia.",
        "personal_data_notes": "Datos de representantes: publicar solo campos necesarios para transparencia.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "senado_senadores",
      "source_name": "Senado - Senadores",
      "domain": "politicos",
      "scope": "nacional",
      "level": "nacional",
      "institution_name": "Senado de Espana",
      "role_title": "Senador/a",
      "format": "xml",
      "default_url": "https://www.senado.es/web/ficopendataservlet?tipoFich=6&legis=15",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Representantes y mandatos (Senado)",
      "tracker_fuentes_objetivo": "Senado OpenData XML (grupos + fichas)",
      "tracker_block_note": "GitHub Actions strict-network devuelve `HTTP 403` en `senado_senadores`; mantener datos previos como evidencia parcial, pero no marcar `DONE` hasta recuperar run reproducible live-clean.",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "stale",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 2,
      "max_loaded_any": 2,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:56:35+00:00",
      "latest_snapshot": "2026-05-14T05:56:35+00:00",
      "last_message": "Ingesta completada: 2/2 registros validos (network-error-fallback: HTTPError: HTTP Error 403: Forbidden)",
      "blocker_reason": "",
      "progress": {
        "loaded": 2,
        "target": 250,
        "percent": 1
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 2,
        "counts": {
          "mandates": 2,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 250,
        "fallback_file": "etl/data/raw/samples/senado_senadores_sample.csv",
        "sample_url": "etl/data/raw/samples/senado_senadores_sample.csv",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "CC BY 4.0 (datos abiertos del Senado)",
        "terms_url": "https://www.senado.es/web/relacionesciudadanos/datosabiertos/catalogodatos/index.html",
        "obligations": [
          "Atribuir la fuente conforme a CC BY 4.0.",
          "Indicar si hubo cambios, transformaciones o elaboraci\u00f3n propia."
        ],
        "notes": "Redistribuci\u00f3n y transformaci\u00f3n permitidas con atribuci\u00f3n.",
        "personal_data_notes": "Datos de representantes: publicar solo campos necesarios para transparencia.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "dir3_unidades_age",
      "source_name": "DIR3 - Unidades organicas de la Administracion General del Estado",
      "domain": "politicos",
      "scope": "organigrama",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "xlsx",
      "default_url": "https://administracionelectronica.gob.es/ctt/resources/Soluciones/238/Descargas/Listado%20Unidades%20AGE.xlsx?idIniciativa=238&idElemento=2741",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "",
      "tracker_tipo_dato": "",
      "tracker_fuentes_objetivo": "",
      "tracker_block_note": "",
      "sql_status": "PARTIAL",
      "ops_state": "partial",
      "catalog_state": "stale",
      "mismatch_state": "UNTRACKED",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 3,
      "max_loaded_any": 3,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:40:40+00:00",
      "latest_snapshot": "2026-05-14T05:40:40+00:00",
      "last_message": "Ingesta completada: 3/3 registros validos (network-error-fallback: HTTPError: HTTP Error 302: The HTTP server returned a redirect error that would lead to an infinite loop.\nThe last 30x error message was:\nMoved Temporarily)",
      "blocker_reason": "",
      "progress": {
        "loaded": 3,
        "target": 1000,
        "percent": 0
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 1000,
        "fallback_file": "etl/data/raw/samples/dir3_unidades_age_sample.json",
        "sample_url": "etl/data/raw/samples/dir3_unidades_age_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": true,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://administracionelectronica.gob.es/ctt/resources/Soluciones/238/Descargas/Listado%20Unidades%20AGE.xlsx?idIniciativa=238&idElemento=2741",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "aemet_opendata_series",
      "source_name": "AEMET OpenData - Indicadores confusores",
      "domain": "politicos",
      "scope": "outcomes",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://opendata.aemet.es/opendata/api/valores/climatologicos",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Indicadores (confusores): AEMET",
      "tracker_fuentes_objetivo": "AEMET OpenData",
      "tracker_block_note": "Done now: NO. Blocker: `aemet_opendata_series` en `strict-network` sigue bloqueado por contrato (`aemet_blocker=contract`, JSON invalido con payload vac\u00edo `payload_sig=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`, `run_id=263`, `run_records_loaded=0`), por lo que la fila permanece `PARTIAL`. Evidencia: `docs/etl/sprints/AI-OPS-14/evidence/blocker-probe-refresh.log`, `docs/etl/sprints/AI-OPS-14/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-14/exports/unblock_feasibility_matrix.csv`. Siguiente comando: `AEMET_API_KEY=<token> python3 scripts/ingestar_politicos_es.py ingest --db etl/data/staging/politicos-es.db --source aemet_opendata_series --url https://opendata.aemet.es/opendata/api/observacion/convencional/todas --snapshot-date 2026-02-17 --strict-network --timeout 30`.",
      "sql_status": "PARTIAL",
      "ops_state": "ok",
      "catalog_state": "blocked",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 2,
      "max_loaded_any": 2,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:35:00+00:00",
      "latest_snapshot": "2026-05-14T05:35:00+00:00",
      "last_message": "Ingesta completada: 2/2 registros validos (contract-error-fallback: HTTPError: HTTP Error 404: No Encontrado)",
      "blocker_reason": "Done now: NO. Blocker: `aemet_opendata_series` en `strict-network` sigue bloqueado por contrato (`aemet_blocker=contract`, JSON invalido con payload vac\u00edo `payload_sig=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`, `run_id=263`, `run_records_loaded=0`), por lo que la fila permanece `PARTIAL`. Evidencia: `docs/etl/sprints/AI-OPS-14/evidence/blocker-probe-refresh.log`, `docs/etl/sprints/AI-OPS-14/evidence/unblock-execution.log`, `docs/etl/sprints/AI-OPS-14/exports/unblock_feasibility_matrix.csv`. Siguiente comando: `AEMET_API_KEY=<token> python3 scripts/ingestar_politicos_es.py ingest --db etl/data/staging/politicos-es.db --source aemet_opendata_series --url https://opendata.aemet.es/opendata/api/observacion/convencional/todas --snapshot-date 2026-02-17 --strict-network --timeout 30`.",
      "progress": {
        "loaded": 2,
        "target": 1,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/aemet_opendata_series_sample.json",
        "sample_url": "etl/data/raw/samples/aemet_opendata_series_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": true
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "CC BY 4.0 (distribuciones AEMET en cat\u00e1logo datos.gob.es)",
        "terms_url": "https://datos.gob.es/es/aviso-legal",
        "obligations": [
          "Atribuir la fuente conforme a CC BY 4.0.",
          "Indicar si hubo cambios, transformaciones o elaboraci\u00f3n propia."
        ],
        "notes": "Confirmado v\u00eda cat\u00e1logo oficial; mantener atribuci\u00f3n de fuente.",
        "personal_data_notes": "No aplica normalmente (series agregadas).",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "bde_series_api",
      "source_name": "Banco de Espana - Indicadores confusores (API series)",
      "domain": "politicos",
      "scope": "outcomes",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://app.bde.es/bierest/resources/srdatosapp/listaSeries?idioma=es&series=D_1NBAA301,D_1NBAA304,D_1NBAA317,D_1NBAA372,D_1NBAA572,D_1NBAC372,D_1NBAC572,D_1NBAC972,D_1NBAD301,D_1NBAD302,D_1NBAD306,D_1NBAD311,D_1NBAD317,D_1NBAD372,D_1NBAD472,D_1NBAD572,D_1NBAD972,D_1NBAE472,D_1NBAE572,D_1NBAE972,D_1NBAF472,D_1NBAF572,D_1NBAS372,D_1NBAS572,D_1NBAS972,D_1NBBO020,D_1NBBO072,D_1NBBO303,D_1NBBO305,D_1NBBO307,D_1NBBO308,D_1NBBO309,D_1NBBO310,D_1NBBO311,D_1NBBO314,D_1NBBO315,D_1NBBO316,D_1NBBO320,D_1NBBO333,D_1NBBO349,D_1NBBO572,D_1NBBP301,D_1NBBP302,D_1NBBP303,D_1NBBP304,D_1NBBP305,D_1NBBP306,D_1NBBP307,D_1NBBP308,D_1NBBP309,D_1NBBP310,D_1NBBP311,D_1NBBP314,D_1NBBP315,D_1NBBP316,D_1NBBP317,D_1NBBP349,D_1NBBP572&rango=30M",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "DONE",
      "tracker_tipo_dato": "Indicadores (confusores): Banco de Espana",
      "tracker_fuentes_objetivo": "Banco de Espana (API series)",
      "tracker_block_note": "Done now: YES. Live ETL `2026-05-11` carg\u00f3 `58/58` registros con red real, y verificaci\u00f3n local `--strict-network` sobre DB limpia confirm\u00f3 `58/58 registros validos` contra BIEREST `listaSeries`. Evidencia: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`; cobertura ampliada: fila `Cobertura BDE multi-serie`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source bde_series_api --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30 && python3 scripts/ingestar_politicos_es.py backfill-indicators --db <db> --source-ids bde_series_api`.",
      "sql_status": "DONE",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 58,
      "max_loaded_any": 58,
      "max_loaded_network": 58,
      "network_fetches": 1,
      "fallback_fetches": 0,
      "last_seen_at": "2026-05-14T05:37:15+00:00",
      "latest_snapshot": "2026-05-14T05:37:15+00:00",
      "last_message": "Ingesta completada: 58/58 registros validos",
      "blocker_reason": "",
      "progress": {
        "loaded": 58,
        "target": 58,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 58,
        "fallback_file": "etl/data/raw/samples/bde_series_api_sample.json",
        "sample_url": "etl/data/raw/samples/bde_series_api_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": true,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "verified",
        "reuse_basis": "T\u00e9rminos de uso estad\u00edsticos Banco de Espa\u00f1a (reutilizaci\u00f3n con integridad/atribuci\u00f3n)",
        "terms_url": "https://www.bde.es",
        "obligations": [
          "No alterar contenido ni metadatos de origen cuando se redistribuyen como mirror.",
          "Atribuir la fuente (Banco de Espa\u00f1a) e indicar fecha de actualizaci\u00f3n.",
          "Si hay elaboraci\u00f3n propia, indicarla expl\u00edcitamente.",
          "No intentar reidentificaci\u00f3n de personas ni circular datos personales identificables."
        ],
        "notes": "Cuando haya tratamiento, indicar elaboraci\u00f3n propia con datos extra\u00eddos.",
        "personal_data_notes": "Difundir solo resultados agregados cuando exista riesgo de identificaci\u00f3n.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "ree_esios_indicators",
      "source_name": "ESIOS/REE - Indicadores confusores (API)",
      "domain": "politicos",
      "scope": "outcomes",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://apidatos.ree.es/es/datos/demanda/evolucion?start_date=2026-02-11T00:00&end_date=2026-02-12T23:59&time_trunc=hour",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Indicadores (confusores): ESIOS/REE",
      "tracker_fuentes_objetivo": "ESIOS/REE API (token)",
      "tracker_block_note": "Done now: PARTIAL. AI-OPS-296 cierra el gap de conector con `ree_esios_indicators` (config/registry + parser de payload REE `included[].attributes.values` + soporte de contenedor serializado `records` + rechazo de snapshots legacy `metric,value` + fallback sample reproducible) y lo integra en `backfill-indicators`/mapeo tracker. Corrida reproducible en DB principal desde muestra (`--from-file`) deja `status=ok`, `records_loaded=2`, `source_records_total=2`; el probe `--strict-network` al endpoint oficial sigue bloqueado de forma reproducible con `HTTP 500`, body HTML y cabecera `x-cdn: Imperva`, por lo que no aplica `DONE` en red real. Evidencia: `docs/etl/sprints/AI-OPS-296/reports/ree-esios-indicators-connector-partial-closure-20260228.md`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_ingest_status_latest.json`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_curl_headers_latest.txt`, `docs/etl/sprints/AI-OPS-296/evidence/e2e_tracker_status_main_db_latest.txt`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_main_db_ingestion_runs_latest.txt`. Siguiente comando: `ESIOS_API_TOKEN=<token> python3 scripts/ingestar_politicos_es.py ingest --db <db> --source ree_esios_indicators --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30 && python3 scripts/ingestar_politicos_es.py backfill-indicators --db <db> --source-ids ree_esios_indicators`.",
      "sql_status": "PARTIAL",
      "ops_state": "ok",
      "catalog_state": "blocked",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 2,
      "max_loaded_any": 2,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:56:35+00:00",
      "latest_snapshot": "2026-05-14T05:56:35+00:00",
      "last_message": "Ingesta completada: 2/2 registros validos (network-error-fallback: HTTPError: HTTP Error 400: Bad Request)",
      "blocker_reason": "Done now: PARTIAL. AI-OPS-296 cierra el gap de conector con `ree_esios_indicators` (config/registry + parser de payload REE `included[].attributes.values` + soporte de contenedor serializado `records` + rechazo de snapshots legacy `metric,value` + fallback sample reproducible) y lo integra en `backfill-indicators`/mapeo tracker. Corrida reproducible en DB principal desde muestra (`--from-file`) deja `status=ok`, `records_loaded=2`, `source_records_total=2`; el probe `--strict-network` al endpoint oficial sigue bloqueado de forma reproducible con `HTTP 500`, body HTML y cabecera `x-cdn: Imperva`, por lo que no aplica `DONE` en red real. Evidencia: `docs/etl/sprints/AI-OPS-296/reports/ree-esios-indicators-connector-partial-closure-20260228.md`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_ingest_status_latest.json`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_curl_headers_latest.txt`, `docs/etl/sprints/AI-OPS-296/evidence/e2e_tracker_status_main_db_latest.txt`, `docs/etl/sprints/AI-OPS-296/evidence/ree_esios_main_db_ingestion_runs_latest.txt`. Siguiente comando: `ESIOS_API_TOKEN=<token> python3 scripts/ingestar_politicos_es.py ingest --db <db> --source ree_esios_indicators --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30 && python3 scripts/ingestar_politicos_es.py backfill-indicators --db <db> --source-ids ree_esios_indicators`.",
      "progress": {
        "loaded": 2,
        "target": 1,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/ree_esios_indicators_sample.json",
        "sample_url": "etl/data/raw/samples/ree_esios_indicators_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": true
      },
      "legal": {
        "verification_status": "pending_review",
        "reuse_basis": "Sin verificaci\u00f3n documental espec\u00edfica en este snapshot",
        "terms_url": "https://apidatos.ree.es/es/datos/demanda/evolucion?start_date=2026-02-11T00:00&end_date=2026-02-12T23:59&time_trunc=hour",
        "obligations": [
          "Verificar aviso legal/licencia del dominio de origen antes de redistribuci\u00f3n comercial."
        ],
        "notes": "Fuente sin ficha legal espec\u00edfica en esta versi\u00f3n. Revisi\u00f3n manual requerida antes de redistribuci\u00f3n comercial.",
        "personal_data_notes": "Si existen datos personales, aplicar minimizaci\u00f3n, evitar reidentificaci\u00f3n y atender solicitudes de derechos.",
        "reviewed_on": "2026-02-21"
      }
    },
    {
      "source_id": "eurostat_sdmx",
      "source_name": "Eurostat - Indicadores outcomes (API/SDMX)",
      "domain": "politicos",
      "scope": "outcomes",
      "level": "",
      "institution_name": "",
      "role_title": "",
      "format": "json",
      "default_url": "https://ec.europa.eu/eurostat/api/dissemination/statistics/1.0/data/",
      "desired": true,
      "in_db": true,
      "active": true,
      "tracker_status": "PARTIAL",
      "tracker_tipo_dato": "Indicadores (outcomes): Eurostat",
      "tracker_fuentes_objetivo": "Eurostat (API/SDMX)",
      "tracker_block_note": "Done now: NO para live-clean. Live ETL `2026-05-11` carg\u00f3 solo fallback (`2/2`) tras `HTTP 404` en red real (`max_net=0`, `net/fallback_fetches=0/1`), as\u00ed que queda `PARTIAL` hasta corregir endpoint/query o confirmar contrato alternativo. Evidencia: `docs/etl/sprints/COMMUNITY-LIVE-ETL/evidence/live_etl_publish_tracker_truth_20260511.md`. Siguiente comando: `python3 scripts/ingestar_politicos_es.py ingest --db <db> --source eurostat_sdmx --snapshot-date <YYYY-MM-DD> --strict-network --timeout 30`.",
      "sql_status": "PARTIAL",
      "ops_state": "ok",
      "catalog_state": "available",
      "mismatch_state": "MATCH",
      "mismatch_waived": false,
      "waiver_expiry": "",
      "runs_total": 1,
      "runs_ok": 1,
      "last_status": "ok",
      "last_loaded": 2,
      "max_loaded_any": 2,
      "max_loaded_network": 0,
      "network_fetches": 0,
      "fallback_fetches": 1,
      "last_seen_at": "2026-05-14T05:40:41+00:00",
      "latest_snapshot": "2026-05-14T05:40:41+00:00",
      "last_message": "Ingesta completada: 2/2 registros validos (network-error-fallback: HTTPError: HTTP Error 404: Not Found)",
      "blocker_reason": "",
      "progress": {
        "loaded": 2,
        "target": 1,
        "percent": 100
      },
      "warehouse": {
        "primary_table": "mandates",
        "primary_rows": 0,
        "counts": {
          "mandates": 0,
          "parl_vote_events": 0,
          "parl_initiatives": 0,
          "infoelectoral_convocatoria_tipos": 0,
          "infoelectoral_procesos": 0
        }
      },
      "execution": {
        "runner_script": "scripts/ingestar_politicos_es.py",
        "strict_target": 1,
        "fallback_file": "etl/data/raw/samples/eurostat_sdmx_sample.json",
        "sample_url": "etl/data/raw/samples/eurostat_sdmx_sample.json",
        "sample_available": true
      },
      "flags": {
        "under_threshold": false,
        "done_zero_real": false,
        "has_network": false,
        "has_any": true,
        "blocked_note": false
      },
      "legal": {
        "verification_status": "partially_verified",
        "reuse_basis": "Pol\u00edtica de reutilizaci\u00f3n Eurostat (permitida con reconocimiento de fuente, con excepciones)",
        "terms_url": "https://ec.europa.eu/eurostat/about/policies/copyright/",
        "obligations": [
          "Reconocer la fuente Eurostat en redistribuci\u00f3n/transformaci\u00f3n.",
          "Indicar cambios/adaptaciones cuando existan.",
          "Revisar excepciones de material de terceros antes de habilitar reutilizaci\u00f3n comercial."
        ],
        "notes": "Revisar excepciones de terceros por dataset antes de etiquetar como libre comercial sin reservas.",
        "personal_data_notes": "No aplica normalmente (series agregadas).",
        "reviewed_on": "2026-02-21"
      }
    }
  ]
}
