Skip to content

fix: paginazione SPARQL fa break silenzioso su DownloadError — perdita dati su endpoint instabile #449

Description

@Gabrymi93

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) → DownloadErrorbreak → 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)

  1. Retry sulle pagine successive (come _do_fetch fa per la prima con retries=2)
  2. Propagate l'errore (non break) se la pagina fallisce dopo i retry — il run deve fallire, non produrre dati troncati
  3. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions