from datetime import UTC, datetime import pytest from pydantic import ValidationError from tht.corpus.models import CanonicalChunk, CanonicalDocument, CorpusManifest def document(source_uri: str = "https://host/a.md") -> CanonicalDocument: return CanonicalDocument( document_id="doc:abc", source_id="source:a", source_uri=source_uri, source_fingerprint="etag:abc", content_hash="sha256:def", title="A", content="# A", media_type="text/markdown", pipeline_version="normalize-v1", ) def chunk() -> CanonicalChunk: return CanonicalChunk( chunk_id="chunk:abc:0", document_id="doc:abc", ordinal=0, content="# A", content_hash="sha256:def", source_uri="https://host/a.md", pipeline_version="chunk-v1", ) def test_manifest_contains_provenance_without_credentials(): manifest = CorpusManifest( manifest_id="manifest:abc", created_at=datetime(2026, 7, 12, tzinfo=UTC), pipeline_version="evidence-v1", embedding_model="nomic-embed-text", embedding_dimensions=768, documents=[document()], chunks=[chunk()], ) payload = manifest.model_dump_json() assert "https://host/a.md" in payload assert "etag:abc" in payload assert "evidence-v1" in payload assert "nomic-embed-text" in payload assert "api_key" not in payload def test_manifest_can_be_assembled_before_publish_identifiers_are_assigned(): manifest = CorpusManifest(documents=[document()]) assert manifest.documents[0].source_uri == "https://host/a.md" assert manifest.manifest_id is None @pytest.mark.parametrize("model", [document(), chunk()]) def test_canonical_records_are_frozen(model): with pytest.raises(ValidationError): model.pipeline_version = "changed" # type: ignore[misc] def test_manifest_collections_have_independent_defaults(): first = CorpusManifest( manifest_id="one", created_at=datetime.now(UTC), pipeline_version="v1" ) second = CorpusManifest( manifest_id="two", created_at=datetime.now(UTC), pipeline_version="v1" ) first.documents.append(document()) assert second.documents == [] def test_manifest_validates_embedding_compatibility_fields(): with pytest.raises(ValidationError): CorpusManifest( manifest_id="bad", created_at=datetime.now(UTC), pipeline_version="v1", embedding_dimensions=0, ) def test_canonical_metadata_rejects_secrets_and_non_json_values(): with pytest.raises(ValidationError, match="credential-like"): CanonicalDocument.model_validate( {**document().model_dump(), "metadata": {"password": "secret"}} ) with pytest.raises(ValidationError): CanonicalChunk( chunk_id="c", document_id="d", ordinal=0, content="x", content_hash="sha256:x", source_uri="file:///x", pipeline_version="v1", metadata={"bad": object()}, )