diff --git a/tools/replay/replay.json b/tools/replay/replay.json index 4cdc122b..b05ece2b 100644 --- a/tools/replay/replay.json +++ b/tools/replay/replay.json @@ -3702,11 +3702,144 @@ "widget": "artifact-gate", "title": "Fase 5 completata — passo alla Fase 6 (Piano CTE)?", "artifact": { + "kind": "phase", "data": { - "check": "OK — completa per il Blocco 3", - "riepilogo": "Ablazione: fact_studio_elettrofisiologico_endocavitario_ablazione (ablazione_transcatetere IS TRUE). Impianto ICD: fact_impianto_defibrillatore_impiantabile. Cross-fact su cod_paz (entrambe FK a dim_patient). Escluse sostituzioni e controlli. Finestre temporali: ablazione in [2011-07-03, 2026-07-03]; impianto dopo e <= ablazione+10 anni." - }, - "kind": "synthesis_recap" + "schema_version": 2, + "phase": { + "id": "F5", + "num": 5, + "name": "sintesi" + }, + "summary": "Sintesi completa per il Blocco 3: ablazione transcatetere e impianto ICD sono ancorati rispettivamente a `fact_studio_elettrofisiologico_endocavitario_ablazione` e `fact_impianto_defibrillatore_impiantabile`, incrociati su `cod_paz` (entrambe FK a `dim_patient`). Escluse sostituzioni e controlli, fuori perimetro della domanda.", + "checks": [ + { + "label": "Copertura tabelle promosse", + "status": "ok", + "detail": "Tutte le tabelle usate sono nel perimetro promosso in F4." + }, + { + "label": "Finestre temporali coerenti", + "status": "ok", + "detail": "Ablazione in [2011-07-03, 2026-07-03]; impianto dopo l'ablazione e <= ablazione + 10 anni." + }, + { + "label": "Chiavi di join verificate", + "status": "ok", + "detail": "cod_paz presente e non nullo in entrambe le fact table candidate." + }, + { + "label": "Ambiguità residue", + "status": "warn", + "detail": "Pazienti con più ablazioni: da chiarire in F6 se contare la prima o l'ultima coppia qualificante." + } + ], + "sections": [ + { + "title": "Criteri di selezione", + "items": [ + { + "label": "Ablazione transcatetere", + "table": "fact_studio_elettrofisiologico_endocavitario_ablazione", + "column": "ablazione_transcatetere", + "value": "IS TRUE", + "kind": "filter", + "description": "Indicazione di ablazione transcatetere derivata dal text analysis sul campo conclusioni (sovrascrive il flag Cardioref).", + "rationale": "Isola le sole procedure transcatetere richieste dalla domanda." + }, + { + "label": "Finestra ablazione", + "table": "fact_studio_elettrofisiologico_endocavitario_ablazione", + "column": "data_ablazione", + "value": "[2011-07-03, 2026-07-03]", + "kind": "filter", + "description": "Data di esecuzione della procedura di ablazione.", + "rationale": "Finestra degli «ultimi 15 anni» calcolata rispetto alla data corrente della domanda." + }, + { + "label": "Impianto successivo all'ablazione", + "table": "fact_impianto_defibrillatore_impiantabile", + "column": "data_impianto", + "value": "> data_ablazione E <= data_ablazione + 10 anni", + "kind": "filter", + "description": "Data di esecuzione dell'impianto del defibrillatore.", + "rationale": "Vincolo «entro 10 anni» richiesto dalla domanda." + }, + { + "label": "Join paziente", + "table": "dim_patient", + "column": "cod_paz", + "value": "cross-fact join", + "kind": "join", + "description": "Codice identificativo del paziente nel sistema sorgente Cardioref.", + "rationale": "Chiave comune tra le due fact table (entrambe FK a dim_patient)." + } + ] + } + ], + "tables": [ + { + "name": "fact_studio_elettrofisiologico_endocavitario_ablazione", + "role": "promoted", + "description": "Fatto clinico derivato da cr_seeablazione relativo a eventi, procedure o rilevazioni del paziente. Esclude record riclassificati come cardioversione o chiusura auricola.", + "columns": [ + { + "name": "cod_paz", + "description": "Codice paziente (FK a dim_patient)." + }, + { + "name": "num", + "description": "Numero progressivo dell'episodio clinico per il paziente." + }, + { + "name": "ablazione_transcatetere", + "description": "Indicazione di ablazione transcatetere derivata dal text analysis sul campo conclusioni.", + "value_filter": "IS TRUE" + } + ] + }, + { + "name": "fact_impianto_defibrillatore_impiantabile", + "role": "promoted", + "description": "Fact table degli impianti di defibrillatori (ICD). Esclude record riclassificati come CRT-P/CRT-D/S-ICD dal classificatore CIED.", + "columns": [ + { + "name": "cod_paz", + "description": "Codice paziente (FK a dim_patient)." + }, + { + "name": "num", + "description": "Numero progressivo dell'episodio clinico per il paziente." + } + ] + }, + { + "name": "dim_patient", + "role": "promoted", + "description": "Dimensione paziente derivata dall'anagrafica Cardioref normalizzata nello schema di integrazione. Popolata solo con pazienti che hanno almeno un record in una tabella flaggata is_activity_table:true in integration-map.yaml (gate di attivita clinica del reparto di aritmologia).", + "columns": [ + { + "name": "cod_paz", + "description": "Codice identificativo del paziente nel sistema sorgente Cardioref." + } + ] + }, + { + "name": "fact_sostituzione_impianto_defibrillatore_impiantabile", + "role": "excluded", + "description": "Fact table delle sostituzioni/revisioni ICD. Esclude record riclassificati come CRT-P/CRT-D/S-ICD dal classificatore CIED.", + "columns": [] + }, + { + "name": "fact_controllo_defibrillatore_impiantabile", + "role": "excluded", + "description": "Fact table dei controlli periodici dei dispositivi ICD.", + "columns": [] + } + ], + "open_questions": [ + "Se un paziente ha più ablazioni transcatetere seguite da impianto, contare la prima o l'ultima coppia qualificante?" + ] + } }, "action": { "kind": "approve_reject", @@ -3851,20 +3984,98 @@ "widget": "artifact-gate", "title": "F6 — CTE 1 approvato: ablazioni_recenti?", "artifact": { + "kind": "cte_result", "data": { - "colonne": [ - "cod_paz", - "num", - "data_ablazione" + "schema_version": 2, + "name": "ablazioni_recenti", + "index": 1, + "total": 4, + "purpose": "Ablazioni transcatetere (ablazione_transcatetere IS TRUE) con data ∈ [2011-07-03, 2026-07-03].", + "rationale": "Punto di partenza della catena: isola l'evento indice (ablazione) prima di cercare l'impianto conseguente.", + "depends_on": [], + "sql": "WITH ablazioni_recenti AS (\n SELECT\n cod_paz,\n num,\n data_ablazione\n FROM fact_studio_elettrofisiologico_endocavitario_ablazione\n WHERE ablazione_transcatetere IS TRUE\n AND data_ablazione BETWEEN DATE '2011-07-03' AND DATE '2026-07-03'\n)\nSELECT * FROM ablazioni_recenti\nLIMIT 10;", + "status": "ok", + "execution_ms": 184, + "row_sample": 10, + "warnings": [ + "righe = limit: risultato troncato dalla preview" ], - "file": "ctes/ablazioni_recenti.sql", - "latenza_ms": 184, - "note": "Tutte le data_ablazione ricadono nel range [2011-07-03, 2026-07-03]; preview troncata a 10 righe. Mantiene le chiavi cod_paz e num.", - "preview": "cod_paz | num | data_ablazione\n3758 | 5 | 2018-09-24\n8175 | 473 | 2025-05-19\n152185 | 3 | 2026-05-28\n20446 | 61 | 2018-05-14\n25492 | 3 | 2013-11-28\n4664 | 94 | 2016-05-31\n39149 | 2 | 2018-04-05\n7243 | 38 | 2012-12-12\n22310 | 9 | 2013-07-15\n4848 | 408 | 2011-10-05", - "scopo": "Ablazioni transcatetere (ablazione_transcatetere IS TRUE) con data ∈ [2011-07-03, 2026-07-03]", - "warning": "righe = limit: risultato troncato dalla preview" - }, - "kind": "cte" + "sql_hash": "a3f6c9d1e8b2047f", + "columns": [ + { + "name": "cod_paz", + "description": "Codice paziente (FK a dim_patient)." + }, + { + "name": "num", + "description": "Numero progressivo dell'episodio clinico per il paziente." + }, + { + "name": "data_ablazione", + "description": "Data di esecuzione della procedura di ablazione." + } + ], + "preview": { + "columns": [ + "cod_paz", + "num", + "data_ablazione" + ], + "rows": [ + [ + 3758, + 5, + "2018-09-24" + ], + [ + 8175, + 473, + "2025-05-19" + ], + [ + 152185, + 3, + "2026-05-28" + ], + [ + 20446, + 61, + "2018-05-14" + ], + [ + 25492, + 3, + "2013-11-28" + ], + [ + 4664, + 94, + "2016-05-31" + ], + [ + 39149, + 2, + "2018-04-05" + ], + [ + 7243, + 38, + "2012-12-12" + ], + [ + 22310, + 9, + "2013-07-15" + ], + [ + 4848, + 408, + "2011-10-05" + ] + ] + }, + "note": "Tutte le data_ablazione ricadono nel range [2011-07-03, 2026-07-03]; preview troncata a 10 righe. Mantiene le chiavi cod_paz e num." + } }, "action": { "kind": "approve_reject", @@ -3905,27 +4116,137 @@ "widget": "artifact-gate", "title": "F6 — Piano CTE (persisti cte_plan.json)", "artifact": { + "kind": "cte_plan", "data": { - "cte_plan": [ + "schema_version": 2, + "question": "Lista dei pazienti che, negli ultimi 15 anni, hanno avuto un'ablazione transcatetere seguita da un impianto di defibrillatore (ICD) entro 10 anni.", + "strategy": "Catena di 4 CTE: prima isolo le ablazioni transcatetere e gli impianti ICD separatamente (con le rispettive finestre temporali), poi li unisco per paziente mantenendo solo le coppie in cui l'impianto segue l'ablazione entro 10 anni, infine riduco a una riga per paziente scegliendo la prima coppia qualificante.", + "ctes": [ { "name": "ablazioni_recenti", - "purpose": "ablazioni transcatetere (flag IS TRUE) con data ∈ [2011-07-03, 2026-07-03]; chiavi cod_paz, num, data_ablazione" + "index": 1, + "purpose": "Ablazioni transcatetere (ablazione_transcatetere IS TRUE) con data ∈ [2011-07-03, 2026-07-03].", + "rationale": "Punto di partenza della catena: isola l'evento indice (ablazione) prima di cercare l'impianto conseguente.", + "depends_on": [], + "tables": [ + { + "name": "fact_studio_elettrofisiologico_endocavitario_ablazione", + "description": "Fatto clinico derivato da cr_seeablazione relativo a eventi, procedure o rilevazioni del paziente. Esclude record riclassificati come cardioversione o chiusura auricola." + } + ], + "keys": [ + "cod_paz", + "num" + ], + "filters": [ + { + "column": "fact_studio_elettrofisiologico_endocavitario_ablazione.ablazione_transcatetere", + "op": "IS", + "value": "TRUE", + "description": "Indicazione di ablazione transcatetere derivata dal text analysis sul campo conclusioni (sovrascrive il flag Cardioref).", + "rationale": "Filtra solo le procedure di ablazione transcatetere richieste dalla domanda, escludendo altre tipologie di intervento." + }, + { + "column": "fact_studio_elettrofisiologico_endocavitario_ablazione.data_ablazione", + "op": "BETWEEN", + "value": "2011-07-03 AND 2026-07-03", + "description": "Data di esecuzione della procedura di ablazione.", + "rationale": "Finestra degli «ultimi 15 anni» calcolata rispetto alla data corrente della domanda." + } + ], + "output_columns": [ + "cod_paz", + "num", + "data_ablazione" + ] }, { "name": "impianti_icd", - "purpose": "impianti ICD iniziali con data; chiavi cod_paz, num, data_impianto" + "index": 2, + "purpose": "Impianti ICD iniziali con data.", + "rationale": "Secondo evento della catena: individua gli impianti candidati che potrebbero seguire un'ablazione già isolata in ablazioni_recenti.", + "depends_on": [], + "tables": [ + { + "name": "fact_impianto_defibrillatore_impiantabile", + "description": "Fact table degli impianti di defibrillatori (ICD). Esclude record riclassificati come CRT-P/CRT-D/S-ICD dal classificatore CIED." + } + ], + "keys": [ + "cod_paz", + "num" + ], + "filters": [], + "output_columns": [ + "cod_paz", + "num", + "data_impianto" + ] }, { "name": "sequenze_abl_imp", - "purpose": "join su cod_paz, coppie con impianto > ablazione e <= ablazione+10 anni" + "index": 3, + "purpose": "Join su cod_paz tra ablazioni_recenti e impianti_icd, mantiene le coppie con data_impianto > data_ablazione E <= data_ablazione + 10 anni.", + "rationale": "Applica il vincolo temporale «entro 10 anni» richiesto dalla domanda, collegando ablazione e impianto per lo stesso paziente.", + "depends_on": [ + "ablazioni_recenti", + "impianti_icd" + ], + "tables": [ + { + "name": "dim_patient", + "description": "Dimensione paziente derivata dall'anagrafica Cardioref normalizzata nello schema di integrazione. Popolata solo con pazienti che hanno almeno un record in una tabella flaggata is_activity_table:true in integration-map.yaml (gate di attivita clinica del reparto di aritmologia)." + } + ], + "keys": [ + "cod_paz" + ], + "filters": [ + { + "column": "sequenze_abl_imp.data_impianto", + "op": ">", + "value": "data_ablazione", + "description": "", + "rationale": "L'impianto deve seguire cronologicamente l'ablazione (non precederla né coincidere)." + }, + { + "column": "sequenze_abl_imp.data_impianto", + "op": "<=", + "value": "data_ablazione + INTERVAL '10 years'", + "description": "", + "rationale": "Vincolo «entro 10 anni» dalla domanda originale." + } + ], + "output_columns": [ + "cod_paz", + "num_ablazione", + "data_ablazione", + "num_impianto", + "data_impianto" + ] }, { "name": "pazienti_qualificati", - "purpose": "una riga per paziente (prima coppia qualificante) + gap in anni" + "index": 4, + "purpose": "Una riga per paziente (prima coppia qualificante: ablazione più recente) + gap in anni.", + "rationale": "Riduce sequenze_abl_imp a una riga per paziente come richiesto dalla «lista dei pazienti», scegliendo la coppia più recente in caso di ablazioni multiple.", + "depends_on": [ + "sequenze_abl_imp" + ], + "tables": [], + "keys": [ + "cod_paz" + ], + "filters": [], + "output_columns": [ + "cod_paz", + "data_ablazione", + "data_impianto", + "gap_anni" + ] } ] - }, - "kind": "cte_plan" + } }, "action": { "kind": "approve_reject",