967 lines
38 KiB
Python
967 lines
38 KiB
Python
"""Unit tests for scripts/apply_proposal.py.
|
|
|
|
Pure tests: exercise the SQL builders, payload validation, and dispatch without
|
|
a live database. Runnable under pytest or standalone (`python3 tests/test_apply_proposal.py`).
|
|
"""
|
|
|
|
import json
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
try:
|
|
import pytest
|
|
except ImportError: # standalone fallback so the file runs without pytest installed
|
|
import contextlib
|
|
import types
|
|
|
|
pytest = types.SimpleNamespace()
|
|
|
|
@contextlib.contextmanager
|
|
def _raises(exc):
|
|
try:
|
|
yield
|
|
except exc:
|
|
return
|
|
raise AssertionError(f"expected {exc.__name__} to be raised")
|
|
|
|
pytest.raises = _raises
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
|
|
import apply_proposal as ap # noqa: E402
|
|
|
|
CLAIM_A = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"
|
|
CLAIM_B = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
|
|
SOURCE_A = "cccccccc-cccc-4ccc-8ccc-cccccccccccc"
|
|
|
|
|
|
def _approval_meta(proposal_type, apply_payload):
|
|
return {
|
|
"proposal_type": proposal_type,
|
|
"payload": {"apply_payload": apply_payload},
|
|
"reviewed_by_handle": "m3ta",
|
|
"reviewed_by_agent_id": None,
|
|
"reviewed_at": "2026-07-10T00:00:00+00:00",
|
|
"review_note": "Reviewed exact strict payload.",
|
|
}
|
|
|
|
|
|
# --- literals ------------------------------------------------------------- #
|
|
def test_sql_literal_escapes_single_quotes():
|
|
assert ap.sql_literal("O'Brien") == "E'O''Brien'"
|
|
|
|
|
|
def test_sql_literal_escapes_backslashes_independently_of_session_mode():
|
|
assert ap.sql_literal("a\\b'c") == "E'a\\\\b''c'"
|
|
|
|
|
|
def test_sql_literal_none_is_null():
|
|
assert ap.sql_literal(None) == "null"
|
|
|
|
|
|
def test_sql_literal_bool_and_number():
|
|
assert ap.sql_literal(True) == "true"
|
|
assert ap.sql_literal(0.5) == "0.5"
|
|
|
|
|
|
# --- revise_strategy ------------------------------------------------------ #
|
|
def _revise_payload():
|
|
return {
|
|
"apply_payload": {
|
|
"agent_id": "11111111-1111-1111-1111-111111111111",
|
|
"strategy": {
|
|
"diagnosis": "Species-level inflection.",
|
|
"guiding_policy": "Build Teleo as a multi-agent public intelligence.",
|
|
"proximate_objectives": ["route before creating", "keep KB calibrated"],
|
|
},
|
|
"strategy_nodes": [
|
|
{"node_type": "diagnosis", "title": "Inflection", "body": "b1", "rank": 1},
|
|
{"node_type": "policy", "title": "Multi-agent PI", "body": "b2", "rank": 1},
|
|
],
|
|
}
|
|
}
|
|
|
|
|
|
def test_revise_strategy_sql_shape():
|
|
payload = _revise_payload()["apply_payload"]
|
|
sql = ap.build_revise_strategy_sql(payload, "pid-1", "kb-apply", _approval_meta("revise_strategy", payload))
|
|
assert sql.startswith("begin;")
|
|
assert sql.rstrip().endswith("commit;")
|
|
# deactivate old, insert versioned active, retire nodes, insert new nodes
|
|
assert "update public.strategies" in sql
|
|
assert "active = false" in sql
|
|
assert "coalesce(max(version), 0) + 1" in sql
|
|
assert "update public.strategy_nodes" in sql
|
|
assert "insert into public.strategy_nodes" in sql
|
|
# ledger + invariant
|
|
assert "kb_stage.finish_approved_proposal" in sql
|
|
assert "exactly one active strategy" in sql
|
|
# proximate_objectives rendered as jsonb
|
|
assert "::jsonb" in sql
|
|
|
|
|
|
def test_guarded_sql_canonicalizes_reviewed_timestamp_to_stable_utc_text():
|
|
payload = _revise_payload()["apply_payload"]
|
|
approval = _approval_meta("revise_strategy", payload)
|
|
approval["reviewed_at"] = "2026-07-10T02:00:00.1+02:00"
|
|
|
|
sql = ap.build_revise_strategy_sql(payload, "pid-1", "kb-apply", approval)
|
|
|
|
assert sql.count("2026-07-10T00:00:00.100000Z") == 2
|
|
assert "2026-07-10T02:00:00.1+02:00" not in sql
|
|
|
|
|
|
def test_guarded_sql_rejects_reviewed_timestamp_without_timezone():
|
|
payload = _revise_payload()["apply_payload"]
|
|
approval = _approval_meta("revise_strategy", payload)
|
|
approval["reviewed_at"] = "2026-07-10T00:00:00"
|
|
|
|
with pytest.raises(ValueError, match="timezone-aware ISO-8601"):
|
|
ap.build_revise_strategy_sql(payload, "pid-1", "kb-apply", approval)
|
|
|
|
|
|
def test_revise_strategy_requires_agent_id():
|
|
payload = _revise_payload()["apply_payload"]
|
|
del payload["agent_id"]
|
|
with pytest.raises(ValueError):
|
|
ap.build_revise_strategy_sql(payload, "pid-1", None, _approval_meta("revise_strategy", payload))
|
|
|
|
|
|
def test_revise_strategy_rejects_bad_node_type():
|
|
payload = _revise_payload()["apply_payload"]
|
|
payload["strategy_nodes"][0]["node_type"] = "manifesto"
|
|
with pytest.raises(ValueError):
|
|
ap.build_revise_strategy_sql(payload, "pid-1", None, _approval_meta("revise_strategy", payload))
|
|
|
|
|
|
# --- add_edge ------------------------------------------------------------- #
|
|
def test_add_edge_sql_dedup_guard():
|
|
payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supersedes", "weight": 0.9}
|
|
sql = ap.build_add_edge_sql(payload, "pid-2", None, _approval_meta("add_edge", payload))
|
|
assert "insert into public.claim_edges" in sql
|
|
assert "not exists" in sql
|
|
assert "::edge_type" in sql
|
|
assert "kb_stage.finish_approved_proposal" in sql
|
|
assert "pg_advisory_xact_lock" in sql
|
|
|
|
|
|
def test_add_edge_semantic_row_accepts_match_and_rejects_weight_mismatch():
|
|
payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supports", "weight": 0.9}
|
|
sql = ap.build_add_edge_sql(payload, "pid-2", None, _approval_meta("add_edge", payload))
|
|
verify = sql[sql.index("do $verify$") : sql.index("kb_stage.finish_approved_proposal")]
|
|
|
|
assert "weight is not distinct from 0.9" in verify
|
|
assert "weight is distinct from 0.9" in verify
|
|
assert "claim_edge row does not match strict apply payload" in verify
|
|
assert sql.startswith("begin;")
|
|
assert sql.rstrip().endswith("commit;")
|
|
assert sql.index("raise exception 'apply_proposal: claim_edge row") < sql.index("kb_stage.finish_approved_proposal")
|
|
|
|
|
|
def test_add_edge_rejects_self_loop():
|
|
payload = {"from_claim": "same", "to_claim": "same", "edge_type": "supports"}
|
|
with pytest.raises(ValueError):
|
|
ap.build_add_edge_sql(payload, "pid-2", None, _approval_meta("add_edge", payload))
|
|
|
|
|
|
# --- attach_evidence ------------------------------------------------------ #
|
|
def test_attach_evidence_sql_with_source_id():
|
|
payload = {"evidence": [{"claim_id": CLAIM_A, "source_id": SOURCE_A, "role": "grounds", "weight": 0.78}]}
|
|
sql = ap.build_attach_evidence_sql(payload, "pid-3", None, _approval_meta("attach_evidence", payload))
|
|
assert "insert into public.claim_evidence" in sql
|
|
assert "public.claim_evidence (id," not in sql
|
|
assert "public.claim_evidence (claim_id, source_id, role, weight)" in sql
|
|
assert "::evidence_role" in sql
|
|
assert "not exists" in sql
|
|
|
|
|
|
def test_attach_evidence_semantic_row_accepts_match_and_rejects_weight_mismatch():
|
|
payload = {"evidence": [{"claim_id": CLAIM_A, "source_id": SOURCE_A, "role": "grounds", "weight": 0.78}]}
|
|
sql = ap.build_attach_evidence_sql(payload, "pid-3", None, _approval_meta("attach_evidence", payload))
|
|
verify = sql[sql.index("do $verify$") : sql.index("kb_stage.finish_approved_proposal")]
|
|
|
|
assert "weight is not distinct from 0.78" in verify
|
|
assert "weight is distinct from 0.78" in verify
|
|
assert "evidence row % does not match strict apply payload" in verify
|
|
assert sql.startswith("begin;")
|
|
assert sql.rstrip().endswith("commit;")
|
|
assert sql.index("raise exception 'apply_proposal: evidence row") < sql.index("kb_stage.finish_approved_proposal")
|
|
|
|
|
|
def test_attach_evidence_requires_source_id():
|
|
payload = {"evidence": [{"claim_id": "cccc"}]}
|
|
with pytest.raises(ValueError):
|
|
ap.build_attach_evidence_sql(payload, "pid-3", None, _approval_meta("attach_evidence", payload))
|
|
|
|
|
|
# --- approve_claim canonical bundle -------------------------------------- #
|
|
def _approve_claim_bundle():
|
|
claim_a = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"
|
|
claim_b = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
|
|
source_a = "cccccccc-cccc-4ccc-8ccc-cccccccccccc"
|
|
source_b = "dddddddd-dddd-4ddd-8ddd-dddddddddddd"
|
|
return {
|
|
"contract_version": 2,
|
|
"agent_id": "11111111-1111-4111-8111-111111111111",
|
|
"claims": [
|
|
{
|
|
"id": claim_a,
|
|
"type": "structural",
|
|
"text": "Canonical claim A",
|
|
"status": "open",
|
|
"confidence": 0.8,
|
|
"tags": ["test", "working-leo"],
|
|
"created_by": None,
|
|
},
|
|
{
|
|
"id": claim_b,
|
|
"type": "concept",
|
|
"text": "Canonical claim B",
|
|
"status": "open",
|
|
"confidence": None,
|
|
"tags": [],
|
|
"created_by": None,
|
|
},
|
|
],
|
|
"sources": [
|
|
{
|
|
"id": source_a,
|
|
"source_type": "paper",
|
|
"url": "https://example.test/a",
|
|
"storage_path": None,
|
|
"excerpt": "Evidence A",
|
|
"hash": "hash-a",
|
|
"created_by": None,
|
|
},
|
|
{
|
|
"id": source_b,
|
|
"source_type": "observation",
|
|
"url": None,
|
|
"storage_path": None,
|
|
"excerpt": "Evidence B",
|
|
"hash": "hash-b",
|
|
"created_by": None,
|
|
},
|
|
],
|
|
"evidence": [
|
|
{"claim_id": claim_a, "source_id": source_a, "role": "grounds", "weight": 0.9},
|
|
{"claim_id": claim_b, "source_id": source_b, "role": "illustrates", "weight": None},
|
|
],
|
|
"edges": [{"from_claim": claim_a, "to_claim": claim_b, "edge_type": "supports", "weight": 0.7}],
|
|
"reasoning_tools": [
|
|
{
|
|
"id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
|
|
"agent_id": None,
|
|
"name": "Canonical test tool",
|
|
"description": "A strict reasoning-tool row.",
|
|
"category": "test",
|
|
}
|
|
],
|
|
}
|
|
|
|
|
|
def _approve_claim_v3_bundle():
|
|
agent_id = "11111111-1111-4111-8111-111111111111"
|
|
source_b = "dddddddd-dddd-4ddd-8ddd-dddddddddddd"
|
|
evidence_a = {
|
|
"id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
|
|
"claim_id": CLAIM_A,
|
|
"source_id": SOURCE_A,
|
|
"polarity": "supports",
|
|
"excerpt": "The primary record supports claim A.",
|
|
"locator_json": {"section": "A", "paragraph": 1},
|
|
"source_content_hash": "a" * 64,
|
|
"rationale": "The cited paragraph directly supports the bounded proposition.",
|
|
"created_by": agent_id,
|
|
}
|
|
evidence_b = {
|
|
"id": "ffffffff-ffff-4fff-8fff-ffffffffffff",
|
|
"claim_id": CLAIM_B,
|
|
"source_id": source_b,
|
|
"polarity": "challenges",
|
|
"excerpt": "The primary record challenges claim B.",
|
|
"locator_json": {"section": "B", "paragraph": 2},
|
|
"source_content_hash": "b" * 64,
|
|
"rationale": "The cited paragraph directly challenges the bounded proposition.",
|
|
"created_by": agent_id,
|
|
}
|
|
evidence = [evidence_a, evidence_b]
|
|
return {
|
|
"contract_version": 3,
|
|
"agent_id": agent_id,
|
|
"claims": [
|
|
{
|
|
"id": CLAIM_A,
|
|
"type": "empirical",
|
|
"proposition": "Claim A has a reproducible evidence chain.",
|
|
"body_markdown": "Claim A is bounded to the cited primary record and exact locator.",
|
|
"scope": "V3 apply-writer disposable verification.",
|
|
"access_scope": "collective_internal",
|
|
"status": "active",
|
|
"revision_criteria": "Revise if the cited source or locator cannot be reproduced.",
|
|
"revision_kind": "original",
|
|
"supersedes_id": None,
|
|
"tags": ["v3", "apply-writer"],
|
|
"created_by": agent_id,
|
|
},
|
|
{
|
|
"id": CLAIM_B,
|
|
"type": "conceptual",
|
|
"proposition": "Claim B remains explicitly challengeable.",
|
|
"body_markdown": "Claim B records a conceptual object together with its challenge evidence.",
|
|
"scope": "V3 apply-writer disposable verification.",
|
|
"access_scope": "collective_internal",
|
|
"status": "contested",
|
|
"revision_criteria": "Revise when the challenge is resolved or materially changes.",
|
|
"revision_kind": "original",
|
|
"supersedes_id": None,
|
|
"tags": ["v3", "challenge"],
|
|
"created_by": agent_id,
|
|
},
|
|
],
|
|
"sources": [
|
|
{
|
|
"id": SOURCE_A,
|
|
"source_type": "paper",
|
|
"canonical_url": "https://example.test/v3/a",
|
|
"storage_uri": None,
|
|
"excerpt": "Primary source A.",
|
|
"content_hash": "a" * 64,
|
|
"access_scope": "collective_internal",
|
|
"ingestion_origin": "operator_upload",
|
|
"provenance_status": "verified",
|
|
"source_class": "primary_record",
|
|
"auto_promotion_policy": "human_required",
|
|
"captured_at": "2026-07-18T10:00:00+00:00",
|
|
"created_by": agent_id,
|
|
},
|
|
{
|
|
"id": source_b,
|
|
"source_type": "observation",
|
|
"canonical_url": None,
|
|
"storage_uri": "gs://livingip-test/v3/source-b",
|
|
"excerpt": "Primary source B.",
|
|
"content_hash": "b" * 64,
|
|
"access_scope": "collective_internal",
|
|
"ingestion_origin": "system_import",
|
|
"provenance_status": "verified",
|
|
"source_class": "primary_record",
|
|
"auto_promotion_policy": "human_required",
|
|
"captured_at": "2026-07-18T10:01:00+00:00",
|
|
"created_by": agent_id,
|
|
},
|
|
],
|
|
"evidence": evidence,
|
|
"edges": [
|
|
{
|
|
"id": "12121212-1212-4121-8121-121212121212",
|
|
"from_claim": CLAIM_A,
|
|
"to_claim": CLAIM_B,
|
|
"relation_type": "challenges",
|
|
"rationale": "Claim A supplies a bounded reason to challenge claim B.",
|
|
"scope_or_conditions": "Only inside the disposable V3 verification scope.",
|
|
"created_by": agent_id,
|
|
}
|
|
],
|
|
"assessments": [
|
|
{
|
|
"id": "13131313-1313-4131-8131-131313131313",
|
|
"claim_id": CLAIM_A,
|
|
"support_tier": "strong",
|
|
"challenge_tier": "none",
|
|
"overall_state": "support_dominant",
|
|
"rationale": "One exact primary record supports the bounded empirical claim.",
|
|
"evidence_set_hash": ap._v3_evidence_set_hash(CLAIM_A, evidence),
|
|
"supersedes_assessment_id": None,
|
|
},
|
|
{
|
|
"id": "14141414-1414-4141-8141-141414141414",
|
|
"claim_id": CLAIM_B,
|
|
"support_tier": None,
|
|
"challenge_tier": None,
|
|
"overall_state": "challenge_dominant",
|
|
"rationale": "The conceptual claim has an explicit challenge without numeric evidence tiers.",
|
|
"evidence_set_hash": ap._v3_evidence_set_hash(CLAIM_B, evidence),
|
|
"supersedes_assessment_id": None,
|
|
},
|
|
],
|
|
"reasoning_tools": [],
|
|
}
|
|
|
|
|
|
def test_approve_claim_bundle_sql_is_atomic_and_row_verified():
|
|
payload = _approve_claim_bundle()
|
|
sql = ap.build_approve_claim_sql(
|
|
payload,
|
|
"99999999-9999-4999-8999-999999999999",
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
assert sql.startswith("begin;")
|
|
assert sql.rstrip().endswith("commit;")
|
|
assert "insert into public.claims" in sql
|
|
assert "insert into public.sources" in sql
|
|
assert "insert into public.claim_evidence" in sql
|
|
assert "public.claim_evidence (id," not in sql
|
|
assert "public.claim_evidence (claim_id, source_id, role, weight, created_by)" in sql
|
|
assert "insert into public.claim_edges" in sql
|
|
assert "insert into public.reasoning_tools" in sql
|
|
assert "source hash collision" in sql
|
|
assert "claim row does not match strict apply payload" in sql
|
|
assert "source row does not match strict apply payload" in sql
|
|
assert "reasoning tool row does not match strict apply payload" in sql
|
|
assert "kb_stage.finish_approved_proposal" in sql
|
|
|
|
|
|
def test_v3_approve_claim_sql_writes_complete_epistemic_bundle() -> None:
|
|
payload = _approve_claim_v3_bundle()
|
|
proposal_id = "99999999-9999-4999-8999-999999999999"
|
|
sql = ap.build_approve_claim_sql(
|
|
payload,
|
|
proposal_id,
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
|
|
shared_lock = f"select pg_catalog.pg_advisory_lock_shared({ap.V3_CATALOG_DDL_ADVISORY_LOCK_KEY});"
|
|
shared_unlock = f"select pg_catalog.pg_advisory_unlock_shared({ap.V3_CATALOG_DDL_ADVISORY_LOCK_KEY});"
|
|
assert sql.startswith(f"{shared_lock}\nbegin;")
|
|
assert "set transaction isolation level serializable" in sql
|
|
assert sql.rstrip().endswith(shared_unlock)
|
|
assert sql.count(shared_lock) == 1
|
|
assert sql.count(shared_unlock) == 1
|
|
assert "insert into public.claims" in sql
|
|
assert "body_markdown" in sql
|
|
assert "accepted_by_proposal_id" in sql
|
|
assert "insert into public.sources" in sql
|
|
assert "content_hash" in sql
|
|
assert "insert into public.claim_evidence (" in sql
|
|
assert "locator_json" in sql
|
|
assert "insert into public.claim_edges (" in sql
|
|
assert "relation_type" in sql
|
|
assert "insert into public.claim_evidence_assessments" in sql
|
|
assert "evidence_set_hash" in sql
|
|
assert "insert into public.reasoning_tools" not in sql
|
|
expected_inserts = sum(len(payload[key]) for key in ("sources", "claims", "evidence", "edges", "assessments"))
|
|
assert sql.lower().count("on conflict do nothing") == expected_inserts
|
|
assert sql.index("do $v3_contract_guard$") < sql.index("kb_stage.assert_approved_proposal")
|
|
relation_locks = [
|
|
f"select kb_stage.{ap.V3_CATALOG_LOCK_FUNCTION}();",
|
|
"lock table public.claim_edges in row exclusive mode;",
|
|
"lock table public.claim_evidence in row exclusive mode;",
|
|
"lock table public.claim_evidence_assessments in row exclusive mode;",
|
|
"lock table public.claims in row exclusive mode;",
|
|
"lock table public.sources in row exclusive mode;",
|
|
]
|
|
ordered_catalog_guard = [
|
|
shared_lock,
|
|
"begin;",
|
|
"set transaction isolation level serializable;",
|
|
*relation_locks,
|
|
"do $v3_contract_guard$",
|
|
"commit;",
|
|
shared_unlock,
|
|
]
|
|
assert [sql.index(statement) for statement in ordered_catalog_guard] == sorted(
|
|
sql.index(statement) for statement in ordered_catalog_guard
|
|
)
|
|
assert sql.index("kb_stage.assert_approved_proposal") < sql.index("insert into public.sources")
|
|
assert sql.index("insert into public.claim_evidence_assessments") < sql.index("kb_stage.finish_approved_proposal")
|
|
assert sql.index("on conflict do nothing") < sql.index("do $verify$")
|
|
assert "set local timezone = 'UTC'" in sql
|
|
assert "apply_proposal: V3 catalog contract is %s; refusing mutating transaction" in sql
|
|
assert "and superseded_by is null" in sql
|
|
expected_creator_checks = sum(len(payload[key]) for key in ("sources", "claims", "evidence", "edges"))
|
|
assert sql.count("created_by is not distinct from") == expected_creator_checks
|
|
|
|
|
|
def test_v3_catalog_guard_requires_the_full_hardened_contract() -> None:
|
|
sql = ap.build_v3_contract_state_query()
|
|
|
|
assert ap.V3_CATALOG_DDL_ADVISORY_LOCK_KEY == 6072343533146485505
|
|
assert ap.V3_PROTECTED_RELATIONS == (
|
|
("kb_stage", "kb_proposals"),
|
|
("public", "claim_edges"),
|
|
("public", "claim_evidence"),
|
|
("public", "claim_evidence_assessments"),
|
|
("public", "claims"),
|
|
("public", "sources"),
|
|
)
|
|
assert (
|
|
tuple(sorted({(row["schema_name"], row["table_name"]) for row in ap.V3_EXPECTED_TRIGGER_CONTRACT}))
|
|
== ap.V3_PROTECTED_RELATIONS
|
|
)
|
|
assert len(ap.V3_EXPECTED_TRIGGER_CONTRACT) == 24
|
|
assert len({row["trigger_name"] for row in ap.V3_EXPECTED_TRIGGER_CONTRACT}) == 24
|
|
assert all(row["when_expression"] is None for row in ap.V3_EXPECTED_TRIGGER_CONTRACT)
|
|
assert "when not artifacts_present then 'V2'" in sql
|
|
assert "when functions_valid and catalog_lock_function_valid and triggers_valid" in sql
|
|
assert "and owner_role_valid and memberships_valid then 'V3'" in sql
|
|
assert "else 'INVALID'" in sql
|
|
assert "actual.tgenabled = 'O'" in sql
|
|
assert "actual.tgtype = expected.trigger_type" in sql
|
|
assert "actual.update_columns = expected.update_columns" in sql
|
|
assert "actual.when_expression is not distinct from expected.when_expression" in sql
|
|
assert "actual.argument_hex = expected.argument_hex" in sql
|
|
assert "actual.tgconstraint = 0::pg_catalog.oid" in sql
|
|
assert "actual.tgoldtable is null" in sql
|
|
assert "actual.tgnewtable is null" in sql
|
|
assert "actual.tgfoid" in sql
|
|
assert "owner_role.rolname = E'kb_gate_owner'" in sql
|
|
assert "actual.function_security_definer = expected.function_security_definer" in sql
|
|
assert "actual.function_source_sha256 = expected.function_source_sha256" in sql
|
|
assert f"procedure.proname = E'{ap.V3_CATALOG_LOCK_FUNCTION}'" in sql
|
|
assert ap.V3_CATALOG_LOCK_FUNCTION_SOURCE_SHA256 in sql
|
|
assert "and prorettype = 'pg_catalog.void'::pg_catalog.regtype" in sql
|
|
assert "and grantee.rolname = 'kb_apply'" in sql
|
|
assert "and execute_acl_exact" in sql
|
|
assert "acl.grantee <> procedure.proowner" in sql
|
|
assert "from pg_catalog.pg_auth_members membership" in sql
|
|
|
|
|
|
def test_migration_trigger_contract_and_catalog_queries_match_worker_builder() -> None:
|
|
migration = (REPO_ROOT / "ops" / "teleo_v3_epistemic_contract.sql").read_text(encoding="utf-8")
|
|
contract_match = re.search(r"\$trigger_contract\$\s*(\[.*?\])\s*\$trigger_contract\$", migration, re.DOTALL)
|
|
|
|
assert contract_match is not None
|
|
assert json.loads(contract_match.group(1)) == list(ap.V3_EXPECTED_TRIGGER_CONTRACT)
|
|
exclusive_lock = f"select pg_catalog.pg_advisory_xact_lock({ap.V3_CATALOG_DDL_ADVISORY_LOCK_KEY});"
|
|
assert migration.count(exclusive_lock) == 1
|
|
assert migration.index(exclusive_lock) < migration.index(
|
|
f"create or replace function kb_stage.{ap.V3_CATALOG_LOCK_FUNCTION}()"
|
|
)
|
|
assert migration.index(exclusive_lock) < migration.index(
|
|
"create or replace function kb_stage.teleo_v3_enforce_apply_contract_cutover()"
|
|
)
|
|
assert migration.index(exclusive_lock) < migration.index("create or replace trigger")
|
|
|
|
expected_query = ap.build_v3_contract_state_query(
|
|
into="v_contract_state",
|
|
expected_contract_expression="pg_catalog.current_setting('teleo.v3_expected_trigger_contract')",
|
|
)
|
|
for marker in ("STATE", "POSTFLIGHT"):
|
|
query_match = re.search(
|
|
rf"TELEO_V3_CONTRACT_{marker}_QUERY_BEGIN\n(.*?)\n\s*-- TELEO_V3_CONTRACT_{marker}_QUERY_END",
|
|
migration,
|
|
re.DOTALL,
|
|
)
|
|
assert query_match is not None
|
|
assert query_match.group(1).strip() == expected_query + ";"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("mutation", "error"),
|
|
[
|
|
(lambda payload: payload["claims"][0].update(body_markdown=""), "body_markdown"),
|
|
(lambda payload: payload["claims"][0].update(revision_kind="semantic"), "original claims only"),
|
|
(lambda payload: payload["sources"][0].update(content_hash="not-a-hash"), "SHA-256"),
|
|
(lambda payload: payload["evidence"][0].update(source_content_hash="b" * 64), "does not match"),
|
|
(lambda payload: payload["assessments"][0].update(evidence_set_hash="c" * 64), "evidence_set_hash"),
|
|
(
|
|
lambda payload: payload["assessments"][0].update(
|
|
supersedes_assessment_id="15151515-1515-4151-8151-151515151515"
|
|
),
|
|
"assessment supersession",
|
|
),
|
|
(lambda payload: payload.update(reasoning_tools=[{"id": CLAIM_A}]), "reasoning_tools"),
|
|
],
|
|
)
|
|
def test_v3_approve_claim_rejects_incomplete_or_unbound_payloads(mutation, error) -> None:
|
|
payload = _approve_claim_v3_bundle()
|
|
mutation(payload)
|
|
with pytest.raises(ValueError, match=error):
|
|
ap.build_approve_claim_sql(
|
|
payload,
|
|
"99999999-9999-4999-8999-999999999999",
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
|
|
|
|
def test_v3_approve_claim_preserves_exact_reviewed_text_for_replay_receipts() -> None:
|
|
payload = _approve_claim_v3_bundle()
|
|
payload["claims"][0]["body_markdown"] = " Exact reviewed body with intentional spacing. "
|
|
|
|
normalized = ap._normalize_v3_approve_claim(payload)
|
|
|
|
assert normalized["claims"][0]["body_markdown"] == payload["claims"][0]["body_markdown"]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("captured_at", "expected"),
|
|
[
|
|
("2026-07-18T10:00:00Z", "2026-07-18T10:00:00.000000Z"),
|
|
("2026-07-18T12:00:00+02:00", "2026-07-18T10:00:00.000000Z"),
|
|
("2026-07-18T12:00:00.123400+02:00", "2026-07-18T10:00:00.123400Z"),
|
|
("2026-07-18T10:00:00.1Z", "2026-07-18T10:00:00.100000Z"),
|
|
],
|
|
)
|
|
def test_v3_approve_claim_normalizes_capture_timestamp_to_fixed_utc(
|
|
captured_at: str,
|
|
expected: str,
|
|
) -> None:
|
|
payload = _approve_claim_v3_bundle()
|
|
payload["sources"][0]["captured_at"] = captured_at
|
|
|
|
normalized = ap._normalize_v3_approve_claim(payload)
|
|
|
|
assert normalized["sources"][0]["captured_at"] == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"captured_at",
|
|
[
|
|
"2026-07-18 10:00:00+00:00",
|
|
"2026-07-18T10:00:00",
|
|
"2026-07-18T10:00:00.1234567Z",
|
|
"not-a-timestamp",
|
|
],
|
|
)
|
|
def test_v3_approve_claim_rejects_untyped_capture_timestamp(captured_at: str) -> None:
|
|
payload = _approve_claim_v3_bundle()
|
|
payload["sources"][0]["captured_at"] = captured_at
|
|
with pytest.raises(ValueError, match="timezone-aware ISO-8601"):
|
|
ap._normalize_v3_approve_claim(payload)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"spelling",
|
|
[
|
|
CLAIM_A.upper(),
|
|
"{" + CLAIM_A + "}",
|
|
CLAIM_A.replace("-", ""),
|
|
],
|
|
)
|
|
def test_v3_approve_claim_rejects_noncanonical_uuid_spellings(spelling: str) -> None:
|
|
payload = _approve_claim_v3_bundle()
|
|
payload["claims"][0]["id"] = spelling
|
|
|
|
with pytest.raises(ValueError, match="canonical lowercase hyphenated UUID"):
|
|
ap._normalize_v3_approve_claim(payload)
|
|
|
|
|
|
def test_approve_claim_semantic_rows_accept_matches_and_reject_payload_mismatches():
|
|
payload = _approve_claim_bundle()
|
|
sql = ap.build_approve_claim_sql(
|
|
payload,
|
|
"99999999-9999-4999-8999-999999999999",
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
verify = sql[sql.index("do $verify$") : sql.index("kb_stage.finish_approved_proposal")]
|
|
|
|
assert "weight is not distinct from 0.9" in verify
|
|
assert "weight is distinct from 0.9" in verify
|
|
assert "weight is not distinct from 0.7" in verify
|
|
assert "weight is distinct from 0.7" in verify
|
|
assert "weight is not distinct from null" in verify
|
|
assert "weight is distinct from null" in verify
|
|
expected_creator = "E'11111111-1111-4111-8111-111111111111'::uuid"
|
|
assert f"created_by is not distinct from {expected_creator}" in verify
|
|
assert f"created_by is distinct from {expected_creator}" in verify
|
|
assert "approve_claim: evidence row does not match strict apply payload" in verify
|
|
assert "approve_claim: edge row does not match strict apply payload" in verify
|
|
assert sql.startswith("begin;")
|
|
assert sql.rstrip().endswith("commit;")
|
|
assert sql.index("raise exception 'approve_claim: evidence row") < sql.index("kb_stage.finish_approved_proposal")
|
|
|
|
|
|
def test_approve_claim_bundle_rejects_duplicate_source_hashes():
|
|
payload = _approve_claim_bundle()
|
|
payload["sources"][1]["hash"] = payload["sources"][0]["hash"]
|
|
with pytest.raises(ValueError):
|
|
ap.build_approve_claim_sql(
|
|
payload,
|
|
"99999999-9999-4999-8999-999999999999",
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
|
|
|
|
def test_approve_claim_bundle_rejects_invalid_enum_and_self_edge():
|
|
payload = _approve_claim_bundle()
|
|
payload["claims"][0]["type"] = "vibes"
|
|
with pytest.raises(ValueError):
|
|
ap.build_approve_claim_sql(
|
|
payload,
|
|
"99999999-9999-4999-8999-999999999999",
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
|
|
payload = _approve_claim_bundle()
|
|
payload["edges"][0]["to_claim"] = payload["edges"][0]["from_claim"]
|
|
with pytest.raises(ValueError):
|
|
ap.build_approve_claim_sql(
|
|
payload,
|
|
"99999999-9999-4999-8999-999999999999",
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
|
|
|
|
def test_approve_claim_rejects_unknown_keys_and_contract_versions():
|
|
payload = _approve_claim_bundle()
|
|
payload["contract_version"] = 1
|
|
with pytest.raises(ValueError):
|
|
ap.build_approve_claim_sql(
|
|
payload,
|
|
"99999999-9999-4999-8999-999999999999",
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
|
|
payload = _approve_claim_bundle()
|
|
payload["contract_version"] = 2
|
|
payload["claimz"] = payload.pop("claims")
|
|
with pytest.raises(ValueError):
|
|
ap.build_approve_claim_sql(
|
|
payload,
|
|
"99999999-9999-4999-8999-999999999999",
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
|
|
|
|
def test_approve_claim_verifies_superseded_by_and_pins_string_mode():
|
|
payload = _approve_claim_bundle()
|
|
payload["contract_version"] = 2
|
|
payload["claims"][0]["superseded_by"] = None
|
|
sql = ap.build_approve_claim_sql(
|
|
payload,
|
|
"99999999-9999-4999-8999-999999999999",
|
|
None,
|
|
_approval_meta("approve_claim", payload),
|
|
)
|
|
assert "superseded_by" in sql
|
|
assert "set local standard_conforming_strings = on" in sql.lower()
|
|
|
|
|
|
def test_apply_sql_locks_and_binds_approval_before_canonical_write():
|
|
payload = _approve_claim_bundle()
|
|
payload["contract_version"] = 2
|
|
proposal = {
|
|
"id": "99999999-9999-4999-8999-999999999999",
|
|
"proposal_type": "approve_claim",
|
|
"status": "approved",
|
|
"payload": {"apply_payload": payload},
|
|
"reviewed_by_handle": "m3ta",
|
|
"reviewed_by_agent_id": None,
|
|
"reviewed_at": "2026-07-10T00:00:00+00:00",
|
|
"review_note": "Reviewed exact strict payload.",
|
|
}
|
|
sql = ap.build_apply_sql(proposal, "kb-apply")
|
|
assert "kb_stage.assert_approved_proposal" in sql
|
|
assert "kb_stage.finish_approved_proposal" in sql
|
|
assert sql.index("kb_stage.assert_approved_proposal") < sql.index("insert into public.claims")
|
|
assert sql.index("insert into public.claims") < sql.index("kb_stage.finish_approved_proposal")
|
|
assert "Reviewed exact strict payload." in sql
|
|
|
|
|
|
def test_fresh_owned_apply_uses_strict_inserts_and_binds_preflight_hash():
|
|
payload = _approve_claim_bundle()
|
|
proposal = {
|
|
"id": "99999999-9999-4999-8999-999999999999",
|
|
"proposal_type": "approve_claim",
|
|
"status": "approved",
|
|
"payload": {"apply_payload": payload},
|
|
"reviewed_by_handle": "m3ta",
|
|
"reviewed_by_agent_id": None,
|
|
"reviewed_at": "2026-07-10T00:00:00+00:00",
|
|
"review_note": "Reviewed exact strict payload.",
|
|
}
|
|
preflight_sha256 = "a" * 64
|
|
|
|
sql = ap.build_apply_sql(
|
|
proposal,
|
|
"kb-apply",
|
|
fresh_owned=True,
|
|
fresh_preflight_sha256=preflight_sha256,
|
|
)
|
|
|
|
assert preflight_sha256 in sql
|
|
assert "set transaction isolation level serializable" in sql.lower()
|
|
assert "on conflict" not in sql.lower()
|
|
assert "where not exists" not in sql.lower()
|
|
assert sql.index("set transaction isolation level serializable") < sql.index("kb_stage.assert_approved_proposal")
|
|
|
|
|
|
def test_build_apply_sql_requires_review_provenance():
|
|
proposal = {
|
|
"id": "99999999-9999-4999-8999-999999999999",
|
|
"proposal_type": "approve_claim",
|
|
"status": "approved",
|
|
"payload": {"apply_payload": _approve_claim_bundle()},
|
|
}
|
|
with pytest.raises(ValueError):
|
|
ap.build_apply_sql(proposal, "kb-apply")
|
|
|
|
|
|
def test_approve_claim_dispatch_and_prerequisite_grants():
|
|
proposal = {
|
|
"id": "99999999-9999-4999-8999-999999999999",
|
|
"proposal_type": "approve_claim",
|
|
"payload": {"apply_payload": _approve_claim_bundle()},
|
|
}
|
|
proposal.update(_approval_meta("approve_claim", proposal["payload"]["apply_payload"]))
|
|
sql = ap.build_apply_sql(proposal, None)
|
|
assert "insert into public.claims" in sql
|
|
assert "approve_claim" in ap.APPLYABLE_TYPES
|
|
|
|
prereqs = (REPO_ROOT / "scripts" / "kb_apply_prereqs.sql").read_text(encoding="utf-8")
|
|
assert "grant select, insert on public.claims to kb_apply" in prereqs.lower()
|
|
assert "grant select, insert on public.sources to kb_apply" in prereqs.lower()
|
|
assert "grant select, insert on public.reasoning_tools to kb_apply" in prereqs.lower()
|
|
|
|
|
|
# --- dispatch + guards ---------------------------------------------------- #
|
|
def test_build_apply_sql_requires_apply_payload():
|
|
proposal = {"id": "pid", "proposal_type": "add_edge", "payload": {"rationale": "x"}}
|
|
with pytest.raises(ValueError):
|
|
ap.build_apply_sql(proposal, None)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("proposal", "error"),
|
|
[
|
|
({"proposal_type": "approve_claim", "payload": []}, "payload must be a JSON object"),
|
|
(
|
|
{"proposal_type": "approve_claim", "payload": {"apply_payload": []}},
|
|
"payload.apply_payload must be a JSON object",
|
|
),
|
|
(
|
|
{
|
|
"proposal_type": "approve_claim",
|
|
"payload": {"apply_payload": {"contract_version": "3"}},
|
|
},
|
|
"must be integer 2 or 3",
|
|
),
|
|
(
|
|
{
|
|
"proposal_type": "approve_claim",
|
|
"payload": {"apply_payload": {"contract_version": 3.0}},
|
|
},
|
|
"must be integer 2 or 3",
|
|
),
|
|
(
|
|
{
|
|
"proposal_type": "approve_claim",
|
|
"payload": {"apply_payload": {"contract_version": True}},
|
|
},
|
|
"must be integer 2 or 3",
|
|
),
|
|
(
|
|
{
|
|
"proposal_type": "add_edge",
|
|
"payload": {"apply_payload": {"contract_version": 3}},
|
|
},
|
|
"must omit contract_version",
|
|
),
|
|
(
|
|
{
|
|
"proposal_type": "add_edge",
|
|
"payload": {"apply_payload": {"contract_version": None}},
|
|
},
|
|
"must omit contract_version",
|
|
),
|
|
],
|
|
)
|
|
def test_exact_contract_gate_rejects_malformed_and_hybrid_proposals(
|
|
proposal: dict,
|
|
error: str,
|
|
) -> None:
|
|
with pytest.raises(ValueError, match=error):
|
|
ap.proposal_contract_version(proposal)
|
|
|
|
|
|
def test_mutating_subprocess_contract_expectation_is_reasserted() -> None:
|
|
payload = _approve_claim_v3_bundle()
|
|
proposal = {
|
|
"id": "99999999-9999-4999-8999-999999999999",
|
|
"proposal_type": "approve_claim",
|
|
"payload": {"apply_payload": payload},
|
|
}
|
|
|
|
assert ap.assert_expected_contract_version(proposal, 3) == 3
|
|
with pytest.raises(ValueError, match="does not match expected version 2"):
|
|
ap.assert_expected_contract_version(proposal, 2)
|
|
|
|
|
|
def test_build_apply_sql_rejects_unsupported_type():
|
|
proposal = {"id": "pid", "proposal_type": "reject_claim", "payload": {"apply_payload": {}}}
|
|
with pytest.raises(ValueError):
|
|
ap.build_apply_sql(proposal, None)
|
|
|
|
|
|
def test_assert_applyable_blocks_pending():
|
|
with pytest.raises(SystemExit):
|
|
ap.assert_applyable({"id": "pid", "status": "pending_review"})
|
|
|
|
|
|
def test_assert_applyable_blocks_already_applied():
|
|
with pytest.raises(SystemExit):
|
|
ap.assert_applyable({"id": "pid", "status": "applied"})
|
|
|
|
|
|
def test_assert_applyable_allows_approved():
|
|
ap.assert_applyable({"id": "pid", "status": "approved"}) # no raise
|
|
|
|
|
|
# --- ledger flip: concurrency guard + FK stamp --------------------------- #
|
|
def test_ledger_transition_uses_payload_bound_security_functions():
|
|
payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supports"}
|
|
sql = ap.build_add_edge_sql(payload, "pid", None, _approval_meta("add_edge", payload))
|
|
assert "kb_stage.assert_approved_proposal" in sql
|
|
assert "kb_stage.finish_approved_proposal" in sql
|
|
assert sql.index("kb_stage.assert_approved_proposal") < sql.index("insert into public.claim_edges")
|
|
assert sql.index("insert into public.claim_edges") < sql.index("kb_stage.finish_approved_proposal")
|
|
|
|
prereqs = (REPO_ROOT / "scripts" / "kb_apply_prereqs.sql").read_text(encoding="utf-8").lower()
|
|
assert "status = 'approved'" in prereqs
|
|
assert "for update" in prereqs
|
|
assert "payload = p_payload" in prereqs
|
|
|
|
|
|
def test_ledger_flip_stamps_agent_fk():
|
|
payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supports"}
|
|
sql = ap.build_add_edge_sql(payload, "pid", "kb-apply", _approval_meta("add_edge", payload))
|
|
# Hard resolve into a variable + NOT-NULL assert, never a silent inline
|
|
# subselect that would stamp NULL on an unresolved handle.
|
|
assert "kb_stage.finish_approved_proposal" in sql
|
|
assert "'kb-apply'" in sql
|
|
|
|
|
|
def test_build_apply_sql_defaults_applied_by_to_service_agent():
|
|
payload = {"from_claim": CLAIM_A, "to_claim": CLAIM_B, "edge_type": "supports"}
|
|
proposal = {
|
|
"id": "pid",
|
|
"proposal_type": "add_edge",
|
|
"payload": {"apply_payload": payload},
|
|
}
|
|
proposal.update(_approval_meta("add_edge", payload))
|
|
sql = ap.build_apply_sql(proposal, None)
|
|
assert f"E'{ap.SERVICE_AGENT_HANDLE}'" in sql
|
|
|
|
|
|
def test_load_password_accepts_live_db_password_key(tmp_path):
|
|
secrets_file = tmp_path / "kb-apply.env"
|
|
secrets_file.write_text("KB_APPLY_DB_PASSWORD=live-secret\n", encoding="utf-8")
|
|
assert ap.load_password(str(secrets_file)) == "live-secret"
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import traceback
|
|
|
|
failures = 0
|
|
for name, fn in sorted(globals().items()):
|
|
if name.startswith("test_") and callable(fn):
|
|
try:
|
|
fn()
|
|
print(f"PASS {name}")
|
|
except Exception:
|
|
failures += 1
|
|
print(f"FAIL {name}")
|
|
traceback.print_exc()
|
|
sys.exit(1 if failures else 0)
|