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
+29 -3
View File
@@ -98,6 +98,19 @@ class ReviewItem(StrictModel):
field: str | None = None
class ManualEvidenceProvenance(StrictModel):
"""The curator supports the current content; an earlier document is only its origin."""
model_config = ConfigDict(extra="forbid", frozen=True)
kind: Literal["manual"] = "manual"
declared_by: str = Field(min_length=1)
original: EvidenceProvenance | None = None
@property
def source_file(self) -> str:
return f"Manual declaration: {self.declared_by}"
class FormulaPayload(StrictModel):
concept: str
columns: tuple[str, ...]
@@ -229,19 +242,23 @@ _EVIDENCE_ID = re.compile(r"^evidence:[a-z0-9]+(?:-[a-z0-9]+)*$")
class CuratedEvidence(StrictModel):
schema_version: Literal[1, 2, 3]
schema_version: Literal[1, 2, 3, 4]
id: str
title: str
kind: EvidenceKind
purposes: tuple[EvidencePurpose, ...]
applies_to: EvidenceScope = Field(default_factory=EvidenceScope)
language: str
provenance: EvidenceProvenance
provenance: EvidenceProvenance | ManualEvidenceProvenance
review_items: tuple[ReviewItem, ...] = ()
payload: EvidencePayload
@model_validator(mode="after")
def _validate_kind_payload(self) -> CuratedEvidence:
if isinstance(self.provenance, ManualEvidenceProvenance) and self.schema_version != 4:
raise ValueError("manual declarations require Curated unit schema v4")
if self.schema_version == 4 and (not self.purposes or not self.language.strip()):
raise ValueError("editable Evidence requires a language and at least one purpose")
if not is_evidence_id(self.id):
raise ValueError("id must use the evidence:<slug> form")
expected = _PAYLOAD_TYPE_BY_KIND.get(self.kind)
@@ -1056,13 +1073,19 @@ def parse_curated_markdown(text: str, *, path: Path | None = None) -> CuratedEvi
_, frontmatter, body = text.split("---\n", 2)
except ValueError as error:
raise ValueError("curated evidence frontmatter is malformed") from error
raw = yaml.safe_load(frontmatter)
try:
raw = yaml.safe_load(frontmatter)
except yaml.YAMLError as error:
raise ValueError("curated evidence frontmatter is malformed") from error
try:
data = dict(raw)
except (TypeError, ValueError) as error:
raise ValueError("curated evidence frontmatter must be a mapping") from error
if data.get("schema_version") == 2:
data = _parse_v2_body(data, body)
elif data.get("schema_version") == 4:
from tht.evidence.editable import parse_document, parse_metadata
data = parse_document(parse_metadata(frontmatter), body)
else:
if body.strip():
raise ValueError("curated evidence must not contain an ignored body")
@@ -1081,6 +1104,9 @@ def parse_curated_markdown(text: str, *, path: Path | None = None) -> CuratedEvi
def dump_curated_markdown(value: CuratedEvidence) -> str:
"""Render one canonical Curated Evidence Markdown document."""
if value.schema_version == 4:
from tht.evidence.editable import render_document
return render_document(value)
if value.schema_version == 3:
return f"{_render_v3_metadata(value)}\n{_render_v3_body(value)}"
if value.schema_version == 2: