from __future__ import annotations import re from pathlib import Path ROOT = Path(__file__).resolve().parents[3] MIGRATION_PATH = ROOT / "backend/migrations/versions/0002_model_profiles_and_invocations.py" MIGRATION = MIGRATION_PATH.read_text(encoding="utf-8") NORMALIZED = " ".join(MIGRATION.lower().split()) def _table_definition(name: str) -> str: pattern = re.compile(rf"(?ms)create table rag\.{re.escape(name)} \((.*?)^ \);") match = pattern.search(MIGRATION.lower()) assert match is not None, f"missing table definition: rag.{name}" return " ".join(match.group(1).split()) def test_revision_is_additive_after_initial_schema() -> None: assert 'revision: str = "0002_model_profiles"' in MIGRATION assert 'down_revision: str | none = "0001_initial_schema"' in MIGRATION.lower() revision_match = re.search(r'^revision: str = "([^"]+)"$', MIGRATION, re.MULTILINE) assert revision_match is not None assert len(revision_match.group(1)) <= 32 assert "alter table rag.chunks" in NORMALIZED assert "alter table rag.knowledge_bases" in NORMALIZED assert "drop table if exists rag.chunks" not in NORMALIZED assert "drop table if exists rag.knowledge_bases" not in NORMALIZED def test_model_profiles_have_governed_identity_and_dimension_contract() -> None: table = _table_definition("model_profiles") for column in ( "profile_hash char(64) primary key", "alias text not null", "kind text not null", "provider text not null", "model text not null", "api_mode text not null", "dimension smallint", "endpoint_identity_hash char(64) not null", "config_snapshot jsonb not null default '{}'::jsonb", "synthetic boolean not null default false", "enabled boolean not null default true", "created_at timestamptz not null default now()", "updated_at timestamptz not null default now()", ): assert column in table assert "model_profiles_alias_key unique (alias)" in table assert "model_profiles_hash_kind_key unique (profile_hash, kind)" in table assert "kind in ('embedding', 'rerank', 'chat')" in table assert "kind = 'embedding' and dimension = 1024" in table assert "kind in ('rerank', 'chat') and dimension is null" in table assert "profile_hash ~ '^[0-9a-f]{64}$'" in table assert "endpoint_identity_hash ~ '^[0-9a-f]{64}$'" in table assert "jsonb_typeof(config_snapshot) = 'object'" in table assert "model_profiles_config_snapshot_has_no_credentials" in table for credential_name in ( "api[_-]?key", "secret", "password", "token", "authorization", "credential", ): assert credential_name in table def test_knowledge_base_active_profile_is_nullable_and_restrictive() -> None: assert "add column active_embedding_profile_hash char(64)" in NORMALIZED assert ( "add column active_embedding_profile_kind text not null default 'embedding'" in NORMALIZED ) assert "knowledge_bases_active_embedding_profile_hash_format" in NORMALIZED assert "knowledge_bases_active_embedding_profile_kind" in NORMALIZED assert "check (active_embedding_profile_kind = 'embedding')" in NORMALIZED assert "knowledge_bases_active_embedding_profile_fk" in NORMALIZED assert ( "foreign key ( active_embedding_profile_hash, active_embedding_profile_kind )" in NORMALIZED ) assert "references rag.model_profiles (profile_hash, kind) on delete restrict" in NORMALIZED assert "active_embedding_profile_hash is null" in NORMALIZED def test_legacy_backfill_only_activates_one_unambiguous_searchable_fake_profile() -> None: assert "insert into rag.model_profiles" in NORMALIZED assert "chunk.searchable is true" in NORMALIZED assert "lower(chunk.embedding_model) like 'fake-%'" in NORMALIZED assert "chunk.embedding_dimension = 1024" in NORMALIZED assert "having count(distinct chunk.embedding_model) = 1" in NORMALIZED assert "'local-synthetic'" in NORMALIZED assert "'deterministic-offline'" in NORMALIZED assert "sha256(convert_to('local-fake', 'utf8'))" in NORMALIZED assert "'existing_searchable_fake_chunks'" in NORMALIZED assert "on conflict (profile_hash) do nothing" in NORMALIZED activation_start = NORMALIZED.index("with unique_searchable_fake_profile as") activation_end = NORMALIZED.index(") update rag.knowledge_bases", activation_start) candidate_query = NORMALIZED[activation_start:activation_end] assert "group by chunk.knowledge_base_id" in candidate_query assert "having count(distinct chunk.embedding_profile_hash) = 1" in candidate_query assert "limit 1" not in candidate_query assert "active_embedding_profile_hash is null" in NORMALIZED[activation_start:] def test_embedding_cache_is_profile_and_exact_text_keyed() -> None: table = _table_definition("embedding_cache") assert "profile_hash char(64) not null" in table assert "profile_kind text not null default 'embedding'" in table assert "embedding_text_sha256 char(64) not null" in table assert "embedding vector(1024) not null" in table assert "resolved_model text not null" in table assert "provider_request_id text" in table assert "usage jsonb not null default '{}'::jsonb" in table assert "elapsed_ms integer not null" in table assert "primary key (profile_hash, embedding_text_sha256)" in table assert "references rag.model_profiles (profile_hash, kind) on delete restrict" in table assert "profile_kind = 'embedding'" in table assert "vector_dims(embedding) = 1024" in table assert "jsonb_typeof(usage) = 'object'" in table def test_chunk_assignments_bind_chunk_text_profile_cache_and_state() -> None: table = _table_definition("chunk_embedding_assignments") assert "primary key (chunk_id, profile_hash)" in table assert "profile_kind text not null default 'embedding'" in table assert "foreign key (chunk_id, embedding_text_sha256)" in table assert "references rag.chunks (id, embedding_text_sha256) on delete cascade" in table assert "foreign key (profile_hash, profile_kind)" in table assert "references rag.model_profiles (profile_hash, kind) on delete restrict" in table assert "profile_kind = 'embedding'" in table assert "foreign key (cache_profile_hash, cache_embedding_text_sha256)" in table assert "references rag.embedding_cache (profile_hash, embedding_text_sha256)" in table assert "status in ('pending', 'embedding', 'ready', 'failed', 'stale')" in table assert "status = 'ready' and cache_profile_hash = profile_hash" in table assert "cache_embedding_text_sha256 = embedding_text_sha256" in table assert "status <> 'ready' and cache_profile_hash is null" in table assert "chunks_id_embedding_text_sha256_key" in NORMALIZED def test_invocation_audit_table_is_metadata_only() -> None: table = _table_definition("model_invocations") for field in ( "trace_id uuid not null", "caller text not null", "operation text not null", "profile_hash char(64) not null", "model text not null", "provider_request_id text", "status text not null", "item_count integer not null default 0", "prompt_tokens integer not null default 0", "completion_tokens integer not null default 0", "total_tokens integer not null default 0", "elapsed_ms integer", "error_code text", "started_at timestamptz not null default now()", "finished_at timestamptz", "created_at timestamptz not null default now()", ): assert field in table for forbidden_field in ( "api_key", "secret", "authorization", "credential", "endpoint", "url", "payload", "request_body", "response_body", "prompt_text", "query_text", "input_text", "output_text", "content", ): assert forbidden_field not in table assert "total_tokens = prompt_tokens + completion_tokens" in table assert "foreign key (profile_hash, operation)" in table assert "references rag.model_profiles (profile_hash, kind)" in table assert "status = 'succeeded' and error_code is null" in table assert "status = 'failed' and error_code is not null" in table assert "status = 'unknown' and error_code is not null" in table assert "status = 'started' and elapsed_ms is null" in table assert "status = 'started' and finished_at is null" in table def test_chunks_get_stable_citations_and_active_profile_filter_index() -> None: assert "add column citation_id uuid not null default gen_random_uuid()" in NORMALIZED assert "chunks_citation_id_key unique (citation_id)" in NORMALIZED assert "create index chunks_active_embedding_profile_filter" in NORMALIZED assert ( "on rag.chunks ( knowledge_base_id, embedding_profile_hash, access_scope_id ) " "where searchable" ) in NORMALIZED def test_downgrade_removes_dependents_before_profiles_and_added_columns() -> None: invocation_drop = NORMALIZED.index("drop table if exists rag.model_invocations") assignment_drop = NORMALIZED.index("drop table if exists rag.chunk_embedding_assignments") cache_drop = NORMALIZED.index("drop table if exists rag.embedding_cache") chunk_binding_drop = NORMALIZED.index( "drop constraint if exists chunks_id_embedding_text_sha256_key" ) knowledge_base_fk_drop = NORMALIZED.index( "drop constraint if exists knowledge_bases_active_embedding_profile_fk" ) profile_drop = NORMALIZED.index("drop table if exists rag.model_profiles") assert invocation_drop < profile_drop assert assignment_drop < cache_drop < chunk_binding_drop < profile_drop assert knowledge_base_fk_drop < profile_drop assert "drop column if exists citation_id" in NORMALIZED assert "drop column if exists active_embedding_profile_hash" in NORMALIZED assert "drop column if exists active_embedding_profile_kind" in NORMALIZED