Skip to content

Commit ffa6e54

Browse files
aborrusoclaude
andcommitted
fix(bill-progress): letterale SPARQL robusto + ?st fuori da DISTINCT
Review PR #57: - sparqlStringLiteral non usa più JSON.stringify (emette \uXXXX per i controlli, rifiutato da alcuni parser SPARQL): escapa solo \, ", newline, CR come da grammatica STRING_LITERAL2. Verificato: letterale con apice → HTTP 200. - cameraIterTimeline: ?st non è più proiettato in SELECT DISTINCT (cambiava la chiave di dedup → possibili righe visivamente duplicate); resta solo come tie-breaker in ORDER BY. Virtuoso accetta ORDER BY su var non proiettata. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent a35693a commit ffa6e54

1 file changed

Lines changed: 18 additions & 2 deletions

File tree

src/tools/bill-progress.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,19 @@ import { ddlRssUrl } from "../core/html-url.js";
77
import { currentLegislature } from "../core/current-legislature.js";
88
import type { Tool } from "./types.js";
99

10-
const sparqlStringLiteral = (value: string): string => JSON.stringify(value);
10+
// Costruisce un letterale-stringa SPARQL valido escapando solo i caratteri che
11+
// la grammatica STRING_LITERAL2 vieta (\, ", newline, CR). Non usare
12+
// JSON.stringify: emette \uXXXX per i caratteri di controllo, sequenza che
13+
// alcuni parser SPARQL rifiutano nel corpo del letterale (o cercano un valore
14+
// diverso), rompendo il filtro keyword invece di fare il match atteso.
15+
const SPARQL_ESC: Record<string, string> = {
16+
"\\": "\\\\",
17+
'"': '\\"',
18+
"\n": "\\n",
19+
"\r": "\\r",
20+
};
21+
const sparqlStringLiteral = (value: string): string =>
22+
`"${value.replace(/[\\"\n\r]/g, (c) => SPARQL_ESC[c] ?? c)}"`;
1123

1224
const inputSchema = z.object({
1325
ddlUri: z
@@ -252,8 +264,12 @@ async function cameraIterTimeline(
252264
filters.push(`FILTER(STR(?date) <= "${opts.dateTo.replace(/-/g, "")}")`);
253265
}
254266

267+
// ?st NON è proiettato: entra in SELECT DISTINCT cambierebbe la chiave di
268+
// dedup (ogni risorsa-stato è unica) e reintrodurrebbe righe visivamente
269+
// duplicate quando due ?st hanno stessi titolo/date/stato. Serve solo come
270+
// tie-breaker deterministico in ORDER BY per stabilizzare la paginazione.
255271
const query = `${OCD_PREFIXES}
256-
SELECT DISTINCT ?st ?titolo ?date ?stato WHERE {
272+
SELECT DISTINCT ?titolo ?date ?stato WHERE {
257273
<${uri}> ocd:rif_statoIter ?st .
258274
OPTIONAL { <${uri}> dc:title ?titolo }
259275
?st dc:date ?date .

0 commit comments

Comments
 (0)