senato-votes— emptyHint dinamico, data-driven (sonda del grafo invece di buchi hardcoded) — l'emptyHintera una stringa statica che su ogni risultato vuoto ripeteva tre blocchi (--ddl-uri, filtri label, buco COVID 10/3–16/4/2020) anche fuori contesto: cercando la fiducia Milleproroghe (26/2/2020,--confidence-vote) l'agente vedeva l'avviso su una finestra che non interseca il 26/2 e il testo su--ddl-urimai usato. Ora, sui risultati vuoti con vincolo di data,execute()valorizzaresult.hint(che ha precedenza su MCP+CLI) sondando il grafo al volo: 2 COUNT leggeri (sedute d'Assembleaosr:SedutaAssemblea+ votazioni) sull'intervallo distinguono lo stato reale senza sapere in anticipo dov'è il buco —sedute=0→ nessuna seduta;sedute>0, votazioni=0→ fingerprint di un buco della fonte (rileva dinamicamente il gap #36 su qualsiasi data);votazioni>0→ dato pieno, è il filtro (caso 26/2: 21 votazioni ma nessuna fiducia). Senza vincolo di data restano i soli frammenti statici pertinenti. Verificato end-to-end su 5 contesti (leg 18 e 19, singola data e range). Funzione purabuildSenatoVotesEmptyHintestratta e testata (8 test); 170/170 suite verde, tsc pulito. Emerso dal report news-agent2026-07-15_12-08.md(P0).
- v0.25.2 — release patch che consolida il fix keyword-entità HTML (bug ad alto impatto: ricerche Camera silenziosamente vuote). Recepiti due rilievi Copilot sulla PR #64 (già mergiata): (1)
htmlEntityKeywordVariantscopriva solo le vocali accentate minuscole → una keyword in maiuscolo (CRIMINALITÀ) non generava la varianteÀe, nonostante il match SPARQL siaLCASE-insensitive, falliva sul dato grezzo; aggiunte À/È/É/Ì/Ò/Ù alla mappa e al regex, con test di regressione dedicato; (2) il test di regressione usavalimit: 10, fragile rispetto all'ordinamento (19 atti matchanocriminalità): alzato a 100. 43 tool invariati, 162/162 test verdi. - fix keyword Camera con entità HTML —
bills --keywordebill-progress --uri/--branch C --keywordora cercano anche la variante HTML-escaped della keyword (criminalità→criminalità). Il LOD Camera salva alcunirdfs:label/dc:titlecon entità HTML ma la CLI decodifica l'output: prima una ricerca sul testo visibile (--keyword "criminalità") non trovava atti il cui titolo mostrato contienecriminalità organizzata; funzionavano solo workaround comecriminalitocriminalità. Aggiunto helper condivisohtmlEntityKeywordVariants, test di regressione suac19_2696, build/tsc/test completi verdi (161/161).
- v0.25.1 — release patch. Un solo fix funzionale dopo la v0.25.0:
senato-votes --ddl-uriora deriva la legislatura dal DDL invece di applicare il default 19 come filtro rigido (#60, PR #61). Prima, passando solo--ddl-uridi un provvedimento di legislatura ≠ 19, il comando dava un falso negativo silenzioso ("Nessuna votazione trovata"): un giornalista che cercava un voto Senato storico (es. il decreto lockdown DL 19/2020, S.1811, leg.18) non trovava nulla e poteva concludere erroneamente che il dato mancasse. Ora la legislatura effettiva è letta daosr:legislaturadel DDL (l'URIdati.senato.it/ddl/{N}non la codifica) e usata in tutte le query — allineando il comportamento avotes --bill-code(Camera), che non vincola la legislatura. Aggiunti alla scoperta anche description e esempio--helpcon un DDL storico, e nota nella skill. Emerso dal run news-drivendocs/news-agent/2026-07-11_18-11.md(era l'unico gap reale con impatto; gli altri due rilievi erano assenze source-side già documentate nel wiki, non gap CLI). Contestualmente rimosso dalla CI il joblive_integration(sempre rosso dai runner GitHub: gli endpoint LOD bloccano gli IP CI — zero segnale; il testing live resta affidabile in locale). 43 tool invariati, 159/159 test verdi in locale.
-
fix
senato-votes --ddl-uri— legislatura derivata dal DDL (non dal default 19) (#60, branchfix/senato-votes-ddl-legislature). Prima--ddl-uridi un DDL di legislatura ≠ 19, senza--legislatureesplicito, dava un falso negativo silenzioso ("Nessuna votazione trovata"): il filtroosr:legislaturacablato al default 19 escludeva le sedute del DDL. L'URI Senatodati.senato.it/ddl/{N}non codifica la legislatura, ma il DDL esponeosr:legislatura: ora quando c'è--ddl-urila legislatura effettiva è derivata dal DDL (una query<ddlUri> osr:legislatura ?leg) e usata in tutte le query, con fallback all'input. Allinea il comportamento avotes --bill-code(Camera) che di default non vincola la legislatura. Ripro: DDL 52988 (S.1811, decreto lockdown DL 19/2020, leg.18) ora torna il voto18-219-1anche senza--legislature, conrss_urlcorretto su/18. +1 test di integrazione. Emerso dal run news-drivendocs/news-agent/2026-07-11_18-11.md. -
v0.25.0 — release minor. Raccoglie tutte le PR mergiate dopo la v0.24.2 (#54–#59). Due nuove capacità utente: (1)
speechesfiltro temporale--date-from/--date-to+ colonnadatesu entrambe le camere (#54, chiude #37); (2) geografia di nascita normalizzatabirth_province/birth_country/birth_regionsusenators/deputies, regione derivata da SITUAS/ISTAT viaopensituas, copertura 100% (#59, chiude #24/#23; corretto l'assunto errato "Senato solo città"). Più fix:bill-progress --branch Cora dà la timeline Camera (#55, chiude #41) e i follow-up di robustezza SPARQL/paginazione (#56/#57/#58). 43 tool invariati, 158/158 test verdi. Dettaglio nelle voci sotto. -
feat geografia di nascita normalizzata — provincia, nazione, regione su entrambe le camere (#24/#23, branch
feat/birth-geography-province-region). Corretto un assunto sbagliato (era anche nel codice e nel wiki): il Senato non espone "solo la città". Ri-verificato conCOUNTsu tutta la leg.19 (254 senatori):osr:cittaNascita254/254,osr:provinciaNascita250/254 (i 4 mancanti sono i nati all'estero),osr:nazioneNascita254/254 (Italiao stato estero).senators listora restituiscebirth_province,birth_country,birth_region. Regione derivata una volta sola insrc/core/province-region.ts(modulo TS bundle-safe) da SITUAS/ISTAT report 64 via CLIopensituas, date-accurate (union snapshot 2010 + 2020 + più recente per le province soppresse/rinominate, + 3 alias per le forme brevi del Senato): copertura 100% (0 province non risolte). Camera (deputies list): la geografia è solo uno slug nell'URI (comune_provincia_regione), non triple — ora decodificata inbirth_city/birth_province/birth_country/birth_regioncon disambiguazione dello slug a 2 parti (Valle d'Aosta / Trentino-Alto Adigecomune_regionevs esterocomune_stato) ebirth_regionportata alla stessa forma canonica del Senato (verificato: "Veneto" identico tra camere).birth_province/birth_countryrestano nella forma nativa di ciascuna fonte (nessun canonicalizzatore province cross-camera). Wikidati-anagrafici.md/index.mdcorretti; nota ai gestori Camera (geografia non strutturata) indocs/note-gestori-lod/. +10 test unitari (risorsa provincia→regione + parser slug Camera), 158/158 verdi. -
follow-up residuale commenti PR #56/#57 (
bill-progress): migliorato l'hint del ramo Camera su risultato vuoto (ora segnala che i filtrikeyword/intervallo di date o la paginazionelimit/offsetpossono escludere tutte le righe), ordinamento timeline Camera reso stabile per paginazione con?stcome tie-breaker inORDER BY(non proiettato inSELECT DISTINCT, che ne altererebbe il dedup), escape robusto dei literal SPARQL perkeyword(Senato + Camera) con helper dedicato che escapa solo\ " newline CRper la grammatica STRING_LITERAL2 (nonJSON.stringify, che emette\uXXXXper i controlli, rifiutato da alcuni parser), e descrizionidateFrom/dateTochiarite sui due significati (presentazione Senato vs data stato-iter Camera). -
CI PR stabilizzata su due livelli: il check richiesto
ciora esegue solo build + typecheck + test deterministici (escludesrc/tools/tools.test.tsesrc/tools/sparql.test.tsdipendenti da endpoint live). Aggiunto joblive_integrationsu PR concontinue-on-errorper mantenere visibilità sui test reali Camera/Senato senza bloccare il merge per anti-bot/instabilità esterna. -
follow-up commenti review su
bill-progress: nel ramo Camera (number + branch=C) ora vengono applicati anche i filtri input (keyword,dateFrom/dateTo,limit,offset) invece di essere ignorati nel return anticipato. Aggiuntohintdinamico specifico quando la timeline Camera è vuota (evita messaggi fuorvianti orientati al Senato) e rese neutrali rispetto all'entrypoint ledescribe()dinumber/branch(niente grafia--flag, testo valido sia per CLI sia MCP). Inclusi test su paginazione e hint del ramo C. -
fix
bill-progress—--number --branch Cdà la timeline Camera (#41, branchfix/bill-progress-branch-c-camera). Prima--number 2617 --branch C --legislature 18restituiva il record Senato di rimando (osr:ramo="C": una riga,phase C.2617, senza date), inutile per chi voleva l'iter Camera. Ora--branch Crisolve l'atto Cameraac<leg>_<num>e ne restituisce la timeline completa degli stati (viacameraIterTimeline, stesso path di--uri): per il dl Covid 2020, 8 stati datati (assegnato→…→legge).--branch Sinvariato (repertorio Senato, stato corrente). Cambio di comportamento del valore--branch C(prima quasi inutile, nessun uso documentato/testato). Framing onesto dell'asimmetria in description/help/skill/wiki (iter-statoIter.md): Camera = timeline stati, Senato = stato corrente (timeline nel feed RSS) — riflette la fonte, non un buco della legislatura. +1 test. -
feat
speeches— filtro--date-from/--date-to+ colonnadate(#37, branchfeat/speeches-date-filter). Prima gli interventi non erano filtrabili né datati nell'output. Camera: la data reale non è sull'intervento (ods:modifiedè il timestamp del record) ma sullaocd:discussioneche lo raggruppa (dc:dateplainAAAAMMGG); verificato che copre sia Aula (stenografico,sezione=assemblea) sia commissione (bollettino), cardinalità 1 per intervento. Il join+FILTERsulle date va dentro la subquery-first (il filtro precede ilLIMIT); performante solo col range filter sul soggetto → il filtro data richiedelegislature(0.5s con, degrada senza). Senato:osr:dataSeduta(xsd:date ISO) già disponibile, filtro conSTR(?ds)(regge sia xsd:date sia xsd:string). Colonnadate(YYYY-MM-DD) ora su entrambe le camere — rinominata dasession_dateper parità (nessun consumer esterno). CLI (--date-from/--date-to), MCP, skill (tools.md + commands.md) e wiki (camera/interventi-data.mdnuova) allineati. +2 test (Camera e Senato), 139/139 verdi, tsc pulito. -
workflow PR quasi-autonomo configurato: aggiunto workflow
CIsupull_request/push main(npm ci,npm run build,NODE_OPTIONS="--max-old-space-size=4096" npx tsc --noEmit,npm test -- --run) per gate automatico su PR; lato repository abilitatoallow_auto_merge, aggiornato rulesetCopilot review for default branchconreview_on_push=true, e impostata branch protection classica sumaincon status check richiestoci(strict). Obiettivo: ridurre il ciclo manuale commenta/correggi/committa nelle PR. -
v0.24.2 — release patch. Raccoglie i fix e i miglioramenti mergiati dopo la 0.24.1 (137/137 test verdi, tsc pulito, 43 tool invariati): (1) fix CLI emptyHint (#49) — l'
emptyHintstatico dei tool ora arriva anche via CLI (prima cablato solo informatResult/MCP), così i vuoti "legittimi" (es. gap COVID leg.18) hanno la spiegazione anche a riga di comando; via OpenSpec +withEmptyHint. (2) anti-refusobill_numberblindato (#52) — test di regressione sul Piano Casa (label "DDL n. 1994" →bill_number1944, dal backfillosr:fase) e wikifiducia-fallbackallineata. (3)senato-vote-detail— dettaglio per tipo di voto (#53) — verificato che il dettaglio nominativo c'è per tutte le modalità; la scelta espressa (Favorevole/Contrario/Astenuto) manca solo susegretaeverifica numero legale(solo presenze). Description del tool, wikivotazione-tipo-semanticoe skill aggiornate; segnaleroll_call_availablederivabile datype, niente campo nuovo. (4) ricetta sede question timeaic— la sede (Aula/commissione) è già filtrabile via--type "immediata in assemblea"/"in commissione"(match sul label regolare), documentata in description/esempio + skill. (5) fix agente news-driven-cli-gap-analyzer che si auto-delegava (#50). Nessuna nuova capacità utente → patch.
-
v0.24.1 — release patch con i fix UX della PR #48 (merge commit
73ea81e, 5 giri di review Copilot/Greptile, 10 commenti gestiti, tutti i thread risolti):whichazionabile con esempi incollabili e catalogo testato (src/core/capabilities.ts), help completo su--format/--limit/--offset, messaggi d'uso/no-match su stderr, link repo aondata,repository/homepage/bugsin package.json. Include anche la raccomandazione README "uso locale consigliato" (push diretto post-#28). 130/130 test verdi. npm + Worker deployati. -
fix CLI —
whichazionabile, help completo, link repo a ondata (PR #48, branchfix/cli-discoverability-and-repo-links). Tre fix UX emersi dall'uso reale: (1)whichrestituiva forme combinate non incollabili ("bill-text links / fetch") senza dire come usarle — ora una voce per comando con esempio pronto da eseguire (dagliexamplesreali dei tool) e rimando a--help; JSON con campoexample; aggiunte capacità mancanti (camera-amendments, audizioni, bill-text fetch come voce propria); query vuota (which " ") → messaggio d'uso + exit 2 invece dell'intero catalogo. (2)--format/--limit/--offsetsenza descrizione nell'help in ~93 occorrenze (inclusosparql query, definizione separata) — ora--formatdocumentacsv | jsonlovunque. (3) Riferimenti al vecchio pathgithub.com/aborruso/...→ondatain README (git clone, npx skills add), manifest.json, User-Agent camera-amendments, 5 citation wiki; aggiuntirepository/homepage/bugsin package.json (la pagina npm non linkava il repo). Il pacchetto npm resta@aborruso/.... 123/123 test verdi. -
v0.24.0 — PR #47 mergiata (merge commit
e0ba02b): fallback bulk AKN completato dopo un lungo ciclo di review (Greptile + 7 giri Copilot, 10 commit, 25 thread tutti risolti). Oltre a quanto già in LOG: colonnasedeseparata datype(semantica diversa per fonte LOD/AKN), fix di correttezza sulla paginazione quando solo il bucket Assemblea del bulk è troncato,enrichProponentsfallisce esplicito su outage sistematico (non più vuoto silenzioso indistinguibile dai file stub), caplimit<=100su--with-proponents(rischio timeout/rate-limit sul Worker conlimitalto), hint distinto per pagina-oltre-la-fine vs vuoto genuino nel fallback AKN. Chiude automaticamente #38 e #30 (issue #45 resta aperta: altri spunti dell'analisi non ancora implementati, es.bill-textcon link AKN raw). 123/123 test verdi. -
feat
amendments— fallback bulk AKN GitHub + proponenti (P1 dell'analisi fonti non-LOD; issue #45→#38+#30, branchfeat/amendments-akn-fallback). Nuovosrc/core/akn.ts(Worker-compatible, fetch nativo): path atto, listing cartelle via endpoint JSON web-UI GitHub (troncamento a 1000 gestito via totalCount, errore esplicito su finestra irraggiungibile), parser AKN. Il tool: (1) esponeakn_xml_urlsu ogni riga LOD (conversioneURLTestoXml→raw,flagCommissionedecide emend/emendc); (2) conddlUrie LOD vuoto fa fallback sul bulk (source=akn); (3)--with-proponentsestrae primo firmatario e cofirmatari dal testo AKN (docProponent/TLCPerson, doppia variante markup Assemblea/Commissione, preferitoshowAscol nome completo). Scoperta in corsa: il LOD osr:Emendamento si è riallineato tra il 7 e il 10 lug (Piano Casa 0→799, match esatto col bulk 400+399) — freschezza intermittente, il fallback resta rete di sicurezza; trappola nuovadataPresentazionexsd:string sui DDL recenti (wiki aggiornato, 3 pagine + log). Verificato: Amidei em. 1.30 ddl/56260 (caso wiki, prima solo via browser WAF), Piano Casa con proponenti da entrambe le sedi. 114/114 test verdi (+11), tsc pulito. Skill CLI e MCP aggiornate. Idea futura annotata: estrattore AKN bulk in Rust per analisi offline (docs/future-ideas.md). -
Analisi fonti non-LOD in
docs/analisi-fonti-non-lod.md: le 3 fonti (listasommcomm #33, AKN bulk GitHub #45, RSS per-DDL #13) valutate contro forza/debolezza degli output LOD correnti. Criterio discriminante: il WAF — in un progetto MCP-first una fonte non fetchabile dal Worker vale solo come URL emesso. Priorità: P1 AKN (unica senza WAF, verificata oggi: raw 200 + listing JSON 200) →amendmentsfallback post-2024 + proponente,bill-textlink AKN; P2 RSS →rss_urlsubills/bill(già emesso da 3 tool), niente parsing server-side; P3 listasommcomm → solo colonnasommari_json_url, niente fetch (WAF + rate). Commentate le 3 issue con gli esiti. -
Wiki LOD: recepite (spersonalizzate) le conferme del gestore del repository LOD Camera via scambio email — ontologia OCD ferma al 2009-2011, RDF pubblicato a lotti alla ricezione delle triple, emendamenti assenti dal repository, audizioni non strutturate. Nuova sezione "provenienza" in
freschezza-e-autorevolezza.md, note di conferma incamera/assenti.mdecamera/audizioni.md. -
fix
votes --confidence-vote— hint "gg-1" su ricerca fiducia vuota (issue #44). La stampa riporta spesso la data dell'approvazione finale, ma la fiducia è tipicamente votata il giorno prima: cercare--confidence-vote truesulla data di stampa dava 0 righe mute. Ora, se il risultato è vuoto e--confidence-vote truecon una finestra di date, un hint dinamico suggerisce di riprovare gg-1 (nessun retry automatico). Verificato sul DL Rilancio 2020 (fiducia 8/7, approvazione 9/7). +1 test, 100/100 verdi. Chiusa anche #31 (già risolta da v0.17.1, non ancora chiusa su GitHub):aic --date-from/--date-tocombacia già sulla data d'Aula, verificato con la riproduzione originale. -
v0.23.0 — i 4 punti critici del report news-agent
2026-07-10_11-10.mdrisolti (nessun tool nuovo, 43 tool; 98/98 test verdi, tsc pulito): (1)bill-signatoriesnon classifica più come Governo i DDL Senato parlamentari da Camera (+person_uri/html_urldeputati viaocd:rif_deputato); (2)senato-votes --keywordtrova le fiducie anche per tema (supplemento via titolo DDL); (3)billguardia instradante "solo-Camera" su URI Senato; (4)bill_numberbackfillato dallaosr:fasedel DDL risolto (corregge anche i refusi della fonte). Wiki:firmatari-iniziativa(seconda trappola + censimentotipoIniziativa),fiducia-fallback(discovery tematica), nuovaakn-bulk-data(bulk AKN GitHub senza WAF, issue #45). Skill CLI aggiornata. Dettaglio nelle voci sotto. -
feat
senato-votes— backfill dibill_numberdal DDL risolto (punto 4 dell'analisi del reportdocs/news-agent/2026-07-10_11-10.md). Sui label generici ("Votazione finale") o coi refusi il numero non è estraibile dal testo, ma quandoddl_uriè risolto (link diretto o fallback) il numero è laosr:fasedel DDL: una query aggiuntiva (solo se servono backfill, solo DDL singolo, solo fasi S.) popola la colonna. Bonus: sul refuso Piano Casa (label "DDL n. 1994") ora esce il numero GIUSTO 1944, derivato dal DDL verificato e non dal testo. Verificato: 19-376-2 → 1457, 19-434-2 → 1944; lista standard 100 righe in ~4,3s (throttle-dominata). +1 test e assert sul refuso, 98/98 verdi. -
fix
bill— guardia instradante sugli URI Senato (punto 3 dell'analisi del reportdocs/news-agent/2026-07-10_11-10.md).bill show --uri http://dati.senato.it/ddl/...rispondeva "Nessun atto trovato": un utente/agente lo legge come dato assente, mentre è il tool sbagliato (bill è Camera-only). Ora errore esplicito "solo-Camera" che indirizza abill-progress --ddl-uri/bill-signatories --bill-uri/bill-text --uri(stesso pattern diamendments"solo-Senato"); description aggiornata anche per i client MCP. +1 test. -
fix
senato-votes --keyword— le fiducie ora emergono anche per tema (punto 2 dell'analisi del reportdocs/news-agent/2026-07-10_11-10.md). Root cause: il match keyword sul titolo del DDL (v0.20.0) passa in SPARQL daosr:oggetto→osr:relativoA→osr:titolo, ma le fiducie non hannoosr:oggetto→?ddlTitolounbound → escluse dal filtro anche quando il tema è nel titolo del DDL citato per numero nel label (--keyword sicurezzanon trovava la fiducia 19-312-1 sul decreto sicurezza). Fix: supplemento fiducie — con--keyworduna seconda query recupera le sole fiducie del periodo (set piccolo, ~55 nell'intera leg. 19), risolve il DDL citato nel label viaosr:faseleggendone ancheosr:titolo, e tiene quelle il cui titolo matcha; righe merged con dedup e riordino, countOnly allineato. Non si applica con--ddl-uri(già coperto),--confidence-vote false,--final-vote true, o offset>0 (eviterebbe righe ripetute per pagina). Residuo documentato: fiducie con refuso nel numero (S.1944 "DDL n. 1994") non recuperabili per keyword (solo Fallback 1, niente propagazione intra-seduta). Verificato:--keyword sicurezzagiu 2025 → fiducia 19-312-1 + pregiudiziale, count=2 coerente; regressioni "corte dei conti" e combinazioni--confidence-vote true/falseinvariate. Wikisenato/fiducia-fallback.mdestesa. +1 test, 96/96 verdi, tsc pulito. -
fix
bill-signatories— i DDL Senato di iniziativa parlamentare arrivati dalla Camera non sono più classificati "Governo (proponente)" (punto 1 dell'analisi del reportdocs/news-agent/2026-07-10_11-10.md). Root cause: l'euristica assumeva atto governativo quando mancavaosr:senatore, ma i firmatari deputati (es.ddl/59070, S.1457 Corte dei Conti, Dep. Foti) vivono nel grafo senzaosr:senatoree conocd:rif_deputato. Fix: la query legge ancheosr:tipoIniziativa(discriminante esplicito: Parlamentare/Governativa/Popolare/Regionale/CNEL/…) eocd:rif_deputato; i deputati ora hanno ruoloprimo firmatario/cofirmatariocorretto piùperson_uri/html_url(scheda camera.it, prima vuoti); le iniziative non parlamentari e non governative hanno ruolo<tipo> (proponente)invece del falso "Governo". Bug annidato trovato in corsa:flattenBindingsrende""i binding assenti, quindi il fallbacksenatore ?? deputatonon scattava mai →||. Verificato su 4 casi reali:ddl/59070(parl-deputati, il bug),ddl/55281(parl-senatori, regressione),ddl/60233(governativo, regressione),ddl/24134(popolare). Wikisenato/firmatari-iniziativa.mdestesa con la seconda trappola + censimentotipoIniziativa. +1 test, 95/95 verdi, tsc pulito.
-
v0.22.0 —
senato-votesmulti-DDL + fix EPIPE CLI (nessun tool nuovo, 43 tool; 94/94 test verdi, tsc pulito). Campi strutturati per i voti su testi unificati (ddl_count,ambiguous_ddl,ddl_uris_json,ddl_html_urls_json,rss_urls_json) e pipe Unix interrotte (| head) che escono pulite. Dettaglio nelle voci sotto. Rimosso anche il dead codejoinMap(rompevatsc --noEmit). Wiki OKF covid-2020 esteso ad altri due decreti (Rilancio, Agosto). -
senato-votes— Fase 1 + 2 sul multi-valore: ambiguità esplicita + campi JSON strutturati. Il problema non era nei dati ma nel nostro output: il tool collassava liste reali di DDL/URL in stringhe piatte separate da|, poi le risplittava internamente. Fix minimale senza rompere retrocompatibilità: i campi esistenti (ddl_uri,ddl_html_url,rss_url) restano invariati, ma si aggiungonoddl_count,ambiguous_ddl,ddl_uris_json,ddl_html_urls_json,rss_urls_json. Così il CSV resta leggibile e il JSONL diventa realmente machine-friendly senza dover parseare pipe custom. Verificato sul caso multi-DDL del 2026-06-23 (votazione/19-431-19):ddl_count=5,ambiguous_ddl=true, array JSON con i 5 DDL e i rispettivi URL/RSS. Root cause classificata correttamente: problema di modellazione output del tool, non del LOD. -
fix CLI
EPIPE— pipe Unix interrotte ora escono pulite: usando pipeline brevi tipoitalianparliament ... | head -3, Node continuava a scrivere sustdoutdopo cheheadaveva chiuso il pipe → stack traceError: write EPIPE, rumoroso ma non legato ai dati. Fix minimo insrc/cli.ts: handler suprocess.stdouteprocess.stderrche intercettaerr.code === "EPIPE"e termina conexit(0)invece di rilanciare. Verificato end-to-end dopo build connode dist/cli.js vote-detail show --vote-uri http://dati.camera.it/ocd/votazione.rdf/vs18_382_001 --format jsonl | head -3→ 3 righe, nessuno stack trace, exit code 0. Problema puro di ergonomia CLI/tooling, non della fonte.
-
v0.21.0 — 3 fix/mitigazioni dai gap del report news-agent
docs/news-agent/2026-07-08_12-57.md(nessun tool nuovo, 43 tool; 94/94 test verdi, tsc pulito): (1)bill-progress --numberrecupera l'intera navetta a più letture (-B/-C); (2)bill-signatoriesrisolve i ministri sui decreti-legge Camera (basta righe con name vuoto); (3) hint di staleness suvotesper non restituire un vuoto muto sul dato Camera più recente. Dettaglio nelle voci sotto. -
fix
bill-signatories— decreti-legge/atti governativi Camera: risolti i ministri (basta righe con name vuoto) (gap 4 del reportdocs/news-agent/2026-07-08_12-57.md). Root cause: sui decreti-leggeocd:primo_firmatarionon punta a un deputato ma a un blank node "membro di governo" privo difoaf:firstName; il tool cercava il nome solo sul nodo → 5 righe conname=""enodeID://…(sembrava un bug/assenza firmatari). Il dato c'è: il nome del ministro è un hop più in là viaocd:rif_persona(→persona.rdf), il dicastero inocd:ruolo. Fix: la query Camera seguerif_persona+ruolo; discriminante netto parlamentare vs governativo = presenza dirif_persona. Ora Piano Casa (ac19_2920) torna Piantedosi/Salvini/Giorgetti/Foti/Meloni conrole="Governo — <dicastero>",is_primary=false(proponenti multipli, coerente con #29/ramo Senato); regressione atto parlamentare (Zielloac19_2941) invariata.html_urlvuoto per i ministri (URIpersona.rdf, non risolvibile senza mandato — limite #14, accettabile). Nuova pagina wiki OKFcamera/firmatari-atti-governativi.md+ index. +1 test. 94/94 verdi. -
fix
bill-progress --number— navetta a più letture (-B/-C) completa (gap 3 del reportdocs/news-agent/2026-07-08_12-57.md). Root cause: il filtro sul numero era un match esattoFILTER(STR(?numeroFase) = "1353"), che intercettava solo la prima lettura; le letture successive hannonumeroFasediverso ("1353-B") e cadevano fuori. Peggio:--number 1353-Bfalliva conERROR --number: Invalid(validazione Zod^\d+$). Fix (1 riga): match esatto →REGEX(STR(?numeroFase), "^<n>(-[A-Z])?$"), così--number 1353 --branch Storna S.1353 e S.1353-B. Verificato: separazione carriere (1353 → entrambe le letture), regressione Cura Italia (1766, singola lettura invariata), ramo C (1917 → C.1917 + C.1917-B). Distinto da #41 (bug diverso,--branch Critorna record Senato). -
feat: hint di staleness su
votes— vuoto recente non più muto (gap 2 del reportdocs/news-agent/2026-07-08_12-57.md; il voto Camera 7/7/2026 sul reclutamento non era verificabile via CLI, LOD fermo all'1/7). Non è "risolvibile" (il dato manca a monte, ritardo di ~7gg del LOD Camera pubblicato a lotti), ma il vuoto silenzioso è mitigabile. Aggiuntohint?dinamico suToolResult:votescalcola una nota di freschezza SOLO quando il risultato è vuoto E la finestra di date tocca gli ultimi ~14 giorni (o il futuro prossimo); niente hint su finestre storiche. Sorgente MCP (server.ts, precede l'emptyHintstatico) e CLI (emit→ stderr, così non sporca CSV/JSONL delle pipeline). +1 test (data futura = vuoto+recente stabile; controprova storica). 93/93 verdi. Advocacy freschezza già in corso (canale Synapta + wikifreschezza-e-autorevolezza.md): nessuna issue aperta, si attendono le risposte gestori. -
v0.20.0 —
senato-votes --keywordcerca anche nel titolo del DDL, throttle anti-403 Senato, emptyHint su due gap di dataset (dai gap del report news-agentdocs/news-agent/2026-07-08_08-17.md).senato-votes --keywordora matcha anche il titolo del DDL collegato, non solo ilrdfs:labeldel voto. Root cause: il tema del provvedimento (es. "bilancio", "caccia") spesso non è nel label ("Votazione finale", "Articolo 143") ma nel titolo del DDL (osr:oggetto/osr:relativoA/osr:titolo). Fix:OPTIONALsul titolo DDL +CONTAINSin OR col label, conBOUND()così le fiducie (prive diosr:oggetto) non fanno fallire l'intero OR. Verificato leg.19:--keyword bilancioora torna le votazioni della legge di bilancio (DDL 59654) che prima erano invisibili (label-only). Allineato anche il ramocountOnly.- Throttle prudenziale sull'endpoint Senato (
src/core/client.ts): un burst di ~9 query dirette in pochi minuti ha bloccato l'endpoint con un 403 l'8/7. Aggiunto un throttle sequenziale (≥2s tra l'inizio di due richieste Senato, coda condivisa così protegge anche chiamate concorrenti); solo Senato (la Camera non ha mai mostrato lo stesso comportamento).snQuerydiventaasync. Il Webmaster (interpellato) non comunica soglie "per ragioni di sicurezza": la soglia è prudenziale. - emptyHint anti-confabulazione su due gap di dataset noti. (1)
amendments: il datasetosr:Emendamentoè fermo al 9 agosto 2024 — nessun DDL condataPresentazionesuccessiva ha emendamenti collegati; un vuoto su un DDL recente NON è "nessun emendamento" (issue #38). (2)senato-votes: tra il 10 marzo e il 16 aprile 2020 (leg.18, COVID) non risulta ALCUNA votazione d'Assemblea nel LOD pur essendoci le sedute con gli interventi — inclusa la fiducia sul Cura Italia (9/4/2020). - Wiki: nuove pagine
senato/emendamenti-freschezza.md,senato/votazioni-covid-2020.md,senato/corrispondenza-webmaster.md(log segnalazioni al Webmaster) + index. Nessun tool aggiunto (43 tool). 92/92 test verdi, tsc pulito.
-
run news-driven CLI gap analyzer: nuova verifica fresca in
docs/news-agent/2026-07-08_08-17.mdsu 6 notizie (current 2026, bucket 2025, bucket 2020). Esito sintetico: Camera regge bene anche su storico leg.18 (fiducia dl Covid 2020 + dettaglio individuale); Senato regge bene su leg.19 recente (separazione carriere, dettaglio voto) ma mostra gap su discovery e storico:senato-votes --keyworddipende troppo dal label, il caso Cura Italia 2020 non emerge viasenato-votes, e la fiducia Piano Casa 2026 resta conddl_urivuoto nel listato base. Emersa anche confusione semantica dibill-progress --number --branch C(ritorna la fase Senato del C.*). Nessun fix applicato in questa run; solo evidenza grounded da comandi reali.
-
feat:
attendance/senato-attendance— presenze/assenze aggregate per legislatura (issue #9). Conteggio aggregato dei voti di un parlamentare su tutte le votazioni della sua legislatura. Camera: query diretta suocd:votofiltrata per URI mandato (già specifico di legislatura, niente join surif_leg— evita il gap di dati noto lì, ~50% delle votazioni senzarif_legpopolato). Colonne: favorevole/contrario/astensione/non_ha_votato/ha_votato (scrutinio segreto)/altro/totale. Senato: 5 query per categoria su proprietà inverseosr:favorevole|contrario|astenuto|presenteNonVotante|inCongedoMissione, filtrate perosr:legislatura(l'URI senatore non la contiene, richiede--legislature). Verificato: Meloni (PM) — 37457/37491 non ha votato; Casellati (senatrice attiva tutta la leg.19) — totale 8008 su 8044 votazioni della legislatura (residuo ~0.4%, non spiegato ma non bloccante); Pera (senatore a vita) — totale 5122, coerente con partecipazione parziale. +2 tool (43 tool), +2 test, 92/92 verdi. -
v0.18.0 — filtri semantici votazioni Camera e Senato (gap #1 e #2 dal report news-agent
docs/news-agent/2026-07-07_13-47.md).- Camera
votes --keywordora cerca anche in description. Root cause:keywordFilterconfrontava solo?labele?title(OPTIONAL), ignorando?description— dove invece vive il testo tematico (es. "Bilancio di previsione dello Stato..."). Risultato:votes list --keyword bilanciorestituiva 0 nonostante il DDL 2750 esistesse. Fix: aggiunto?descriptionalCONTAINSdel filtro e reso vincolante (?s dc:description ?description .) nella inner query quando la keyword è attiva. Verificato:--keyword bilancioora torna DDL 2750/2574/2537; regressione su label-only keyword e confidence+date OK. Limite residuo (dati, non tool): votazioni con description povera (es. "DDL.n. 2920-A") non sono ricercabili per tema — il tema vive nel titolo del decreto (bill-progress). - Senato
senato-votes: nuovi filtri--keyword,--confidence-vote,--final-vote. Verificato per enumerazione cheosr:tipoVotazioneè la modalità di voto (elettronica/nominale/segreta), NON il tipo semantico: "Votazione finale" e "questione di fiducia" vivono solo nelrdfs:label. I tre filtri sono quindi label-based (CONTAINSsurdfs:label). Trappola gestita:sfiducia⊃fiducia→--confidence-vote trueesclude esplicitamentesfiducia(le mozioni di sfiducia). Verificato leg.19:--confidence-vote true→ 55 (vs 56 keyword "fiducia" grezzo, 1 sfiducia esclusa),--final-vote true→ 246; validazione bool CLI (true/false, errore chiaro altrimenti). Limite dati: il tema del decreto NON è nel label delle votazioni Senato —--keyword cacciatorna vuoto (il tema vive nel DDL collegato: usare--ddl-uri+bill-progress). Nuova pagina wikisenato/votazione-tipo-semantico.md. - Nessun tool aggiunto (41 tool). Test 90/90 verdi.
- Camera
-
v0.17.2 — fix vuoto silenzioso dei filtri data Camera (bug #1 dal report news-agent
docs/news-agent/2026-07-07_09-03.md). Root cause:FILTER(?date >= "AAAAMMGG")sulla variabile nuda legata adc:date(literalAAAAMMGG) faceva un confronto numerico su Virtuoso → range errati o 0 righe mute. Es.:votes list --legislature 19 --date-from 2025-02-01 --date-to 2025-02-28restituiva 0 pur essendoci 436 votazioni, e gennaio ne "catturava" 7378 (conteggi assurdi); riprodotto su leg.18 (marzo 2020: 2 invece di 35). Un giornalista non poteva distinguere «nessun voto» da «query rotta». Fix: avvolti inSTR(...)tutti i confronti data Camera in 5 tool —votes,bills,sessions,committee-sessions,audizioni(le date Senato tipizzate^^xsd:daterestano invariate). Verificato: votes leg.19 gen/feb/mar 2025 → 313/436/464 (coerente conSTRSTARTS); bills feb 2025 → 60; sessions feb 2025 → 18; votes leg.18 marzo 2020 → 35. Nessun tool aggiunto (41 tool). Test Camera invariati (i 13 fallimenti sono tutti Senato 403, quirk endpoint). Wikitrappole-virtuoso-funzioni-stringa.mdgeneralizzato: la trappola #2 vale anche sulle variabilidc:datenude, non solo sui risultati diSUBSTR/REPLACE.
-
v0.17.1 — 2 fix da stress-test news-driven (report
docs/news-agent/2026-07-06_18-51.md). Nessun tool aggiunto (41 tool). Dettaglio nelle due voci sotto. -
fix
aic --date-from/--date-to: ora combacia anche sulla data d'Aula (question time) (bug #2 dal report news-agentdocs/news-agent/2026-07-06_18-51.md). Root cause: il filtro usava solo la data di presentazione (SUBSTR(dc:date,1,8)); i question time sono presentati la vigilia e trattati in Aula il giorno dopo (dc:date="AAAAMMGG-AAAAMMGG", presentazione-modifica), quindi--date-from/--date-tosul giorno d'Aula dava 0 righe. Fix: il filtro combacia se cade nell'intervallo la presentazione oppure la modifica (2° gruppo del composto, estratto conREPLACE); nessun flag nuovo. Verificato: 9/7/2025 → 19 interrogazioni immediata; 25/6/2025 → 33; presentazione singola invariata. Due trappole Virtuoso incontrate e ora documentate (docs/lod-wiki/trappole-virtuoso-funzioni-stringa.md): (1)SUBSTRfuori range aborta la query senza short-circuit dell'&&→ estrarre conREPLACE, nonSUBSTR(...,10,8); (2)>=/<=sul risultato diSUBSTR/REPLACEfa un confronto numerico che dà 0 righe → forzare conSTR(...). +1 test sentinella, 89/89. Aggiornatiaic.ts(descrizione), skill CLI+MCP, wikicamera/aic-date.md+ nuova pagina trasversale Virtuoso (referenziata da index e dasenato/trappole.md). -
fix
senato-votes --ddl-uri: ora include la fiducia collegata (bug #1 dal report news-agentdocs/news-agent/2026-07-06_18-51.md). Root cause: il filtro server-sideosr:relativoA <ddlUri>escludeva a monte le fiducie (prive diosr:oggetto); i fallback che ricollegano il DDL giravano solo nel percorso per data. Fix: con--ddl-urisi risolvono prima le date delle sedute in cui il DDL è votato (queryosr:relativoA), si interroga per quelle date e si applicano i fallback esistenti, poi si post-filtra. Post-filtro selettivo: si tengono i voti collegati fortemente (link direttoosr:relativoAo Fallback 1 via numero nel label) più le sole fiducie; i voti agganciati per sola propagazione-data (Fallback 2) che fiducie non sono (es. una risoluzione votata la stessa seduta) vengono scartati.countOnlyallineato alla lista. Verificato Piano Casa (ddl/60233): restituisce pregiudiziale (57/79) + fiducia (106/62/2,19-434-2), esclusa la risoluzione19-434-3; DDL con voto finale (ddl/58039) invariato (42 voti). +1 test sentinella live, tsc pulito. Aggiornatidescription/emptyHintdel tool, skill CLI+MCP edocs/lod-wiki/senato/fiducia-fallback.md. -
v0.17.0 — 5 miglioramenti da stress-test news-driven (report
docs/news-agent/2026-07-06_08-10.md, notizia Piano Casa approvato al Senato con fiducia il 1/7/2026). (1) Nuovo helpersrc/core/current-legislature.ts: risolve la legislatura corrente in modo dinamico dall'endpoint Camera (ultimarepubblica_*perdc:date), cache in-memory + fallback 19 con warning su stderr. Sostituisce l'hardcode19insenator,committees,committee-sessions,bill-texte nel ramo Camera dibill-progress(si romperebbe alla prossima legislatura). (2)bill-progress --numbersenza--legislatureora defaulta alla legislatura corrente invece di pescare omonimi storici cross-legislatura (S.1809 → solo leg.19). (3)search find: ranking lato TS — match esatto sul cognome/token finale (batte le sottostringhe:Boschi>Tiraboschi) + preferenza per la legislatura corrente + tie-break Camera;boschi→ Maria Elena Boschi leg.19 in cima senza bisogno del nome completo. (4)votes listCamera: due colonne nuoveaic_code(es.1/00586) eaic_link(URL scheda AIC) per mozioni/risoluzioni, estratte dadescription/title(MOZ 1-586,RIS 6-263,Risoluzione 6_00266); i voti su DDL restano vuoti. Link verificato HTTP 200. (5)senato-votes: Fallback 2 intra-seduta — un voto di fiducia rimasto senzaddl_uri(per refuso della fonte nel numero, es. "DDL n. 1994" per S.1944) eredita ilddl_urida altri voti della stessa data se non ambiguo; sblocca la fiducia Piano Casa19-434-2→ddl/60233. (6)bill-signatories: gli atti Senato di iniziativa governativa (nessunosr:senatore) ora hanno ruoloGoverno (proponente)invece diprimo firmatario, senzaperson_uri/html_urlfittizi. Nessun tool aggiunto (41 tool). 87/87 test, tsc pulito. README + skill CLI/MCP aggiornati.
-
v0.16.1 — direzionamento lato MCP anti-confabulazione (issue #32, checkbox 1). Emerso da uno stress-test di un chatbot terzo (basato su Mistral, che non carica le skill): all'"iter completo della legge sul salario giusto" produceva una confabulazione su scheletro reale — dato vero al ~70% ma con voto finale Camera inventato ("342/180/20"), emendamenti presi da un DDL Senato omonimo sbagliato (59851 invece di 60201/S.1933) e contenuto della legge ricamato. Verificato che i tool restituivano il dato giusto: il difetto era orchestrazione+interpretazione del client. Un agente neutro guidato dalla skill ha ricostruito l'iter corretto → i tool bastano, ma i client senza skill vanno direzionati. Interventi (solo path MCP
server.ts, CLI invariata): (1) nuovo campoTool.emptyHint+ messaggio di default anti-confabulazione sul risultato vuoto ("non dedurre né inventare; un vuoto è spesso un mismatch"); (2) descrizioni prescrittive subill-progress(spina dorsale dell'iter, aggancio DDL Senato per numero non per keyword),senato-votes(caveat fiducia:ddl_urivuoto → filtra per data + label),votes(voto finale/fiducia per intervallo di date),bills(mismatch lessicale),bill-text(se non recuperi il testo, non descrivere il contenuto). Nessun tool aggiunto/rimosso (41 tool). 87/87 test, tsc pulito. Skill CLI v1.4 / MCP v1.3 già aggiornate con la ricetta "iter completo" e la sezione Grounding. -
v0.16.0 — filtri demografici su
deputiesesenators(issue #23: genere, data e luogo di nascita). Nuovi parametri (CLI + MCP):--gender male|female,--born-from/--born-to(YYYY-MM-DD),--birth-place. Camera: genere già sul nododeputato; nascita sul nodopersona(foaf:Person) agganciato via lo stessoocd:rif_mandatoCamera(vincoloa foaf:Personper non duplicare le righe),bio:date(YYYYMMDD→YYYY-MM-DD in output) eocd:rif_luogo. Esposte 2 colonne nuovebirth_date+birth_place:birth_placeè lo slugcomune_provincia_regione(es.messina_messina_sicilia) → il filtro per regione/provincia di nascita è nativo (10 deputate leg.19 nate in Sicilia, coerente col wiki). Senato: i campi c'erano già; aggiunti solo i filtri —dataNascita(YYYY-MM-DD, confronto viaSTR()),cittaNascita(solo città, no provincia/regione: limite documentato). Quirk:foaf:genderal Senato è letterale tipizzato →FILTER(?gen="F")dà 0, serveFILTER(STR(?gen)="F")(stesso caso disiglaGruppo). +4 test (Camera gender+luogo, range nascita; Senato gender STR, born-from). 87/87 test. Aggiornati reference skill CLI+MCP. -
skill: nuovo reference condiviso
obiettivi-giornalistici.md(in entrambe le skill CLI e MCP) — catalogo di analisi giornalistiche derivabili combinando i tool esistenti, senza tool dedicato. Prima voce: dissidenti/ribelli (voto difforme dalla linea di gruppo), con ricettavote-detail/senato-vote-detail+jq(Camera e Senato), scelte analitiche e limite di volume. Credito e ringraziamento a openpolis/openparlamento (parlamento19.openpolis.it). Referenziato da entrambe le SKILL.md; bump skill CLI v1.3, MCP v1.2. -
fix
vote-detail— enum--vote-typeCamera:Astenuto→Astensione(emerso valutando issue #7). Il valore reale didc:typesui voti Camera èAstensione(verificato: campione 5000 → 4 valori nettiFavorevole/Contrario/Astensione/Non ha votato, nessun "In missione"), ma l'enum del tool accettavaAstenuto(→ 0 righe muto) e rifiutavaAstensione→ filtrare gli astenuti era impossibile. Corretto invote-detail.ts(enum + descrizione) ecli.ts(descrizione + cast). Il Senato non è toccato:senato-vote-detailcostruisce i label viaosr:astenutoe usa correttamenteAstenuto. 83/83 test. -
issue #7 (filtro dissidenti) chiusa senza nuovo tool — derivabile via pipeline. Verificato che i dissidenti (voto difforme dalla linea di gruppo) sono già calcolabili da
vote-detail show(Camera) /senato-vote-detail show(Senato), che espongono già nome+voto+gruppo: una sola pipeline... --format jsonl | jq(moda del gruppo sui voti espressi → chi diverge). Testato suvs19_641_046→ 1 dissidente (Lorenzo Cesa, M-ALT). Aggregato "più ribelle della legislatura" = problema di volume (iterare su migliaia di votazioni), non di dato. Regola acquisita: niente nuovi tool/flag se il risultato è derivabile combinando i tool esistenti. -
v0.15.0 — Due nuovi agganci sui DDL: ricerca per numero + commissioni assegnate (emersi da confronto con una scheda atto di riferimento su S.1809). (A)
bill-progress listora accetta--number <n>+--branch S|C(default S): risolve un atto Senato dal suo numero (es.--number 1809 --branch S→ S.1809,ddl/59924), colmando il buco per cui si poteva cercare solo per parola chiave nel titolo.osr:numeroFaseè tipizzato →FILTER(STR(?n)); il ramo è obbligatorio perché lo stesso numero esiste in entrambi (C.1809 e S.1809). (B) Nuovo toolbill-committees list --bill-uri <ddl/atto>(dual-branch, auto-detect ramo): elenca le commissioni a cui l'atto è assegnato con sede/ruolo (Referente/Consultiva/…), tipo, data e URI organo. Dato già nel LOD ma prima non esposto: Senatoosr:assegnazione, Cameraocd:rif_assegnazione. Verificato su S.1809 → 7 commissioni (1ª Referente + 6 Consultive, 30/04/2026) e su C.2822 (I Commissione Referente). Aggiuntoª/ºal decoder HTML (label Senato "1ª (…)"). Registrati in CLI, MCPserver.tse registry; vocewhichper "commissione/assegnazione". 83/83 test, tsc pulito. 41 tool. -
"Il cielo del Parlamento" — pagina vetrina live su GitHub Pages (
site/+ workflowpages.yml): pagina animata (GSAP + ScrollTrigger, canvas) che racconta CLI/MCP con dati sempre live dal Worker: costellazioni = parlamentari in carica per gruppo (Camera+Senato viagroup-members/senator-group-members), strada delle legislature 1848→oggi (legislatures), ultime votazioni con contatori (votes), griglia dei 40 strumenti datools/list(si auto-aggiorna a ogni release). Nessun dato precotto: ogni visita interroga/mcp(JSON-RPCtools/callstateless, parse SSE, cache localStorage 1-24h). Fix worker necessario: la risposta ditransport.handleRequestnon avevaAccess-Control-Allow-Origin(solo il preflight lo aveva) → aggiunto wrap con header CORS, deployato. Deploy Pages via Actions (actions/deploy-pages, pathsite/). Testata con agent-browser: desktop 1440, mobile 390 (layout compatto senza etichette), barre voti (fixdisplay:blocksu span inline),ScrollTrigger.refresh()dopo il load asincrono. Click su una stella → scheda ufficiale del parlamentare (camera.it/senato.it, dahtml_urldei tool membership), cursore pointer + hint nel tooltip; verificato con click sintetici su entrambe le camere. Card votazioni arricchite: le sigle criptiche ("MOZ 1-569") vengono agganciate all'atto AIC reale — una sola query SPARQL VALUES per tutte le card risolve presentatore (gruppo) e incipit del "premesso che"; doppio link per card: testo dell'atto (aic.camera.it; DDL → scheda camera.it) + scheda votazione. Nota deploy:gh run rerunsu deploy-pages fallito produce "Multiple artifacts named github-pages" — mai rerun, sempre run nuova (gh workflow run pages.yml). -
v0.14.1 —
camera-amendments: fallimento diagnostico su Worker + header browser-like. Verifica del Worker live (requisito): SPARQL eaudizioniOK;camera-amendmentsfallisce da Cloudflare — camera.it serve agli IP Worker una pagina anti-bot (~4.5KB senza i marcatori attesi), non un errore, quindi prima tornava "No results" ingannevole. Ora: header Accept/Accept-Language + se la scheda non ha i marcatori di un atto valido → errore chiaro ("fonte non raggiungibile, riprovare da CLI locale"). L'atto senza emendamenti (scheda valida) resta vuoto senza errore. Diagnosi confermata: IP-blocking dei Worker Cloudflare (issue #28). Distinzione verificata: il tool funziona da CLI e dal server MCP locale (dist/index.jsstdio, 37/25 confermati) — è solo il Worker remoto a essere bloccato. Chi usa l'MCP installato in locale ha il tool pieno. -
v0.14.0 — nuovo tool
camera-amendments+ fix esposizione MCP diaudizioni. -
fix:
audizionimancava daserver.ts allTools— era registrato nella CLI (tools/index.ts) ma mai esposto via MCP/Worker: Claude Desktop non aveva il tool audizioni. Emerso allineando il contatoretools:del worker durante la release (diceva 39 "aspirazionale" mentreallToolserano 38). Aggiunto al server MCP → 40 tool coerenti in CLI, registry, worker. -
Nuovo tool
camera-amendments(emendamenti Camera via scraping app HTML): colma il gap #19. Fonte:getProposteEmendative.aspx(non LOD). Pipeline tuttafetch(no browser; Camera senza WAF): scheda atto (actHtmlUrl) → link liste per sede → parsing righe con cheerio/slim (àncoretr.rigaArticoloNormale/tr.normale/idPropostaEmendativa/idPersona). Output per emendamento: sede, articolo, numero, primo firmatario (+person_id), emendamenti identici, link al testo;--count-only→ conteggio per sede. Esito escluso di proposito (vuoto nelle liste cumulative; vive nella vista per-seduta → possibile Phase 2). cheerio/slim obbligatorio: cheerio full trascinaencoding-sniffer→iconv-lite→require("buffer")che rompe il bundle ESM e gonfia il Worker a 2.8mb (con slim: 484kb). Guardiaamendmentssu URI Camera → rimanda acamera-amendments. Test-sentinella che fissano i conteggi noti (AC 2696: referente 37, Assemblea 25; lista 62 righe) per intercettare cambi di markup. Validato anche su AC 2920 (479 emendamenti referente). MCP + CLI. 83/83 test. Da verificare: raggiungibilità di documenti.camera.it dal Worker Cloudflare (la CLI locale funziona). -
Emendamenti Camera: assenti dal LOD ma raggiungibili via HTML (indagine agent-browser): verificato che l'app
documenti.camera.it/apps/emendamenti/getProposteEmendative.aspxè attiva per leg 19 e pubblica per ogni atto/sede l'elenco completo con art., testo, firmatari ed esito (es. C.2696-A legge elettorale: 25 proposte in Assemblea). Traffico ispezionato (HAR): nessuna API JSON/XHR, solo HTML server-rendered → un toolcamera-amendmentssarebbe fattibile solo via scraping. URL corretto va preso dal pulsante EMENDAMENTI della scheda atto (URN a mano → lista vuota). Aggiornati issue #19 (commento con esito+strategia) e nota gestori Camera (advocacy: esporre come LOD/JSON). Memoriaproject_camera_amendments_absentaggiornata. -
amendments: guardia esplicita su URI non-Senato (anti falso-vuoto): il tool interroga solo l'endpoint Senato; un--ddl-uridella Camera passava ilFILTERsenza match → CSV vuoto silenzioso, scambiabile per "nessun emendamento". Ma gli emendamenti Camera non esistono come entità nel LOD OCD (issue #19 chiusa, notacamera-assistenza-dati.mdpunto 1): l'unica traccia è testuale nelle descrizioni delle votazioni. Fix:amendments.tsora lancia un errore esplicito seddlUrinon contienedati.senato.it, spiegando che il vuoto non significa assenza e rimandando al toolvotes. +1 test offline di regressione (/solo-Senato/). Verificato: URI Camera → errore; URI Senato (ddl/56260) → emendamenti regolari. 80/80 test. -
Difesa
bill_numberfantasma su votazioni + segnalazione refuso fonte Senato: emerso dalla run news-driven del 2026-07-05 (docs/news-agent/2026-07-05_09-16.md, gap n.3). Il voto di fiducia Piano Casa19-434-2hardfs:label= "DDL n. 1994. Votazione questione di fiducia", ma nessun DDL 1994 esiste in leg.19: il provvedimento reale è S.1944 (ddl/60233,osr:numeroFase=1944) — refuso (trasposizione cifre) nel campo testo libero della fonte, non bug CLI. Il voto non haosr:oggetto→ unico appiglio al DDL è la label → il typo rompe l'aggancio per numero (aggancio affidabile = seduta/data: seduta 434 = 2026-07-01 =dataStatoDdldel 60233). Fix difensivo (senato-votes.ts+votes.ts, simmetria Camera): dopo il fallback di risoluzionebill_number→URI atto, se il numero citato non corrisponde ad alcun atto reale della legislatura,bill_numberviene azzerato — così non si espone un identificativo non interrogabile (restituirebbe sempre zero); il testo grezzo resta inlabel/description. Verificato via CLI:19-434-2(typo) →bill_numbervuoto;19-432-3(fiducia DDL 1933, numero valido) →bill_number=1933 +ddl_uri=ddl/60201risolto. 79/79 test. Refuso annotato nella bozza gestoridocs/note-gestori-lod/senato-webmaster.md(punto 1, esempio concreto). Regola di workflow acquisita: ogni problema dati a monte → prima verificare se già annotato nelle note webmaster.
- v0.13.1 — fix
committee-members(Camera) — bug di completezza grave: emerso dalla run news-driven del 2026-07-04 (docs/news-agent/2026-07-04_19-02.md, gap n.1). Il ramo Camera interrogava soloocd:ufficioParlamentare(cariche apicali) legato viaocd:rif_deputato, ignorando del tutto (a) i membri effettivi, modellati come?deputato ocd:membro [ ocd:rif_organo ?organo ; dc:type "Titolare"/"Sostituto" ], e (b) i presidenti/segretari senatori delle bicamerali, legati viaocd:rif_senatore. Effetto: sulla Commissione d'inchiesta Covid (o19_4281) restituiva 3 persone invece di 16 e Giuseppe Conte (Titolare) non compariva; il presidente Marco Lisei (senatore) veniva scartato. Verificato il modello RDF empiricamente su bicamerale (Covid) e permanente (XIII Agricolturao19_3513) prima di toccare la query. Fix: query a UNION dei due path (ocd:membro+ufficioParlamentareconrif_deputatoORrif_senatore); merge lato TS con priorità ruolo (Presidente>Vicepresidente>Segretario>Capogruppo>Titolare>Sostituto) per collassare a una riga per persona — ma solo conactiveOnly=true; conactiveOnly=falsele righe storiche restano distinte. Fallback ruolo mancante → "Componente". Verificato: Covid 3→16 con Conte e Lisei presenti; Agricoltura 33 membri con breakdown ruoli coerente;--member-uricon URI senatore ora ritorna le cariche (prima nulla); Senato non toccato (0-1 → 24 membri invariati). Copertura completata lato Camera: i senatori membri semplici delle bicamerali vivono solo nel LOD Senato (osr:afferisce), fuori scope di una query per URI-organo Camera. 79/79 test.
- v0.13.0 — fix
searchmulti-token +committee-sessions --count-only: due difetti emersi da uso reale su Claude Desktop (connector remoto → il fix arriva all'utente solo col redeploy del Worker). (1)search: il match era su sottostringa contigua del nome anagrafico (rdfs:label/CONCAT(fn,ln)), quindi "Elena Schlein" falliva perché in banca dati è "Elena Ethel Schlein" (il secondo nome spezza la sottostringa) e chiunque abbia un secondo nome era irraggiungibile con "nome cognome". Fix: tokenizzazione su spazi + AND diCONTAINSper token, sia Camera che Senato — l'ordine diventa indifferente (sostituisce anche il doppio-CONCAT del fix #20). Verificato: "Elena Schlein" ✅, "Schlein Elena" ✅, "Ignazio La Russa" (Senato) ✅, regressione "Giorgia Meloni" ✅. Resta scoperto "Elly Schlein": "Elly" è nome d'uso non presente nel LOD (limite fonte, non del codice). (2)committee-sessions: mancavacountOnly(a differenza di votes/aic/speeches), così alla domanda "quante audizioni ha svolto la commissione X" il tool scaricava tutte le sedute complete (femminicidio → 76 KB/146 righe) — query pesante che va in timeout dal Worker (IP Cloudflare vs endpoint Camera) mentre da CLI locale passa. Aggiunto--count-only(schema+CLI, esposto via MCP/Worker automaticamente):COUNTleggero, una riga per ramo (chamber,count). Verificato: femminicidio Camera → 146. +1 test di regressione middle-name, 79/79. - Relazione + proposta "modellare audizioni e auditi" (Camera) — deliverable strategico di advocacy verso i gestori LOD (Camera/Synapta), in
docs/proposta-audizioni-auditi/. Coordinati 3 esperti (SPARQL, ricerca web/Exa, campagne civiche). Tesi: l'audito è già scritto neldc:titledellaocd:discussione(nome+ruolo+ente) ma vive come stringa, mai entità → strutturarlo ha costo ~zero per il publisher. Proposta = 2 mosse di riuso OCD: (A) ripristinaredc:type="Audizione"come in leg.14; (B) popolareocd:rif_persona(slot vivo su 45.808 discussioni, mai valorizzato sulle audizioni) con entitàocd:soggettoAuditotipizzata + link all'atto. Benchmark: USA "Truth in Testimony" (conflitto dentro il dato), UK oral evidence, UE Integrity Watch/LobbyFacts; hook IT = Registro rappresentanti di interessi Camera + A.C. 2336 (approvata Camera 29/01/2026, ora al Senato). File:00-relazione.md(sintesi),01-as-is-to-be-sparql.md,02-benchmark-web.md,03-perche-conta-civico.md. Correzione numerica verificata: il "6.636" citato prima era non-distinct —6.636 = 2×3.318coppie dibattito–discussione (raddoppio rdf:type); discussioni distinte = 3.311, ~935 nella forma pulita "Audizione di ". Corretto anche in memoria etasks/todo.md.
- v0.12.0 —
bill-signatoriesesteso a Camera (news-agent punto 5): era[SENATO]puro. Scoperto che il LOD Camera espone i firmatari come proprietà dirette dell'atto —ocd:primo_firmatario(1 deputato) eocd:altro_firmatario(cofirmatari) — quindi nessun buco di dati, mancava solo il tool. Riscritto come dual-branch sul modello dibill-rapporteurs: ramo rilevato dall'URI, colonne unificatename, role, is_primary, person_uri, html_url. Nome deputato composto dafoaf:firstName+foaf:surname(fallbackrdfs:labelsenza suffisso legislatura). Parametro rinominatoddlUri→billUri(--bill-uri), con--ddl-urimantenuto come alias retrocompat. Verificato: C.2696 "Liberi di scegliere" → 28 firmatari (Colosimo prima firmataria + 27 cofirmatari); Senato ddl/25597 invariato. +1 test Camera, 78/78. Skill CLI+MCP allineate. Gap dalla run news-driven del 2026-07-02. - v0.11.3 — backoff più lungo sui retry SPARQL (flap Camera): l'endpoint
dati.camera.it/sparql"flappa" (finestre di errore di pochi secondi); i 3 tentativi con backoff500·attempt(~1,5s totali) cadevano spesso tutti nella stessa finestra → errore visibile all'utente. OraDEFAULT_MAX_RETRIES=5e backoff esponenziale con tetto a 2s (250→500→1000→2000ms, ~4s totali) insrc/core/client.ts, così i buchi transitori vengono assorbiti senza esporre l'errore. Nessuna modifica ai tool. 77/77 test. NB: verificato che il fix decode v0.11.2 è live e corretto sul Worker (curl diretto a/mcpsuac18_2853→dell'articolo 13-bispulito); la grezza vista via l'integrazione claude.ai era connessione stale del client MCP, non il Worker. - v0.11.2 —
decodeHtmlgestisce anche le entità numeriche: il fix v0.11.1 era incompleto. L'helpersrc/core/decode-html.tsdecodificava solo le entità con nome (’,à), lasciando grezze quelle numeriche decimali (') ed esadecimali ('), frequenti nei titoli OCD della Camera (es.all'articolo,nell'area). Aggiunta la decodifica dei riferimenti numerici (con guardia sui codepoint non validi), prima dello strip dei tag. Beneficia tutti i tool che usano l'helper (bill-progress,bills,member-bills,audizioni,person-career). Nuovo filesrc/core/decode-html.test.ts(7 test: named, numeriche dec/hex, strip tag,^^xsd, codepoint invalido, idempotenza). Verificato end-to-end suac18_1397(locale pulito vs Worker 0.11.1 ancora grezzo → motivo del redeploy). 77/77 test. - v0.11.1 — decode HTML nei titoli di
bill-progress(Camera): il ramo Camera (cameraIterTimeline) restituivatitle/statusgrezzi dall'endpoint OCD, con entità HTML non risolte (es.l’assistenza,criminalità), a differenza degli altri tool (bills,member-bills, ecc.) che già applicanodecodeHtml. Applicato l'helper condivisosrc/core/decode-html.tsai due campi. Verificato che le entità sono single-encoded (’/à), quindi il single-pass è corretto; fix validato sulla stringa esatta del report news-agent, indipendente dall'endpoint (che era intermittente). 70/70 test. Gap emerso dalla run news-driven del 2026-07-02 (docs/news-agent/2026-07-02_13-11.md, punto 5). - wiki LOD — freschezza e autorevolezza (
docs/lod-wiki/freschezza-e-autorevolezza.md): sondato il segnale di freschezza sui due endpoint (2026-07-02). Camera esponedcterms:modifiedsuivoid:Datasetma congelato a feb 2024 su dataset vivi fino a metà 2026; Senato non ha metadati di freschezza (le 926 tripledcterms:modifiedsono interni Virtuoso del 2012). Documentata la conseguenza (un "non trovato" su dato recente è ambiguo: non caricato / assente / non avvenuto), la gerarchia di autorevolezza sull'esito (resoconto stenografico → scheda iter → GU) e la distinzione critica "approvato da un ramo" ≠ "legge". Le bozze ai gestori LOD (docs/note-gestori-lod/, non versionata) hanno un punto freschezza aggiunto per ciascuna camera. - Nuovo tool
audizioni(solo Camera) — estrae le audizioni delle commissioni via SPARQL, cosa finora ritenuta impossibile per la legislatura corrente. Scoperta chiave: le audizioni leg. 19 NON si trovano viadc:type(valorizzato solo leg. 14, 619 dibattiti storici) ma via il titolo dellaocd:discussionecollegata al dibattito (ocd:dibattitorif_leg →ocd:rif_discussione→dc:titlecon "Audizione di …"): ~3.167 audizioni reali leg. 19 (dato vivo fino a giu 2026), con nome+ruolo dell'audito nel titolo, data, commissione (dal titolo del dibattito), atti collegati e link al bollettino. Filtro server-side con REGEX mirata per escludere i falsi positivi d'agenda ("…allo svolgimento di un'audizione"). Due modalità: leg. 19 (titolo discussione) e leg. 14 (dc:type storico, con data ricavata dal suffisso URI). Colonne:date, committee, title, bill_codes, bill_uris, bulletin_url, discussion_uri, dibattito_uri. CLI+MCP allineati, 70/70 test. Testato: Confindustria, prefetto, femminicidio (180 audizioni). Senato non coperto:osr:Proceduratipo="Audizioni"(1.833 leg.19, flag strutturato) esiste ma il nodo è orfano di data e commissione (unico link entrante =intervento/null, rotto) → segnalabile ai gestori LOD. Nessun link video/YouTube nel LOD (tutti idc:relation→ bollettino testuale). Contesto: primo step della pipeline per ricostruire il lavoro manuale di The Good Lobby (mappatura audizioni leg. 18); step 2-4 (estrazione audito, classificazione categoria, statistiche) previsti come skill+duckdb. Doc aggiornata: README, skill CLI+MCP, wiki LOD (camera/sedute-commissione.mdVia A/Via B),tmp/audizioni.mdv2,tasks/todo.md. committeesesteso a Camera (#6): il tool era[SENATO]puro (osr:Commissione). Aggiunto--chamber(camera/senato/both, default both). Camera:ocd:organofiltrato per legislatura (default 19, le istanze sono per-legislatura), condc:typeesposto come nuova colonnacategory(COMMISSIONE PERMANENTE/BICAMERALE D'INCHIESTA/GIUNTA/COMITATO/...) esession_countdaocd:seduta+rif_organo. Aggiuntacategoryanche lato Senato (daosr:categoriaCommissione, prima non esposta). Nuova colonnachamberin testa, come già incommittee-sessions/committee-members. Retrocompatibile: senza--chamberdefaultboth; Senato senza--legislaturecontinua a mostrare tutte le 300 commissioni storiche. +1 test (Camera leg. 19), 70/70. Verificato manualmente: camera/senato/both, legislature diverse, errore chamber invalido, jsonl.- Fix
sparqltool — falso positivo "Solo query SELECT supportate": bug reale (non un problema di query malformate lato utente), segnalato intmp/audizioni.md§7.3.validateSelectQuerytoglieva i "commenti" conquery.replace(/#[^\n]*/g, ""), ma non distingueva un#di commento da un#dentro un IRI (es.<http://www.w3.org/2000/01/rdf-schema#>, terminazione standard di rdfs/rdf/owl/xsd). Su query scritte su una riga sola (tipico da CLI/agente), unPREFIX rdfs: <...#>prima diSELECTfaceva sparire tutto il resto della riga —SELECTincluso — dalla stringa validata, con conseguente rifiuto di query perfettamente valide. Fix: nuovostripCommentsche traccia se si è dentro<...>e ignora i#in quel caso. +1 test di regressione, 69/69. Le altre voci di §7 ditmp/audizioni.md(timeout su scansioni globali non vincolate a una classe; "nessun risultato" per audizione in Senato) sono limiti reali dell'endpoint pubblico/assenza di dato, non bug del progetto. - Fix
committee-sessions(verifica delle modifiche del 01/07): due bug trovati testando manualmente tutte le varianti CLI. (1)toTitleCase(pensato per nomi di persona) applicato anche al nome della commissione rompeva i numerali romani e gli apostrofi ("XIV COMMISSIONE (POLITICHE DELL'UNIONE EUROPEA)"→"Xiv Commissione (politiche Dell'Unione Europea)"), disallineato dacommittee-membersche lascia il label grezzo — rimosso il title-case sul campocommittee. (2)--committee-uriCamera senza--committee-namelascivacommitteevuoto (asimmetrico rispetto al Senato, che risolve sempre il label); aggiuntofetchCameraOrganoLabelper popolarlo anche in quel caso. Verificato: build, typecheck, 68/68 test, e ri-eseguiti tutti i casi manuali (DDL, committee-uri/committee-name, camera/senato/both, date range, paginazione, errori) senza regressioni.
committee-sessionsesteso: "segui una commissione" (Camera+Senato) — il tool era limitato all'iter di un DDL (--ddl-uriobbligatorio, solo Senato). Ora--ddl-uriè opzionale e si possono elencare tutte le sedute di una commissione via--committee-urio--committee-name(ricerca fuzzy), filtrabili per--chamber(camera/senato/both),--legislature,--date-from/--date-to. Aggiunto supporto Camera (ocd:seduta+ocd:rif_organo+dc:datestringaAAAAMMGG+dc:relation→bollettino), oltre al Senato (osr:SedutaCommissione+osr:dataSedutaxsd:date+osr:tipoSeduta+ conteggio interventi). Nuova colonnabulletin_url(Camera) echamber/ddl_uriper uniformare. Caso d'uso guida: la Commissione parlamentare di inchiesta sul femminicidio (bicamerale) ha composizione esposta da entrambi i rami (24 senatori membri incommissione/4-223), ma sedute/interventi solo in OCD comeo19_3941(181 URI seduta / 157 date distinte fino a giu 2026) — nel Senato LOD 0 sedute per la XIX; oracommittee-sessions list --committee-name femminicidio --chamber camerala rende visibile. (Correzione in corso di verifica: i "292" iniziali erano triplerif_bollettino, non sedute distinte.) Decisioni utente: scope Camera in fase 1 (sì); input sia--committee-uriche--committee-name(entrambi); rami separati nell'output (no merge). Bug trovato e fixato in corso:RDFS_LABELtypo (namespace senzalabel) → 0 risultati; e una edit maldestra aveva invertito l'ordineflatten/query. Wiki LOD: nuove paginesenato/sedute-commissione.mdecamera/sedute-commissione.md(proprietà reali verificate + trappole: doppiaosr:titoloBreveSenato →MIN(?tb)+GROUP BY; filtro legislatura Camera obbligatorio). CLI+MCP allineati. 68/68 test.- v0.9.1 — fix output disomogeneo Camera/Senato in
search,people,committee-members: segnalato dall'utente via screenshot VisiData susearch find --name Meloni— colonnefirst_name/last_name/gender/legislature_urinon uniformi tra righe. Causa: pass-through dei dati SPARQL grezzi, e le due camere modellano gli stessi concetti in formati diversi (Camera nomi MAIUSCOLI +genderesteso +legislature_uricome vero URI; Senato Capitalizzato +gendersiglaM/F+ legislatura come intero nudo). Nuovo helper condivisosrc/core/normalize.ts(toTitleCase,normalizeGender) applicato ai tre tool che mescolano righe delle due camere nello stesso output (search.ts,people.ts,committee-members.ts --chamber both); per il Senatolegislature_uriora è un URI sinteticohttp://dati.senato.it/legislatura/{n}. Non toccati i tool a camera singola (senator.ts/senators.ts/deputy.ts/deputies.ts, decisione utente) né quelli multi-camera ma single-chamber-per-call (rank.ts,bill-rapporteurs.ts, dove non c'è mescolamento nella stessa colonna). +8 unit test sunormalize.ts, 68/68. - v0.9.0 —
bill_numbercopre gli Ordini del Giorno Camera + fixaic:extractBillNumber(src/core/bill-number.ts) esteso per chiudere il gap residuo Camera dell'#21 (in v0.8.0 solo 4/62 voti del DDL 2920 avevanobill_uri, quasi tutti ODG). Scoperto che gli ODG citano l'atto senza la parola "DDL", con la numerazione ufficiale9/<atto>/<progressivo>in forma breve ("ODG 9/2920/46") ed estesa ("Ordine del giorno n. 9/1049/3 COGNOME (GRUPPO)"), tollerante al suffisso "E ABB" (e abbinate); aggiunta anche l'alternativa "PDL"/"proposta di legge" accanto a "DDL"/"disegno di legge". Risultato:votes list --bill-code 2920ora 62/62 conbill_uri; su campione di 6000 voti leg. 19, 1591/1606 ODG risolti (99%) — i residui sono voci "Doc. VIII" (non un DDL, correttamente vuote) o testi unificati a 4 segmenti, lasciati vuoti per non rischiare un'estrazione sbagliata. +5 unit test. Toolaic:--keywordora matcha a confini di parola (eraCONTAINSa sottostringa: "CETA" includeva falsi positivi come "Acetamiprid"/"Cetara"; oraREGEX(...,"\\bKEYWORD\\b","i")su label/title/description, verificato 31→10 righe reali su "CETA" leg. 19); nuovo filtro--typesudc:typecon fallback sullabel(per la leg. 19dc:typenon distingue "a risposta immediata"/question time da "a risposta orale" — la differenza è solo testuale nel label); fix filtro data:dc:dateè compostoYYYYMMDD-YYYYMMDD(presentazione-modifica) sul 62% degli aic leg. 19 e rompeva il confronto lessicografico di--date-from/--date-to— ora si confronta solo la data di presentazione viaSUBSTR, e l'output mostra entrambe le date quando modificato. Considerato ma scartato un endpoint HTML non documentato dietrodocumenti.camera.it/apps/votazioni/votazionitutte/(reverse-engineered con agent-browser, stesso testo deldc:descriptionma più fragile) — documentato solo nel wiki (docs/lod-wiki/camera/votazioni-ricerca-html.md) come prova indipendente del gap, non integrato. 60/60 test. - v0.8.0 — link voto→DDL/atto risolto (#21): i tool
senato-votesevotesespongono ora la colonnabill_number(numero provvedimento estratto dal testo:labelSenato,dc:descriptionCamera; es.562-B,2920-A) e popolanoddl_uri/bill_urianche quando il legame diretto manca. Senato: le fiducie (prive diosr:oggetto) si risolvono dal numero viaosr:fase="S.<num>"(univoco intra-legislatura; verificato1933→ddl/60201). Camera: i voti senzarif_attoCamerasi risolvono sul numero base (2920-A→2920) verificando l'esistenza dell'atto viadc:identifier(una query per legislatura, mai URI fabbricati). Estrazione in nuovo coresrc/core/bill-number.ts(extractBillNumber/billBaseNumber, regex tollerante aDDL n./DDL.n./Disegno di legge n.e suffissi-B/-bis). Fallback in una sola query aggiuntiva (OR-chain, noVALUESbatch su Virtuoso), solo per le righe non già risolte che citano un provvedimento. Wiki OKF aggiornata (senato/votazione-ddl-link.md); skill CLI+MCP allineate. +6 unit test, 56/56. - fix
search— matching Senato nome+cognome (#20):search find --name "Ignazio La Russa"non trovava il senatore (mentre"La Russa"sì). Causa:searchSenatofiltravaCONTAINS(?fn, q) || CONTAINS(?ln, q)confrontando la query separatamente confirstNameelastName→ un nome completo non matcha nessuno dei due campi. La Camera non aveva il problema (match surdfs:labelintero). Fix:FILTER(CONTAINS(LCASE(CONCAT(?fn," ",?ln)), q) || CONTAINS(LCASE(CONCAT(?ln," ",?fn)), q))(concat nei due ordini;CONCATin FILTER funziona sul Virtuoso Senato,BINDno). Verificato:senatore/1275per "Ignazio La Russa",senatore/29480per "Roberto Marti"; nessuna regressione. 51/51 test. - avvio LOD wiki OKF (
docs/lod-wiki/): bundle [OKF](Open Knowledge Format) come fonte di verità dello schema LOD Camera (OCD) / Senato (OSR), pattern "compile don't retrieve" (idea indocs/future-ideas.md). Scaffold (index.md,camera/,senato/,log.md) + prime concept page verificate:camera/assenti.md(emendamenti Camera assenti dal LOD, con query di verifica) esenato/trappole.md(quirk Virtuoso: 403 su curl, no BIND, legislatura integer, matching nomi). Il differenziale sono trappole e assenti verificati. - issue: #19 (emendamenti Camera: verificato assenti dal LOD OCD — nessuna classe emendamento tra i 47 tipi RDF; solo testo in
dc:descriptionvotazioni) chiusa not planned. #20 (fix sopra). #21 (link voto→DDL parziale: fiducie senzaosr:oggetto) risolta in v0.8.0 (vedi voce in cima).
- v0.7.1 — rifiniture discoverability:
bill-rapporteursora registrato anche insrc/tools/index.ts(tools/toolsByName), allineato aserver.ts(era discoverabile solo via CLI/MCP, non datoolsByName); aggiuntopeople resolvealla lista capability diwhich/guide(+ termini iter Camera subill-progress). MCP invariato a 38 tool. 51/51 test. Resta da fare: sync documentazione README/skills con le feature 0.6.0/0.7.0 (issue dedicata). - v0.7.0 — risoluzione URI→nome (issue #12). Nuovo tool
people: risolve in batch una lista di URI persona misti Camera + Senato ai nomi, con una query per endpoint (FILTER(?s IN (...));VALUESdà 400 sul Senato), dedup per URI, outputuri/first_name/last_name/label/chamber/html_url; URI non risolti restano in output con label vuota. CLIpeople resolve --uris a,b,c; registrato in MCP (38 tool) e CLI. Inoltregroup-membersesenator-group-membersora includonodeputy_name/senator_namedirettamente (prima solo URI nudo → niente più lookup a valle). 51/51 test. - v0.6.0 — URL human-readable + iter Camera.
bill-progressora copre la Camera (timeline iter viaocd:rif_statoIter); colonnahtml_url(scheda istituzionale camera.it/senato.it) su tutti i tool persone e atti/DDL;rss_url(feed RSS iter dettagliato) sui tool DDL Senato; fix pathleg19hardcoded. Nuovo coresrc/core/html-url.ts(personHtmlUrl/actHtmlUrl/ddlRssUrl). 50/50 test. Issue aperte per i follow-up. - Audit
html_urlleggi +rss_urlDDL: centralizzati helperactHtmlUrl(atto Camera + DDL Senato) eddlRssUrl(feed RSS per-DDL, richiede legislatura) insrc/core/html-url.ts. Colmati i gap:member-bills(html_url atto),bill-signatories/bill-rapporteurs(html_url persona, righe sono firmatari/relatori),amendmentsesenato-votes(ddl_html_url+rss_url, gestione multi-valorea | b),bill-progressSenato (rss_urlper riga, schema allineato col ramo Camera). Refactor dibills/billsuactHtmlUrl(fix bug pathleg19hardcoded → oraleg{N}).aiclasciato com'è (URL portale AIC, schema diverso). Verifica agent-browser: did=60201→S.1933, rss 59372 ok. 50/50 test (+5 unit). Feed RSS tracciato in #13. html_urlper le persone (PRDdocs/prd-human-readable-urls.md): i tool che restituiscono parlamentari espongono ora l'URL della scheda istituzionale accanto all'URI SPARQL. Helper purosrc/core/html-url.ts(personHtmlUrl, zero query): deputato…/deputato.rdf/d{ID}_{LEG}→camera.it/deputati/elenco/{LEG}-{ID}; senatore…/senatore/{N}→senato.it/…/scheda-attivita?did={N}. Cablato indeputies,senators,search,group-members,senator-group-members,rank,vote-detail,senato-vote-detail(colonna aggiuntiva, nessuna rottura di schema). Verifica end-to-end con agent-browser:19-307302→Ascari,did=32578→Alfieri,did=32→Casellati. Differitigov-members/person-career(URIpersona.rdf, non risolve) espeeches(schema misto). Unit test pattern inhtml-url.test.ts; 45/45 test. Scoperti anche: feed RSS per-DDL del Senato con iter dettagliato (issue #13) e gemello S.1822 della legge elettorale.bill-progressesteso alla Camera (parità tool, issue #11): con--uri <atto Camera>il tool restituisce ora la cronologia completa dell'iter (timeline di tutti gli stati attraversati), non solo lo stato corrente come per il Senato. Modello Camera scoperto via SPARQL:atto → ocd:rif_statoIter → {dc:date, dc:title=stato}(DISTINCT obbligatorio per ilrdf:typeduplicato). Routing per host dell'URI (dati.camera.it→ timeline,dati.senato.it/default → lista Senato invariata); stesso schema colonne in entrambi i rami (colonne solo-Senato vuote nel ramo Camera, date normalizzate aYYYY-MM-DD,phase=C.<id>). CLI:bill-progress list --uri …; MCP auto-registrato viainputSchema.shape. Verificato su C.2822 (4 stati: Da assegnare → Assegnato → In corso di esame in Commissione → Concluso l'esame in Commissione) e C.302. Test parità schema intools.test.ts; 41/41 verdi. Nota: il dataset Senato rispecchia lo stato corrente anche di atti Camera (1 riga), la Camera ne dà la storia (N righe).- v0.5.2 — Perf
speeches(Camera, path legislatura): da ~6s a ~1.8s (3-4×). Gli interventi Camera non hannoocd:rif_leg(la legislatura è solo nel pattern URI); il vecchioFILTER(STRSTARTS(...))+ORDER BY DESC(?modified)impediva l'uso dell'indice sul soggetto e materializzava/ordinava tutti gli interventi (~126k distinti) prima del LIMIT. Riscritto: (1) STRSTARTS → range filterFILTER(?s >= <…in19_> && ?s < <…in19_z>)che Virtuoso esegue come scansione indicizzata all'indietro fermandosi al LIMIT; (2) ordinamento perDESC(?s)(ID intervento = ordine di creazione, proxy della cronologia reale;ods:modifiedera un timestamp di modifica del record); (3) subquery-first conGROUP BY ?snell'interna — la tripla?s a ocd:interventoè duplicata alla fonte (2× per intervento, COUNT(*)=253354 vs DISTINCT=126677), GROUP BY collassa i doppioni ed è ~2× più veloce di DISTINCT; (4) dedup per uri in TS (modified/relation multi-valore). Path per deputato già selettivo (invariato), Senato invariato. Testspeechesda 7570ms a 1440ms; suite 40/40. - v0.5.1 — allineamento campi
aic/sindacato-ispettivo: susindacato-ispettivorinominatitipo→type,data→date,numero→identifier,senatore_uri→sponsor_uri,legislatura→legislature; aggiunto filtrokeyword(cerca in label/tipo/numero) ecountOnly. Suaic:legislature_uri→legislature(numero estratto dall'URI), date normalizzata daYYYYMMDDaYYYY-MM-DD. Fix TS (comparazione boolean/string sucountOnly). countOnly Senato implementato conCOUNT(DISTINCT ?s)diretto (Virtuoso non supporta subquery wrap). - Nuovo tool
senato-groups[SENATO]: elenca i gruppi parlamentari del Senato con sigla (acronym) e numero di componenti distinti (members), filtrabile per legislatura. È il parallelo diretto digroups(Camera). Query SPARQL conCOUNT(DISTINCT ?sen)per evitare il doppio conteggio dovuto a senatori con carica interna (Presidente, Tesoriere, ecc.) che hanno due adesioni attive. Output:uri,title,acronym,members,html_url. Testato: XIX leg. → 9 gruppi, FdI 63, PD-IDP 36, Lega 29. CLI:senato-groups list --legislature 19. MCP, skill e README aggiornati.
-
v0.4.1 (patch, doc-only): case study
docs/case-study-salario-giusto.md(fiducia DL "salario giusto", catena verificata 94+61+2+36=193); avvertenza trasversale sui voti di fiducia Senato (ddl_urivuoto, legame solo nellalabel) in README + 2 skill; fixsrc/cli.ts(versione CLI letta dapackage.jsoninvece dell'hardcoded0.0.1). Versione allineata 0.4.1 nei 3 punti; tsc/build/worker puliti; 40/40 test. -
Docs: nuovo case study
docs/case-study-salario-giusto.md— inchiesta end-to-end sul voto di fiducia del 2026-06-24 per la conversione del DL "salario giusto" (S.1933 / ddl 60201). Catena verificata: legislatures/governments → bill-progress (keyword) → bill-signatories → bill-rapporteurs → senato-votes → senato-vote-detail (voto per gruppo + filtri assenti) → bill-text links/fetch. Tabella voto per gruppo con totali coerenti (94+61+2+36=193). Linkato dal README accanto al box Corte dei Conti. -
Docs/avvertenza trasversale: i voti di fiducia al Senato hanno
ddl_urivuoto (il legame col DDL è solo nel testo dellalabel), quindisenato-votes list --ddl-uri <uri>non li restituisce — va filtrato per data seduta (--date-from/--date-to). Le votazioni "finali" trovate per data possono inoltre appartenere a un atto diverso (testo unificato). Nota aggiunta in README "Note sui dati" + sezione Tips della skill CLI + blocco "Who voted how (Senato)" della skill MCP. Emersa verificando il case study (prima la tabella voti mescolava DDL 60201 e 60220 e citava un--confidence-voteinesistente su senato-votes). -
v0.4.0: nuove capacità da verifica giornalistica. Relatori Senato in
bill-rapporteurs(ora Camera+Senato), gruppo di voto insenato-vote-detail(voto per gruppo al Senato), timeline gruppi inperson-career,group-membersordinato,sparqlusabile senza il sotto-comandoquery, pulizia label gruppi Camera. README con esempio d'inchiesta e skill allineate. Dettagli nelle voci sotto. -
Perf
votes(Camera): da ~33s a <1s (45×). La query usavaFILTER(?rif_leg = …)su una variabile OPTIONAL +ORDER BY DESC(?date)con 17 OPTIONAL: Virtuoso materializzava tutte le votazioni di tutte le legislature prima di ordinare/limitare (timeout del test a 30s). Riscritta subquery-first: l'interna seleziona/filtra/ordina/limita i soli?s(legislatura come triple vincolante;GROUP BY ?s+MAX(?date)perché alcune votazioni hannodc:datemultiplo), l'esterna aggancia i 17 OPTIONAL solo alle righe risultanti; dedup per uri in TS contro la moltiplicazione delle OPTIONAL multi-valore. Tutti i filtri (keyword/approved/confidence/date/bill-code) spostati nell'interna. Testvotesora verde in 0.5s; suite 40/40. -
Secondo round dalla stessa verifica giornalistica (gap media/bassa) + esempio d'inchiesta. (1)
group-members: aggiuntoORDER BY ?deputy_uri ?start_date→ timeline cambi-gruppo in ordine cronologico (prima FDI compariva prima di IV-CR). (2)person-career: nuovo ramo UNION (ocd:siComponeDi) → ora include le righekind=gruppo(appartenenza ai gruppi con date, label pulita viacleanGroupLabel), output riordinato per categoria+data. (3)sparql: shim argv che inserisce il sotto-comandoqueryquando manca →sparql --endpoint senato --query …funziona (prima mostrava l'help/"Unknown command");sparql query …resta valido,sparql --helpresta help. (4) Help sotto-comandi: NON era un bug —bills list --helpecc. mostrano i flag; il falso positivo del report nasceva da zsh (niente word-splitting su$c). Allineamento CLI↔MCP+skill:bill-rapporteursmancava da entrambe le reference skill (gap pre-esistente) → aggiunto; aggiornate descrizioni di person-career/senato-vote-detail/sparql nelle 2 skill; check automatico: 36/36 tool presenti in CLI+MCP reference. README: nuovo box "Un'inchiesta passo per passo: la riforma della Corte dei Conti" (catena verificata bill-progress→bill-signatories→bill-rapporteurs→senato-votes→senato-vote-detail con voto per gruppo), tabelle aggiornate. tsc --noEmit pulito; 39/40 test (l'unico KO è timeout di rete suvotes, non legato alle modifiche). -
Due gap "alta priorità" emersi da una verifica giornalistica (3 notizie 2025: riforma Corte dei Conti S.1457, legge IA S.1146-B, cambio gruppo Gruppioni). (1) Relatori Senato in
bill-rapporteurs: prima solo-Camera; ora il ramo è rilevato dall'URI (dati.senato.it→ queryosr:relatore, blank node conrdfs:label/tipoRelatore/organo/dataNomina/senatore, mappati sulle stesse colonne Camera). Es. S.1146-B → Rosa/Minasi (commissione 09/07) + Rosa/Minasi/Mazzella f.f. (assemblea 30/07); Camera invariata (ac19_2316). (2) Gruppo insenato-vote-detail: nuova colonnagroup_label= gruppo del senatore alla data del voto. Query gruppi separata (logicasenator-group-membersconasOf= data seduta) → mappa JS unita ai risultati: le 5 query di conteggio restano invariate (verificato 19-376-2 → 93/51/5 intatti, group_label 100%). Abilita il voto-per-gruppo al Senato (es. Corte dei Conti: FdI 49 + Lega 25 + FI 12 fav, PD 27 + M5S 21 contr, IV 5 ast). Analisi intmp/analisi-notizie-2025-verifica-cli.md. -
Fix label gruppi Camera:
rdfs:label/dc:titlearrivano troncati alla fonte comeNOME (ACRONIMO) (DD.MM.YYYY(parentesi sulla data di inizio mai chiusa, sistematico su tutti i gruppi). Nuovo helpersrc/core/group-label.ts(cleanGroupLabel) che rimuove la coda(data→ restaNOME (ACRONIMO). Applicato agroup-members(group_label) egroups(label + title); acronimo estratto dalla label grezza prima della pulizia,dcterms:alternativeresta la fonte primaria. Verificato su gr4133 (FDI) e tutti i gruppi leg19. -
Fix README: due domande "Quante interrogazioni..." (xylella, deputato) corrette in "Quali", perché il comando
aic listelenca (non conta). Per il conteggio resta--format jsonl | wc -l. -
v0.3.3 (doc-only): skill CLI/MCP corrette (flag kebab, formato default CSV, parametri voteUri/ddlUri, valori --rank-by completi); README sezione "Uso con un agente AI (skill)" (install cross-agent
npx skills, consiglio CLI+MCP in coppia con la skill). Republish per allineare la README su npm. -
v0.3.2: fix
groupsacronimo — ora dal campo dedicatodcterms:alternative(prima puntava aocd:acronimoinesistente, ripiegando su parsing regex della label). README "Note sui dati" corretta. Spostato l'esempiomember-billsda "Riferimento" a "Esempi pratici". -
v0.3.1: repo reso pubblico e pubblicato su npm come
@aborruso/italianparliament-mcp(CLI + MCP installabili connpm i -g). Aggiunta sezione "Installazione" al README (CLI npm / MCP remoto-locale / da sorgente),prepublishOnlyin package.json, e step npm in RELEASING.md. -
Affordance di scoperta CLI stile opensdmx: comando
guide(flusso tipico di orchestrazione: scoperta→URI→dettaglio, catene, opzioni trasversali); comandowhich <capacità>(mappa capacità→comando, es.which "testo ddl"→ bill-text); errori enum con valori validi via wrapperrunToolche valida l'input Zod prima diexecute(prima la CLI chiamava execute senza validare: gli enum errati scivolavano nella query). Solo-CLI, non tool MCP. -
Nuovo tool
person-career[CAMERA] (gap US-22 + US-31): carriera unificata di una persona via il hubpersona.rdf/p{id}, che collega tutti i mandati da deputato (per legislatura, joinrif_mandatoCamera) e gli incarichi di governo (rif_membroGoverno), piùowl:sameAsWikidata. Risolve doppio incarico parlamento+governo e carriera multi-legislatura. Es. Meloni: 5 mandati (leg15-19) + PM + ministra; Wikidata Q451791. NB: Camera↔Senato non collegabile dai dati (namespace separati, nessun ID condiviso, nessun owl:sameAs sul Senato) → match solo per nome+data nascita (non implementato). Tot tool 36. -
Nuovo tool
committee-sessions[SENATO] (gap US-28): sedute di commissione in cui un DDL è stato trattato, con data, commissione (osr:titoloBreve), tipo seduta e n. interventi. Catena:osr:Intervento → osr:oggetto → osr:relativoA → ddl+osr:Intervento → osr:seduta. Es. ddl/56260 → 32 sedute (Industria/agricoltura 8, Politiche UE 6, Affari Costituzionali 5...). Tot tool 35. -
Roadmap gap-analysis #1 e #2. (1)
--count-onlysubills/aic/votes/senato-votes: restituisce solo il totale (colonna count) per confronti senza scaricare le righe. bills/aic via wrap COUNT del SELECT (veloce su dataset piccoli); votes/senato-votes via count minimale sui soli pattern vincolanti (il wrap con gli OPTIONAL su decine di migliaia di righe va in timeout). Verificato: votes leg19 18587 (0.6s), senato-votes leg19 8030, fiducia 70. (2) Nuovo toolgroup-rank[CAMERA]: classifica i gruppi per AIC/DDL (via gruppo del primo firmatario) con conteggio, membri e media per membro (count_per_member). Es. AIC leg19: AVS 4195/12 = 349.6 per membro vs FDI 2714/108 = 25.1. Tot tool 34. #3 (assenteismo) rinviato: il dato grezzo "Non ha votato" è fuorviante (governo/ministri in testa, nessun tipo "missione"). -
Fix due bug emersi dalla gap-analysis. (1)
aic --keywordera accettato dalla CLI ma ignorato (né schema né query lo gestivano): ora filtra davvero su label/titolo/description(COALESCE per i campi opzionali). Verificato:--keyword xylella→ 28/28 risultati pertinenti. (2)amendmentsnon aveva filtro per DDL: aggiunto--ddl-uriviaosr:oggetto → osr:relativoA(niente BIND, non supportato da Virtuoso) + colonnaddl_uri. Verificato: ddl/56260 → 119 emendamenti. -
Nuovi tool
senato-votes+senato-vote-detail[SENATO]: chiudono il gap n.1 della ripartenza (votazioni Senato).senato-voteslista le votazioni d'Assemblea (osr:Votazione) con esito, contatori, tipo, data seduta (viaosr:seduta/osr:dataSeduta, filtro^^xsd:date) e DDL collegato (osr:oggetto → osr:relativoA); dedup TS per voti su DDL unificati.senato-vote-detaildà il voto del singolo senatore viaosr:favorevole/contrario/astenuto/presenteNonVotante/inCongedoMissione(una query per categoria: Virtuoso non supporta VALUES/BIND); nome via foaf. Gruppo non incluso (membership temporale) → incrociare consenator-group-members. Tot tool MCP: 33. -
Gap analysis (ripartenza) in
docs/gap-analysis-2026-06-28/: re-test mirato dei 16 gap residui di aprile + user story openparlamento, metodo a due agenti (giornalista+developer) con chiamate reali. Copertura framework 33 US: da 17/10/6 a 23 OK / 8 PARZIALE / 2 KO. Gap n.1 ora: votazioni Senato (dato presente,osr:Votazione~63.911 voti leg19, ma nessun tool dedicato — solo viasparql). Bug emersi:aic --keywordaccettato ma ignorato;amendmentssenza filtro DDL. Vecchia analisi marcata archiviata. README: aggiunto openparlamento come riferimento per le esigenze giornalistiche. -
Nuovo tool
bill-text[CAMERA+SENATO]: link diretti al testo di un DDL, conformat(html/pdf/urn) eauth(none/browser) pensati per un orchestratore. Il testo integrale NON è nei dati SPARQL: il Senato espone solo l'URNosr:testoPresentato. Registrato in MCP+CLI (bill-text links). Aggiunto anchemember-billsal server MCP (era solo in CLI). -
Nuovo comando CLI locale
bill-text fetch(Senato): scarica e converte il testo in markdown.www.senato.itè dietro AWS WAF (fetch diretto → HTTP 202): apre un browser reale viaagent-browser, estrae il cookieaws-waf-token+ UA, scarica il PDF (singolo testo via scraping del tab "Testi ed emendamenti", oppure--fascicoloper il dossier completo) e converte conlit(liteparse). Opzioni--which,--all,--fascicolo,--out. Pulizia soft-hyphen (­) per ricongiungere le parole sillabate. Token effimero → preso fresco a ogni run. -
Pattern URL Senato verificati: testo presentato
…/Ddliter/testi/{N}_testi.htm, fascicolo…/FascicoloSchedeDDL/ebook/{N}.pdf, singoli testi…/service/PDF/PDFServer/BGT/{idDoc}.pdf;scheda-ddl?did={N}con{N}= numero indati.senato.it/ddl/{N}(non idDdl). Camera: nessun WAF, pagine fetchabili. -
Skill
italian-parliament-mcp(v1.1) eitalian-parliament-cliaggiornate conbill-text. Test unitario perparseTextList. Totale tool MCP: 31.
member-bills[CAMERA+SENATO]: nuovo tool unificato per DDL come primo firmatario. Camera: filtraocd:primo_firmatario+ tipo atto. Senato: patternINIZ-DDL-{ddl_id}-{id}+osr:primoFirmatario="1"(REGEX[^0-9]{id}$perché Virtuoso non supporta BIND/STRAFTER nidificato).bill[CAMERA]: aggiunto campocosignatoriescon tutti i cofirmatari (dc:contributor) separati da|.deputy[CAMERA]: aggiunticommittees,election_list,election_date,election_validated,birth_date,birth_place. Nascita viapersona.rdf/p{id}→bio:Birth.senator[SENATO]: fixbirth_city(viabio:birth→bio:place→rdfs:label); fix CLI--legislaturenon passato all'execute (mandato sempre leg 19); fix filtroosr:legislaturaconFILTER(STR(...))(eraxsd:integer, non stringa).
- Nuovo tool
bill-rapporteurs[CAMERA]: relatori di un DDL per commissione con nome, tipo (Relatore/Relatore f.f.), commissione, data inizio esame e URI deputato. Path SPARQL: atto→rif_dibattito→dibattito→rif_discussione→discussione→rif_relatore. Totale tool: 26. - Aggiunto campi mandato/elezione a
deputy(Camera) esenator(Senato):election_region,election_district(solo Camera),election_type,mandate_start,mandate_end. Camera viaocd:rif_mandatoCamera → ocd:rif_elezione; Senato viaosr:mandatofiltrato per legislatura. - Aggiunto campo
descriptional toolvotes(Camera):dc:descriptioncontiene il testo reale della votazione (es. "Votazione Fiducia A.C. 2807-A"), mentrelabeletitlesono spesso vuoti. Utile soprattutto con--confidence-vote true. - Aggiunto parametro
--bill-codeal toolvotes(Camera): filtra votazioni collegate a un DDL per numero atto (es.--bill-code 2807). Restituisce fiducia, voto finale e ordini del giorno. Combina con--legislatureper evitare falsi positivi tra legislature.
- Gap analysis giornalista vs MCP: 33 user stories testate con tool reali. 13 OK, 14 PARZIALI, 6 KO. Documenti in
docs/gap-analysis-2026-04-13/. - Fix
group-members: campostart_dateconteneva inizio+fine concatenati (20221018-20240916),end_datesempre vuoto. Ora split su-con date separate. - Aggiunto filtro
regional tooldeputies: filtra per circoscrizione/regione con CONTAINS case-insensitive su election_label. Testato: sicilia, lombardia. Circoscrizioni estero: AFRICA, AMERICA, EUROPA. - Aggiunto campo
descriptional toolaic(Camera): contiene il testo/oggetto dell'interrogazione, interpellanza o mozione. Il Senato (sindacato-ispettivo) non espone l'oggetto nell'endpoint SPARQL. - Tool
rankesteso al Senato: 2 nuove dimensionisindacato-ispettivoeddl-senato. Aggiunto campochambernell'output. Top Senato atti ispettivi: Camusso 786, Rojc 753. Con--order asc: Casellati, Bernini, Durigon con 1 atto. Totale dimensioni rank: 7 (5 Camera + 2 Senato). - Nuovo tool
committee-members[CAMERA+SENATO]: composizione commissioni con ruoli. Camera:ocd:ufficioParlamentareconcarica(PRESIDENTE, VICEPRESIDENTE, SEGRETARIO, CAPOGRUPPO, COMPONENTE). Senato:osr:Afferenza+osr:afferisceconcarica(Presidente, Membro, ecc.). Parametrochamber: camera|senato|both, filtrabile per commissione, parlamentare, legislatura, activeOnly. Totale tool: 25. - Fix
sindacato-ispettivo: campopresentatoreesenatore_uriora sempre popolati (anche senza filtro senatore). Riscrittura query conGROUP BY+MIN()per evitare duplicati da join multi-firmatario. Subquery non supportata da Virtuoso Senato, usato MIN su tutti i campi. - Sprint 1 (6 quick wins):
keywordsubills,bill-progress,votes: ricerca full-text nei titoli DDL e votazioni. Cerca in title+label (OR).confidenceVotesuvotes: filtra votazioni di fiducia. 10 fiducie leg19 testate.dateFrom/dateTosusessions: filtra sedute per data.deputyUrisugroup-members: storia cambi gruppo di un singolo deputato. Testato con Enrico Costa (Azione→FI).order: asc|descsurank: ordinamento inverso per trovare i meno attivi. asc mostra ministri con 4 speeches.initiativesubills: filtra per iniziativa (Popolare/Governo/Parlamentare/Regioni). Tutti e 4 testati.
- Nuovo helper
src/core/decode-html.ts: rimuove^^xsd:type, decodifica entità HTML (",’,à, ecc.), rimuove tag HTML (<em>ecc.). - Applicato a
billssu campilabeletitle. Titoli ora leggibili. - Deploy worker aggiornato.
- Fix
vote-detail: aggiunto campodeputy_name(nome leggibile) alla query. Usatordfs:labelcon URI completo (Camera rifiuta prefissordfs:). Suffisso legislatura rimosso constripLegLabel. - Deploy worker aggiornato.
- Fix dedup
bills: blank node multipli suprimo_firmatariogovernativi → aggiuntoFILTER(!isBlank(?sponsor_uri)). DDL governativi ora hannosponsor_urivuoto (corretto). - Fix dedup
sindacato-ispettivo: join suosr:iniziativaproduceva N righe per N firmatari → rimosso join quando nessun filtro senatore.senatore_uri/presentatorevuoti nella lista generale, presenti solo quando si filtra per senatore. - Deploy worker aggiornato.
- Fix bug
rank: senatori comparivano nella classifica Camera perchélegFilternon vincolava?person a ocd:deputato. Aggiunto il tipo esplicito in entrambi i rami (con e senza legislatura). - Deploy worker aggiornato.
- Aggiunto filtro
dateFrom/dateTo(YYYY-MM-DD) a 4 tool:votes,aic,bills,sindacato-ispettivo. - Aggiunto
ORDER BY DESC(?date)su tutti e 4 i tool — le più recenti escono per prime. - Fix: Senato usa
xsd:datetipizzato → FILTER con"data"^^xsd:date(non plain string). - CLI: aggiunto
--date-from/--date-tonei 4 subcommand corrispondenti. - Testato: votes leg19 dal 1 apr 2026 → seduta 641 del 9 apr; sindacato-ispettivo dal 1 apr → interrogazione 3-02528 del 10 apr.
- Nuovo tool
sindacato-ispettivo[SENATO]: equivalente Senato degli AIC Camera (interrogazioni, interpellanze, mozioni, risoluzioni). - Filtrabile per legislatura, senatore URI, tipo atto.
- Fix:
BINDnon supportato su Virtuoso Senato → sostituito conFILTER(?senatore_uri = <URI>). - Fix: legislatura come triple pattern diretto (
?s osr:legislatura 19) non OPTIONAL+FILTER.
- Nuovo tool
rank[CAMERA]: classifica deputati per attività parlamentare in una sola chiamata. - 5 dimensioni:
aic-primo-firmatario,aic-cofirmatario,bills-primo-firmatario,bills-cofirmatario,speeches. - Evita N batch da 1000 righe: GROUP BY lato SPARQL, risposta diretta top-N.
- Fix trovato: prefisso
PREFIX rdfs:causa errore silenzioso su endpoint Camera — usare URI completo<http://www.w3.org/2000/01/rdf-schema#label>.
- Nuovo tool
senator-group-members[SENATO]: membri attivi di un gruppo parlamentare del Senato. - Default
asOf = oggi; opzionale--as-of YYYY-MM-DD,--legislature,--group-uri. - Schema Senato differisce dalla Camera:
ocd:aderisce(direzione inversa), label gruppo via blank nodeosr:Denominazionecon storico nomi filtrato per data.
- Fase 6 batch 3: +4 tool Camera (
speeches,aic,vote-detail,group-members). Totale tool: 17/24. - Fix
vote-detail: la query R usavaocd:votocome proprietà ma non esiste — il valore del voto è indc:type. Scoperto con query esplorativa sulle proprietà reali del triplo. speeches: dati disponibili solo per legislatura 17, molti campi opzionali vuoti (limite dati upstream Camera).- README aggiornato con riferimento al repo upstream
italyParlR. - README riscritto in italiano per giornalisti parlamentari (tabella comandi, esempi pratici, note sui limiti dati).
- Verifica completa dei 17 tool, 3 fix applicati:
groups: acronimo ora estratto dalla label con regex (era campo vuoto nell'endpoint).roles: proprietà correttaocd:ruoloinvece didc:type(VICEPRESIDENTE, SEGRETARIO, ecc. ora popolati).sessions: filtroSTRSTARTSper escludere bollettini (BF_*), ora solo sedute formali con numero progressivo.speeches: riscritto completamente.rif_leg/dc:date/rif_sedutanon esistono; la legislatura è nell'URI (in19_), filtro conSTRSTARTS. Ora funziona per tutte le legislature (>1M interventi totali). Colonne: uri, label, deputy_uri, document_url, modified.deputy/senator/bill show: riscritti con query mirate invece di triple RDF grezze. Output ora con campi leggibili (first_name, last_name, gender, photo, ecc.). Deputy usafoaf:firstName/foaf:surname/foaf:gender.governments: riscritta query, ora interroga direttamenteocd:governocondc:date. Ordinamento cronologico DESC (Meloni→Draghi→Conte II→...). Aggiunto campostart_date.
- Fase 6 batch 4: +5 tool (
gov-members,committees,bill-progress,bill-signatories,amendments). Totale tool: 22.gov-members: membri del governo con nome persona, ruolo (MINISTRO, SOTTOSEGRETARIO, ecc.), date, motivo termine. Cerca per nome.committees: 279 commissioni Senato (permanenti, speciali, d'inchiesta).bill-progress: iter DDL Senato con stato, date, iniziativa, natura. Dati freschi (DDL del 10 aprile 2026).bill-signatories: firmatari DDL Senato con primo firmatario/cofirmatari e link senatore.amendments: 53K emendamenti Senato leg 19, con link al testo.
documentsCamera (ocd:documento): 0 istanze nell'endpoint. Nessun tipo documento alternativo trovato. Senato haosr:Documento(48K), implementato.documentsSenato: atti del governo, atti UE, relazioni Corte dei Conti, risoluzioni commissioni. Dati freschi (9 aprile 2026).committees: migliorato con filtro legislatura via SedutaCommissione. Con--legislature 19mostra 12 commissioni attive con conteggio sedute (Affari Costituzionali: 681 sedute). Senza filtro mostra catalogo storico (279).
-
Commit root: 26 file (Fase 0-4).
-
Fase 6 batch 1: +4 tool Camera (
legislatures,groups,sessions,governments). Query portate daitalyParlR(clone intmp/). Type check pulito. Smoke test CLI reali verdi su tutti e 4. Totale tool: 9/24. -
Fase 6 batch 2: +4 tool dettaglio (
deputy,senator,billproperty/value;rolesCamera con filtri deputy/group/legislature). Totale tool: 13/24. -
Refactor obbligato:
makeHandlerinsrc/index.tspassato da<I>generico aanyperché a 13 tool la generic instantiation combinata Zod × MCP SDK × helper mandavatscin OOM (FATAL heap limit) anche con--max-old-space-size=4096. Con handler non generico il type check torna pulito. -
Nota su
deputy: rimossa laz.refine()sullo schema (producevaZodEffectssenza.shape, incompatibile conregisterToolMCP). Validazione ora dentroexecute(). -
Repo creato. Fase 0 completata.
-
Struttura:
src/core/,src/tools/, entrypoint previstisrc/cli.ts,src/index.ts,src/worker.ts. -
Stack: TypeScript + citty + axios + zod + @modelcontextprotocol/sdk.
-
Scripts
package.jsonclonati dackan-mcp-server: build (esbuild cli+index), build:worker, build:dxt, pack:skill, deploy. -
Paradigma vincolante: CLI agent-friendly (non-interattiva, flag+stdin, errori actionable, output machine-readable, no emoji).
-
Naming CLI:
italianparliament <resource> <verb>. -
Fase 1 COMPLETATA:
src/core/conendpoints.ts,prefixes.ts(OCD/OSR copiati da italyParlR),types.ts(SparqlResults, Row),flatten.ts(flattenBindings),client.ts(cdQuery/snQuery con axios, retry, SparqlError),format.ts(toCsv/toJsonl),index.tsbarrel. -
Endpoint: Camera
https://dati.camera.it/sparql, Senatohttp://dati.senato.it/sparql. Timeout 60s, retry 3. -
Test vitest: 10/10 passati (flatten + format). Type check pulito.
-
Smoke test reale contro Camera SPARQL (SELECT ?s ?label WHERE Person LIMIT 3) → OK end-to-end.
-
Fase 2 COMPLETATA: 5 tool MVP in
src/tools/(deputies, senators, bills, votes, search) +types.ts(Tool interface con name, description, inputSchema Zod, examples, execute) +index.ts(barrel + toolsByName). -
Ogni tool: schema Zod per input, lista
columnsper output stabile,execute()che chiama cdQuery/snQuery → flattenBindings → riga rinominata secondo naming coerente (uri invece di s, legislature_uri invece di rif_leg, in_favour/against/abstentions per i voti, ecc.). -
Fix importanti scoperti durante smoke test:
- Endpoint Senato aggiornato a HTTPS (il vecchio http://dati.senato.it/sparql redirige e il redirect mangia le
{}della query). - Formato response:
format=application/json+Accept: application/json(il vecchioapplication/sparql-results+jsonrestituisce 406 su Senato). User-Agentcustom obbligatorio su Senato (default axios → 403 CloudFront).
- Endpoint Senato aggiornato a HTTPS (il vecchio http://dati.senato.it/sparql redirige e il redirect mangia le
-
Smoke test reale verde su Camera (deputies leg 19), Senato (senators leg 19), search (Camera "meloni"). 10/10 vitest ancora verdi, type check pulito.
-
Fase 3 COMPLETATA:
src/cli.tscon citty. Patternitalianparliament <resource> <verb>:deputies list,senators list,bills list,votes list,search find.--helpper ogni subcommand include sezione Examples con invocazioni copiabili.--format csv|jsonlsu tutti (default csv, machine-readable, no colori/emoji). Errori fail-fast:--limit abc→ "Invalid --limit value. Expected a positive integer", argomento required mancante → citty mostra help + errore. Catch top-level gestisceSparqlErrorcon endpoint/status. -
Test reali verdi: deputies, senators, search, jsonl output, error handling.
-
Fase 4 COMPLETATA:
src/index.ts— MCP stdio server con @modelcontextprotocol/sdk.McpServer+StdioServerTransport. Registrazione esplicita (non loop) dei 5 tool viaregisterTool(name, {description, inputSchema: tool.inputSchema.shape}, handler). HelpermakeHandlergeneric per catturare SparqlError/Error e restituireisError: true. Output in formato JSONL viatoJsonl. -
Nota TS2589: il loop generico su
tools[]generava "Type instantiation is excessively deep". Fix: chiamate registerTool esplicite per ogni tool. -
Test stdio end-to-end: initialize + tools/list → 5 tool con JSON Schema completo da Zod (properties, required, default, enum). tools/call
search {name:"meloni",chamber:"camera",limit:2}→ 2 righe JSONL da Camera SPARQL reale. -
Prossimo: Fase 5 — Cloudflare Worker (
src/worker.tscon MCP HTTP server clonando pattern da ckan-mcp-server).