Skip to content

Latest commit

 

History

History
297 lines (220 loc) · 89.8 KB

File metadata and controls

297 lines (220 loc) · 89.8 KB

LOG

2026-07-10

  • feat amendments — fallback bulk AKN GitHub + proponenti (P1 dell'analisi fonti non-LOD; issue #45→#38+#30, branch feat/amendments-akn-fallback). Nuovo src/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) espone akn_xml_url su ogni riga LOD (conversione URLTestoXml→raw, flagCommissione decide emend/emendc); (2) con ddlUri e LOD vuoto fa fallback sul bulk (source=akn); (3) --with-proponents estrae primo firmatario e cofirmatari dal testo AKN (docProponent/TLCPerson, doppia variante markup Assemblea/Commissione, preferito showAs col 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 nuova dataPresentazione xsd: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) → amendments fallback post-2024 + proponente, bill-text link AKN; P2 RSS → rss_url su bills/bill (già emesso da 3 tool), niente parsing server-side; P3 listasommcomm → solo colonna sommari_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 in camera/assenti.md e camera/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 true sulla data di stampa dava 0 righe mute. Ora, se il risultato è vuoto e --confidence-vote true con 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-to combacia 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.md risolti (nessun tool nuovo, 43 tool; 98/98 test verdi, tsc pulito): (1) bill-signatories non classifica più come Governo i DDL Senato parlamentari da Camera (+ person_uri/html_url deputati via ocd:rif_deputato); (2) senato-votes --keyword trova le fiducie anche per tema (supplemento via titolo DDL); (3) bill guardia instradante "solo-Camera" su URI Senato; (4) bill_number backfillato dalla osr:fase del DDL risolto (corregge anche i refusi della fonte). Wiki: firmatari-iniziativa (seconda trappola + censimento tipoIniziativa), fiducia-fallback (discovery tematica), nuova akn-bulk-data (bulk AKN GitHub senza WAF, issue #45). Skill CLI aggiornata. Dettaglio nelle voci sotto.

  • feat senato-votes — backfill di bill_number dal DDL risolto (punto 4 dell'analisi del report docs/news-agent/2026-07-10_11-10.md). Sui label generici ("Votazione finale") o coi refusi il numero non è estraibile dal testo, ma quando ddl_uri è risolto (link diretto o fallback) il numero è la osr:fase del 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 report docs/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 a bill-progress --ddl-uri / bill-signatories --bill-uri / bill-text --uri (stesso pattern di amendments "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 report docs/news-agent/2026-07-10_11-10.md). Root cause: il match keyword sul titolo del DDL (v0.20.0) passa in SPARQL da osr:oggetto→osr:relativoA→osr:titolo, ma le fiducie non hanno osr:oggetto?ddlTitolo unbound → escluse dal filtro anche quando il tema è nel titolo del DDL citato per numero nel label (--keyword sicurezza non trovava la fiducia 19-312-1 sul decreto sicurezza). Fix: supplemento fiducie — con --keyword una seconda query recupera le sole fiducie del periodo (set piccolo, ~55 nell'intera leg. 19), risolve il DDL citato nel label via osr:fase leggendone anche osr: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 sicurezza giu 2025 → fiducia 19-312-1 + pregiudiziale, count=2 coerente; regressioni "corte dei conti" e combinazioni --confidence-vote true/false invariate. Wiki senato/fiducia-fallback.md estesa. +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 report docs/news-agent/2026-07-10_11-10.md). Root cause: l'euristica assumeva atto governativo quando mancava osr:senatore, ma i firmatari deputati (es. ddl/59070, S.1457 Corte dei Conti, Dep. Foti) vivono nel grafo senza osr:senatore e con ocd:rif_deputato. Fix: la query legge anche osr:tipoIniziativa (discriminante esplicito: Parlamentare/Governativa/Popolare/Regionale/CNEL/…) e ocd:rif_deputato; i deputati ora hanno ruolo primo firmatario/cofirmatario corretto 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: flattenBindings rende "" i binding assenti, quindi il fallback senatore ?? deputato non 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). Wiki senato/firmatari-iniziativa.md estesa con la seconda trappola + censimento tipoIniziativa. +1 test, 95/95 verdi, tsc pulito.

2026-07-09

  • v0.22.0 — senato-votes multi-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 code joinMap (rompeva tsc --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 aggiungono ddl_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 tipo italianparliament ... | head -3, Node continuava a scrivere su stdout dopo che head aveva chiuso il pipe → stack trace Error: write EPIPE, rumoroso ma non legato ai dati. Fix minimo in src/cli.ts: handler su process.stdout e process.stderr che intercetta err.code === "EPIPE" e termina con exit(0) invece di rilanciare. Verificato end-to-end dopo build con node 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.

2026-07-08

  • 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 --number recupera l'intera navetta a più letture (-B/-C); (2) bill-signatories risolve i ministri sui decreti-legge Camera (basta righe con name vuoto); (3) hint di staleness su votes per 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 report docs/news-agent/2026-07-08_12-57.md). Root cause: sui decreti-legge ocd:primo_firmatario non punta a un deputato ma a un blank node "membro di governo" privo di foaf:firstName; il tool cercava il nome solo sul nodo → 5 righe con name="" e nodeID://… (sembrava un bug/assenza firmatari). Il dato c'è: il nome del ministro è un hop più in là via ocd:rif_persona (→ persona.rdf), il dicastero in ocd:ruolo. Fix: la query Camera segue rif_persona+ruolo; discriminante netto parlamentare vs governativo = presenza di rif_persona. Ora Piano Casa (ac19_2920) torna Piantedosi/Salvini/Giorgetti/Foti/Meloni con role="Governo — <dicastero>", is_primary=false (proponenti multipli, coerente con #29/ramo Senato); regressione atto parlamentare (Ziello ac19_2941) invariata. html_url vuoto per i ministri (URI persona.rdf, non risolvibile senza mandato — limite #14, accettabile). Nuova pagina wiki OKF camera/firmatari-atti-governativi.md + index. +1 test. 94/94 verdi.

  • fix bill-progress --number — navetta a più letture (-B/-C) completa (gap 3 del report docs/news-agent/2026-07-08_12-57.md). Root cause: il filtro sul numero era un match esatto FILTER(STR(?numeroFase) = "1353"), che intercettava solo la prima lettura; le letture successive hanno numeroFase diverso ("1353-B") e cadevano fuori. Peggio: --number 1353-B falliva con ERROR --number: Invalid (validazione Zod ^\d+$). Fix (1 riga): match esatto → REGEX(STR(?numeroFase), "^<n>(-[A-Z])?$"), così --number 1353 --branch S torna 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 C ritorna record Senato).

  • feat: hint di staleness su votes — vuoto recente non più muto (gap 2 del report docs/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. Aggiunto hint? dinamico su ToolResult: votes calcola 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'emptyHint statico) e CLI (emitstderr, 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 + wiki freschezza-e-autorevolezza.md): nessuna issue aperta, si attendono le risposte gestori.

  • v0.20.0 — senato-votes --keyword cerca anche nel titolo del DDL, throttle anti-403 Senato, emptyHint su due gap di dataset (dai gap del report news-agent docs/news-agent/2026-07-08_08-17.md).

    • senato-votes --keyword ora matcha anche il titolo del DDL collegato, non solo il rdfs:label del 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: OPTIONAL sul titolo DDL + CONTAINS in OR col label, con BOUND() così le fiducie (prive di osr:oggetto) non fanno fallire l'intero OR. Verificato leg.19: --keyword bilancio ora torna le votazioni della legge di bilancio (DDL 59654) che prima erano invisibili (label-only). Allineato anche il ramo countOnly.
    • 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). snQuery diventa async. 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 dataset osr:Emendamento è fermo al 9 agosto 2024 — nessun DDL con dataPresentazione successiva 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.md su 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 --keyword dipende troppo dal label, il caso Cura Italia 2020 non emerge via senato-votes, e la fiducia Piano Casa 2026 resta con ddl_uri vuoto nel listato base. Emersa anche confusione semantica di bill-progress --number --branch C (ritorna la fase Senato del C.*). Nessun fix applicato in questa run; solo evidenza grounded da comandi reali.

2026-07-07

  • 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 su ocd:voto filtrata per URI mandato (già specifico di legislatura, niente join su rif_leg — evita il gap di dati noto lì, ~50% delle votazioni senza rif_leg popolato). Colonne: favorevole/contrario/astensione/non_ha_votato/ha_votato (scrutinio segreto)/altro/totale. Senato: 5 query per categoria su proprietà inverse osr:favorevole|contrario|astenuto|presenteNonVotante|inCongedoMissione, filtrate per osr: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 --keyword ora cerca anche in description. Root cause: keywordFilter confrontava solo ?label e ?title (OPTIONAL), ignorando ?description — dove invece vive il testo tematico (es. "Bilancio di previsione dello Stato..."). Risultato: votes list --keyword bilancio restituiva 0 nonostante il DDL 2750 esistesse. Fix: aggiunto ?description al CONTAINS del filtro e reso vincolante (?s dc:description ?description .) nella inner query quando la keyword è attiva. Verificato: --keyword bilancio ora 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 che osr:tipoVotazione è la modalità di voto (elettronica/nominale/segreta), NON il tipo semantico: "Votazione finale" e "questione di fiducia" vivono solo nel rdfs:label. I tre filtri sono quindi label-based (CONTAINS su rdfs:label). Trappola gestita: sfiduciafiducia--confidence-vote true esclude esplicitamente sfiducia (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 caccia torna vuoto (il tema vive nel DDL collegato: usare --ddl-uri + bill-progress). Nuova pagina wiki senato/votazione-tipo-semantico.md.
    • Nessun tool aggiunto (41 tool). Test 90/90 verdi.
  • 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 a dc:date (literal AAAAMMGG) 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-28 restituiva 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 in STR(...) tutti i confronti data Camera in 5 toolvotes, bills, sessions, committee-sessions, audizioni (le date Senato tipizzate ^^xsd:date restano invariate). Verificato: votes leg.19 gen/feb/mar 2025 → 313/436/464 (coerente con STRSTARTS); 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). Wiki trappole-virtuoso-funzioni-stringa.md generalizzato: la trappola #2 vale anche sulle variabili dc:date nude, non solo sui risultati di SUBSTR/REPLACE.

2026-07-06

  • 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-agent docs/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-to sul giorno d'Aula dava 0 righe. Fix: il filtro combacia se cade nell'intervallo la presentazione oppure la modifica (2° gruppo del composto, estratto con REPLACE); 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) SUBSTR fuori range aborta la query senza short-circuit dell'&& → estrarre con REPLACE, non SUBSTR(...,10,8); (2) >=/<= sul risultato di SUBSTR/REPLACE fa un confronto numerico che dà 0 righe → forzare con STR(...). +1 test sentinella, 89/89. Aggiornati aic.ts (descrizione), skill CLI+MCP, wiki camera/aic-date.md + nuova pagina trasversale Virtuoso (referenziata da index e da senato/trappole.md).

  • fix senato-votes --ddl-uri: ora include la fiducia collegata (bug #1 dal report news-agent docs/news-agent/2026-07-06_18-51.md). Root cause: il filtro server-side osr:relativoA <ddlUri> escludeva a monte le fiducie (prive di osr:oggetto); i fallback che ricollegano il DDL giravano solo nel percorso per data. Fix: con --ddl-uri si risolvono prima le date delle sedute in cui il DDL è votato (query osr: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 diretto osr:relativoA o 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. countOnly allineato alla lista. Verificato Piano Casa (ddl/60233): restituisce pregiudiziale (57/79) + fiducia (106/62/2, 19-434-2), esclusa la risoluzione 19-434-3; DDL con voto finale (ddl/58039) invariato (42 voti). +1 test sentinella live, tsc pulito. Aggiornati description/emptyHint del tool, skill CLI+MCP e docs/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 helper src/core/current-legislature.ts: risolve la legislatura corrente in modo dinamico dall'endpoint Camera (ultima repubblica_* per dc:date), cache in-memory + fallback 19 con warning su stderr. Sostituisce l'hardcode 19 in senator, committees, committee-sessions, bill-text e nel ramo Camera di bill-progress (si romperebbe alla prossima legislatura). (2) bill-progress --number senza --legislature ora 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 list Camera: due colonne nuove aic_code (es. 1/00586) e aic_link (URL scheda AIC) per mozioni/risoluzioni, estratte da description/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 senza ddl_uri (per refuso della fonte nel numero, es. "DDL n. 1994" per S.1944) eredita il ddl_uri da altri voti della stessa data se non ambiguo; sblocca la fiducia Piano Casa 19-434-2ddl/60233. (6) bill-signatories: gli atti Senato di iniziativa governativa (nessun osr:senatore) ora hanno ruolo Governo (proponente) invece di primo firmatario, senza person_uri/html_url fittizi. Nessun tool aggiunto (41 tool). 87/87 test, tsc pulito. README + skill CLI/MCP aggiornati.

2026-07-05

  • 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 campo Tool.emptyHint + messaggio di default anti-confabulazione sul risultato vuoto ("non dedurre né inventare; un vuoto è spesso un mismatch"); (2) descrizioni prescrittive su bill-progress (spina dorsale dell'iter, aggancio DDL Senato per numero non per keyword), senato-votes (caveat fiducia: ddl_uri vuoto → 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 deputies e senators (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 nodo deputato; nascita sul nodo persona (foaf:Person) agganciato via lo stesso ocd:rif_mandatoCamera (vincolo a foaf:Person per non duplicare le righe), bio:date (YYYYMMDD→YYYY-MM-DD in output) e ocd:rif_luogo. Esposte 2 colonne nuove birth_date+birth_place: birth_place è lo slug comune_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 via STR()), cittaNascita (solo città, no provincia/regione: limite documentato). Quirk: foaf:gender al Senato è letterale tipizzato → FILTER(?gen="F") dà 0, serve FILTER(STR(?gen)="F") (stesso caso di siglaGruppo). +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 ricetta vote-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-type Camera: AstenutoAstensione (emerso valutando issue #7). Il valore reale di dc:type sui voti Camera è Astensione (verificato: campione 5000 → 4 valori netti Favorevole/Contrario/Astensione/Non ha votato, nessun "In missione"), ma l'enum del tool accettava Astenuto (→ 0 righe muto) e rifiutava Astensione → filtrare gli astenuti era impossibile. Corretto in vote-detail.ts (enum + descrizione) e cli.ts (descrizione + cast). Il Senato non è toccato: senato-vote-detail costruisce i label via osr:astenuto e usa correttamente Astenuto. 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 su vs19_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 list ora 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 tool bill-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: Senato osr:assegnazione, Camera ocd:rif_assegnazione. Verificato su S.1809 → 7 commissioni (1ª Referente + 6 Consultive, 30/04/2026) e su C.2822 (I Commissione Referente). Aggiunto &ordf;/&ordm; al decoder HTML (label Senato "1ª (…)"). Registrati in CLI, MCP server.ts e registry; voce which per "commissione/assegnazione". 83/83 test, tsc pulito. 41 tool.

  • "Il cielo del Parlamento" — pagina vetrina live su GitHub Pages (site/ + workflow pages.yml): pagina animata (GSAP + ScrollTrigger, canvas) che racconta CLI/MCP con dati sempre live dal Worker: costellazioni = parlamentari in carica per gruppo (Camera+Senato via group-members/senator-group-members), strada delle legislature 1848→oggi (legislatures), ultime votazioni con contatori (votes), griglia dei 40 strumenti da tools/list (si auto-aggiorna a ogni release). Nessun dato precotto: ogni visita interroga /mcp (JSON-RPC tools/call stateless, parse SSE, cache localStorage 1-24h). Fix worker necessario: la risposta di transport.handleRequest non aveva Access-Control-Allow-Origin (solo il preflight lo aveva) → aggiunto wrap con header CORS, deployato. Deploy Pages via Actions (actions/deploy-pages, path site/). Testata con agent-browser: desktop 1440, mobile 390 (layout compatto senza etichette), barre voti (fix display:block su span inline), ScrollTrigger.refresh() dopo il load asincrono. Click su una stella → scheda ufficiale del parlamentare (camera.it/senato.it, da html_url dei 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 rerun su deploy-pages fallito produce "Multiple artifacts named github-pages" — mai rerun, sempre run nuova (gh workflow run pages.yml).

  • v0.14.1camera-amendments: fallimento diagnostico su Worker + header browser-like. Verifica del Worker live (requisito): SPARQL e audizioni OK; camera-amendments fallisce 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.js stdio, 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 di audizioni.

  • fix: audizioni mancava da server.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 contatore tools: del worker durante la release (diceva 39 "aspirazionale" mentre allTools erano 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 tutta fetch (no browser; Camera senza WAF): scheda atto (actHtmlUrl) → link liste per sede → parsing righe con cheerio/slim (àncore tr.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 trascina encoding-sniffer→iconv-lite→require("buffer") che rompe il bundle ESM e gonfia il Worker a 2.8mb (con slim: 484kb). Guardia amendments su URI Camera → rimanda a camera-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 tool camera-amendments sarebbe 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). Memoria project_camera_amendments_absent aggiornata.

  • amendments: guardia esplicita su URI non-Senato (anti falso-vuoto): il tool interroga solo l'endpoint Senato; un --ddl-uri della Camera passava il FILTER senza match → CSV vuoto silenzioso, scambiabile per "nessun emendamento". Ma gli emendamenti Camera non esistono come entità nel LOD OCD (issue #19 chiusa, nota camera-assistenza-dati.md punto 1): l'unica traccia è testuale nelle descrizioni delle votazioni. Fix: amendments.ts ora lancia un errore esplicito se ddlUri non contiene dati.senato.it, spiegando che il vuoto non significa assenza e rimandando al tool votes. +1 test offline di regressione (/solo-Senato/). Verificato: URI Camera → errore; URI Senato (ddl/56260) → emendamenti regolari. 80/80 test.

  • Difesa bill_number fantasma 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 Casa 19-434-2 ha rdfs: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 ha osr:oggetto → unico appiglio al DDL è la label → il typo rompe l'aggancio per numero (aggancio affidabile = seduta/data: seduta 434 = 2026-07-01 = dataStatoDdl del 60233). Fix difensivo (senato-votes.ts + votes.ts, simmetria Camera): dopo il fallback di risoluzione bill_number→URI atto, se il numero citato non corrisponde ad alcun atto reale della legislatura, bill_number viene azzerato — così non si espone un identificativo non interrogabile (restituirebbe sempre zero); il testo grezzo resta in label/description. Verificato via CLI: 19-434-2 (typo) → bill_number vuoto; 19-432-3 (fiducia DDL 1933, numero valido) → bill_number=1933 + ddl_uri=ddl/60201 risolto. 79/79 test. Refuso annotato nella bozza gestori docs/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.

2026-07-04

  • 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 solo ocd:ufficioParlamentare (cariche apicali) legato via ocd: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 via ocd: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 Agricoltura o19_3513) prima di toccare la query. Fix: query a UNION dei due path (ocd:membro + ufficioParlamentare con rif_deputato OR rif_senatore); merge lato TS con priorità ruolo (Presidente>Vicepresidente>Segretario>Capogruppo>Titolare>Sostituto) per collassare a una riga per persona — ma solo con activeOnly=true; con activeOnly=false le 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-uri con 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.

2026-07-03

  • v0.13.0 — fix search multi-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 di CONTAINS per 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: mancava countOnly (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): COUNT leggero, 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 nel dc:title della ocd:discussione (nome+ruolo+ente) ma vive come stringa, mai entità → strutturarlo ha costo ~zero per il publisher. Proposta = 2 mosse di riuso OCD: (A) ripristinare dc:type="Audizione" come in leg.14; (B) popolare ocd:rif_persona (slot vivo su 45.808 discussioni, mai valorizzato sulle audizioni) con entità ocd:soggettoAudito tipizzata + 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.318 coppie dibattito–discussione (raddoppio rdf:type); discussioni distinte = 3.311, ~935 nella forma pulita "Audizione di ". Corretto anche in memoria e tasks/todo.md.

2026-07-02

  • v0.12.0 — bill-signatories esteso a Camera (news-agent punto 5): era [SENATO] puro. Scoperto che il LOD Camera espone i firmatari come proprietà dirette dell'attoocd:primo_firmatario (1 deputato) e ocd:altro_firmatario (cofirmatari) — quindi nessun buco di dati, mancava solo il tool. Riscritto come dual-branch sul modello di bill-rapporteurs: ramo rilevato dall'URI, colonne unificate name, role, is_primary, person_uri, html_url. Nome deputato composto da foaf:firstName+foaf:surname (fallback rdfs:label senza suffisso legislatura). Parametro rinominato ddlUribillUri (--bill-uri), con --ddl-uri mantenuto 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 backoff 500·attempt (~1,5s totali) cadevano spesso tutti nella stessa finestra → errore visibile all'utente. Ora DEFAULT_MAX_RETRIES=5 e backoff esponenziale con tetto a 2s (250→500→1000→2000ms, ~4s totali) in src/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 /mcp su ac18_2853dell'articolo 13-bis pulito); la grezza vista via l'integrazione claude.ai era connessione stale del client MCP, non il Worker.
  • v0.11.2 — decodeHtml gestisce anche le entità numeriche: il fix v0.11.1 era incompleto. L'helper src/core/decode-html.ts decodificava solo le entità con nome (&rsquo;, &agrave;), lasciando grezze quelle numeriche decimali (&#39;) ed esadecimali (&#x27;), frequenti nei titoli OCD della Camera (es. all&#39;articolo, nell&#39;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 file src/core/decode-html.test.ts (7 test: named, numeriche dec/hex, strip tag, ^^xsd, codepoint invalido, idempotenza). Verificato end-to-end su ac18_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) restituiva title/status grezzi dall'endpoint OCD, con entità HTML non risolte (es. l&rsquo;assistenza, criminalit&agrave;), a differenza degli altri tool (bills, member-bills, ecc.) che già applicano decodeHtml. Applicato l'helper condiviso src/core/decode-html.ts ai due campi. Verificato che le entità sono single-encoded (&rsquo;/&agrave;), 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 espone dcterms:modified sui void:Dataset ma congelato a feb 2024 su dataset vivi fino a metà 2026; Senato non ha metadati di freschezza (le 926 triple dcterms:modified sono 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 via dc:type (valorizzato solo leg. 14, 619 dibattiti storici) ma via il titolo della ocd:discussione collegata al dibattito (ocd:dibattito rif_leg → ocd:rif_discussionedc:title con "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:Procedura tipo="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 i dc: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.md Via A/Via B), tmp/audizioni.md v2, tasks/todo.md.
  • committees esteso a Camera (#6): il tool era [SENATO] puro (osr:Commissione). Aggiunto --chamber (camera/senato/both, default both). Camera: ocd:organo filtrato per legislatura (default 19, le istanze sono per-legislatura), con dc:type esposto come nuova colonna category (COMMISSIONE PERMANENTE/BICAMERALE D'INCHIESTA/GIUNTA/COMITATO/...) e session_count da ocd:seduta+rif_organo. Aggiunta category anche lato Senato (da osr:categoriaCommissione, prima non esposta). Nuova colonna chamber in testa, come già in committee-sessions/committee-members. Retrocompatibile: senza --chamber default both; Senato senza --legislature continua 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 sparql tool — falso positivo "Solo query SELECT supportate": bug reale (non un problema di query malformate lato utente), segnalato in tmp/audizioni.md §7.3. validateSelectQuery toglieva i "commenti" con query.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), un PREFIX rdfs: <...#> prima di SELECT faceva sparire tutto il resto della riga — SELECT incluso — dalla stringa validata, con conseguente rifiuto di query perfettamente valide. Fix: nuovo stripComments che traccia se si è dentro <...> e ignora i # in quel caso. +1 test di regressione, 69/69. Le altre voci di §7 di tmp/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 da committee-members che lascia il label grezzo — rimosso il title-case sul campo committee. (2) --committee-uri Camera senza --committee-name lasciva committee vuoto (asimmetrico rispetto al Senato, che risolve sempre il label); aggiunto fetchCameraOrganoLabel per 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.

2026-07-01

  • committee-sessions esteso: "segui una commissione" (Camera+Senato) — il tool era limitato all'iter di un DDL (--ddl-uri obbligatorio, solo Senato). Ora --ddl-uri è opzionale e si possono elencare tutte le sedute di una commissione via --committee-uri o --committee-name (ricerca fuzzy), filtrabili per --chamber (camera/senato/both), --legislature, --date-from/--date-to. Aggiunto supporto Camera (ocd:seduta + ocd:rif_organo + dc:date stringa AAAAMMGG + dc:relation→bollettino), oltre al Senato (osr:SedutaCommissione + osr:dataSeduta xsd:date + osr:tipoSeduta + conteggio interventi). Nuova colonna bulletin_url (Camera) e chamber/ddl_uri per uniformare. Caso d'uso guida: la Commissione parlamentare di inchiesta sul femminicidio (bicamerale) ha composizione esposta da entrambi i rami (24 senatori membri in commissione/4-223), ma sedute/interventi solo in OCD come o19_3941 (181 URI seduta / 157 date distinte fino a giu 2026) — nel Senato LOD 0 sedute per la XIX; ora committee-sessions list --committee-name femminicidio --chamber camera la rende visibile. (Correzione in corso di verifica: i "292" iniziali erano triple rif_bollettino, non sedute distinte.) Decisioni utente: scope Camera in fase 1 (sì); input sia --committee-uri che --committee-name (entrambi); rami separati nell'output (no merge). Bug trovato e fixato in corso: RDFS_LABEL typo (namespace senza label) → 0 risultati; e una edit maldestra aveva invertito l'ordine flatten/query. Wiki LOD: nuove pagine senato/sedute-commissione.md e camera/sedute-commissione.md (proprietà reali verificate + trappole: doppia osr:titoloBreve Senato → 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 su search find --name Meloni — colonne first_name/last_name/gender/legislature_uri non uniformi tra righe. Causa: pass-through dei dati SPARQL grezzi, e le due camere modellano gli stessi concetti in formati diversi (Camera nomi MAIUSCOLI + gender esteso + legislature_uri come vero URI; Senato Capitalizzato + gender sigla M/F + legislatura come intero nudo). Nuovo helper condiviso src/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 Senato legislature_uri ora è un URI sintetico http://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 su normalize.ts, 68/68.
  • v0.9.0 — bill_number copre gli Ordini del Giorno Camera + fix aic: 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 avevano bill_uri, quasi tutti ODG). Scoperto che gli ODG citano l'atto senza la parola "DDL", con la numerazione ufficiale 9/<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 2920 ora 62/62 con bill_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. Tool aic: --keyword ora matcha a confini di parola (era CONTAINS a sottostringa: "CETA" includeva falsi positivi come "Acetamiprid"/"Cetara"; ora REGEX(...,"\\bKEYWORD\\b","i") su label/title/description, verificato 31→10 righe reali su "CETA" leg. 19); nuovo filtro --type su dc:type con fallback sul label (per la leg. 19 dc:type non distingue "a risposta immediata"/question time da "a risposta orale" — la differenza è solo testuale nel label); fix filtro data: dc:date è composto YYYYMMDD-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 via SUBSTR, e l'output mostra entrambe le date quando modificato. Considerato ma scartato un endpoint HTML non documentato dietro documenti.camera.it/apps/votazioni/votazionitutte/ (reverse-engineered con agent-browser, stesso testo del dc:description ma 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-votes e votes espongono ora la colonna bill_number (numero provvedimento estratto dal testo: label Senato, dc:description Camera; es. 562-B, 2920-A) e popolano ddl_uri/bill_uri anche quando il legame diretto manca. Senato: le fiducie (prive di osr:oggetto) si risolvono dal numero via osr:fase="S.<num>" (univoco intra-legislatura; verificato 1933→ddl/60201). Camera: i voti senza rif_attoCamera si risolvono sul numero base (2920-A2920) verificando l'esistenza dell'atto via dc:identifier (una query per legislatura, mai URI fabbricati). Estrazione in nuovo core src/core/bill-number.ts (extractBillNumber/billBaseNumber, regex tollerante a DDL n./DDL.n./Disegno di legge n. e suffissi -B/-bis). Fallback in una sola query aggiuntiva (OR-chain, no VALUES batch 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: searchSenato filtrava CONTAINS(?fn, q) || CONTAINS(?ln, q) confrontando la query separatamente con firstName e lastName → un nome completo non matcha nessuno dei due campi. La Camera non aveva il problema (match su rdfs:label intero). Fix: FILTER(CONTAINS(LCASE(CONCAT(?fn," ",?ln)), q) || CONTAINS(LCASE(CONCAT(?ln," ",?fn)), q)) (concat nei due ordini; CONCAT in FILTER funziona sul Virtuoso Senato, BIND no). Verificato: senatore/1275 per "Ignazio La Russa", senatore/29480 per "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 in docs/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) e senato/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:description votazioni) chiusa not planned. #20 (fix sopra). #21 (link voto→DDL parziale: fiducie senza osr:oggetto) risolta in v0.8.0 (vedi voce in cima).

2026-06-29

  • v0.7.1 — rifiniture discoverability: bill-rapporteurs ora registrato anche in src/tools/index.ts (tools/toolsByName), allineato a server.ts (era discoverabile solo via CLI/MCP, non da toolsByName); aggiunto people resolve alla lista capability di which/guide (+ termini iter Camera su bill-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 (...)); VALUES dà 400 sul Senato), dedup per URI, output uri/first_name/last_name/label/chamber/html_url; URI non risolti restano in output con label vuota. CLI people resolve --uris a,b,c; registrato in MCP (38 tool) e CLI. Inoltre group-members e senator-group-members ora includono deputy_name/senator_name direttamente (prima solo URI nudo → niente più lookup a valle). 51/51 test.
  • v0.6.0 — URL human-readable + iter Camera. bill-progress ora copre la Camera (timeline iter via ocd:rif_statoIter); colonna html_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 path leg19 hardcoded. Nuovo core src/core/html-url.ts (personHtmlUrl/actHtmlUrl/ddlRssUrl). 50/50 test. Issue aperte per i follow-up.
  • Audit html_url leggi + rss_url DDL: centralizzati helper actHtmlUrl (atto Camera + DDL Senato) e ddlRssUrl (feed RSS per-DDL, richiede legislatura) in src/core/html-url.ts. Colmati i gap: member-bills (html_url atto), bill-signatories/bill-rapporteurs (html_url persona, righe sono firmatari/relatori), amendments e senato-votes (ddl_html_url + rss_url, gestione multi-valore a | b), bill-progress Senato (rss_url per riga, schema allineato col ramo Camera). Refactor di bills/bill su actHtmlUrl (fix bug path leg19 hardcoded → ora leg{N}). aic lasciato 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_url per le persone (PRD docs/prd-human-readable-urls.md): i tool che restituiscono parlamentari espongono ora l'URL della scheda istituzionale accanto all'URI SPARQL. Helper puro src/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 in deputies, 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. Differiti gov-members/person-career (URI persona.rdf, non risolve) e speeches (schema misto). Unit test pattern in html-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-progress esteso 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 il rdf:type duplicato). 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 a YYYY-MM-DD, phase=C.<id>). CLI: bill-progress list --uri …; MCP auto-registrato via inputSchema.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 in tools.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.2Perf speeches (Camera, path legislatura): da ~6s a ~1.8s (3-4×). Gli interventi Camera non hanno ocd:rif_leg (la legislatura è solo nel pattern URI); il vecchio FILTER(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 filter FILTER(?s >= <…in19_> && ?s < <…in19_z>) che Virtuoso esegue come scansione indicizzata all'indietro fermandosi al LIMIT; (2) ordinamento per DESC(?s) (ID intervento = ordine di creazione, proxy della cronologia reale; ods:modified era un timestamp di modifica del record); (3) subquery-first con GROUP BY ?s nell'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. Test speeches da 7570ms a 1440ms; suite 40/40.
  • v0.5.1 — allineamento campi aic / sindacato-ispettivo: su sindacato-ispettivo rinominati tipotype, datadate, numeroidentifier, senatore_urisponsor_uri, legislaturalegislature; aggiunto filtro keyword (cerca in label/tipo/numero) e countOnly. Su aic: legislature_urilegislature (numero estratto dall'URI), date normalizzata da YYYYMMDD a YYYY-MM-DD. Fix TS (comparazione boolean/string su countOnly). countOnly Senato implementato con COUNT(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 di groups (Camera). Query SPARQL con COUNT(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.

2026-06-28

  • 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_uri vuoto, legame solo nella label) in README + 2 skill; fix src/cli.ts (versione CLI letta da package.json invece dell'hardcoded 0.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_uri vuoto (il legame col DDL è solo nel testo della label), quindi senato-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-vote inesistente su senato-votes).

  • v0.4.0: nuove capacità da verifica giornalistica. Relatori Senato in bill-rapporteurs (ora Camera+Senato), gruppo di voto in senato-vote-detail (voto per gruppo al Senato), timeline gruppi in person-career, group-members ordinato, sparql usabile senza il sotto-comando query, 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 usava FILTER(?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 hanno dc:date multiplo), 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. Test votes ora verde in 0.5s; suite 40/40.

  • Secondo round dalla stessa verifica giornalistica (gap media/bassa) + esempio d'inchiesta. (1) group-members: aggiunto ORDER 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 righe kind=gruppo (appartenenza ai gruppi con date, label pulita via cleanGroupLabel), output riordinato per categoria+data. (3) sparql: shim argv che inserisce il sotto-comando query quando manca → sparql --endpoint senato --query … funziona (prima mostrava l'help/"Unknown command"); sparql query … resta valido, sparql --help resta help. (4) Help sotto-comandi: NON era un bugbills list --help ecc. mostrano i flag; il falso positivo del report nasceva da zsh (niente word-splitting su $c). Allineamento CLI↔MCP+skill: bill-rapporteurs mancava 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 su votes, 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 → query osr:relatore, blank node con rdfs: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 in senato-vote-detail: nuova colonna group_label = gruppo del senatore alla data del voto. Query gruppi separata (logica senator-group-members con asOf = 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 in tmp/analisi-notizie-2025-verifica-cli.md.

  • Fix label gruppi Camera: rdfs:label/dc:title arrivano troncati alla fonte come NOME (ACRONIMO) (DD.MM.YYYY (parentesi sulla data di inizio mai chiusa, sistematico su tutti i gruppi). Nuovo helper src/core/group-label.ts (cleanGroupLabel) che rimuove la coda (data → resta NOME (ACRONIMO). Applicato a group-members (group_label) e groups (label + title); acronimo estratto dalla label grezza prima della pulizia, dcterms:alternative resta 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 list elenca (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 groups acronimo — ora dal campo dedicato dcterms:alternative (prima puntava a ocd:acronimo inesistente, ripiegando su parsing regex della label). README "Note sui dati" corretta. Spostato l'esempio member-bills da "Riferimento" a "Esempi pratici".

  • v0.3.1: repo reso pubblico e pubblicato su npm come @aborruso/italianparliament-mcp (CLI + MCP installabili con npm i -g). Aggiunta sezione "Installazione" al README (CLI npm / MCP remoto-locale / da sorgente), prepublishOnly in 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); comando which <capacità> (mappa capacità→comando, es. which "testo ddl" → bill-text); errori enum con valori validi via wrapper runTool che valida l'input Zod prima di execute (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 hub persona.rdf/p{id}, che collega tutti i mandati da deputato (per legislatura, join rif_mandatoCamera) e gli incarichi di governo (rif_membroGoverno), più owl:sameAs Wikidata. 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-only su bills/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 tool group-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 --keyword era 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) amendments non aveva filtro per DDL: aggiunto --ddl-uri via osr:oggetto → osr:relativoA (niente BIND, non supportato da Virtuoso) + colonna ddl_uri. Verificato: ddl/56260 → 119 emendamenti.

  • Nuovi tool senato-votes + senato-vote-detail [SENATO]: chiudono il gap n.1 della ripartenza (votazioni Senato). senato-votes lista le votazioni d'Assemblea (osr:Votazione) con esito, contatori, tipo, data seduta (via osr:seduta/osr:dataSeduta, filtro ^^xsd:date) e DDL collegato (osr:oggetto → osr:relativoA); dedup TS per voti su DDL unificati. senato-vote-detail dà il voto del singolo senatore via osr:favorevole/contrario/astenuto/presenteNonVotante/inCongedoMissione (una query per categoria: Virtuoso non supporta VALUES/BIND); nome via foaf. Gruppo non incluso (membership temporale) → incrociare con senator-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 via sparql). Bug emersi: aic --keyword accettato ma ignorato; amendments senza 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, con format (html/pdf/urn) e auth (none/browser) pensati per un orchestratore. Il testo integrale NON è nei dati SPARQL: il Senato espone solo l'URN osr:testoPresentato. Registrato in MCP+CLI (bill-text links). Aggiunto anche member-bills al 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 via agent-browser, estrae il cookie aws-waf-token + UA, scarica il PDF (singolo testo via scraping del tab "Testi ed emendamenti", oppure --fascicolo per il dossier completo) e converte con lit (liteparse). Opzioni --which, --all, --fascicolo, --out. Pulizia soft-hyphen (&shy;) 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 in dati.senato.it/ddl/{N} (non idDdl). Camera: nessun WAF, pagine fetchabili.

  • Skill italian-parliament-mcp (v1.1) e italian-parliament-cli aggiornate con bill-text. Test unitario per parseTextList. Totale tool MCP: 31.

2026-04-15

  • member-bills [CAMERA+SENATO]: nuovo tool unificato per DDL come primo firmatario. Camera: filtra ocd:primo_firmatario + tipo atto. Senato: pattern INIZ-DDL-{ddl_id}-{id} + osr:primoFirmatario="1" (REGEX [^0-9]{id}$ perché Virtuoso non supporta BIND/STRAFTER nidificato).
  • bill [CAMERA]: aggiunto campo cosignatories con tutti i cofirmatari (dc:contributor) separati da |.
  • deputy [CAMERA]: aggiunti committees, election_list, election_date, election_validated, birth_date, birth_place. Nascita via persona.rdf/p{id}bio:Birth.
  • senator [SENATO]: fix birth_city (via bio:birthbio:placerdfs:label); fix CLI --legislature non passato all'execute (mandato sempre leg 19); fix filtro osr:legislatura con FILTER(STR(...)) (era xsd:integer, non stringa).

2026-04-14

  • 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) e senator (Senato): election_region, election_district (solo Camera), election_type, mandate_start, mandate_end. Camera via ocd:rif_mandatoCamera → ocd:rif_elezione; Senato via osr:mandato filtrato per legislatura.
  • Aggiunto campo description al tool votes (Camera): dc:description contiene il testo reale della votazione (es. "Votazione Fiducia A.C. 2807-A"), mentre label e title sono spesso vuoti. Utile soprattutto con --confidence-vote true.
  • Aggiunto parametro --bill-code al tool votes (Camera): filtra votazioni collegate a un DDL per numero atto (es. --bill-code 2807). Restituisce fiducia, voto finale e ordini del giorno. Combina con --legislature per evitare falsi positivi tra legislature.

2026-04-13

  • 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: campo start_date conteneva inizio+fine concatenati (20221018-20240916), end_date sempre vuoto. Ora split su - con date separate.
  • Aggiunto filtro region al tool deputies: filtra per circoscrizione/regione con CONTAINS case-insensitive su election_label. Testato: sicilia, lombardia. Circoscrizioni estero: AFRICA, AMERICA, EUROPA.
  • Aggiunto campo description al tool aic (Camera): contiene il testo/oggetto dell'interrogazione, interpellanza o mozione. Il Senato (sindacato-ispettivo) non espone l'oggetto nell'endpoint SPARQL.
  • Tool rank esteso al Senato: 2 nuove dimensioni sindacato-ispettivo e ddl-senato. Aggiunto campo chamber nell'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:ufficioParlamentare con carica (PRESIDENTE, VICEPRESIDENTE, SEGRETARIO, CAPOGRUPPO, COMPONENTE). Senato: osr:Afferenza + osr:afferisce con carica (Presidente, Membro, ecc.). Parametro chamber: camera|senato|both, filtrabile per commissione, parlamentare, legislatura, activeOnly. Totale tool: 25.
  • Fix sindacato-ispettivo: campo presentatore e senatore_uri ora sempre popolati (anche senza filtro senatore). Riscrittura query con GROUP 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):
    • keyword su bills, bill-progress, votes: ricerca full-text nei titoli DDL e votazioni. Cerca in title+label (OR).
    • confidenceVote su votes: filtra votazioni di fiducia. 10 fiducie leg19 testate.
    • dateFrom/dateTo su sessions: filtra sedute per data.
    • deputyUri su group-members: storia cambi gruppo di un singolo deputato. Testato con Enrico Costa (Azione→FI).
    • order: asc|desc su rank: ordinamento inverso per trovare i meno attivi. asc mostra ministri con 4 speeches.
    • initiative su bills: filtra per iniziativa (Popolare/Governo/Parlamentare/Regioni). Tutti e 4 testati.

2026-04-12 (aggiornamento 8)

  • Nuovo helper src/core/decode-html.ts: rimuove ^^xsd:type, decodifica entità HTML (&quot;, &rsquo;, &agrave;, ecc.), rimuove tag HTML (<em> ecc.).
  • Applicato a bills su campi label e title. Titoli ora leggibili.
  • Deploy worker aggiornato.

2026-04-12 (aggiornamento 7)

  • Fix vote-detail: aggiunto campo deputy_name (nome leggibile) alla query. Usato rdfs:label con URI completo (Camera rifiuta prefisso rdfs:). Suffisso legislatura rimosso con stripLegLabel.
  • Deploy worker aggiornato.

2026-04-12 (aggiornamento 6)

  • Fix dedup bills: blank node multipli su primo_firmatario governativi → aggiunto FILTER(!isBlank(?sponsor_uri)). DDL governativi ora hanno sponsor_uri vuoto (corretto).
  • Fix dedup sindacato-ispettivo: join su osr:iniziativa produceva N righe per N firmatari → rimosso join quando nessun filtro senatore. senatore_uri/presentatore vuoti nella lista generale, presenti solo quando si filtra per senatore.
  • Deploy worker aggiornato.

2026-04-12 (aggiornamento 5)

  • Fix bug rank: senatori comparivano nella classifica Camera perché legFilter non vincolava ?person a ocd:deputato. Aggiunto il tipo esplicito in entrambi i rami (con e senza legislatura).
  • Deploy worker aggiornato.

2026-04-12 (aggiornamento 4)

  • 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:date tipizzato → FILTER con "data"^^xsd:date (non plain string).
  • CLI: aggiunto --date-from/--date-to nei 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.

2026-04-12 (aggiornamento 3)

  • Nuovo tool sindacato-ispettivo [SENATO]: equivalente Senato degli AIC Camera (interrogazioni, interpellanze, mozioni, risoluzioni).
  • Filtrabile per legislatura, senatore URI, tipo atto.
  • Fix: BIND non supportato su Virtuoso Senato → sostituito con FILTER(?senatore_uri = <URI>).
  • Fix: legislatura come triple pattern diretto (?s osr:legislatura 19) non OPTIONAL+FILTER.

2026-04-12 (aggiornamento 2)

  • 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>.

2026-04-12 (aggiornamento)

  • 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 node osr:Denominazione con storico nomi filtrato per data.

2026-04-12

  • Fase 6 batch 3: +4 tool Camera (speeches, aic, vote-detail, group-members). Totale tool: 17/24.
  • Fix vote-detail: la query R usava ocd:voto come proprietà ma non esiste — il valore del voto è in dc: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à corretta ocd:ruolo invece di dc:type (VICEPRESIDENTE, SEGRETARIO, ecc. ora popolati).
    • sessions: filtro STRSTARTS per escludere bollettini (BF_*), ora solo sedute formali con numero progressivo.
    • speeches: riscritto completamente. rif_leg/dc:date/rif_seduta non esistono; la legislatura è nell'URI (in19_), filtro con STRSTARTS. 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 usa foaf:firstName/foaf:surname/foaf:gender.
    • governments: riscritta query, ora interroga direttamente ocd:governo con dc:date. Ordinamento cronologico DESC (Meloni→Draghi→Conte II→...). Aggiunto campo start_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.
  • documents Camera (ocd:documento): 0 istanze nell'endpoint. Nessun tipo documento alternativo trovato. Senato ha osr:Documento (48K), implementato.
  • documents Senato: 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 19 mostra 12 commissioni attive con conteggio sedute (Affari Costituzionali: 681 sedute). Senza filtro mostra catalogo storico (279).

2026-04-11

  • Commit root: 26 file (Fase 0-4).

  • Fase 6 batch 1: +4 tool Camera (legislatures, groups, sessions, governments). Query portate da italyParlR (clone in tmp/). 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, bill property/value; roles Camera con filtri deputy/group/legislature). Totale tool: 13/24.

  • Refactor obbligato: makeHandler in src/index.ts passato da <I> generico a any perché a 13 tool la generic instantiation combinata Zod × MCP SDK × helper mandava tsc in OOM (FATAL heap limit) anche con --max-old-space-size=4096. Con handler non generico il type check torna pulito.

  • Nota su deputy: rimossa la z.refine() sullo schema (produceva ZodEffects senza .shape, incompatibile con registerTool MCP). Validazione ora dentro execute().

  • Repo creato. Fase 0 completata.

  • Struttura: src/core/, src/tools/, entrypoint previsti src/cli.ts, src/index.ts, src/worker.ts.

  • Stack: TypeScript + citty + axios + zod + @modelcontextprotocol/sdk.

  • Scripts package.json clonati da ckan-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/ con endpoints.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.ts barrel.

  • Endpoint: Camera https://dati.camera.it/sparql, Senato http://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 columns per 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 vecchio application/sparql-results+json restituisce 406 su Senato).
    • User-Agent custom obbligatorio su Senato (default axios → 403 CloudFront).
  • 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.ts con citty. Pattern italianparliament <resource> <verb>: deputies list, senators list, bills list, votes list, search find. --help per ogni subcommand include sezione Examples con invocazioni copiabili. --format csv|jsonl su 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 gestisce SparqlError con 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 via registerTool(name, {description, inputSchema: tool.inputSchema.shape}, handler). Helper makeHandler generic per catturare SparqlError/Error e restituire isError: true. Output in formato JSONL via toJsonl.

  • 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.ts con MCP HTTP server clonando pattern da ckan-mcp-server).