feat: implement memory and evidence administration with guided repairs
Publish documentation / publish (push) Successful in 1m27s

Add PostgreSQL-backed memory, editable evidence with source review and activation, and human-approved archive repairs across the harness, API, and UI. Include migrations, deployment support, regression coverage, and validation documentation.

Refresh permissions from validated session roles so existing administrator logins can access newly deployed archive management features.
This commit is contained in:
Codex
2026-09-10 10:31:34 +02:00
parent 8fe526dd6e
commit 82e2c91f42
168 changed files with 11914 additions and 1772 deletions
+18 -49
View File
@@ -2,7 +2,6 @@ from __future__ import annotations
import hashlib
import json
from datetime import UTC, datetime
from pathlib import Path
from types import SimpleNamespace
@@ -10,7 +9,6 @@ import pytest
from typer.testing import CliRunner
from tht.cli import app
from tht.memory import MemoryRecord, save_registry
from tht.ports.vector import VectorStoreError
@@ -102,22 +100,6 @@ def _write_catalog_snapshot(tmp_path: Path) -> None:
}))
def _memory_record() -> MemoryRecord:
return MemoryRecord(
id="mem-0001",
ts=datetime(2026, 1, 1, tzinfo=UTC),
session_id="s1",
decision_seq=7,
type="concept_clarified",
subject="paziente attivo",
detail="flag_attivo = TRUE",
rationale="r",
question_context="dammi i pazienti attivi",
tables=[],
concepts=["paziente attivo"],
)
def test_vector_index_schema_accepts_qdrant_only_runtime_config(tmp_path, monkeypatch):
cfg = _qdrant_runtime_config(tmp_path)
_write_catalog_snapshot(tmp_path)
@@ -196,42 +178,29 @@ def test_vector_index_schema_json_failure_is_pristine(tmp_path, monkeypatch):
}
def test_memory_promote_accepts_qdrant_only_runtime_config(tmp_path, monkeypatch):
def test_memory_promote_adapts_qdrant_runtime_to_authoritative_service(tmp_path, monkeypatch):
cfg = _qdrant_runtime_config(tmp_path)
store = _FakeVectorStore()
promoted = [_memory_record()]
snapshot = SimpleNamespace(manifest=SimpleNamespace(id="s1"))
snapshot = object()
calls = []
service = SimpleNamespace(close=lambda: None, promote=lambda source, seqs:
calls.append((source, seqs)) or [{"indexed": True, "card": {"id": "mem-test"}}])
monkeypatch.setattr("tht.cli.memory_cmd.load_snapshot_or_exit", lambda cfg, session: snapshot)
monkeypatch.setattr("tht.memory.promote_snapshot", lambda *args, **kwargs: promoted)
monkeypatch.setattr("tht.memory.load_registry", lambda path: promoted)
monkeypatch.setattr("tht.adapters.factory.build_vector_store", lambda cfg, require_write: store)
monkeypatch.setattr("tht.cli.vector_cmd.make_embedder", lambda _: _FakeEmbedder())
res = CliRunner().invoke(
app,
["memory", "promote", "--session", "s1", "--decision", "7", "--json", "-c", str(cfg)],
)
assert res.exit_code == 0, res.output
assert json.loads(res.stdout)["indexed"] is True
assert store.upserts
monkeypatch.setattr("tht.cli.memory_cmd.memory_service", lambda cfg: service)
result = CliRunner().invoke(app, [
"memory", "promote", "--session", "s1", "--decision", "7", "--json", "-c", str(cfg),
])
assert result.exit_code == 0, result.output
assert json.loads(result.stdout)["indexed"] is True
assert calls == [(snapshot, [7])]
def test_memory_index_accepts_qdrant_only_runtime_config(tmp_path, monkeypatch):
def test_memory_index_rebuilds_only_through_authoritative_service(tmp_path, monkeypatch):
cfg = _qdrant_runtime_config(tmp_path)
store = _FakeVectorStore()
records = [_memory_record()]
save_registry(records, tmp_path / "artifacts" / "memory" / "registry.jsonl")
monkeypatch.setattr("tht.adapters.factory.build_vector_store", lambda cfg, require_write: store)
monkeypatch.setattr("tht.cli.vector_cmd.make_embedder", lambda _: _FakeEmbedder())
res = CliRunner().invoke(app, ["memory", "index", "-c", str(cfg)])
assert res.exit_code == 0, res.output
assert "OK:" in res.output
assert store.upserts
service = SimpleNamespace(close=lambda: None, rebuild=lambda: [{"indexed": True}])
monkeypatch.setattr("tht.cli.memory_cmd.memory_service", lambda cfg: service)
result = CliRunner().invoke(app, ["memory", "index", "--json", "-c", str(cfg)])
assert result.exit_code == 0, result.output
assert json.loads(result.stdout) == [{"indexed": True}]
def test_vector_help_exposes_only_the_supported_qdrant_command():