Skip to content

fix(pipeline): fallback DuckDB sniff, estrazione anni, circuit breaker condiviso - #413

Merged
Gabrymi93 merged 3 commits into
mainfrom
fix/validate-duckdb-years-circuitbreaker
Aug 1, 2026
Merged

fix(pipeline): fallback DuckDB sniff, estrazione anni, circuit breaker condiviso#413
Gabrymi93 merged 3 commits into
mainfrom
fix/validate-duckdb-years-circuitbreaker

Conversation

@Gabrymi93

Copy link
Copy Markdown
Member

Sintesi

Tre fix della pipeline di validazione SO (scripts/pipeline/run_pipeline.py + scripts/collectors/), che migliorano copertura, dati e velocità del validated.parquet.

Contesto collegato

Nessuna issue dedicata — emersi da diagnosi pipeline (attrito SO→DI): 268 CSV "reachable senza schema", 0 gruppi con anni su fonti grosse (INPS), run completo lento su host giù.

Dipendenza: PR lab-connectors#73 (fix verify duplicato nel fallback SSL HEAD). Senza di essa, ministero_salute torna a perdere 38 CSV. Da mergiare prima o insieme.

Cosa cambia

  • Nuova fonte o modifica registro (sources_registry.yaml)
  • Source-check o inventory-triage
  • Modifica script (radar, inventory, source-check, MCP)
  • Modifica funnel o criteri di osservazione
  • Workflow CI (radar.yml, observatory.yml)
  • Skills o MCP tools
  • Documentazione
  • Altro

Dettaglio fix

1. Fallback DuckDB nello sniff CSV (_validate_base.py)

Il parser standard (csv.Sniffer + DictReader) fallisce su SDMX-CSV e CSV con newline nei campi non quotati → gruppi "reachable ma senza schema". DuckDB li gestisce. Risultato reale (run completo): +43 gruppi profilati (INPS 37, ministero_interno 4, pagopa 1, unioncamere 1).

2. Estrazione range anni (_extract_year_range + propagazione)

Popola dataset_group_year_min/max con 3 strategie: anni da nomi colonna → valori via DuckDB tipizzato → filename. Include fix del NaN (il merge pandas produce NaN, non None: il check is None non scattava e gli anni restavano vuoti). Risultato reale (run completo): gruppi con anni 101 → 2.751 (INPS 0 → 1.764, openga 401, unioncamere 142).

3. Circuit breaker condiviso (run_pipeline.py + firme validate)

Un solo HttpClient(circuit_threshold=3, timeout=5) per tutta la run, passato a probe_reachability/sniff_csv_schema/validate_tabular_group (e ai validatori ckan/sdmx/sparql, che accettano client — sdmx/sparql lo ignorano). Host giù (lavoro_opendata, dati.anticorruzione.it, bdap-opendata) bloccati dopo 3 errori invece di ~11s per gruppo. Run completo: ~15min+ → 8min. Nota: timeout=5 corretto — il default 60s del client faceva bruciare ~114s per fallimento prima dell'apertura del circuito.

Verifica

pytest tests/
ruff check .
mypy scripts/ so_mcp/
  • pytest tests/pipeline/test_validate_utils.py passa (25 test, 5 nuovi: TestExtractYearRange + fallback DuckDB)
  • ruff check scripts/ passa
  • mypy scripts/collectors/_validate_base.py scripts/pipeline/run_pipeline.py passa
  • Run completo reale: run_pipeline --workers 8 → 11.129 gruppi in 484,8s. BEFORE vs AFTER: csv profilati 2.914→2.957, con_anni 101→2.751, ministero_salute 2→40 profilati
  • Circuit breaker verificato in produzione: host giù bloccati dopo 3 errori (log Circuit open for host), centinaia di gruppi skippati in ms
  • Perimetro stretto: una PR = i fix della validazione (6 file)

Note per chi revisiona

  • anac 47→0 nel run locale NON è regressione: dati.anticorruzione.it oggi risponde InvalidBodyLengthError (probe diretto confermato). Era vivo al 27/07. Drift di fonte, non dei fix.
  • Non coperti da questa PR (documentati come follow-up): opencoesione 27 ZIP dichiarati CSV (serve apertura archivio), INPS ~34 dfb_st_* a riga unica (reshape non banale, dati fermi 2015-2022 → condizionato ad aggiornamento fonte).
  • Il validated.parquet rigenerato vive in /tmp/opencode/validated_full.parquet (non versionato nel repo) — la CI lo rigenererà al merge.
  • lab-connectors è stato reinstallato in editable nel venv locale per testare il fix tests: aggiungere test per resource_monitor.py #73 insieme (allinea lo standard workspace: tutti gli altri repo sono editable).

…r condiviso

Tre fix della pipeline di validazione (source-observatory):

1. Fallback DuckDB nello sniff CSV: il parser standard (csv.Sniffer +
   DictReader) fallisce su SDMX-CSV e CSV con newline nei campi non
   quotati. DuckDB li gestisce: recupera 43/112 gruppi 'reachable senza
   schema' (INPS 37, ministero_interno 4, pagopa 1, unioncamere 1).

2. Estrazione range anni: popola dataset_group_year_min/max da tre
   strategie (nomi colonna -> valori via DuckDB -> filename). Nel run
   completo: gruppi con anni 101 -> 2751 (INPS 0 -> 1764). Include il
   fix del NaN: il merge pandas produce NaN non None, il check 'is None'
   non scattava e gli anni non venivano propagati.

3. Circuit breaker condiviso nella pipeline: un solo HttpClient con
   circuit_threshold=3 per tutta la run, passato a probe/sniff. Host giu'
   (es. lavoro_opendata) bloccati dopo 3 errori invece di ~11s per
   gruppo: run completo da ~15min+ a ~8min. Fix timeout da 60s a 5s
   (il default del client faceva bruciare ~114s per fallimento).

Dipende dalla PR #73 in lab-connectors (fix verify duplicato nel
fallback SSL HEAD): senza, ministero_salute torna a perdere 38 CSV.
lab-connectors installato in editable locale per test.
Stabilizzazione CI:
- test di rete (MEF/httpstat.us) marcati smoke: la CI non deve
  dipendere da fonti esterne. I rami prima coperti solo dalla rete ora
  hanno test deterministici con fake_http (lab_connectors.testing).
- coverage repo 58% -> 64% (sopra la soglia 60%), coprendo codice di
  produzione che gira in CI senza test:
  * sparql.py (collector 5 fonti radar): 15% -> 84%
  * gha/gcs_upload.py (in CI): 0% -> 100%
  * gha/publish_radar_summary.py (in CI): 0% -> 100%
  * sync_datasets_in_use.py (in CI): 0% -> 75%
  * _validate_base.py: 81% -> 89% (rami di errore/NaN/anni)

Tutti i test usano mock (fake_http, monkeypatch) — nessuna rete.
298 test non-smoke + 23 smoke, tutti verdi.
- test_validate_one_without_client_creates_own: patch su
  scripts.collectors._validate_base.HttpClient (nome bindato nel modulo)
  invece di lab_connectors.http.HttpClient — con lab-connectors installato
  come pacchetto (CI) il path sul modulo sorgente non intercetta il nome
  gia' importato; in locale (editable) passava comunque.
- TestSmokeNetwork: skip (non fail) quando la fonte esterna non risponde
  (timeout/connection) — la CI non deve dipendere da MEF/ACI vivi.
  Il fallimento reale del codice resta coperto dai test deterministici.

321 test passati, coverage 68% (>60).
@Gabrymi93
Gabrymi93 merged commit 1343c3f into main Aug 1, 2026
2 checks passed
@Gabrymi93
Gabrymi93 deleted the fix/validate-duckdb-years-circuitbreaker branch August 1, 2026 09:54
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.

tests: aggiungere test per resource_monitor.py

1 participant