perf(f1): cache-guard schema introspect + F1 toolbox in skill (~-5 min per session)
Transcript analysis (session 2026-07-06-175012, GLM 5.2) showed F1 at 567s: 182s wasted on a useless `tht schema introspect` (re-introspecting the remote DWH although physical.yaml was already materialized) plus ~220s of model thinking inflated by ~7 exploratory turns (--help/find/cat). The actual searches cost ~15s; reviewer gates (~145s, untouched) are the quality contract. - schema_cmd.py: introspect now exits 0 with "OK (cache)" in ~1s when physical.yaml exists; --refresh forces the real re-introspection. Deterministic cross-model guarantee, verified live on psd (163 tables, 1.2s). - SKILL.md: F1 toolbox (only `tht search find` + `tht schema render`; no introspect/--help/filesystem browsing; batch all searches in one turn); F4 step 1 is render-only with a one-shot introspect fallback. - tht-gate.js: `tht schema introspect ... --refresh` added to FORBIDDEN (maintenance stays shell-only, never in-session). - tests: 4 new pytest cases (cache hit placement proven with fake credentials, refresh bypass, corrupt-catalog fall-through, render fallback message) and 2 gate anti-bypass JS cases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,9 +30,40 @@ def annotations_path(cfg) -> Path:
|
||||
|
||||
|
||||
@schema_app.command("introspect")
|
||||
def introspect_cmd(config: Path = CONFIG_OPT) -> None:
|
||||
"""Introspeziona lo schema target e genera artifacts/mschema/physical.yaml."""
|
||||
def introspect_cmd(
|
||||
config: Path = CONFIG_OPT,
|
||||
refresh: bool = typer.Option(
|
||||
False,
|
||||
"--refresh",
|
||||
help="Forza la re-introspezione del DWH anche se physical.yaml esiste già.",
|
||||
),
|
||||
) -> None:
|
||||
"""Introspeziona lo schema target e genera artifacts/mschema/physical.yaml.
|
||||
|
||||
Se physical.yaml esiste già, esce subito (cache); usa --refresh per rigenerarlo.
|
||||
"""
|
||||
cfg = _load_config_or_exit(config)
|
||||
out = physical_path(cfg)
|
||||
if out.exists() and not refresh:
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from tht.mschema.models import PhysicalSchema
|
||||
|
||||
try:
|
||||
cached = PhysicalSchema.from_yaml(out)
|
||||
except Exception:
|
||||
pass # catalogo illeggibile: procedi con la re-introspezione
|
||||
else:
|
||||
ts = cached.introspected_at
|
||||
if ts.tzinfo is None:
|
||||
ts = ts.replace(tzinfo=UTC)
|
||||
age_days = (datetime.now(UTC) - ts).days
|
||||
typer.secho(
|
||||
f"OK (cache): {out} esistente ({len(cached.tables)} tabelle, "
|
||||
f"età {age_days}g). Re-introspezione solo con --refresh (manutenzione).",
|
||||
fg=typer.colors.GREEN,
|
||||
)
|
||||
return
|
||||
if cfg.database.transport == "rest":
|
||||
from tht.db.introspect import introspect_rest
|
||||
from tht.db.sampling import add_examples_rest
|
||||
@@ -59,7 +90,6 @@ def introspect_cmd(config: Path = CONFIG_OPT) -> None:
|
||||
except (OperationalError, IntrospectionError) as e:
|
||||
typer.secho(f"ERRORE: {e}", fg=typer.colors.RED, err=True)
|
||||
raise typer.Exit(code=1)
|
||||
out = physical_path(cfg)
|
||||
phys.to_yaml(out)
|
||||
n_cols = sum(len(t.columns) for t in phys.tables.values())
|
||||
n_ignored = sum(
|
||||
|
||||
Reference in New Issue
Block a user