Sintomo
Con pages: 3, step: 10000 su camera-deputati-legislature (endpoint dati.camera.it/sparql), il raw esce con 10.000 righe invece di ~27.764 — solo la pagina 1. Il run resta SUCCESS e la perdita è invisibile (il dataset va su GCS troncato).
Causa radice
toolkit/plugins/sparql.py, loop di paginazione (~riga 183):
except DownloadError:
# Endpoint non ha piu' pagine (es. OFFSET oltre la fine) → esci
break
Il break su DownloadError confonde errore di rete con fine dati:
- Caso legittimo "fine dati": l'endpoint risponde HTTP 200 con header vuoto → gestito dal check
data_start < 0 PRIMA dell'except
- Caso reale "errore": l'endpoint risponde 500/503 (Camera è instabile) →
DownloadError → break → CSV troncato
Verificato live (2026-08-04): pagina 2 (OFFSET 10000) risponde 500, il plugin fa break, raw = 10.000 righe.
Nota: su dati.camera.it, anche OFFSET 1000000 (oltre la fine) risponde 503 — quindi il check "header vuoto" non scatta MAI su questo endpoint; oggi "funziona" solo perché il 503 oltre-fine viene scambiato per fine dati. Il break su errore è un caso-fortuna, non un comportamento corretto.
Fix atteso (root fix)
- Retry sulle pagine successive (come
_do_fetch fa per la prima con retries=2)
- Propagate l'errore (non break) se la pagina fallisce dopo i retry — il run deve fallire, non produrre dati troncati
- La condizione di "fine dati" deve essere SOLO l'header vuoto (HTTP 200, 0 righe), non un DownloadError
Impatto
camera-deputati-legislature: unico candidate con pages — affetto oggi
- Altri candidate SPARQL (membri-governo, camera-votazioni, camera-incarichi): non paginano → non affetti
- Guard rail
min_rows + fail_on_error: true smascherano la perdita (run FAILED) — ma il fix deve stare nel plugin, non nel candidate
Test
adapter (test-policy): mock _do_fetch che fallisce su pagina 2 → assert che l'errore propaghi (run fallisce), non che il CSV sia troncato
adapter: pagina oltre fine (header vuoto) → break legittimo (regressione preservata)
Sintomo
Con
pages: 3, step: 10000sucamera-deputati-legislature(endpointdati.camera.it/sparql), il raw esce con 10.000 righe invece di ~27.764 — solo la pagina 1. Il run resta SUCCESS e la perdita è invisibile (il dataset va su GCS troncato).Causa radice
toolkit/plugins/sparql.py, loop di paginazione (~riga 183):Il
breaksuDownloadErrorconfonde errore di rete con fine dati:data_start < 0PRIMA dell'exceptDownloadError→break→ CSV troncatoVerificato live (2026-08-04): pagina 2 (
OFFSET 10000) risponde 500, il plugin fa break, raw = 10.000 righe.Nota: su
dati.camera.it, ancheOFFSET 1000000(oltre la fine) risponde 503 — quindi il check "header vuoto" non scatta MAI su questo endpoint; oggi "funziona" solo perché il 503 oltre-fine viene scambiato per fine dati. Il break su errore è un caso-fortuna, non un comportamento corretto.Fix atteso (root fix)
_do_fetchfa per la prima conretries=2)Impatto
camera-deputati-legislature: unico candidate conpages— affetto oggimin_rows+fail_on_error: truesmascherano la perdita (run FAILED) — ma il fix deve stare nel plugin, non nel candidateTest
adapter(test-policy): mock_do_fetchche fallisce su pagina 2 → assert che l'errore propaghi (run fallisce), non che il CSV sia troncatoadapter: pagina oltre fine (header vuoto) → break legittimo (regressione preservata)