Files
ThothII/harness/.pi/skills/tht-sessione/sql-generation.md
T
marcopan de61034a8d feat(harness): riscrittura skill tht-sessione (F1-F8 + 4 sottomoduli)
Skill ex-novo che riflette Thoth (non copia di ChironeWp3):
- vocabolario widget-descriptor (reviewer_select/decide/confirm) invece di 'dialog native'
- D11 save-one in F2 (upsert mirato vs full resync)
- D14a value_grounded (LSH multi-colonna non collassa) + D14b concept_formula in F4
- D13 free-text e D15 rollback nelle discipline trasversali
- memory vive SOLO nel vectordb (drop registry, spec 5): save-one/promote senza registry
- F8 datamart onesto (stub NotImplementedError)

Sottomoduli cte/memoria/rewriting/sql-generation portati adattando nsp->tht, con
i vincoli precisi trasferiti fedelmente (max 5 memorie, solo 3 tipi riusabili,
CTE solo WITH senza SELECT, dim_time join non aritmetica, sql_final pulito).

Verifica: zero residui nsp/chirone/psd nella skill; ogni 'tht <cmd>' citato e'
registrato (correzione: 'tht formula retrieve' era inesistente -> riformulato in
'ricerca nelle evidence'). Suite: 165 passed.
2026-06-27 14:24:20 +02:00

2.8 KiB

Tecnica di generazione del SQL finale

Adattata dallo step "query generation" di AV-SQL (divide-and-conquer ricorsivo) e dalla sua checklist di revisione.

Generazione (divide-and-conquer)

  1. Dividi: scomponi la domanda riscritta in sotto-domande, ognuna mirata a un pezzo di informazione o logica (una popolazione, un filtro, un aggregato).
  2. Conquista: per ogni sotto-domanda formula uno pseudo-SQL, con segnaposto per le sotto-domande non ancora risolte. I CTE gia' testati in Fase 6 sono i mattoni preferenziali: riusali per nome, col loro esito noto.
  3. Ricombina: sostituisci i segnaposto dal basso verso l'alto fino al SQL completo. Il SQL finale puo' includere i CTE nel proprio WITH.
  4. Dialetto: PostgreSQL. Copia ESATTAMENTE i nomi di tabelle e colonne dal contesto schema; mai inventare oggetti.

Il file sessions/<id>/sql_final.sql deve contenere SOLO il SQL, pulito e copiabile: niente commenti di razionale (quello vive negli artefatti di audit).

Dimensione tempo (analisi per anno/mese/trimestre)

Le fact table hanno data_time_key (integer, formato YYYYMMDD): è la FK verso dim_time.day_key. Questa FK non è dichiarata nel DWH (le fact hanno foreign_keys: []), quindi non comparirà in schema_linking.json: vai aggiunta a mano nel join.

  • Per estrarre anno, mese, trimestre, semestre ecc. fai JOIN dim_time dt ON dt.day_key = <fact>.data_time_key e usa le colonne della dimensione: dt.year, dt.month, dt.quarter, dt.semester, dt.full_date, dt.month_name_it, dt.year_month.
  • Non fare aritmetica sulla chiave (es. data_time_key / 10000 per l'anno): funziona per caso ma è fragile e si rompe appena serve formattare una data o fare cast. Usa sempre dim_time.
  • "Ultimi N anni dall'anno più recente": dt.year >= (SELECT MAX(year) FROM dim_time WHERE day_key IN (SELECT data_time_key FROM <fact>)) - (N-1), oppure calcola il max anno sulle righe effettivamente presenti nella fact.

Checklist di revisione (su errori o risultati sospetti)

  • Le colonne restituite rispondono esattamente alla domanda?
  • I filtri (WHERE/HAVING) riflettono tutte le condizioni della domanda riscritta?
  • Aggregazioni, raggruppamenti e ordinamenti sono quelli richiesti?
  • Risultato vuoto o zero: quasi sempre indica un problema in condizioni o join. Verifica i valori dei filtri con tht search "<valore>" (match sui valori reali).
  • I join seguono quelli promossi in schema_linking.json? (eccezione: la FK data_time_key → dim_time.day_key non è dichiarata, vedi sezione tempo.)
  • Analisi temporali: stai usando JOIN dim_time e non aritmetica sulla chiave?

Ogni revisione sostanziale va registrata con: reviewer_decide(options:[{label:"Registra revisione", type:"sql_revised", subject:"sql_final", detail:"<cosa e' cambiato>", rationale:"<perche'>"}], allow_other:false).