Skip to content

fix(resolver): mart locali nello scan + perf find + discovery dir≠slug - #460

Merged
Gabrymi93 merged 3 commits into
mainfrom
fix/resolver-perf-marts-discovery
Aug 9, 2026
Merged

fix(resolver): mart locali nello scan + perf find + discovery dir≠slug#460
Gabrymi93 merged 3 commits into
mainfrom
fix/resolver-perf-marts-discovery

Conversation

@Gabrymi93

Copy link
Copy Markdown
Member

Tipo

root fix (3 problemi del resolver emersi da audit + prove cross-repo MCP).

Problema reale

  1. Mart locali non leggibili: _scan_workspace_parquets scansionava solo *_clean.parquet — i mart su disco (bologna/eurostat/DI, 479 file) non erano risolvibili in catalog mode. resolve_slug(layer='mart') mostrava solo i mart GCS. Inoltre la dedup (slug, year, bucket) faceva collidere 2 mart dello stesso dataset+anno con tabelle diverse (vinceva il primo).

  2. Find lento: _scan_workspace_parquets faceva rglob su tutti i repo del workspace (48 dir), inclusi project residui non-dati (open-conto-annuale 106 parquet, open-siope, out/, data/) → 3.8s al primo find di ogni istanza MCP. read_yaml (PyYAML ~7ms/file) riparsava 158 dataset.yml a ogni istanza.

  3. Discovery dir≠slug: resolve_config_path Stage 3 cercava {section}/{slug}/dataset.yml con lo slug letterale (underscore), ma le dir reali possono essere hyphen ≠ slug (es. eurostat-nrg-chddr2-a-nuts3 vs slug eurostat_nrg_chddr2_a_nuts3). Colpiva 3/39 dataset eurostat/bologna.

Contratto riusato/sostituito

  • Riusato: naming canonico pipeline mart_{table}.parquet (già usato dalla pipeline per scrivere); repo_dataset_dirs/euristica repo-dati (già usata da _scan_workspace_configs); il table filter di resolve_slug (già usato da toolkit_layer).
  • Sostituito: read_yaml senza cache → cache mtime-based.

Implementazione

File Cosa
toolkit/domain/catalog.py Scan mart locali (bucket local-mart, dedup con table, flat multi-anno year=None); filtro repo dati nello scan parquet; _matches_layer riconosce local-mart; escluso None da years (crash sorted)
toolkit/core/io.py Cache YAML mtime-based in read_yaml/read_yaml_or_none (keyed su path+mtime_ns+size)
toolkit/core/discovery.py resolve_config_path prova entrambe le forme slug (underscore/hyphen)
tests/test_catalog_ops.py 4 test mart (con anno, flat, skip non-data, resolve locale+gcs)
tests/test_paths.py 1 test dir≠slug

Verifica

  • Mart locali: centraline_aria risolve 2 mart locali + 2 GCS; spire_traffico 3 locali (2 per-anno + 1 flat multi-anno) + 3 GCS; query toolkit_layer table=mart_trend su eurostat funziona sul locale
  • Perf: find cold 3.8s → ~2.4s, secondo find ~0.8s (cache YAML); scan parquet 1.95s → 0.26s
  • Discovery: resolve_config_path('eurostat_nrg_chddr2_a_nuts3') ora risolve; casi standard invariati
  • 1329 test verdi, ruff pulito

Rischio residuo

  • I mart flat multi-anno locali (es. spire_traffico/mart_spire_trend.parquet senza anno) sono esposti con year=None — coerente col fatto che il registry GCS li pubblica flat.
  • bologna non è su GCS: il registry dichiara location gs:// inesistenti (35 file) — il resolver le espone come has_remote=True. Noto e fuori scope: fix al wrapper build_registry di bologna (derive_mode check-gcs), repo separato.
  • resolve_config_path risolve per dir (hyphen o underscore); non risolve slug presenti solo nel registry senza dir locale (es. chddr2_m) — serve la dir o il fallback registry.

Follow-up obbligatorio

  • Riavvio MCP per caricare i fix (cache resolver per istanza).
  • (repo bologna) --check-gcs nel wrapper per non committare location GCS inesistenti.

Cleanup audit: due file senza consumer reali.
- cmd_batch.py: comando 'toolkit batch' deprecato da tempo, sostituito da
  'toolkit run --batch' (cmd_run.py). Unico riferimento: registrazione in app.py.
- sql_dry_run.py: shim di reindirizzamento verso core.sql_validation;
  nessun import (cmd_run usa sql_validation direttamente).

Rimossa registrazione register_batch da app.py. Nessun test dipendeva dai
file rimossi (1324 verdi invariati), ruff pulito, zero riferimenti orfani.
Tre fix del resolver, emersi da audit e prove cross-repo:

1. mart locali: _scan_workspace_parquets scansionava solo *_clean.parquet —
   i mart locali (bucket local-mart, naming canonico mart_{table}.parquet)
   non erano risolvibili in catalog mode; dedup per (slug,year,bucket,table)
   per non collidere tabelle diverse; gestiti flat multi-anno (year=None).

2. perf find: scan parquet solo sui repo dati (registry/ o datasets/) —
   esclusi project residui (open-conto-annuale, out/, data/, ...) con
   rglob costosi; cache YAML mtime-based in read_yaml (PyYAML ~7ms/file,
   ~1.1s su 158 dataset.yml a ogni istanza).

3. discovery: resolve_config_path Stage 3 cercava {slug} letterale ma le
   dir possono essere hyphen ≠ slug underscore (es. eurostat-nrg-chddr2-a)
   — ora prova entrambe le forme. 3/39 dataset eurostat/bologna colpiti.

Test: +5 (scan mart con/flat/skip non-data, resolve mart locale+gcs,
resolve dir≠slug). 1329 verdi, ruff pulito.
…ionale)

CI: mypy falliva su catalog.py — dedup_key riusata con 3-tuple (clean) e
4-tuple (mart) e year None su variabile int. Variabili dedicate
(mart_slug/mart_year/mart_key) + tipo union per seen.
@Gabrymi93
Gabrymi93 merged commit f0a4973 into main Aug 9, 2026
3 checks passed
@Gabrymi93
Gabrymi93 deleted the fix/resolver-perf-marts-discovery branch August 9, 2026 09:16
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