fix: close task3 qdrant and config quality gaps
This commit is contained in:
@@ -420,16 +420,23 @@ class QdrantVectorStore:
|
||||
offset = None
|
||||
seen_offsets = set()
|
||||
while True:
|
||||
response = self._call(
|
||||
"POST",
|
||||
f"/collections/{self._collection}/points/scroll",
|
||||
{
|
||||
"with_payload": True,
|
||||
"limit": 10000,
|
||||
"filter": {"must": must},
|
||||
"offset": offset,
|
||||
},
|
||||
)
|
||||
try:
|
||||
response = self._call(
|
||||
"POST",
|
||||
f"/collections/{self._collection}/points/scroll",
|
||||
{
|
||||
"with_payload": True,
|
||||
"limit": 10000,
|
||||
"filter": {"must": must},
|
||||
"offset": offset,
|
||||
},
|
||||
)
|
||||
except VectorTransportError as exc:
|
||||
if self._collection_lifecycle == "require_existing" and exc.status_code == 404:
|
||||
raise SemanticIndexIncompatibleError(
|
||||
"Qdrant collection disappeared during semantic index reconciliation"
|
||||
) from exc
|
||||
raise
|
||||
result = response.get("result", {})
|
||||
page = result.get("points")
|
||||
if not isinstance(page, list):
|
||||
|
||||
@@ -537,6 +537,41 @@ def _format_validation_error(error: ValidationError) -> str:
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _validate_raw_config_shape(raw: dict[str, Any], path: Path) -> None:
|
||||
"""Reject unsafe YAML shapes before compatibility translation or sorting keys."""
|
||||
seen: set[int] = set()
|
||||
|
||||
def walk(value: Any, location: str) -> None:
|
||||
if isinstance(value, dict):
|
||||
marker = id(value)
|
||||
if marker in seen:
|
||||
return
|
||||
seen.add(marker)
|
||||
for key, item in value.items():
|
||||
if not isinstance(key, str):
|
||||
raise ConfigError(
|
||||
f"Configurazione non valida in {path}: mapping key at {location} "
|
||||
"must be a string"
|
||||
)
|
||||
walk(item, f"{location}.{key}")
|
||||
elif isinstance(value, list):
|
||||
for index, item in enumerate(value):
|
||||
walk(item, f"{location}[{index}]")
|
||||
|
||||
walk(raw, "configuration")
|
||||
resources = raw.get("resources")
|
||||
if "resources" in raw and not isinstance(resources, dict):
|
||||
raise ConfigError(
|
||||
f"Configurazione non valida in {path}: resources must be a mapping"
|
||||
)
|
||||
if isinstance(resources, dict):
|
||||
for name in ("vector", "embeddings"):
|
||||
if name in resources and not isinstance(resources[name], dict):
|
||||
raise ConfigError(
|
||||
f"Configurazione non valida in {path}: resources.{name} must be a mapping"
|
||||
)
|
||||
|
||||
|
||||
def load_config(path: Path) -> Config:
|
||||
if not path.exists():
|
||||
raise ConfigError(f"File di configurazione non trovato: {path}")
|
||||
@@ -546,6 +581,7 @@ def load_config(path: Path) -> Config:
|
||||
raise ConfigError(f"Configurazione YAML non valida: {path}") from exc
|
||||
if not isinstance(raw, dict):
|
||||
raise ConfigError(f"Configurazione non valida (atteso un mapping YAML): {path}")
|
||||
_validate_raw_config_shape(raw, path)
|
||||
expanded = _resolve_secret_files(_resolve_evidence_secret_files(_expand_env(raw)))
|
||||
_validate_internal_embedding_contract(expanded, path)
|
||||
_validate_internal_vector_contract(expanded, path)
|
||||
|
||||
Reference in New Issue
Block a user