# Fidelidade — Usos (`ou`, `cu`) e estado (`est`, conservação)

> Auditoria de fidelidade MonumentosES, dimensão **USOS** (`ou` = uso original, `cu` = uso actual), página `/reutilizacion` (Sankey de mudanças de uso) e **estado** (`est` na vista; `te_integri`/conservação na fonte asturiana).
> Data: 2026-09-04. Auditor: agente 5/8 do painel (derivação independente a partir do cru + dos intermédios + da vista; leitura do pipeline; não modifiquei nada).
> Convenção: **[C]** = confirmado por re-derivação/leitura directa do ficheiro ou doc; **[I]** = inferido/julgamento semântico do auditor.

## Âmbito

- **Dataset servido**: `www/explorer/bic_data.json` — `total` = **22.237** registos, 15 fontes (`src`) [C]. **Nota de estado**: os relatórios irmãos 01–05 (escritos antes das 15:13 de hoje) reportam 24.337 com cant 2.400; entretanto `ingest_cantabria.py` foi corrigido (a fonte duplica cada bem ×8 → kept 2.400 → **300** distintos; `EXPECTED kept=300` no parser) e a vista foi regenerada hoje 15:15 — todos os números aqui são **pós-dedupe** [C].
- **Objectos**: (1) cobertura de `ou`/`cu` — quem os publica, quantos valores, sanidade vazio/preenchido; (2) fidelidade intermédio→vista campo a campo; (3) convenção «ou/cu crus» e o estado da página `/reutilizacion` (stub `bic-reuse.json`); (4) interacção com `est` (estado administrativo na vista) e a sua proveniência; (5) estado de conservação (`te_integri`) — existe na fonte? foi ingerido?
- Fora de âmbito: datação/estilos (02), estatuto de protecção em detalhe (03), detalhes por ficha (08).

## Método

1. Leitura directa da vista (`www/explorer/bic_data.json`) e do intermédio `raw/interm/asturias.json`; distribuições e tabelas cruzadas em Python sobre a população inteira [C].
2. **Comparação campo a campo** intermédio ast ↔ vista (join por `i`, 331 pares), para `ou` e `cu` [C]. (Nota de honestidade: a minha primeira passagem acusou 84 divergências em `ou` — era um bug do MEU script, que comparava `interm.ou` com `view.cu`; corrigido, ver Achados 2.)
3. Re-leitura do cru: `raw/ast_bic_areas.geojson` (234 feições L1 — campos `te_usoori`, `te_usoact`, `te_estadmo`, `te_estiloa`, `te_integri`) e `raw/ast_bic_puntos.geojson` (336 feições L0, 8 campos, sem usos) [C].
4. Leitura do pipeline: `tools/ingest_asturias.py` (linhas 72-74: `ou=te_usoori`, `cu=te_usoact`, `est=te_estiloa`), `tools/build_dataset.py` (cópia verbatim dos items), `tools/build_site_view.py` (linhas 69-73, 92-94, 107-116) [C].
5. Leitura do front-end: `www/js/explorer.js` (`useCat`, `matches`, `rebuildSelect`), `www/js/reuse.js` (com **simulação em node** do comportamento face ao stub), `www/js/monument.js` (display de `ou`/`cu` na ficha), `site/src/page-components/Reutilization.astro` [C].
6. **Scan de usos/conservação nos crus das outras 14 fontes**: headers de cyl (JSON), gva/mad/arg/clm (CSV), cant/ten (GeoJSON), eus (GeoJSON), ext (XLSX via openpyxl), cat (GeoJSON), gal (ODS, folha BIC: 18 colunas ID_BIC…BOE), eiv (KML), rio (GML), nav (shape BICarqueo/BICarquite) — procurados padrões `uso|destinaci|utilizaci` [C].
7. Documentação cruzada: `docs/fuentes/asturias.md`, `docs/relatorio-proveniencia.md`, `site/src/page-components/Methodologie.astro` [C].

## Achados

### 1. Cobertura: `ou`/`cu` existem **só para Astúrias** [C]

- **Na vista**: `ou` preenchido em **201** registos (0,90% de 22.237) e `cu` em **198** (0,89%) — **100% `src=ast`**; as outras 14 fontes têm 0 [C].
- **No intermédio ast** (331): as chaves `ou`/`cu` só existem nos **234 registos L1 «Áreas»** (a fonte só publica `te_usoori`/`te_usoact` nessa camada); os **97 pontos L0** nem têm os campos [C]. Dos 234 L1: `ou` 201 preenchidos / 33 vazios (85,9%); `cu` 198 / 36 (84,6%); **198 com ambos**, 3 com só `ou` (PALACIO DE LOS PARDO DONLEBÚN e PALACIO DE VILLANUEVA DE SAN CUCAO, «Residencial»; NECRÓPOLIS DEL MONTE AREO T.XV, «Necropolis»), 0 com só `cu` [C].
- **Sanidade**: sem valores órfãos nem assimetrias anormais — tudo vazio/preenchido coerente com a fonte [C].
- O pedido do painel falava em «usos só para Astúrias (**31 bens?**)»: **nenhum corte produz 31** [C]. Números reais: 201 bens com algum uso (0,9% nacional), 198 com `cu`, 81 mudanças `ou≠cu`, 75 mudanças por 1.ª categoria, 22 com `cu` «Sin uso».

### 2. Fidelidade intermédio→vista: **zero perdas** [C]

- Comparação campo a campo (join por `i`, 331/331 encontrados): `view.ou == interm.ou` em **331/331** e `view.cu == interm.cu` em **331/331** [C].
- O pipeline não toca nos valores: `build_dataset.py` copia os items verbatim (só normaliza `d`) e `build_site_view.py` faz `"ou": it.get("ou") or ""` / `"cu": it.get("cu") or ""` [C].
- **Nenhum `ou`/`cu` se perdeu no pipeline.** A única «perda» estrutural é a da FONTE: os 97 L0 nunca tiveram usos [C].

### 3. Distribuições (valores crus, 25 `ou` / 20 `cu` distintos) [C]

| `ou` (uso original) | n | | `cu` (uso actual) | n |
|---|---|---|---|---|
| Religioso | 78 | | Religioso | 66 |
| Residencial | 66 | | Residencial | 28 |
| Urbano | 18 | | Cultural | 22 |
| Defensivo | 8 | | **Sin Uso** | **19** |
| Industrial | 4 | | Urbano | 16 |
| Dotacional | 4 | | Dotacional | 14 |
| Infraestructuras | 3 | | Hostelero | 12 |
| Rural | 2 | | **Sin uso** | **3** |
| Infraestructura | 2 | | Infraestructura | 3 |
| 16 valores ×1 | 16 | | 11 valores ×1 | 11 |

- **Resíduos crus da fonte, fiéis ao original** [C]: gralhas «Resiencial», «Rsidencial», «Infraestrcutura», «Defensica»; dupla caixa «Sin Uso» (19) vs «Sin uso» (3); compostos com separadores heterogéneos «.» «/» «espaço» (`Residencial.Defensivo`, `Residencial/Defensivo`, `Residencial. Industrial`, `Cultural. Religioso`, `Dotacional/Comercial`); e conteúdo **tipológico** em campo de uso («Palacio», «Conjunto», «Necropolis») [C]. Normalização básica (caixa + pontuação) reduziria `ou` 25→24 e `cu` 20→19 [C].
- **Mudanças de uso documentadas**: 81 registos com `ou≠cu` (40,3% dos 198 com ambos); 117 iguais; 47 pares (ou,cu) distintos; por 1.ª categoria, 75 mudanças [C]. Destinos principais das mudanças: «Sin uso*» 22 · Cultural 21 · Dotacional* 16 · Hostelero 12 [C] — palácios torreresidenciais → Dotacional/Hostelero, religioso → Cultural, defensivo → Sem uso: o padrão é plausível [I].

### 4. Convenção «ou/cu crus» — praticada, **não documentada** [C/I]

- Os valores servidos são **transcrição literal** da fonte (gralhas e caixa incluídas — ver Achados 3), sem a camada de categorização do FR (que inferia «Categoria: termo» via `usage_map` de 301 entradas) [C]. É a mesma lição PT aplicada ao `t1` («filtros ficam crus — lição PT», `docs/relatorio-proveniencia.md` linha 103; «24 categorías de display (los filtros conservan el valor bruto)», Methodologie passo 4) [C].
- Porém, para `ou`/`cu` **a decisão não está escrita em lado nenhum**: nem `docs/relatorio-proveniencia.md`, nem `docs/fuentes/asturias.md`, nem a Methodologia mencionam os campos de uso [C — ausência verificada por grep]. Documentá-la é recomendado (ver Recomendações 1).
- Consequência prática no explorer: `useCat(v)` divide por «:» (formato FR); com valores crus devolve o valor inteiro, pelo que os filtros `fUseOrig`/`fUseCurr` **funcionam** (reconstruídos client-side via `countFieldFn`, os selects existem no HTML) mas ficam **fragmentados**: 25/20 entradas com as gralhas como categorias próprias [C]. Nenhum valor de uso está no `es_vocab.json` (traduções), pelo que aparecem sempre em bruto [C].

### 5. `/reutilizacion`: stub por design, mas **crash silencioso + resíduos FR** [C]

- `www/data/bic-reuse.json` = **`{}` literal (2 bytes)**, gerado por `build_site_view.py` na lista de stubs (Fases C/D «páginas renderizam estado vazio em vez de 404») [C].
- O `reuse.js` faz `data.nodes.map(...)` sem salvaguarda: com `{}`, lança **«Cannot read properties of undefined (reading 'map')»** (confirmado por simulação em node) → SVG fica vazio e `#statsBar` fica em «—», **sem mensagem de estado vazio** [C].
- **Resíduos FR no `reuse.js`** [C]: linha 3 `window.__LOCALE__ === 'fr'`; linha 50 texto **hardcoded em francês** «… changements d'usage documentés (Destination actuelle renseignée : 3,8 % des notices)» + `toLocaleString('fr-FR')` — mesmo com dados, a barra de estatísticas mostraria francês e uma percentagem FR.
- **Viabilidade do Sankey hoje: não é viável a nível nacional** [C/I]. Os únicos pares (ou→cu) que existem são os 198 asturianos = 0,89% da base; um gráfico sem aviso pareceria «mudanças de uso em Espanha» com n=198. **Recomendação honesta: manter o stub e renderizar um estado vazio desenhado e i18nizado a explicar a lacuna** (ver Recomendações 2). A alternativa «popular só com Astúrias, claramente legendado» é defensável (198 pares, 47 combinações, 81 mudanças) mas convive mal com o título nacional da página [I].

### 6. Interacção com `est` (estado administrativo na vista) [C]

Distribuição na vista (22.237):

| `est` | n | % | fontes |
|---|---|---|---|
| *(vazio)* | 20.177 | 90,7% | eus 10.295 · cyl 2.479 · cat 2.161 · nav 1.426 · gva 1.185 · eiv 728 · gal 723 · clm 631 · ext 250 · ten 199 · ast 99 · rio 1 |
| `Declarado` | 1.609 | 7,2% | arg 1.021 · ast 229 · cant 296 · rio 63 |
| `Incluido` | 309 | 1,4% | mad 309 |
| `Anotación Preventiva` | 134 | 0,6% | mad 134 |
| `Incoado` | 8 | 0,04% | cant 4 · ast 3 · rio 1 |

- Fontes de `est`: cant/mad/ast/arg/rio (re-derivado do cru; coerente com o relatório 03, com cant corrigido de 2.400→300 e Declarado 3.681→1.609, Incoado 36→8) [C].
- **Cruzamento com usos**: dos 201 registos com uso, 199 são «Declarado» e 2 «Incoado»; os 130 ast sem uso repartem-se em 99 sem `est` (97 são os pontos L0, que não trazem nem `st` nem usos) + 30 Declarado + 1 Incoado [C]. Ou seja: **usos e estado administrativo têm a mesma lacuna estrutural** — ambos dependem da camada L1 Áreas de Astúrias e das 4 fontes que publicam estado [C].
- **Colisão de nomes `est`** [C]: no intermédio ast, `est` = **estilo** (`te_estiloa`: ROMÁNICO 30, BARROCO 29, POPULAR/…); na vista, `est` = **estado administrativo** (`"est": it.get("st")`). O estilo asturiano **não sobrevive** à vista (nem como `cp`/`era`, que para ast ficam vazios) — campo pendente no intermédio, padrão idêntico à flag `en` catalã perdida já reportada no 03. Sem consequência de dados (nada é sobrescrito: a vista lê `st`, não `est`), mas é uma armadilha de manutenção [I].

### 7. Estado de conservação: existe na fonte asturiana, **não foi ingerido** [C]

- O cru L1 tem `te_integri`, que a própria documentação do projecto identifica como «conservación» (`docs/fuentes/asturias.md` linha 26) [C]. Valores nas 234 feições: **Media 111 · Alta 54 · Baja 27 · (vazio) 23 · ' ' 8 · Medio 5 · Alto 3 · Bajo 1 · Buena 1 · Allta 1 (gralha da fonte)** [C] — escala mista (Alta/Alto/Allta; Media/Medio; Baja/Bajo/Buena) que exigiria canon de display com valor cru retido [I].
- `ingest_asturias.py` **não mapeia** `te_integri`; não existe campo de conservação no intermédio nem na vista [C].
- Nenhuma outra fonte publica usos ou conservação: scan dos headers de cyl, gva, mad, arg, clm, cant, ten, eus, ext, cat, gal (folha BIC: ID_BIC…BOE), eiv, rio, nav — **0 campos de uso/conservação** para além de Astúrias [C]. A lacuna é de fonte, não de pipeline [C].

### 8. Usos na ficha do monumento: código existe, **nunca executa** [C]

- `monument.js` (linhas 596-598) tem código para mostrar «Uso original / uso actual» na ficha, mas `detail` vem de `/data/bic-detail-index.json` — ficheiro que **não existe em `www/data/`** (o stub está em `/explorer/bic-detail-index.json`, outro caminho) → a fetch devolve 404, o `try/catch` engole o erro, `detail=null` e o bloco de usos nunca renderiza [C]. Mesmo com o caminho certo, o stub `{}` daria o mesmo resultado [C].

## Desvios

1. **Metadados de filtro mortos/enganadores** [C]: `filters.use_original = {}`, `use_current = {}` e `use_changed_count = 0` são **hardcoded** no `build_site_view.py` (linhas 92/94) apesar de existirem 201 usos; nenhum JS os lê (os selects são reconstruídos dos records). O `uc` é gravado **0 para todos os registos** (linha 71), pelo que o filtro «uso mudou» (`fuch`) do motor devolve sempre 0 resultados — enganador face às 81 mudanças reais.
2. **`/reutilizacion` sem estado vazio desenhado** [C]: crash silencioso do `reuse.js` com o stub (TypeError), página fica vazia com «—».
3. **Resíduos FR no `reuse.js`** [C]: teste de locale `'fr'`, texto FR hardcoded com «3,8 %» e `fr-FR` — não adaptados ao ES multi-língua.
4. **`te_integri` (conservação) disponível e documentado, mas não ingerido** [C] — decisão por omissão, não registada em lado nenhum.
5. **Convenção «ou/cu crus» não documentada** [C — ausência]; filtros de uso fragmentados (25/20 valores, dupla caixa «Sin Uso/Sin uso», gralhas como categorias) [C].
6. **Colisão `est` = estilo (intermédio ast) vs estado (vista)** [C]; estilo asturiano perdido para a vista [C].
7. **Usos invisíveis na ficha** (detail index em caminho errado + stub) [C].
8. **Sankey não viável a nível nacional** — 198 pares = 0,89% da base, todos da mesma CCAA [C]; a expectativa «31 bens» do painel não corresponde a nenhum corte real [C].

## Recomendações

1. **Manter `ou`/`cu` crus** (coerente com a lição PT do `t1`) e **documentar a convenção**: nota em `docs/fuentes/asturias.md` («te_usoori/te_usoact transcritos sem normalização; só L1 Áreas»), linha no `relatorio-proveniencia.md` e na Methodologia («dados de uso só existem para Astúrias: 201 bens, 0,9% da base») [I].
2. **`/reutilizacion` honesto**: (a) corrigir o `reuse.js` para detectar stub vazio e renderizar mensagem i18n do tipo «Sem dados de uso suficientes: apenas Astúrias publica uso (201 de 22.237 bens) — gráfico suspenso até haver mais fontes»; (b) limpar já os resíduos FR (locale, texto, `fr-FR`); (c) só popular `bic-reuse.json` se se assumir a variante «Astúrias-only» claramente legendada (198 pares/81 mudanças) — recomendo **não** popular hoje [I].
3. **Ligar os metadatos ao dado**: preencher `use_original`/`use_current`/`use_changed_count` reais no `build_site_view.py` (ou remover as chaves mortas); decidir o `uc` (1 nas 81 mudanças por categoria) ou remover o filtro `fuch` do UI — nunca deixar um filtro que devolve sempre vazio [I].
4. **Normalização só-display para os filtros de uso** (ex.: «Sin Uso/Sin uso» → mesma etiqueta; gralhas → forma correcta), mantendo o valor cru nos dados, na linha do `t1_canon` [I].
5. **Conservação**: decidir explicitamente — (a) ingerir `te_integri` como `cons` (só 234 registos, mas é o único dado do género em toda a base; canon de display para a escala mista Alta/Alto/Allta…) ou (b) não ingerir e registar a lacuna no `asturias.md`. Qualquer das duas é defensável; a omissão silenciosa não [I].
6. **Ficha**: resolver o caminho/geração de `bic-detail-index.json` (coordenar com o agente 08) para que o bloco de usos de `monument.js` possa funcionar [I].
7. **Renomear o `est` do intermédio ast para `estilo`** na próxima re-ingerência e avaliar levar `te_estiloa`/`te_cronolo` para `cp`/`era` (hoje Astúrias não contribui para a cronologia da vista) — em articulação com o agente 02 [I].

## Fontes

**Ficheiros do projecto (lidos/re-derivados)** [C]:

- Vista: `www/explorer/bic_data.json` (22.237; gerada 2026-09-04 15:15); `www/explorer/bic-stats.json`
- Intermédio: `raw/interm/asturias.json` (331; os restantes 14 verificados quanto a `ou`/`cu` = 0)
- Cru: `raw/ast_bic_areas.geojson` (234 L1: `te_usoori`, `te_usoact`, `te_estadmo`, `te_estiloa`, `te_integri`), `raw/ast_bic_puntos.geojson` (336 L0); headers de `raw/cyl_bic_inmu_0.json`, `raw/gva_bic_inmuebles.csv`, `raw/mad_inmuebles_bic.csv`, `raw/arg_bic_puntos.csv`, `raw/clm_catalogo.csv`, `raw/cant_bic.geojson`, `raw/ten_bic_inmuebles.geojson`, `raw/eus_L2_0.json`, `raw/ext_bic.xlsx`, `raw/cat_bcin_arquitec.geojson`, `raw/gal_bic.ods`, `raw/eiv_bics.kml`, `raw/rio_arquitectura_defensiva.gml`, `raw/nav_bicarqueo.zip`
- Código: `tools/ingest_asturias.py`, `tools/ingest_cantabria.py` (EXPECTED kept=300), `tools/build_dataset.py`, `tools/build_site_view.py`; front-end: `www/js/explorer.js`, `www/js/reuse.js`, `www/js/monument.js`, `site/src/page-components/Reutilization.astro`, `site/src/page-components/Methodologie.astro`
- Dados servidos: `www/data/bic-reuse.json` (stub `{}`), `www/explorer/bic-detail-index.json` (stub), `www/reutilizacion/index.html`
- Docs: `docs/fuentes/asturias.md`, `docs/relatorio-proveniencia.md`
- Relatório FR anterior (contexto, cópia substituída): `www/audit/04-uso.md`; relatório irmão: `site/public/audit/03-protecao.md`

**URLs das fontes de dados** (conforme docs/fuentes, não re-testados nesta auditoria):

- Astúrias (única fonte de usos; CC BY 4.0): https://sig.asturias.es/servicios/rest/services/BienesDeInteresCultural/MapServer/0/query (L0 Puntos) e …/MapServer/1/query (L1 Áreas, com `te_usoori`/`te_usoact`/`te_integri`)

## Comandos (re-derivação)

```bash
cd "C:/Users/Atelier X/Nextcloud/Documents/00_Website/MonumentosES"

# 1) Cobertura e distribuições na vista
python - <<'EOF'
import json
from collections import Counter
d = json.loads(open('www/explorer/bic_data.json', encoding='utf-8').read())
recs = d['records']
print('total:', d['total'])
print('ou:', sum(1 for r in recs if r.get('ou')),
      '| cu:', sum(1 for r in recs if r.get('cu')),
      '| por src:', Counter(r['i'].split(':',1)[0] for r in recs if r.get('ou')))
print('ou dist:', Counter(r['ou'] for r in recs if r.get('ou')).most_common())
print('cu dist:', Counter(r['cu'] for r in recs if r.get('cu')).most_common())
print('est:', Counter(r['est'] or '(vazio)' for r in recs).most_common())
print('meta filtros:', d['filters']['use_original'], d['filters']['use_current'],
      d['filters']['use_changed_count'])
EOF

# 2) Fidelidade campo a campo intermédio ast -> vista (join por i)
python - <<'EOF'
import json
interm = {it['i']: it for it in json.loads(open('raw/interm/asturias.json', encoding='utf-8').read())['items']}
view = {r['i']: r for r in json.loads(open('www/explorer/bic_data.json', encoding='utf-8').read())['records'] if r['i'].startswith('ast:')}
print('view.ou==interm.ou:', sum(1 for i in view if (view[i].get('ou') or '')==(interm[i].get('ou') or '')), '/', len(view))
print('view.cu==interm.cu:', sum(1 for i in view if (view[i].get('cu') or '')==(interm[i].get('cu') or '')), '/', len(view))
both = [it for it in interm.values() if it.get('ou') and it.get('cu')]
print('ambos:', len(both), '| mudanças ou!=cu:', sum(1 for it in both if it['ou']!=it['cu']))
EOF

# 3) Sanity no intermédio + te_integri (conservação) no cru
python - <<'EOF'
import json
from collections import Counter
items = json.loads(open('raw/interm/asturias.json', encoding='utf-8').read())['items']
l1 = [it for it in items if 'ou' in it]
print('L1:', len(l1), '| L0 sem campos:', len(items)-len(l1))
print('ou preench:', sum(1 for it in l1 if it.get('ou')), '| cu preench:', sum(1 for it in l1 if it.get('cu')),
      '| ambos:', sum(1 for it in l1 if it.get('ou') and it.get('cu')),
      '| só ou:', sum(1 for it in l1 if it.get('ou') and not it.get('cu')))
g = json.loads(open('raw/ast_bic_areas.geojson', encoding='utf-8').read())
print('te_integri:', Counter(f['properties'].get('te_integri') or '(vazio)' for f in g['features']).most_common())
EOF

# 4) Simulação do crash do reuse.js com o stub
node -e "var d={}; try { d.nodes.map(x=>x) } catch(e) { console.log('THROW:', e.message) }"

# 5) Scan de campos de uso nas outras fontes (exemplo gva/mad; restantes no §Método 6)
python - <<'EOF'
import csv, re
for p, enc, dl in [('raw/gva_bic_inmuebles.csv','utf-8-sig',';'), ('raw/mad_inmuebles_bic.csv','cp1252',';')]:
    hdr = next(csv.reader(open(p, encoding=enc), delimiter=dl))
    print(p, [h for h in hdr if re.search('uso|destinaci|utilizaci', h, re.I)] or '(sem uso)')
EOF
```
