fix(senato-votes): elimina i 403 da query troppo lunga (chunking + query compatta)#76
Merged
Conversation
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>
…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>
|
| 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
There was a problem hiding this comment.
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%20vs+). UsandosenatoRequestUriLength+ 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[]) =>
- 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #72.
senato-votes --keywordfalliva sistematicamente con 403, a meno di aggiungere--final-vote trueo--confidence-vote false.La causa, misurata
Non è il blocco per frequenza: il front-end di
dati.senato.itaccetta 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:369ha lo stesso pattern OR-chain ma non è a rischio, e resta invariato.Due difetti distinti, non uno
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.--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 eBIND, che risolverebbe il problema alla radice, non è supportato da questa istanza Virtuoso. Per questoassertQueryFitsblocca in partenza le query troppo lunghe con un messaggio che dice cosa fare, invece di lasciare arrivare un 403 opaco.Verifica
--keyword "corte dei conti", dicembre 2025): tutte le richieste a 200, record19-376-2conbill_number1457 e DDL 59070 come atteso.npm test -- --run: 189 passati su 189. I due testsenato-votesche fallivano con 403 ora passano; prima fallivano anche isolati, in 0,6 s, con l'endpoint raggiungibile — non era rate limit.chunk(6) esenato-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