"""G2 runtime contract and SQL SSOT regression checks.""" from __future__ import annotations import re import unittest from pathlib import Path from .runtime_schema import OUTCOME_TRAJECTORY_SCHEMA_CONTRACT REPO_ROOT = Path(__file__).resolve().parents[3] SQL = (REPO_ROOT / "infra" / "db" / "init" / "08_outcome_trajectory.sql").read_text( encoding="utf-8" ) class OutcomeTrajectorySchemaTest(unittest.TestCase): def test_runtime_contract_is_owned_by_g2_sql(self) -> None: contract = OUTCOME_TRAJECTORY_SCHEMA_CONTRACT for relation in contract.relations: self.assertRegex( SQL, rf"CREATE TABLE IF NOT EXISTS\s+{re.escape(relation)}\b", msg=f"missing relation {relation}", ) for name in contract.columns: column = name.split(".")[-1] self.assertRegex(SQL, rf"\b{re.escape(column)}\b", msg=f"missing {name}") for name in contract.policies: schema, table, policy = name.split(".") self.assertRegex( SQL, rf"CREATE POLICY\s+{re.escape(policy)}[\s\S]*?ON\s+{schema}\.{table}\b", msg=f"missing policy {name}", ) for name in contract.triggers: schema, table, trigger = name.split(".") self.assertRegex( SQL, rf"CREATE TRIGGER\s+{re.escape(trigger)}[\s\S]*?ON\s+{schema}\.{table}\b", msg=f"missing trigger {name}", ) for name in contract.indexes: _schema, _table, index = name.split(".") self.assertRegex( SQL, rf"CREATE UNIQUE INDEX IF NOT EXISTS\s+{re.escape(index)}\b", msg=f"missing index {name}", ) def test_revision_and_observation_ledgers_are_append_only(self) -> None: for trigger in ( "trg_outcome_trajectory_revision_append_only", "trg_outcome_trajectory_observation_append_only", "trg_relationship_memory_event_append_only", "trg_relationship_memory_projection_append_only", ): self.assertIn(trigger, SQL) self.assertIn("UNIQUE (supersedes_revision_id)", SQL) self.assertNotIn("p_outcome_trajectory_revision_update", SQL) self.assertNotIn("p_outcome_trajectory_observation_update", SQL) def test_safety_is_not_stored_as_an_outcome_feature(self) -> None: revision_block = SQL.split( "CREATE TABLE IF NOT EXISTS app.outcome_trajectory_revision", 1 )[1].split( "CREATE TABLE IF NOT EXISTS app.outcome_trajectory_observation", 1 )[0] self.assertNotIn("safety", revision_block.lower()) def test_role_private_memory_text_is_in_projection_table(self) -> None: event_block = SQL.split( "CREATE TABLE IF NOT EXISTS app.relationship_memory_event", 1 )[1].split( "CREATE TABLE IF NOT EXISTS app.relationship_memory_projection", 1 )[0] self.assertNotIn("summary", event_block) self.assertIn("summary TEXT NOT NULL", SQL) self.assertIn("ai_view = current_setting('app.current_ai_view', true)", SQL) def test_expected_arc_is_explicitly_synthetic_and_nonclinical(self) -> None: self.assertIn("data_classification = 'synthetic_educational'", SQL) self.assertIn("clinical_claim_allowed = FALSE", SQL) self.assertIn("jsonb_array_length(expected_arc->'distributions') = 15", SQL) def test_learner_submission_has_idempotency_and_turn_ownership_guards(self) -> None: self.assertIn("vignette-session-outcome-checkin", SQL) self.assertIn("ck_measurement_event_outcome_submission_metadata", SQL) self.assertIn("uq_measurement_event_outcome_submission_axis", SQL) self.assertIn("trg_outcome_submission_turn_ownership", SQL) self.assertIn( "outcome submission evidence turns must belong to its session", SQL ) self.assertIn( "relationship memory evidence turns must belong to its session", SQL ) if __name__ == "__main__": unittest.main()