Skip to content

feat(amendments): fallback bulk AKN GitHub + proponenti dal testo AKN#47

Merged
aborruso merged 10 commits into
mainfrom
feat/amendments-akn-fallback
Jul 10, 2026
Merged

feat(amendments): fallback bulk AKN GitHub + proponenti dal testo AKN#47
aborruso merged 10 commits into
mainfrom
feat/amendments-akn-fallback

Conversation

@aborruso

Copy link
Copy Markdown
Member

Cosa fa

Implementa la priorità P1 dell'analisi fonti non-LOD (#45): il tool amendments usa il bulk AKN GitHub del Senato (SenatoDellaRepubblica/AkomaNtosoBulkData, CC BY 4.0, senza WAF → funziona in CLI e Worker).

  1. akn_xml_url su ogni riga LOD — conversione osr:URLTestoXml → URL raw (pura sostituzione di stringa, osr:flagCommissione decide emend/ vs emendc/): testo machine-readable scaricabile con un curl.
  2. Fallback automatico — con ddlUri e LOD vuoto, listing di emend/+emendc/ via endpoint JSON web-UI GitHub, righe source=akn. Rete di sicurezza contro la freschezza intermittente del LOD.
  3. withProponents / --with-proponents — primo firmatario e cofirmatari (con URI persona) dal testo AKN: il proponente NON è nel LOD (amendments (Senato): aggiungere il proponente via parsing AKN (simmetria con camera-amendments) #30). Fetch puntuali, concorrenza 4, mai bulk.

Valore giornalistico

Chi firma gli emendamenti di un provvedimento — finora dietro WAF, recuperabile solo a mano col browser — esce ora da un comando: verificato il caso wiki (em. 1.30 ddl/56260 → Bartolomeo Amidei + 5) e il Piano Casa (proponenti da entrambe le sedi).

Scoperta in corsa

Il dataset osr:Emendamento del LOD si è riallineato tra il 7 e il 10 luglio (Piano Casa 0→799, match esatto col bulk 400+399): il claim "fermo ad ago 2024" è superato e rimosso da description/emptyHint. Documentata nel wiki anche la trappola nuova: dataPresentazione dei DDL recenti ora tipizzata xsd:string (la query cutoff tipizzata sottoconta).

Note tecniche

  • src/core/akn.ts Worker-compatible (solo fetch nativo); listing troncato a 1000 gestito via totalCount con errore esplicito su finestra irraggiungibile (no cap silenziosi); forma payload validata con errore esplicito se GitHub cambia l'endpoint (non documentato).
  • Parser AKN a regex mirate (niente parser XML nel bundle Worker); gestite le due varianti markup (Assemblea: testo diretto; Commissione: nome in an:span; preferito TLCPerson@showAs col nome completo); file stub vuoti della fonte → campi vuoti, non errore.

Test

Closes #38, closes #30. Rif. #45.

🤖 Generated with Claude Code

- src/core/akn.ts (Worker-compatible): path atto, listing via endpoint
  JSON web-UI GitHub (troncamento 1000 gestito via totalCount), URL raw,
  parser AKN (FRBRnumber/name/date, docProponent/TLCPerson con doppia
  variante markup Assemblea/Commissione, preferito showAs)
- amendments: colonna akn_xml_url su righe LOD (URLTestoXml->raw,
  flagCommissione decide emend/emendc); fallback source=akn con ddlUri
  e LOD vuoto; withProponents/--with-proponents (concorrenza 4)
- hint doppia-fonte; emptyHint senza claim "fermo ad ago 2024" (LOD
  riallineato tra 7 e 10 lug: Piano Casa 0->799, match esatto bulk)
- wiki: emendamenti-freschezza (refresh + trappola dataPresentazione
  xsd:string), emendamenti-firmatario (risolto, markup, stub vuoti),
  akn-bulk-data (implementazione + quirks); skill CLI e MCP aggiornate
- test: +10 unit akn, +3 integrazione; 114/114 verdi, tsc pulito

Closes #38, closes #30. Rif. #45.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 10, 2026 16:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@aborruso
aborruso requested a review from Copilot July 10, 2026 16:55
@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown

Greptile Summary

This PR implements AKN bulk data integration for the amendments tool, using the Senato's GitHub repository (SenatoDellaRepubblica/AkomaNtosoBulkData, WAF-free) as a fallback when the LOD is stale and as the source for proponent data not available in the LOD. Issues raised in the previous review round (XML attribute ordering in regex, stale internal comment) have been addressed.

  • src/core/akn.ts: New Worker-compatible module with listAknDir (GitHub web-UI JSON endpoint, explicit error on format change, sorted for determinism), parseAknAmendment (two-pass attribute extraction), fetchAknFile, and mapLimit (concurrency-limited async map preserving order).
  • src/tools/amendments.ts: Every LOD row now carries akn_xml_url; when the LOD returns empty with ddlUri the tool falls back to the AKN bulk listing; withProponents fetches individual XML files with concurrency 4, an all-failures guard detects network outages vs. legitimate stub files, and truncation beyond the 1000-item GitHub listing cap is caught with explicit errors.
  • Test coverage: 10 new unit tests (offline) and 3 new integration tests bring the suite to 114/114 green.

Confidence Score: 5/5

Safe to merge: new code is well-isolated, all edge cases are handled explicitly, and previous review concerns have been addressed.

The two core additions — listAknDir/parseAknAmendment in akn.ts and the dual-source orchestration in amendments.ts — handle their edge cases explicitly: format changes on the undocumented GitHub endpoint throw instead of returning a silent empty, the 1000-item listing truncation guard prevents incorrect pagination, and the all-failures check in enrichProponents distinguishes a network outage from legitimate empty stub files. No silent failure paths remain.

No files require special attention.

Important Files Changed

Filename Overview
src/core/akn.ts New module: AKN bulk data helpers (aknAttoPath, listAknDir, parseAknAmendment, mapLimit, fetchAknFile). Two-pass attribute extraction addresses previous review concerns; listing sorted for determinism; explicit errors on format/truncation changes.
src/tools/amendments.ts Extends the amendments tool with akn_xml_url on every LOD row, automatic fallback to AKN bulk when LOD is empty with ddlUri, and withProponents enrichment; truncation guard and all-failures detection are correctly implemented.
src/core/akn.test.ts New offline unit tests covering path construction, URL conversion, AKN parsing (incl. attribute-order inversion regression), deduplication, and mapLimit concurrency semantics.
src/tools/tools.test.ts Adds integration tests for akn_xml_url presence, AKN fallback with hint, withProponents extraction, limit guard, all-failures detection, and checkAknTruncation variants (online + offline).
src/cli.ts Adds --with-proponents boolean flag to amendments list command, correctly wired to withProponents input parameter.

Reviews (8): Last reviewed commit: "fix(amendments): hint distinto per pagin..." | Re-trigger Greptile

Comment thread src/core/akn.ts Outdated
Comment thread src/core/akn.ts Outdated
Comment thread src/tools/amendments.ts Outdated
Comment thread src/core/akn.ts

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@aborruso
aborruso requested a review from Copilot July 10, 2026 17:01
…tile)

- FRBRdate e TLCPerson: two-pass (isola il tag, poi estrae ogni
  attributo) invece di assumere un ordine date=/name= o id=/href=/showAs=
  fisso, non garantito dallo standard XML
- rimosso claim obsoleto "fermo al 2024-08-09" da un commento interno
  (LOD osservato riallinearsi 7-10 lug, gia' riflesso nelle stringhe
  user-facing)
- +1 test di regressione con attributi in ordine invertito

115/115 test verdi, tsc pulito.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 7 comments.

Comment thread src/tools/amendments.ts Outdated
Comment thread src/tools/amendments.ts
Comment thread src/tools/amendments.ts
Comment thread src/tools/amendments.ts
Comment thread src/tools/amendments.ts
Comment thread src/core/akn.ts Outdated
Comment thread src/core/akn.ts Outdated
parseAknAmendment gia' restituiva l'URI per proponente, ma le colonne
first_proponent/proponents scartavano tutto tranne il nome - impossibile
il join con altri tool (es. risalire alla scheda senatore, disambiguare
omonimie). Aggiunte first_proponent_uri/proponents_uri, inizializzate
su entrambi i rami (LOD e fallback AKN) per coerenza JSONL.

115/115 test verdi, tsc pulito. Verificato live: DE CRISTOFARO ->
dati.senato.it/22918.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Comment thread src/tools/tools.test.ts Outdated
Comment thread src/tools/tools.test.ts Outdated
Comment thread src/tools/amendments.ts
Comment thread src/tools/amendments.ts
Comment thread src/core/akn.ts
Comment thread src/core/akn.ts
- listAknDir: sort esplicito dei nomi file (l'ordine di tree.items non e'
  un contratto garantito dell'endpoint non documentato); senza sort la
  paginazione offset/limit rischiava duplicati/salti tra esecuzioni
- mapLimit: limit<=0 normalizzato ad almeno 1 worker invece di tornare
  un array di holes in silenzio
- test: accettano source lod|akn invece di assumere quale sorgente
  risponde (freschezza LOD intermittente); withProponents verifica
  "almeno una riga popolata" invece di rows[0] (esistono file AKN stub
  vuoti nella fonte)
- +1 test mapLimit con limit 0 e negativo

116/116 test verdi, tsc pulito.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Comment thread src/tools/amendments.ts Outdated
…ioso

enrichProponents intercettava ogni errore di fetch/parsing lasciando i
campi proponenti vuoti, indistinguibili dai file AKN stub della fonte
(nessun docProponent, ma HTTP 200). Se GitHub e' irraggiungibile (es.
dal Worker, verifica ancora pendente) l'utente otteneva righe valide
con proponenti vuoti senza segnale d'errore.

Fix: la tolleranza per-file resta (un 404 isolato non affossa la
finestra), ma se TUTTI i fetch della finestra falliscono viene
lanciato un errore esplicito. enrichProponents esportata per test
unitario mirato (404 reali su file inesistenti, deterministico).

117/117 test verdi, tsc pulito.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Comment thread src/tools/amendments.ts
Comment thread skills/italian-parliament-mcp/references/tools.md
Comment thread skills/italian-parliament-cli/references/commands.md Outdated
- hint fallback AKN: indica ora il nome parametro (legislature) e il
  flag CLI equivalente (--legislature), non solo "ripetere passando
  legislature"
- skill CLI e MCP: menzionano la colonna date, popolata dai metadati
  AKN quando si usa withProponents/--with-proponents

117/117 test verdi, tsc pulito.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Comment thread src/tools/amendments.ts
Comment thread src/core/akn.ts
…erente

- type cambiava semantica in base a source: E/G/Q (osr:tipo) sul ramo
  LOD, "commissione"/"assemblea" sul ramo AKN fallback. Aggiunta
  colonna sede dedicata (popolata su entrambi i rami: LOD via
  osr:flagCommissione, AKN via emend/emendc); type resta E/G/Q e vuoto
  sulle righe source=akn (non deducibile in modo affidabile dal solo AKN)
- aknAttoPath: messaggio d'errore diceva "atteso http://dati.senato.it/
  ddl/<n>" ma la regex accetta qualsiasi URI con /ddl/<n> (http/https/
  altro host); reso coerente

117/117 test verdi, tsc pulito. Verificato live: source=lod -> type=G,
sede=assemblea.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Comment thread src/tools/amendments.ts Outdated
…a/Commissione

Il controllo unico "offset+limit > entries.length" non copriva il caso
in cui SOLO il bucket Assemblea e' troncato: un offset oltre
aula.names.length veniva letto come "Commissione" nell'array
concatenato, ma potrebbe in realta' essere un elemento di Assemblea
non visibile (posizione reale non determinabile nel bucket troncato).
Bug di correttezza silenzioso, non solo di raggiungibilita'.

Estratta checkAknTruncation (pura, esportata per test offline): guarda
le due troncature separatamente, fallisce esplicito se la finestra
richiesta rischia di attraversare il confine Assemblea/Commissione
mentre Assemblea e' troncata.

+4 test unitari (offset dentro/oltre il visibile, singola vs doppia
troncatura, nessuna troncatura). 121/121 test verdi, tsc pulito.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/tools/amendments.ts:169

  • withProponents esegue un fetch per emendamento, ma al momento limit può arrivare a 1000: basta un uso “distratto” (es. --with-proponents senza abbassare --limit) per innescare centinaia/migliaia di richieste HTTP, con alta probabilità di timeout/rate limit (specie nel Worker). Suggerirei di imporre un cap (o un errore esplicito) quando withProponents è true e limit supera una soglia ragionevole (es. 100), lasciando invariato il caso senza proponenti.
  async execute(input) {
    // amendments interroga solo l'endpoint Senato: un ddlUri della Camera
    // passerebbe il FILTER senza match, restituendo un CSV vuoto che si può
    // scambiare per "nessun emendamento". In realtà gli emendamenti della
    // Camera NON esistono come entità nel LOD OCD (nessuna classe emendamento):

Raccolto da un suggerimento a bassa confidenza soppresso dall'ultima
review Copilot (mai pubblicato come commento, quindi nessun thread da
risolvere, ma tecnicamente fondato): withProponents fa un fetch HTTP
per riga, con limit fino a 1000 (max schema) sono centinaia/migliaia
di richieste, rischio concreto di timeout/rate-limit specie dal Worker.

Fix: errore esplicito se withProponents=true e limit>100, invece di un
timeout silenzioso a metà esecuzione. Coerente con lo stile del
progetto (errori espliciti, mai cap silenziosi).

+1 test, 122/122 verdi, tsc pulito.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Comment thread src/tools/amendments.ts
…genuino

L'hint sul ramo fallback AKN diceva sempre "nessun emendamento né nel
LOD né nel bulk" quando aknRows era vuoto - ma questo succede anche
quando l'atto HA emendamenti e l'offset richiesto pagina oltre la fine
(entries.length > 0, page.length === 0): un falso "assente" per un
mero problema di paginazione.

Estratta aknEmptyHint (pura, esportata per test offline): distingue
vuoto genuino (entriesLength 0) da pagina oltre la fine (entriesLength
> 0), con hint che indica il totale disponibile e l'offset valido.

+1 test, 123/123 verdi, tsc pulito.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

@aborruso
aborruso merged commit e0ba02b into main Jul 10, 2026
2 checks passed
@aborruso
aborruso deleted the feat/amendments-akn-fallback branch July 10, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants