Skip to content

fix(senato-votes): elimina i 403 da query troppo lunga (chunking + query compatta)#76

Merged
aborruso merged 5 commits into
mainfrom
fix/senato-query-chunking
Jul 25, 2026
Merged

fix(senato-votes): elimina i 403 da query troppo lunga (chunking + query compatta)#76
aborruso merged 5 commits into
mainfrom
fix/senato-query-chunking

Conversation

@aborruso

Copy link
Copy Markdown
Member

Closes #72.

senato-votes --keyword falliva sistematicamente con 403, a meno di aggiungere --final-vote true o --confidence-vote false.

La causa, misurata

Non è il blocco per frequenza: il front-end di dati.senato.it accetta una request-URI (/sparql?query=…) fino a 2047 byte e respinge da 2048 in su con una pagina 403 HTML — non un 414, non un errore SPARQL. Confine trovato per bisezione, con una query di controllo a 200 subito prima e subito dopo ogni misura: un blocco per frequenza respinge anche l'hello-world, qui no. Il POST è sempre rifiutato (403 anche su una query da 448 byte), quindi non si può aggirare spostando la query nel corpo: l'unica strada è tenere corta la GET.

Per confronto, l'endpoint della Camera accetta query da 4 KB: votes.ts:369 ha lo stesso pattern OR-chain ma non è a rischio, e resta invariato.

Due difetti distinti, non uno

  1. OR-chain non limitate (FILTER(STR(?f) = "S.345" || …)): con 53 fiducie in legislatura 19 la query sfora. Due i punti, non uno — il supplemento fiducie e il Fallback 1. Spezzate in blocchi da 25 (45 termini sfiorano la soglia, 50 la superano), merge invariato first-wins: l'esito non dipende dai confini dei blocchi.
  2. La query principale sfora da sola, e lì non c'è nessuna lista da spezzare: con --keyword "corte dei conti" arrivava a 2059 byte. Rimossa l'indentazione (che finisce nella URI) e ridotto l'header dei prefissi ai due effettivamente usati — xsd: solo quando serve davvero: 2081 → 1926 byte.

La keyword entra tre volte nella query (label, osr:titolo, osr:titoloBreve), quindi la lunghezza cresce di circa tre volte la keyword: il margine non è infinito e BIND, che risolverebbe il problema alla radice, non è supportato da questa istanza Virtuoso. Per questo assertQueryFits blocca in partenza le query troppo lunghe con un messaggio che dice cosa fare, invece di lasciare arrivare un 403 opaco.

Verifica

  • Il comando che falliva ora funziona e contiene la riga di controllo: fiducia sul DL 48/2025 del 2025-06-04, 109-69-1. È anche la prova che il chunking non perde righe — quella fiducia arriva dal supplemento, il suo label non contiene "sicurezza".
  • Il caso del test che sforava (--keyword "corte dei conti", dicembre 2025): tutte le richieste a 200, record 19-376-2 con bill_number 1457 e DDL 59070 come atteso.
  • npm test -- --run: 189 passati su 189. I due test senato-votes che fallivano con 403 ora passano; prima fallivano anche isolati, in 0,6 s, con l'endpoint raggiungibile — non era rate limit.
  • Nuovi test unitari: chunk (6) e senato-query-size (4), incluso il confine esatto 2047/2048, così che il prossimo filtro aggiunto alla query non rompa di nuovo la soglia in silenzio.

Segnalazione a monte

Il limite e il fatto che tutte le cause di rifiuto rispondano con lo stesso 403 indistinguibile sono materiale per i gestori del dato: annotati nella nota al Webmaster e nel dossier della campagna (voci D2/D3).

🤖 Generated with Claude Code

aborruso and others added 2 commits July 25, 2026 15:17
L'endpoint Senato respinge con 403 le richieste con query string oltre
~2 KB, e il POST è sempre rifiutato: l'unica strada è tenere corta la
GET. Con 53 fiducie in leg. 19 la OR-chain su osr:fase superava la
soglia e --keyword falliva sistematicamente.

Due i punti interessati: il supplemento fiducie e il Fallback 1. Il
merge resta first-wins, quindi l'esito non dipende dai confini dei
blocchi.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Il chunking non bastava: la query principale sfora da sola con keyword
multi-parola (2059 byte con "corte dei conti", limite 2047), e lì non
c'è nessuna lista da spezzare. Indentazione rimossa e header prefissi
ridotto ai due usati: 2081 -> 1926 byte di URL.

La keyword entra tre volte nella query, quindi il margine non è
infinito: assertQueryFits blocca in partenza le query troppo lunghe con
un messaggio che dice cosa fare, invece del 403 opaco.

Soglia misurata al byte per bisezione (2047 passa, 2048 no), con query
di controllo a 200 prima e dopo: non è il blocco per frequenza.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 25, 2026 13:49
…nza)

Stesso codice e stessa pagina di errore per due cause opposte: nel primo
caso ritentare è inutile (va accorciata la query), nel secondo è dannoso.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR prevents oversized Senato SPARQL requests.

  • Splits variable-length DDL lookup filters into bounded batches while preserving first-match behavior.
  • Compacts the primary vote query, minimizes its prefix declarations, and rejects requests exceeding the documented URI limit.
  • Adds unit coverage for chunking and request-size boundaries and documents shorter-keyword guidance.

Important Files Changed

Filename Overview
src/tools/senato-votes.ts Batches both variable-length DDL resolution queries and compacts and size-checks the primary Senato votes query.
src/core/senato-query-size.ts Introduces request-URI measurement, the Senato size limit, and an actionable preflight error.
src/core/senato-query-size.test.ts Covers client-equivalent encoding, oversized queries, batched OR filters, and the exact URI boundary.
src/core/chunk.ts Adds an order-preserving generic batching helper with invalid-size protection.
src/core/chunk.test.ts Covers chunk boundaries, ordering, empty input, and invalid sizes.
skills/italian-parliament-cli/SKILL.md Documents the Senato request-size constraint and practical keyword guidance.

Reviews (4): Last reviewed commit: "docs: rimanda a SENATO_MAX_REQUEST_URI i..." | Re-trigger Greptile

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Questa PR affronta i 403 dell’endpoint SPARQL del Senato causati da query-string in GET troppo lunghe (limite ~2047 byte), rendendo senato-votes --keyword affidabile anche su finestre ampie.

Changes:

  • Chunking delle OR-chain (FILTER(... || ...)) in batch per ridurre la lunghezza delle query su Senato.
  • Compattazione della query principale e riduzione dei prefissi, con guard-rail assertQueryFits() per fallire “presto” con messaggio azionabile.
  • Introduzione di helper + test unitari per chunking e per il confine esatto 2047/2048.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/tools/senato-votes.ts Chunking delle OR-chain + query compatta + preflight assertQueryFits per evitare 403 da URL troppo lunga.
src/core/senato-query-size.ts Nuove costanti/helper per stimare la request-URI del Senato e bloccare query fuori soglia.
src/core/senato-query-size.test.ts Test unitari per lunghezza request-URI e confine 2047/2048.
src/core/chunk.ts Helper generico per spezzare liste in batch (usato per query Senato).
src/core/chunk.test.ts Test di chunk (incl. caso d’uso “query-size” per Senato).
Comments suppressed due to low confidence (1)

src/core/chunk.test.ts:26

  • Questo test usa encodeURIComponent, che non replica l'encoding del client (URLSearchParams) e quindi può sovra/sotto-stimare la request-URI (es. spazi %20 vs +). Usando senatoRequestUriLength + una query simile a quella reale, il test resta allineato al confine 2047/2048.
  it("tiene la query sotto la soglia di ~2 KB del Senato", () => {
    // 53 fiducie in leg. 19: la OR-chain intera supera i 2 KB di query string
    // e l'endpoint risponde 403. A blocchi di 25 ogni query resta ben sotto.
    const nums = Array.from({ length: 53 }, (_, i) => String(1000 + i));
    const orChain = (batch: string[]) =>

Comment thread src/tools/senato-votes.ts
Comment thread src/core/chunk.test.ts
aborruso and others added 2 commits July 25, 2026 15:56
- il commento sulla query compatta rimandava a SENATO_MAX_OR_TERMS, che
  riguarda il chunking: il vincolo qui è SENATO_MAX_REQUEST_URI
- l'asserzione sulla dimensione usava encodeURIComponent su un frammento;
  ora sta accanto agli helper, misura con senatoRequestUriLength (stesso
  encoding del client) su una query intera con i suoi prefissi

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aborruso
aborruso merged commit 3d2ff2e into main Jul 25, 2026
2 checks passed
@aborruso
aborruso deleted the fix/senato-query-chunking branch July 25, 2026 14:07
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.

senato-votes: 403 su --keyword + --confidence-vote senza range di date (probabile limite WAF sulla query-string in GET)

2 participants