From d42cd27a66e2feab558c31a4093924cfc722fb43 Mon Sep 17 00:00:00 2001 From: aborruso Date: Sun, 26 Jul 2026 09:55:12 +0200 Subject: [PATCH 1/2] =?UTF-8?q?fix(which):=20copri=20la=20Giunta=20per=20l?= =?UTF-8?q?e=20autorizzazioni,=20togli=20il=20mis-route=20su=20immunit?= =?UTF-8?q?=C3=A0=20(#78)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Il term "parlamentare" nudo su `search find` catturava query di tutt'altro tema — "immunità parlamentare", "gruppo parlamentare" — perché lo scorer assegna 60 quando la query contiene il term. Diventa "cerca parlamentare": chi cerca "parlamentare" da solo trova ancora il comando, chi cerca altro no. Aggiunti a `committees list` e `committee-members list` i termini su giunta, autorizzazione a procedere, immunità e insindacabilità: il tema era scoperto pur essendo pienamente servito da quei due comandi. Closes #78 Co-Authored-By: Claude Opus 5 (1M context) --- src/core/capabilities.test.ts | 32 ++++++++++++++++++++++++++++++++ src/core/capabilities.ts | 9 ++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/core/capabilities.test.ts b/src/core/capabilities.test.ts index 5fa2b26..1f3c129 100644 --- a/src/core/capabilities.test.ts +++ b/src/core/capabilities.test.ts @@ -48,6 +48,38 @@ describe("capabilityScore", () => { expect(capabilityScore(cap, " ")).toBe(0); }); + // Il tema Giunta per le autorizzazioni era scoperto, e "immunità + // parlamentare" veniva instradata su `search find` per via del term + // "parlamentare" nudo: un match sbagliato è peggio di nessun match (#78). + const best = (q: string) => + CAPABILITIES.map((c) => ({ cmd: c.cmd, score: capabilityScore(c, q) })) + .filter((c) => c.score > 0) + .sort((a, b) => b.score - a.score); + + it("le formulazioni sulla Giunta portano ai comandi su commissioni e giunte", () => { + for (const q of ["giunta per le autorizzazioni", "autorizzazione a procedere", "immunità parlamentare"]) { + const cmds = best(q).map((c) => c.cmd); + expect(cmds, `query "${q}"`).toContain("committee-members list"); + expect(cmds, `query "${q}"`).toContain("committees list"); + } + }); + + it("'immunità parlamentare' non instrada più su search find", () => { + expect(best("immunità parlamentare").map((c) => c.cmd)).not.toContain("search find"); + }); + + it("'gruppo parlamentare' resta sui gruppi, non sulla ricerca per nome", () => { + const cmds = best("gruppo parlamentare").map((c) => c.cmd); + expect(cmds).toContain("groups list"); + expect(cmds).not.toContain("search find"); + }); + + it("non-regressione: cercare una persona porta ancora a search find", () => { + for (const q of ["cerca", "parlamentare", "nome", "trova persona"]) { + expect(best(q).map((c) => c.cmd), `query "${q}"`).toContain("search find"); + } + }); + it("match case-insensitive sui terms", () => { const cap = CAPABILITIES.find((c) => c.cmd === "person-career show")!; expect(capabilityScore(cap, "CARRIERA")).toBe(100); diff --git a/src/core/capabilities.ts b/src/core/capabilities.ts index 9db86bd..e44974a 100644 --- a/src/core/capabilities.ts +++ b/src/core/capabilities.ts @@ -6,7 +6,10 @@ export type Capability = { cmd: string; terms: string[]; desc: string; example: string }; export const CAPABILITIES: Capability[] = [ - { cmd: "search find", terms: ["cerca", "nome", "parlamentare", "trova persona", "search"], desc: "Cerca un parlamentare per nome (Camera+Senato)", example: 'italianparliament search find --name "rossi"' }, + // "cerca parlamentare" e non "parlamentare" nudo: la parola sola compare in + // query di tutt'altro tema ("immunità parlamentare", "gruppo parlamentare") + // e le tirava qui con il match `q.includes(term)` (issue #78). + { cmd: "search find", terms: ["cerca", "nome", "cerca parlamentare", "trova persona", "search"], desc: "Cerca un parlamentare per nome (Camera+Senato)", example: 'italianparliament search find --name "rossi"' }, { cmd: "person-career show", terms: ["carriera", "governo", "ministro", "doppio incarico", "legislature", "wikidata"], desc: "Carriera unificata di una persona (mandati + governo)", example: "italianparliament person-career show --uri http://dati.camera.it/ocd/persona.rdf/p302103" }, { cmd: "deputy show", terms: ["scheda", "deputato", "anagrafica", "nascita"], desc: "Scheda di un deputato", example: "italianparliament deputy show --uri http://dati.camera.it/ocd/deputato.rdf/d306921_17" }, { cmd: "senator show", terms: ["scheda", "senatore", "anagrafica", "nascita"], desc: "Scheda di un senatore", example: "italianparliament senator show --uri http://dati.senato.it/senatore/29110" }, @@ -35,8 +38,8 @@ export const CAPABILITIES: Capability[] = [ { cmd: "rank list", terms: ["classifica", "ranking", "più attivi", "top"], desc: "Classifiche per parlamentare (aic, bills, speeches, ...)", example: "italianparliament rank list --rank-by speeches --legislature 19 --limit 10" }, { cmd: "group-rank list", terms: ["classifica gruppi", "per gruppo", "gruppi più attivi"], desc: "Classifiche per gruppo con media per membro", example: "italianparliament group-rank list --rank-by aic --legislature 19" }, { cmd: "gov-members list", terms: ["ministro", "governo", "sottosegretario", "rimpasto"], desc: "Membri del governo", example: "italianparliament gov-members list --legislature 19" }, - { cmd: "committees list", terms: ["commissioni", "elenco commissioni"], desc: "Commissioni Camera+Senato", example: "italianparliament committees list --chamber both --legislature 19" }, - { cmd: "committee-members list", terms: ["membri commissione", "composizione commissione"], desc: "Membri di una commissione con ruoli", example: "italianparliament committee-members list --committee-uri http://dati.senato.it/commissione/0-2 --chamber senato" }, + { cmd: "committees list", terms: ["commissioni", "elenco commissioni", "giunta", "giunta per le autorizzazioni", "autorizzazione a procedere", "immunità parlamentare", "insindacabilità"], desc: "Commissioni e giunte Camera+Senato", example: "italianparliament committees list --chamber both --legislature 19" }, + { cmd: "committee-members list", terms: ["membri commissione", "composizione commissione", "membri giunta", "giunta per le autorizzazioni", "autorizzazione a procedere", "immunità parlamentare", "insindacabilità"], desc: "Membri di una commissione o giunta con ruoli", example: "italianparliament committee-members list --committee-uri http://dati.senato.it/commissione/0-2 --chamber senato" }, { cmd: "speeches list", terms: ["intervento", "discorso", "aula"], desc: "Interventi in aula (Camera+Senato)", example: "italianparliament speeches list --deputy-uri http://dati.camera.it/ocd/deputato.rdf/d306921_17 --count-only" }, { cmd: "sparql query", terms: ["sparql", "query libera", "dato non coperto"], desc: "Query SPARQL libera (ultima risorsa)", example: 'italianparliament sparql query --endpoint senato --query "PREFIX osr: SELECT DISTINCT ?type WHERE { ?s a ?type } LIMIT 20"' }, ]; From 2eda555273731ba54d263a19264b1be7706da0f9 Mon Sep 17 00:00:00 2001 From: aborruso Date: Sun, 26 Jul 2026 10:00:43 +0200 Subject: [PATCH 2/2] fix(which): "giunta parlamentare" invece di "giunta" nuda MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Da review PR #81: il term nudo ricreava lo stesso difetto che questa PR rimuove per "parlamentare" — "giunta regionale" o "delibera di giunta" avrebbero pescato un comando che copre solo il Parlamento. Chi cerca "giunta" da solo trova ancora committees; le giunte locali no. Co-Authored-By: Claude Opus 5 (1M context) --- src/core/capabilities.test.ts | 9 +++++++++ src/core/capabilities.ts | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/core/capabilities.test.ts b/src/core/capabilities.test.ts index 1f3c129..fb79109 100644 --- a/src/core/capabilities.test.ts +++ b/src/core/capabilities.test.ts @@ -68,6 +68,15 @@ describe("capabilityScore", () => { expect(best("immunità parlamentare").map((c) => c.cmd)).not.toContain("search find"); }); + it("'giunta' porta alle giunte parlamentari, ma non le giunte locali", () => { + // Il catalogo copre solo il Parlamento: consigliare `committees` a chi + // cerca una giunta regionale o comunale sarebbe lo stesso errore. + expect(best("giunta").map((c) => c.cmd)).toContain("committees list"); + for (const q of ["giunta regionale", "delibera di giunta", "giunta comunale"]) { + expect(best(q).map((c) => c.cmd), `query "${q}"`).not.toContain("committees list"); + } + }); + it("'gruppo parlamentare' resta sui gruppi, non sulla ricerca per nome", () => { const cmds = best("gruppo parlamentare").map((c) => c.cmd); expect(cmds).toContain("groups list"); diff --git a/src/core/capabilities.ts b/src/core/capabilities.ts index e44974a..d6660eb 100644 --- a/src/core/capabilities.ts +++ b/src/core/capabilities.ts @@ -38,7 +38,10 @@ export const CAPABILITIES: Capability[] = [ { cmd: "rank list", terms: ["classifica", "ranking", "più attivi", "top"], desc: "Classifiche per parlamentare (aic, bills, speeches, ...)", example: "italianparliament rank list --rank-by speeches --legislature 19 --limit 10" }, { cmd: "group-rank list", terms: ["classifica gruppi", "per gruppo", "gruppi più attivi"], desc: "Classifiche per gruppo con media per membro", example: "italianparliament group-rank list --rank-by aic --legislature 19" }, { cmd: "gov-members list", terms: ["ministro", "governo", "sottosegretario", "rimpasto"], desc: "Membri del governo", example: "italianparliament gov-members list --legislature 19" }, - { cmd: "committees list", terms: ["commissioni", "elenco commissioni", "giunta", "giunta per le autorizzazioni", "autorizzazione a procedere", "immunità parlamentare", "insindacabilità"], desc: "Commissioni e giunte Camera+Senato", example: "italianparliament committees list --chamber both --legislature 19" }, + // "giunta parlamentare" e non "giunta" nuda, per la stessa ragione del term + // "parlamentare" su `search find`: la parola sola tirerebbe qui anche + // "giunta regionale" o "delibera di giunta", che questo tool non copre. + { cmd: "committees list", terms: ["commissioni", "elenco commissioni", "giunta parlamentare", "giunta per le autorizzazioni", "autorizzazione a procedere", "immunità parlamentare", "insindacabilità"], desc: "Commissioni e giunte Camera+Senato", example: "italianparliament committees list --chamber both --legislature 19" }, { cmd: "committee-members list", terms: ["membri commissione", "composizione commissione", "membri giunta", "giunta per le autorizzazioni", "autorizzazione a procedere", "immunità parlamentare", "insindacabilità"], desc: "Membri di una commissione o giunta con ruoli", example: "italianparliament committee-members list --committee-uri http://dati.senato.it/commissione/0-2 --chamber senato" }, { cmd: "speeches list", terms: ["intervento", "discorso", "aula"], desc: "Interventi in aula (Camera+Senato)", example: "italianparliament speeches list --deputy-uri http://dati.camera.it/ocd/deputato.rdf/d306921_17 --count-only" }, { cmd: "sparql query", terms: ["sparql", "query libera", "dato non coperto"], desc: "Query SPARQL libera (ultima risorsa)", example: 'italianparliament sparql query --endpoint senato --query "PREFIX osr: SELECT DISTINCT ?type WHERE { ?s a ?type } LIMIT 20"' },