fix: complete P2 Task 2 schema machine contracts

This commit is contained in:
2026-08-11 05:38:25 +02:00
parent b235132d89
commit 554de4ff2f
4 changed files with 356 additions and 30 deletions
+91 -13
View File
@@ -1,9 +1,14 @@
# ruff: noqa: BLE001
from pathlib import Path
from typing import TypedDict
import typer
from tht.cli._guards import require_server_profile, require_vector_write_allowed
from tht.cli._guards import (
has_vector_write_rest,
require_server_profile,
require_vector_write_allowed,
)
from tht.cli.config_cmd import CONFIG_OPT
from tht.cli.schema_cmd import _load_config_or_exit, annotations_path, physical_path
from tht.ports.vector import VectorWriteRecord
@@ -117,20 +122,63 @@ def init_cmd(
)
def index_schema_data(config: Path) -> dict:
class _MachineVectorError(Exception):
"""Expected vector CLI failure with a stable machine-readable code."""
def __init__(self, code: str):
self.code = code
super().__init__(code)
class IndexCounts(TypedDict):
added: int
updated: int
deleted: int
unchanged: int
class IndexSchemaResult(TypedDict):
status: str
code: str
counts: IndexCounts
def _vector_cfg_or_error(cfg) -> None:
missing = []
if cfg.embeddings is None:
missing.append("embeddings")
if cfg.vectors is None:
missing.append("vectors")
if missing:
raise _MachineVectorError("vector_configuration_missing")
def _vector_write_or_error(cfg) -> None:
if cfg.profile == "workstation" and not has_vector_write_rest(cfg):
raise _MachineVectorError("vector_write_not_allowed")
def index_schema_data(config: Path) -> IndexSchemaResult:
"""Synchronize schema records and return a bounded machine result."""
from tht.cli.schema_cmd import _machine_config
from tht.mschema.models import Annotations, PhysicalSchema
from tht.vectorstore.records import schema_records
cfg = _machine_config(config)
require_vector_write_allowed(cfg, "vector index-schema")
require_vector_cfg(cfg)
try:
cfg = _machine_config(config)
except Exception:
# Keep this helper free of Typer rendering while preserving a stable code.
raise _MachineVectorError("invalid_configuration") from None
_vector_write_or_error(cfg)
_vector_cfg_or_error(cfg)
phys_file = physical_path(cfg)
if not phys_file.exists():
raise ValueError("physical schema missing")
physical = PhysicalSchema.from_yaml(phys_file)
annotations = Annotations.from_yaml(annotations_path(cfg))
raise _MachineVectorError("physical_schema_missing")
try:
physical = PhysicalSchema.from_yaml(phys_file)
annotations = Annotations.from_yaml(annotations_path(cfg))
except Exception:
raise _MachineVectorError("schema_artifacts_invalid") from None
records = schema_records(physical, annotations)
from tht.adapters.factory import build_vector_store
@@ -158,14 +206,44 @@ def index_schema_cmd(
json_output: bool = typer.Option(False, "--json", help="Emetti JSON puro su stdout."),
) -> None:
"""Embedda e sincronizza i record schema (tabelle e colonne) nel semantic store."""
import json
if json_output:
try:
payload = index_schema_data(config)
except Exception:
payload = {"status": "failed", "code": "schema_index_failed"}
typer.echo(__import__("json").dumps(payload, sort_keys=True, separators=(",", ":")))
except _MachineVectorError as error:
typer.echo(json.dumps({"status": "failed", "code": error.code}, sort_keys=True, separators=(",", ":")))
raise typer.Exit(code=1) from None
typer.echo(__import__("json").dumps(payload, sort_keys=True, separators=(",", ":")))
except Exception:
typer.echo(json.dumps({"status": "failed", "code": "schema_index_failed"}, sort_keys=True, separators=(",", ":")))
raise typer.Exit(code=1) from None
typer.echo(json.dumps(payload, sort_keys=True, separators=(",", ":")))
return
payload = index_schema_data(config)
try:
payload = index_schema_data(config)
except _MachineVectorError as error:
_render_index_schema_error(error, config)
except Exception:
typer.secho("ERRORE: impossibile indicizzare lo schema.", fg=typer.colors.RED, err=True)
raise typer.Exit(code=1) from None
_print_stats(type("Stats", (), payload["counts"])())
def _render_index_schema_error(error: _MachineVectorError, config: Path) -> None:
"""Render expected failures without changing the old human CLI messages."""
cfg = _load_config_or_exit(config)
if error.code == "physical_schema_missing":
typer.secho(
f"ERRORE: {physical_path(cfg)} non trovato. Esegui prima `tht schema introspect`.",
fg=typer.colors.RED,
err=True,
)
elif error.code == "vector_configuration_missing":
require_vector_cfg(cfg)
elif error.code == "vector_write_not_allowed":
require_vector_write_allowed(cfg, "vector index-schema")
elif error.code == "schema_artifacts_invalid":
typer.secho("ERRORE: schema artifacts non validi.", fg=typer.colors.RED, err=True)
else:
typer.secho("ERRORE: impossibile indicizzare lo schema.", fg=typer.colors.RED, err=True)
raise typer.Exit(code=1) from None