Skip to content

feat(validation): sensible defaults — min_rows=1, NOT NULL inference, column type sanity, PAQA score, warn_only mode#399

Merged
Gabrymi93 merged 9 commits into
mainfrom
feat/sensible-validation-defaults
Jun 24, 2026
Merged

feat(validation): sensible defaults — min_rows=1, NOT NULL inference, column type sanity, PAQA score, warn_only mode#399
Gabrymi93 merged 9 commits into
mainfrom
feat/sensible-validation-defaults

Conversation

@Gabrymi93

Copy link
Copy Markdown
Member

Sintesi

Validazione automatica per tutti i dataset senza necessità di configurazione esplicita. Tre cambiamenti complementari:

  1. Sensible defaults — check che partono sempre senza configurazione
  2. PAQA score — qualità CSV PA nei run record
  3. Fix falsi positivi — transition check normalizza nomi colonna

Contesto collegato

Basato sulla gap analysis _local/tasks/2026-06-13-pipeline-quality-certificate.md: i gap 2 (type check), 5 (PAQA score) e il problema dei falsi positivi nel transition check.

Cosa cambia

  • Nuova funzionalità del motore
  • Refactor / performance

Sensible defaults

Check Automatico Comportamento
min_rows=1 Sempre Parquet vuoto = errore
NOT NULL inference Se raw profile disponibile Colonne 0% null nel raw → not_null implicito nel clean
Column type sanity Sempre Nome numerico ma tipo VARCHAR → warning
validation.mode Default strict warn_only per migrazione graduale
Transition row drop Disabilitato in sample mode Evita falsi positivi su campioni

PAQA score nei run record

  • paqa_score (0-100, qualità strutturale CSV)
  • paqa_verdict (buona/accettabile/scarsa)
  • paqa_semantic (0-100, euristico O+L)
  • Letto da CSV raw (campione 15MB), salta se Excel

Fix

  • compare_layer_profiles() ora normalizza spazi/trattini/underscore nei nomi colonna prima del confronto. Risolve falsi positivi columns removed per rinomine tipo 'Tipo ufficio' → 'tipo_ufficio'.

Impatto su contratti pubblici

  • Struttura dataset.yml — nuovo campo opzionale validation.mode: strict | warn_only

Nessun altro contratto pubblico modificato.

Verifica

pytest tests/ -x -q --ignore=tests/test_smoke_e2e_flow.py --ignore=tests/test_smoke_scout.py
# 1107 passed, 13 deselected
  • pytest -m core passa
  • ruff check . passa
  • mypy toolkit/ passa (o motiva le eccezioni)

Checklist PR

  • Perimetro stretto: una PR = un layer o un fix mirato
  • Issue collegata o motivazione dell'assenza

Note per chi revisiona

  • Il PAQA score è calcolato su un campione di 15MB del CSV raw per performance. Per file più piccoli viene letto integralmente.
  • La NOT NULL inference usa missingness_top dal raw profile (colonne con 0% null). Funziona sia per CSV che per Excel.
  • In sample mode (--smoke), il transition row drop check è disabilitato perché il campione non è rappresentativo.

Integra pa_csv_quality.assess_quality() nel validation flow CLEAN:
- Dopo validate_promotion(), legge il primo CSV raw
- Campione a 15MB (stessa soglia CI sample-bytes)
- Usa encoding/delim/skip dal raw_profile come hint
- Aggiunge paqa_score, paqa_verdict, paqa_semantic, paqa_sampled
  alle stats del run record
- Critical fail produce warning nel validation report
- Eccezioni silenziose (skip) — non blocca mai la pipeline

Test: 1107 pass, 0 fallimenti
Sample mode tronca i dati (sample-bytes per raw, sample-rows per clean).
Il calo righe raw->clean e' un falso positivo sistematico.
Disabilitiamo max_row_drop_pct, lasciamo warn_removed_columns attivo.
@Gabrymi93

Copy link
Copy Markdown
Member Author

Fix applicati (commit fa05abe)

1. NOT NULL inference spostata prima di validate_clean() — Critical

L'inferenza ora fa una pre-DESCRIBE del parquet clean per ottenere le colonne, poi aggiorna spec.validate.not_null prima di chiamare validate_clean(). Le colonne inferite vengono effettivamente verificate. Non più solo nel report.

2. logger.debug() safe — Critical

Usa getattr(logger, "debug", lambda *a, **kw: None) per evitare AttributeError su logger minimale (SimpleNamespace nei test).

Test: 1107 pass, CI riattivata.

@Gabrymi93

Copy link
Copy Markdown
Member Author

Fix applicato (commit d7d4ae8)

Critical: NOT NULL inference basata su null_counts (full map) invece di missingness_top (top 25)

  • raw_profile.json ora espone null_counts: {col_name: missing_pct} per TUTTE le colonne (non troncato)
  • La NOT NULL inference usa null_counts quando disponibile
  • Fallback a missingness_top solo per profili vecchi (senza null_counts), ma in quel caso non inferisce nulla — lista incompleta = non affidabile

Profilo raw: _sample_profile_rows() e profile_excel() ora producono null_counts oltre a missingness_top. Aggiunto al dict di output, test 1107 pass.

…ente in null_counts con pct=0) + PAQA da clean metadata
@Gabrymi93

Copy link
Copy Markdown
Member Author

Fix applicati (commit 08356c2)

Critical: NOT NULL inference ora è positiva

Prima: _rc not in _cols_with_nulls → inferiva NOT NULL se la colonna non era nella lista dei nulli. Con missingness_top troncato a 25, colonne nullable fuori top 25 passavano.

Ora: inferisce NOT NULL solo se:

  1. null_counts è presente nel profile (profili nuovi)
  2. La colonna è esplicitamente in null_counts
  3. null_counts[colonna] == 0.0

Se null_counts manca (profile legacy) o la colonna non è nella mappa (oltre la 200ª): non inferisce. Zero falsi positivi.

Medium: PAQA score ora usa il file CSV corretto

Prima: sorted(raw_dir.glob("*.csv"))[0] — prendeva il primo in ordine alfabetico, rischiando di processare un versioned backup (file_1.csv) invece del file originale.

Ora: legge il file CSV effettivamente usato da clean dal metadata.json. Fallback al primo *.csv solo se il metadata non è disponibile.

@Gabrymi93 Gabrymi93 merged commit d734e25 into main Jun 24, 2026
2 checks passed
@Gabrymi93 Gabrymi93 deleted the feat/sensible-validation-defaults branch June 24, 2026 16:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant