Skip to content

MAPA: pipeline de ubicaciones y nueva vista geográfica del archivo - #67

Merged
Bu-chip merged 13 commits into
mainfrom
feat/mapa
Sep 20, 2026
Merged

Bu-chip merged 13 commits into
mainfrom
feat/mapa

Conversation

@Bu-chip

@Bu-chip Bu-chip commented Sep 20, 2026

Copy link
Copy Markdown
Owner

La ubicación de Bandcamp dejaba de existir al entrar al catálogo: el descubrimiento la leía (band_location) y el merge la descartaba. Este PR la conserva como evidencia trazable fuera del canónico y, encima de esos datos, añade una tercera puerta: MAPA, el mismo archivo interrogado desde los lugares.

El canónico (data/bandcamp_bilbaotags_clean.json, 9 campos) no se toca.

Pipeline de ubicaciones

Cuatro capas separadas en data/locations/, todas reproducibles con scripts/locations.py:

  1. Observación — el texto crudo de Bandcamp («Zarautz, Spain») con su fuente, cuenta, URL y fecha. Un fichero por lote, así cada PR mensual añade el suyo sin conflictos. value: null = se consultó y no había ubicación.
  2. Normalización — cada texto va a una categoría: resolved, region_only, ambiguous, outside_scope, unexpected, invalid o unresolved, contra un registro controlado de 684 municipios (Wikidata: INE/INSEE + P625; Iparralde = las comunas de la Communauté d'agglomération du Pays Basque) y reglas en rules.json.
  3. Resolución — por release, con su procedencia y sus contradicciones: direct, same_account, artist_inferred, manual, region_only, outside_scope, tag_hint, unresolved. Una cuenta de sello nunca propaga su ubicación al artista, y un tag geográfico nunca ubica por defecto.
  4. Índice del mapa — 208 KB, referencias por id, solo se descarga al abrir MAPA.

Cómo se recuperó y completó:

  • Sin red: recover reconstruyó 5.181 ubicaciones desde el histórico git (incluidas las ramas candidates/2026-08, 2026-09 y discovery-state), con 0 contradicciones entre versiones.
  • Con red: scrape visitó una ficha por cuenta sin evidencia previa (638 peticiones en vez de 1.414, al ritmo del scraper actual): 621 cuentas con ubicación, 10 sin ella y 8 resueltas por la portada de la cuenta al estar los discos retirados.
  • Guardia: locations.py check falla si algún band_location de un fichero de candidatos no está registrado. Corre en CI y está enganchada al workflow mensual, así que los PR Candidatos 2026-08: 29 discos para revisión #65 y Candidatos 2026-09: 76 discos para revisión #66 ya no pueden perder sus ubicaciones.

Escenario D por defecto

El mapa dibuja directas + misma cuenta de un solo artista + inferidas por artista: 5.904 releases (78 % del catálogo) en 104 municipios.

Quedan fuera por defecto, activables en «Más filtros» o con ?ubic=dcamt, las 618 inferencias desde cuentas con varios artistas y las 36 pistas de tag. Los datos no se borran ni cambia la resolución almacenada: solo cambia qué se dibuja.

El porqué está medido en la auditoría multiartista:

  • Escenario A (todo): 6.522 releases, pero 618 venían de cuentas multiartista, 612 de ellas en Bilbo: era la ciudad del sello, no la del grupo.
  • Escenario B (solo directas): 4.953, y hundía Bilbo de 2.440 a 941 por un artefacto del método (el scrapeo visitó una ficha por cuenta, así que el resto de releases de una cuenta de un solo artista quedaron como same_account siendo el mismo dato).
  • Escenario D: quita solo lo dudoso. Bilbo queda en 1.828.

Vista MAPA

#/mapa, #/mapa/:lugar, con los mismos filtros que ARCHIVO (busqueda.filtra, que gana rango desde/hasta compartido) más territorio y procedencia. URLs compartibles, atrás/adelante y recarga conservan el estado.

Mapa propio, sin cartografía comercial: retícula de celdas de ~5 km generada en build desde los núcleos del nomenclátor, marcadores cuadrados cuyo tamaño es la cantidad documentada y escala absoluta (un cuadrado significa lo mismo con y sin filtros; un «fantasma» muestra el total sin filtrar).

Escritorio: cabecera compacta, una línea de filtros con desplegables, chips de lo activo, una línea de cobertura con la metodología plegada, y mapa (~65 %) + panel de contexto (~35 %) que entran sin scroll. Panel de municipio mínimo (cifras, 6 tags, 4 releases) con Artistas, Releases, Sellos, Estadísticas y Procedencia en secciones plegadas; panel de tag con el reparto por municipio.

Móvil (≤ 760 px, modo propio, no la versión encogida): mapa acotado (~46 vh) que orienta y selecciona, con gestos (un dedo desplaza, dos acercan) y botones +/−/⟲; solo 5 rótulos en la vista general (Bilbo, Donostia, Gasteiz, Iruñea, Baiona) y más al acercar o por territorio; hoja inferior de tres estados (asomada / media a 42 vh / expandida) con tirador arrastrable, que se abre al seleccionar dejando el municipio visible en el mapa; modo Mapa | Lista con el ranking de municipios respetando los filtros; metodología como capa.

El lima queda reservado a selección y estado activo, y la procedencia solo se dibuja si se activan datos débiles.

Cobertura del dataset

Releases %
direct 4.953 65,4
same_account 1.486 19,6
artist_inferred 83 1,1
region_only 558 7,4
outside_scope 286 3,8
tag_hint 36 0,5
unresolved 166 2,2

Por territorio (escenario A): Bizkaia 3.003 · Gipuzkoa 1.894 · Nafarroa 961 · Araba 586 · Iparralde 78. Sin resolver: 141 porque Bandcamp no da ubicación, 22 con evidencia descartada y 3 sin evidencia. Contradicciones registradas: 33, todas por tags que apuntan a otro municipio. Lo que no tiene municipio se cuenta en la interfaz, no se esconde.

Limitaciones conocidas

  • La ubicación es la de la cuenta que publica, no la del artista, y es la actual: no es residencia ni reconstrucción histórica. Filtrar por año filtra releases.
  • Cuentas con varios artistas (probables sellos): sitúan 2.026 releases en el escenario A. Sus 618 inferencias quedan fuera por defecto, pero las directas de esas cuentas sí se dibujan (1.345): un disco publicado por un sello aparece en la ciudad del sello. El panel del municipio lo dice y la sección «Sellos y cuentas» las lista.
  • El índice de sellos es heurístico (cuentas con ≥2 artistas o léxico de sello), así que incluye splits y recopilatorios: por eso la interfaz dice «probables sellos».
  • Concentraciones que dependen mucho de una cuenta: Santurtzi 53 % (muertematarrecords), Irun 43 % (petruskarecords), Zarautz 35 % (zaratazarautz).
  • El lift con pocas releases es inestable (umbrales: 3 en el lugar y 10 en el archivo); describe el archivo, no la escena.
  • Pendiente de revisión humana: 27 releases con topónimo del ámbito y país incoherente (Navarre, Florida, Pamplona, Colombia, Irun, Nigeria…) y Afghanistan (24 releases del sello Mendeku Diskak), marcadas y fuera del mapa. Detalle en data/locations/reports/review.md.
  • Iparralde está poco poblado (78 releases): el catálogo nació en Bilbao y la oleada 2 sigue en cola.
  • resolutions.json pesa 3,3 MB: es para trazabilidad, la app no lo carga.

Tests y build

  • python3 -m unittest discover tests: 24 OK (preservación de band_location, aliases, ISO 3166-2, region_only, fuera de ámbito, colisiones, conflictos, sellos que no contaminan al artista).
  • npm test (node --test, sin dependencias nuevas): 12 OK (rutas, URLs, filtros combinados, escenario D, densidad de etiquetas, encaje del zoom, lift).
  • npm run lint limpio y npm run build correcto.
  • Nuevo workflow Tests en cada PR: tests de Python, guardia de ubicaciones, comprobación de que los derivados están al día (son deterministas, verificado con distintos PYTHONHASHSEED) y tests + lint + build de la app.
  • Simulado en un worktree limpio: CI completa y el ensamblado del deploy (7.568 stubs y map_index en assets). Probado en navegador a 1440×900 y 375 px: rutas, selección, filtros, atrás/adelante, modo lista y activación de multiartista.

Documentación

Después de fusionar

Al incorporar los candidatos de #65 y #66 hay que ejecutar python3 scripts/locations.py all y commitear los derivados; si no, el workflow Tests lo marca.

🤖 Generated with Claude Code

Bu-chip and others added 13 commits September 19, 2026 22:38
…(fase 0)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… canónico (fase 1)

- data/locations/observations/: evidencia cruda por lote (un fichero por
  fichero de candidatos, sin normalizar, con fuente, cuenta, URL y fecha).
- scripts/locations.py ingest/check + locations_lib.py (funciones puras).
- discover_tags.py registra observaciones en cada checkpoint; el workflow
  mensual las incluye en el PR de candidatos.
- Guardia check + tests (unittest) y workflow Tests en PR y main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…fase 2)

locations.py recover lee data/candidates_*.json del árbol y todas sus
versiones en ramas locales y remote-tracking (candidates/2026-08, 2026-09,
discovery-state, smoke) sin tocar el remoto. Unión sin pérdidas, valores
crudos, procedencia por observación e informe reproducible en
data/locations/reports/recover.{md,json}: 5.181 releases con ubicación
directa, 124 consultadas sin ubicación, 2.263 sin información, 0
contradicciones.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…solución y auditoría (fases 3–6, código)

- scrape: una ficha por cuenta sin evidencia (<span class=location>, JSON-LD
  byArtist/publisher), caché reanudable, presupuesto y ritmo del scraper
  existente, respaldo a la portada de la cuenta si los discos dan 404.
- gazetteer/places: nomenclátor de Wikidata (INE P772 + CAPB para Iparralde,
  P625, municipios disueltos como núcleos) y registro controlado de 684
  municipios con alias oficiales bilingües y núcleos.
- normalize: categorías resolved/region_only/ambiguous/outside_scope/
  unexpected/invalid/unresolved + informe de revisión; reglas en rules.json.
- resolve: manual > direct > same_account > artist_inferred > región/fuera >
  tag_hint > unresolved; sellos no propagan al artista; contradicciones y
  valores descartados trazados.
- audit/query/build: auditoría, cruces municipio × tag con lift documentado
  e índice compacto del mapa con silueta en retícula.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… auditado (fases 3–6)

- 638 peticiones (una ficha por cuenta sin evidencia): 621 con ubicación,
  10 sin ella; caché reanudable y observaciones en bandcamp_pages.json.
- Reglas: códigos ISO del selector de Bandcamp (NC = Navarra, CT =
  Cataluña), lugares fuera de ámbito, Afghanistan como no literal.
- Resultado: 6.522/7.568 releases en el mapa (86,2 %), 6.439 sin inferencia,
  104 municipios; 558 solo región, 286 fuera, 166 sin resolver, 36 pistas.
- Auditoría en docs/mapa-data-audit.md y tests de regresión sobre el
  registro real.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…–17)

- #/mapa[/:lugar] con los MISMOS filtros que ARCHIVO (busqueda.filtra, que
  gana rango desde/hasta compartido) + territorio y procedencia; URLs
  compartibles, atrás/adelante, from/to aceptados al leer.
- Retícula de puntos cuadrados generada desde el nomenclátor (sin mapas
  externos), marcadores por municipio con escala absoluta, fantasma del
  total sin filtros, procedencia en relleno/borde (nunca opacidad).
- Paneles de municipio (procedencia, tags principales y sobrerrepresentados
  con lift documentado, artistas, releases → mini-ficha), de tag (reparto
  por municipio con lift a filtros iguales) y general; contadores de huecos
  siempre visibles; recorrido año a año sin llenar el historial.
- Índice precalculado (~125 KB, referencias por id) cargado solo en MAPA;
  consultas cacheadas por clave de filtros.
- Tests node --test (rutas, filtros combinados, agregación, lift), CI de
  tests + derivados al día, docs/mapa.md y README.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…al canónico

- discover-tags.yml: el ingest se hace en el paso de descubrimiento (checkout
  de main); el paso del PR trabaja sobre ramas con scripts antiguos. No
  bloqueante: la guardia check del workflow Tests cubre el fallo.
- normalize solo cuenta evidencia de releases/cuentas del canónico: un PR
  de candidatos no desactualiza los derivados; se regeneran al fusionar.
- Desempates alfabéticos explícitos (el orden de un set de cadenas cambia
  entre procesos): salida idéntica con distintos PYTHONHASHSEED.
- recover informa solo de lo recuperado del histórico (discover_web).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
python3 scripts/multiartist_audit.py (solo lectura) mide qué parte del mapa
depende de cuentas con varios artistas: 618 inferencias (9,5 %) más 1.345
directas. Escenario D (sin esas inferencias): 5.904 releases, 78 % del
catálogo, 104 municipios.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… por capas

- Escenario D por defecto: se dibujan directas + misma cuenta de un solo
  artista + inferidas por artista (5.904 releases, 104 municipios). Las
  inferencias desde cuentas multiartista (618) y las pistas de tag (36)
  quedan fuera pero se activan en «Más filtros» o con ?ubic=dcamt. Los datos
  y la resolución no cambian.
- map_index incorpora la cuenta de cada release (marca de multiartista).
- Cabecera compacta en MAPA; filtros en una línea con desplegables; chips de
  lo activo; cobertura en una línea con metodología plegable; mapa 65 % y
  panel 35 % del alto de la ventana, sin scroll inicial.
- Rótulos por densidad (7 en Euskal Herria, 18 por territorio, capitales
  primero); territorios al fondo; lima solo para selección y estado activo;
  leyenda mínima; la procedencia solo se dibuja con datos débiles activados.
- Panel de municipio mínimo (cifras, 6 tags, 4 releases) con artistas,
  releases, sellos, estadísticas y procedencia en secciones plegadas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ra el detalle

- useMovil: la vista móvil se estructura distinto, no se encoge.
- Mapa acotado (~46vh) con gestos (un dedo desplaza, dos acercan), botones
  +/−/⟲ y encuadre siempre dentro del mapa (encajaVista, con tests).
- Rótulos por densidad: 5 capitales en la vista general móvil, hasta 14 al
  acercar o por territorio (maxEtiquetas, con tests); solo los visibles.
- Hoja inferior de tres estados (asomada/media/expandida) con tirador
  arrastrable y línea-resumen; se abre al seleccionar, el mapa sigue visible.
- Modo Mapa | Lista con el ranking de municipios y los filtros activos.
- Metodología como capa en móvil; cabecera y filtros compactos; anillo en el
  municipio seleccionado y blancos táctiles de 34 px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… scroll en filtros

- Asomada: 62 px, asa 52×4 al 70 %, nombre en negrita, glifo ▴/▾ y realce
  lima al pulsar: se lee como control y no como pie estático.
- Media 46vh → 42vh: a 46vh la hoja tapaba el municipio recién seleccionado
  en el sur (Tutera quedaba en 440-447 px con la hoja desde 438). Ahora el
  marcador más bajo del mapa (447) queda por encima del borde (471).
- Filtros: velo de papel pegado al borde derecho (sticky ::after) que
  difumina el botón que asoma; sin textos ni flechas añadidas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La rama candidates/smoke no aporta evidencia propia (sus 12 filas están
también en los candidatos del mes y ninguna está en el canónico): recover
la ignora y su fichero sale del repo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Bu-chip
Bu-chip merged commit a5cf21c into main Sep 20, 2026
1 check passed
@Bu-chip
Bu-chip deleted the feat/mapa branch September 20, 2026 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant