# Fidelidade — Coordenadas

Auditoria de fidelidade da dimensão **coordenadas georreferenciadas** do projeto MonumentosFR.
Data: 2026-09-01. Verificação executada sobre a população inteira (46.760 registos CSV) com rederivação da pipeline em Python.

## Método

- Fonte de verdade: `raw/merimee.csv` — 46.760 linhas, sem referências duplicadas [C]. Coluna 77, `coordonnees_au_format_WGS84`, em **graus decimais WGS84** no formato «lat,lng» (ex.: `48.3916559789157,4.52479043755344`) [C].
- Transformação (rederivada de `tools/build_dataset.py`, linhas 272–286) [C]:
  1. `float()` de cada parte separada por vírgula; falha de parse → registo vai para `raw/coord_outliers.json` e fica sem `la`/`lo`.
  2. Validação `coords_ok()` contra BOUNDS: métropole 41–51.5N / −5.5–9.8E; Guadeloupe **alargada** 15.7–18.3N / −63.3–−60.9E (inclui Saint-Martin/Saint-Barthélemy); Martinique 14–15N / −61.3–−60.7E; Guyane 2–6N / −54.8–−51.5E; Réunion −21.5–−20.6N / 55.2–55.9E; Mayotte −13.1–−12.5N / 44.9–45.4E; Saint-Pierre-et-Miquelon 46.7–47.2N / −56.5–−56.1E.
  3. `COORD_FIXES = {"PA95000004": "swap"}` — swap lat/lng aplicado apenas se o valor original estiver fora de todos os bounds.
  4. Se passar a validação → `rec["la"], rec["lo"]` no dataset + entrada `[lat,lng]` em `www/data/merimee-coords.json`; caso contrário → outlier (sem coords no dataset).
- Verificação: script Python sobre a população inteira, comparando campo-a-campo `la`/`lo` do dataset vs CSV rederivado, tolerância 1e-6 (e adicionalmente igualdade exata). Lê `www/explorer/merimee_data.json`, `www/data/merimee-coords.json`, `www/data/merimee-geo.json`, `www/js/map.js`, `www/data/france-departements.geojson`.

## População inteira

| Indicador | CSV (fonte) | Dataset servido | Igual? |
|---|---|---|---|
| Registos totais | 46.760 [C] | 46.760 (`total`) [C] | sim |
| Com coordenadas (campo preenchido / `la`+`lo` não nulos) | 44.484 [C] | 44.484 [C] | sim |
| Sem coordenadas | 2.276 [C] | 2.276 [C] | sim |
| Erros de parse / fora de bounds (rederivado com código atual) | 0 / 0 [C] | — | sim |
| Igualdade campo-a-campo (tol. 1e-6) | — | **44.484 / 44.484 = 100%** [C] | — |
| Igualdade exata (sem tolerância) | — | **44.484 / 44.484 = 100%** [C] | — |
| Registos com só um dos eixos (`la` xor `lo`) | — | 0 [C] | — |
| `www/data/merimee-coords.json` (nº entradas) | — | 44.484, idêntico campo-a-campo ao dataset e ao rederivado (0 divergências) [C] | — |
| `www/data/merimee-geo.json` `points` (usados pelo mapa) | — | 44.484, idênticos a `la`/`lo` do dataset (0 divergências) [C] | — |

Conjuntos de refs: dataset ⊂⊃ CSV em correspondência exata (0 refs extra, 0 em falta) [C]. Não há registos com lat/lng trocados não detetados: em **0** pontos o par permutado `(lo,la)` também cairia dentro de algum bound (as gamas de lat e lng das regiões são disjuntas), pelo que nenhum swap silencioso é possível [C].

`with_coords` do dataset: 44.484 = contagem real de `la`/`lo` não nulos (44.484) = nº de entradas de `merimee-coords.json` — **coerente** [C]. Nota técnica [I]: o build conta `r.get("la")` (truthy) e não `is not None`; como nenhum `la` é 0.0, os dois critérios coincidem hoje.

## Divergências

Tolerância 1e-6. **Exatamente 1 divergência em 44.484 pares comparados — e é a correção intencional documentada:**

| ref | CSV-fonte (bruto) | Dataset servido (la, lo) | Classificação |
|---|---|---|---|
| PA95000004 | `1.9968162410986903, 49.1631330999842` | `49.1631330999842, 1.9968162410986903` | **Correção intencional** (`COORD_FIXES["PA95000004"]="swap"`) [C] — o valor bruto da fonte põe o edifício do Val-d'Oise perto do equador (1.99N, 49.16E); trocado fica em 49.16N, 2.00E, coerente com o dept 95. Não é desvio de fidelidade. |

Não há mais nenhuma divergência: os restantes 44.483 registos são **exatamente** iguais ao valor do CSV (floats servidos sem arredondamento) [C].

Observações fora do âmbito estrito de fidelidade (são fiéis à fonte, mas convive-se com qualidade da fonte):
- `raw/coord_outliers.json` está **obsoleto**: tem 10 entradas de um build anterior (bounds da Guadeloupe mais estreitos + PA95000004 ainda sem fix). No build atual a rederivação produz **0** outliers e todos os 10 refs estão hoje servidos com coordenadas válidas (PA97100004/05/06/07/08/12/36, PA00105883, PA97200009, PA95000004 — esta última trocada) [C]. O ficheiro não é servido ao site; recomenda-se regenerar/apagar para evitar confusão futura [I].
- PA97200009 (Martinique) tem coordenadas redondas exatas (14.0, −61.0) na fonte — provável placeholder; servida tal como está, fiel [C].

## Sanidade geográfica

Atribuição de região por bounds da pipeline sobre os 44.484 pontos [C]:

| Região | n | lat [min,max] | lng [min,max] | Bounds esperados (missão) | Veredicto |
|---|---|---|---|---|---|
| Métropole | 43.919 | 41.340 – 51.061 | −5.151 – 9.517 | lat 41–52.5, lng −6–10 | dentro [C]; extremos plausíveis: S da Córsega (PA00099080), Dunkerque (PA59000049), Pointe du Raz (PA29000083), Córsega oriental (PA2B000005) |
| Guadeloupe (incl. SM/SB) | 117 | 15.851 – 18.072 | −63.040 – −61.004 | ~15–16N (Guad. propriamente dita) | dentro; valores >17.9N são Saint-Barthélemy/Saint-Martin (−62.8/−63.0), cobertos pelo bound alargado [C] |
| Martinique | 123 | 14.000 – 14.874 | −61.226 – −60.838 | ~14–15N | dentro [C] |
| Guyane | 91 | 2.227 – 5.668 | −54.231 – −51.693 | ~4N | dentro [C] |
| La Réunion | 202 | −21.382 – −20.873 | 55.221 – 55.805 | ~−21 | dentro [C] |
| Mayotte | 16 | −12.904 – −12.765 | 45.105 – 45.280 | ~−13 | dentro [C] |
| Saint-Pierre-et-Miquelon | 16 | 46.775 – 47.105 | −56.403 – −56.149 | ~46.7–47.2N | dentro [C] |

- **Pontos fora dos bounds esperados da sua região: 0** [C].
- **Pontos (0,0): 0** [C]. Porém, **70 pontos têm lng exatamente 0.0** (67 Gironde, 1 Dordogne, 1 Indre-et-Loire, 1 Sarthe; ex.: PA00083150 `44,0`, PA00083232 `44.841031,0`) — vêm assim do CSV e são servidos fielmente; parece truncamento na fonte [I]. Fidelidade não é afetada; queda na precisão desses 70.
- **Lat/lng trocados**: o único caso trocado detetável na fonte (PA95000004) foi corrigido; nenhum ponto servido tem o par permutado dentro de bounds (ver §Divergências) [C].
- **Coerência dept ↔ região dos coords**: 104 códigos de departamento com coords; **0** departamentos com pontos em mais do que uma região; **0** incoerências dept-DOM↔coords-métropole e vice-versa (971→Guad., 972→Mart., 973→Guy., 974→Réu., 975→SPM, 976→May., restos→métropole) [C].

## Coerência com o mapa

- `www/js/map.js` confirma (linha 32): `function inMetropole(lat, lng) { return lat > 41 && lat < 52.5 && lng > -6 && lng < 10; }`, aplicada ao contador de pontos (linha 26) e aos círculos D3 (linha 102) [C].
- Pontos com coords excluídos do mapa por `inMetropole`: **565** = Réunion 202 + Martinique 123 + Guadeloupe/SM/SB 117 + Guyane 91 + SPM 16 + Mayotte 16 [C].
- Total do mapa rederivado: 44.484 − 565 = **43.919**, exatamente o valor esperado (~43.919) [C]. Contagem independente sobre `merimee-geo.json` (ficheiro que o mapa consome): também 43.919 [C].
- A base cartográfica `www/data/france-departements.geojson` tem **96 features** (departamentos métropole, código+nome) — coerente com um mapa só métropole [C]. Os 565 pontos DOM/SPM continuam no dataset e no `merimee-geo.json` (bom: o excluído é só a camada de pontos do mapa) [C].

## Veredicto

**Conformidade: 100%.** A transformação CSV→`la`/`lo` é fiel a 100% na população inteira: 44.484 de 44.484 pares coordenados são exatamente iguais à fonte (tolerância 1e-6 não chega a ser necessária), as 2.276 ausências reproduzem fielmente o CSV, `with_coords`, `merimee-coords.json` e `merimee-geo.json` são mutuamente coerentes e a rederivação do total do mapa dá 43.919, o valor esperado. A única alteração de valores é o swap de PA95000004, correção intencional, documentada no código e correta. A sanidade geográfica é integral (0 pontos fora da região do seu departamento, 0 (0,0), 0 swaps silenciosos, 565 pontos DOM/SPM devidamente excluídos do mapa métropole); ressalvas menores de qualidade da fonte (70 lng=0.0; PA97200009 redondo) e a staleza de `raw/coord_outliers.json` não afetam a fidelidade servida.

## Fontes

Locais (consultados read-only):
- `raw/merimee.csv` — CSV-fonte, coluna 77 `coordonnees_au_format_WGS84` (46.760 linhas)
- `raw/coord_outliers.json` — outliers de build anterior (stale)
- `www/explorer/merimee_data.json` — dataset mestre servido (`la`/`lo`, `with_coords`)
- `www/data/merimee-coords.json` — mapa `ref -> [lat,lng]` (44.484)
- `www/data/merimee-geo.json` — pontos/agregados consumidos pelo mapa
- `www/data/france-departements.geojson` — 96 departamentos métropole
- `www/js/map.js` — filtro `inMetropole` (linhas 26, 32, 102)
- `tools/build_dataset.py` — BOUNDS, `COORD_FIXES`, lógica de parse/validação (linhas 30–38, 175–179, 272–286)

Externas:
- https://www.data.gouv.fr/api/1/datasets/r/3a52af4a-f9da-4dcc-8110-b07774dfb3bc — CSV da base Mérimée, Ministère de la Culture (France), Licence Ouverte 2.0 (origem do `merimee.csv`)
- https://github.com/gregoiredavid/france-geojson — contornos dos departamentos (origem do `france-departements.geojson`)
