Skip to content

Commit 44d6c40

Browse files
committed
Build clean-room v2 dataset
1 parent 05af80d commit 44d6c40

63 files changed

Lines changed: 471591 additions & 268492 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ data/*.json linguist-generated=true
33
data/*.xlsx binary linguist-generated=true
44
data/*.sqlite binary linguist-generated=true
55
legacy/** linguist-vendored=true
6+
baselines/** linguist-vendored=true
7+
sources/snapshots/** binary linguist-vendored=true

.github/workflows/data-pipeline.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ jobs:
9090
- name: Validate committed data and quality contracts
9191
run: python scripts/validate_dataset.py
9292

93+
- name: Verify declared source snapshots and checksums
94+
run: >-
95+
python -c
96+
"import sys; sys.path.insert(0, 'scripts');
97+
from source_data import validate_declared_sources;
98+
validate_declared_sources()"
99+
93100
- name: Build twice and verify determinism
94101
run: python scripts/check_determinism.py
95102

@@ -126,6 +133,8 @@ jobs:
126133
data
127134
":(exclude)data/italian_locations.sqlite"
128135
reports/release-diff.json
136+
reports/build-metadata.json
137+
reports/legacy-comparison.json
129138
reports/export-manifest.json
130139
reports/determinism.json
131140
reports/quality-validation.json

.github/workflows/release.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ jobs:
3939
- name: Validate tagged data
4040
run: python scripts/validate_dataset.py
4141

42+
- name: Verify declared source snapshots and checksums
43+
run: >-
44+
python -c
45+
"import sys; sys.path.insert(0, 'scripts');
46+
from source_data import validate_declared_sources;
47+
validate_declared_sources()"
48+
4249
- name: Run tests
4350
run: python -m unittest discover -s tests -v
4451

CHANGELOG.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,47 @@
11
# Changelog
22

3+
## v2.0.0 — prerelease candidate, not yet published
4+
5+
### Breaking
6+
7+
- Replaced the legacy-derived canonical dataset with a clean-room build from
8+
ISTAT municipalities and GeoNames Postal Codes IT.
9+
- Raised the dataset schema to `3.0.0` and the quality gate to `5.0.0`.
10+
- Changed the canonical grain to one row per location–postal-code relation.
11+
- Removed `legacy_uuid`, `legacy_province_name`, `coordinate_status` and
12+
`source_snapshot` from the current schema.
13+
14+
### Added
15+
16+
- All 7,894 municipalities from the declared ISTAT snapshot, including 396
17+
without a GeoNames postal-code match.
18+
- Many-to-many postal relations, explicit reconciliation outcomes, source
19+
record identities, source dates, confidence and GeoNames `accuracy`.
20+
- Immutable GeoNames snapshot, checksum gate, attribution and
21+
`reports/legacy-comparison.json`.
22+
- Separate `structural_quality=passed` and
23+
`operational_data_readiness=experimental_non_official`.
24+
- Clean-room warnings and GeoNames attribution in JSON, XLSX, SQLite, Pages
25+
and release notes.
26+
27+
### Changed
28+
29+
- Legacy data is historical comparison material only and no longer
30+
contributes to current outputs or Pages.
31+
- Coordinates are labelled `geonames_place_match`,
32+
`geonames_estimated` or `missing`; none are official.
33+
- Pages uses absolute counts rather than a potentially misleading coverage
34+
percentage.
35+
36+
### Known limitations
37+
38+
- GeoNames is not Poste Italiane; CAP and coordinates are non-official and
39+
provided without warranty.
40+
- 10,320 GeoNames records are not reconciled with a municipality.
41+
- GeoNames still contains 76 records using historical province code `SU`;
42+
they remain unparented instead of being remapped automatically.
43+
- The `v2.0.0` tag and GitHub release await maintainer confirmation.
44+
345
## v1.1.0 — pre-release
446

547
### Added

CITATION.cff

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
cff-version: 1.2.0
2-
message: "If you use this dataset, cite the repository and the exact version or commit."
2+
message: "Cite the repository, exact version or commit, ISTAT and GeoNames."
33
title: "Italian Cities"
44
type: dataset
55
authors:
66
- family-names: "Codewriter90x"
7-
version: "1.1.0-prerelease"
7+
version: "2.0.0-prerelease"
88
date-released: 2026-07-30
99
repository-code: "https://github.com/Codewriter90x/Italian_Cities"
1010
url: "https://codewriter90x.github.io/Italian_Cities/"
1111
abstract: >-
12-
Experimental, reproducible dataset of Italian municipalities, unclassified
13-
postal localities, legacy postal codes and legacy coordinates. Postal codes
14-
and coordinates are not presented as authoritatively verified.
12+
Experimental clean-room dataset of all municipalities in a declared ISTAT
13+
snapshot, GeoNames postal-place relations and non-official coordinates.
14+
GeoNames is not Poste Italiane; CAP and coordinates are provided without
15+
warranty and the release is not operationally certified.
1516
keywords:
1617
- Italy
1718
- municipalities
1819
- postal codes
20+
- GeoNames
21+
- ISTAT
1922
- geodata

CONTRIBUTING.md

Lines changed: 60 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,80 @@
11
# Contributing
22

3-
## Principi
3+
## Regola fondamentale
44

5-
Ogni modifica ai dati deve essere verificabile, attribuibile e riproducibile.
6-
Non modificare manualmente alcun CSV, JSON, XLSX, SQLite o SQL generato.
7-
`data/` è interamente prodotto dalla pipeline.
5+
Non modificare manualmente file sotto `data/`, SQL di release o report
6+
generati. Ogni correzione parte da una fonte dichiarata o da una regola
7+
riproducibile.
88

9-
I file sotto `legacy/2023-05-02-original/` sono una baseline immutabile. Non
10-
correggerli, rinominarli o rigenerarli.
9+
Non modificare o eliminare `legacy/`, i tag storici o le baseline di release.
1110

12-
## Correzioni e nuove fonti
11+
## Correzione dati
1312

14-
Una proposta che modifica un valore deve includere:
13+
Una proposta deve indicare:
1514

16-
1. record interessato e campo;
17-
2. valore precedente e valore proposto;
18-
3. URL o artefatto sorgente, editore, data di riferimento e data di accesso;
19-
4. licenza e attribuzione richiesta;
20-
5. regola riproducibile implementata nello script;
21-
6. eventuali conseguenze sugli identificativi.
15+
1. record e campo interessati;
16+
2. valore corrente e proposto;
17+
3. editore, URL, data di riferimento e data di accesso;
18+
4. licenza e attribuzione;
19+
5. regola riproducibile;
20+
6. conseguenze su ID, riconciliazione e report.
2221

23-
Non inferire una frazione, un comune padre o una coordinata dalla sola
24-
somiglianza del nome. Non usare il CAP come chiave univoca. Conservare i CAP
25-
come stringhe di cinque cifre.
22+
Non usare scraping, Poste “Cerca CAP”, API non autorizzate o il servizio
23+
pubblico Nominatim per bulk geocoding. Non acquistare una fonte per conto del
24+
progetto e non accettare condizioni commerciali senza decisione del
25+
maintainer.
2626

27-
Le coordinate devono essere una coppia WGS84 completa e provenire da una
28-
fonte autorizzata. Non eseguire geocoding massivo contro il servizio pubblico
29-
Nominatim; rispettare sempre termini, limiti e attribuzione della fonte scelta.
27+
## Regole di riconciliazione
3028

31-
## Workflow locale
32-
33-
1. Dichiarare o aggiornare la fonte in `sources/manifest.json`.
34-
2. Scaricare il riferimento descritto in `sources/README.md`.
35-
3. Modificare la trasformazione o lo schema, non gli output generati.
36-
4. Rigenerare e validare:
37-
38-
```bash
39-
python3 scripts/build_dataset.py
40-
python3 scripts/check_determinism.py
41-
python3 scripts/validate_dataset.py
42-
python3 -m unittest discover -s tests -v
43-
python3 scripts/build_release.py
44-
python3 scripts/validate_release.py
45-
```
46-
47-
5. Esaminare `reports/release-diff.json`: cambi aggiunti, rimossi o
48-
modificati devono essere intenzionali e spiegati.
49-
6. Verificare le baseline:
50-
51-
```bash
52-
cd legacy/2023-05-02-original
53-
shasum -a 256 -c SHA256SUMS
54-
```
55-
56-
7. Controllare che `reports/determinism.json` e
57-
`reports/quality-validation.json` abbiano `"status": "passed"` e che
58-
ogni voce `quality_checks` sia superata.
59-
60-
I warning non vanno nascosti: descrivono debito dati o gate di pubblicazione
61-
ancora aperti.
29+
- il codice ISTAT identifica il comune;
30+
- un CAP non identifica un comune;
31+
- il nome simile non basta;
32+
- più candidati restano ambigui;
33+
- una località senza match resta senza comune padre;
34+
- `official_verified` e `official_boundary_derived` non possono essere usati
35+
senza una nuova fonte ufficiale compatibile e documentata;
36+
- il campo GeoNames `accuracy` va preservato;
37+
- GeoNames non deve essere presentato come Poste Italiane.
6238

63-
La pull request deve superare il check richiesto `Data quality gate`. Il check
64-
viene eseguito su ogni PR e il branch `main` non accetta merge quando manca o
65-
fallisce.
66-
67-
Per una correzione dati aprire il modulo GitHub più specifico:
68-
69-
- `Località errata`;
70-
- `CAP errato`;
71-
- `Coordinata mancante`;
72-
- `Variazione amministrativa`.
39+
## Workflow locale
7340

74-
Il modulo generico `Data correction` resta disponibile per casi che non
75-
rientrano nelle categorie precedenti. Domande, proposte e casi d'uso vanno
76-
invece nelle GitHub Discussions.
41+
```bash
42+
python -m pip install -r requirements.txt -r requirements-dev.txt
43+
python scripts/build_dataset.py
44+
python scripts/check_determinism.py
45+
python scripts/validate_dataset.py
46+
ruff check scripts tests
47+
mypy
48+
coverage run -m unittest discover -s tests
49+
coverage report
50+
node --test tests/pages_core.test.mjs
51+
python scripts/build_pages.py
52+
python scripts/build_release.py
53+
python scripts/validate_release.py
54+
git diff --check
55+
```
7756

78-
## Regole sugli identificativi
57+
Verificare che:
7958

80-
- Non cambiare `legacy_uuid`.
81-
- Non assegnare manualmente un codice ISTAT.
82-
- Una riconciliazione deve essere basata su una fonte e deve conservare alias
83-
se cambia un `location_id`.
84-
- Nuovi tipi di record richiedono prima un aggiornamento a `SCHEMA.md` e ai
85-
controlli automatici.
59+
- `structural_quality` sia `passed`;
60+
- `operational_data_readiness` resti `experimental_non_official`;
61+
- due build siano identiche;
62+
- nessun `source_ids` canonico contenga `legacy_csv`;
63+
- il report legacy sia limitato, deterministico e non affermi provenienza;
64+
- la Pages mostri warning e attribuzione GeoNames.
8665

87-
## Export
66+
## Pull request
8867

89-
`scripts/export_formats.py` genera JSON, XLSX e SQLite esclusivamente da
90-
`data/italian_locations.csv`. Non correggere un formato derivato: correggere
91-
fonte o trasformazione e rigenerare tutti gli export.
68+
La PR deve descrivere fonti/licenze, schema, statistiche prima/dopo, rischi
69+
residui e comandi eseguiti. Tutti i check richiesti devono essere verdi prima
70+
del merge.
9271

93-
`scripts/export_sql.py` genera lo script SQL SQLite-compatible.
94-
`scripts/build_release.py` copia esclusivamente gli artefatti generati, crea lo
95-
script SQL e scrive `SHA256SUMS`. Il dump SQL Server sotto `legacy/` non entra
96-
mai nel bundle.
72+
Per segnalazioni usare gli issue form per località, CAP, coordinate o
73+
variazioni amministrative. Discussioni e casi d'uso possono essere aperti in
74+
GitHub Discussions.
9775

9876
## Release
9977

100-
Il tag deve corrispondere a `dataset_version` in `project.json`. Il workflow
101-
`.github/workflows/release.yml`:
102-
103-
1. valida dataset e test sul commit taggato;
104-
2. costruisce e valida `dist/<versione>/`;
105-
3. conserva il bundle come artifact CI;
106-
4. crea una GitHub Release senza sovrascrivere asset già pubblicati;
107-
5. usa `release_status` per creare una pre-release finché il gate dati/licenze
108-
resta aperto.
109-
110-
La promozione da pre-release a release stabile è un gate maintainer separato.
111-
Richiede il controllo di note, checksum, asset e stato di provenienza/licenze.
112-
113-
## GitHub Pages
114-
115-
`scripts/build_pages.py` costruisce il sito statico esclusivamente dal CSV
116-
canonico. La build deve essere deterministica e non deve introdurre:
117-
118-
- geocoding lato client o server;
119-
- analytics o cookie;
120-
- dipendenze da tile provider;
121-
- copie divergenti del dataset;
122-
- HTML generato manualmente contenente dati.
123-
124-
Prima di modificare ricerca o mappa eseguire:
125-
126-
```bash
127-
node --test tests/pages_core.test.mjs
128-
python3 -m unittest discover -s tests -p 'test_pages.py' -v
129-
python3 scripts/build_pages.py
130-
```
131-
132-
## Licenze
133-
134-
Non incorporare dati finché la loro licenza non è documentata e compatibile
135-
con il modo in cui il dataset sarà distribuito. L'attribuzione ISTAT e il gate
136-
descritto in `DATA_SOURCES.md` devono accompagnare ogni futura release.
78+
Il tag deve coincidere con `project.json`. Preparare `release/<versione>.md`,
79+
costruire e validare `dist/<versione>/`, ma non creare tag o release senza
80+
conferma esplicita del maintainer.

0 commit comments

Comments
 (0)