164 lines
6.5 KiB
Python
164 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
import copy
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
|
|
import run_leo_local_ingestion_proposal_canary as canary # noqa: E402
|
|
|
|
|
|
def _loaded() -> tuple[dict, dict, dict]:
|
|
fixture, input_receipt = canary.load_fixture(canary.DEFAULT_FIXTURE)
|
|
row_ids = canary.build_row_ids(input_receipt["artifact_sha256"])
|
|
return fixture, input_receipt, row_ids
|
|
|
|
|
|
def test_fixture_is_realistic_hash_bound_and_exactly_evidenced() -> None:
|
|
fixture, input_receipt, row_ids = _loaded()
|
|
|
|
assert fixture["extraction"]["evidence"]["body"] in fixture["source"]["body"]
|
|
assert len(input_receipt["artifact_sha256"]) == 64
|
|
assert len(input_receipt["source_content_sha256"]) == 64
|
|
assert input_receipt["artifact_sha256"] != input_receipt["source_content_sha256"]
|
|
assert len(set(row_ids.values())) == 4
|
|
|
|
|
|
def test_fixture_validation_fails_closed_when_evidence_is_not_in_source(tmp_path: Path) -> None:
|
|
fixture = json.loads(canary.DEFAULT_FIXTURE.read_text(encoding="utf-8"))
|
|
fixture["extraction"]["evidence"]["body"] = "invented evidence"
|
|
path = tmp_path / "bad-fixture.json"
|
|
path.write_text(json.dumps(fixture), encoding="utf-8")
|
|
|
|
with pytest.raises(canary.CanaryError, match="exact substring"):
|
|
canary.load_fixture(path)
|
|
|
|
|
|
def test_fixture_validation_fails_closed_when_claim_body_is_not_in_source(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
fixture = json.loads(canary.DEFAULT_FIXTURE.read_text(encoding="utf-8"))
|
|
fixture["extraction"]["claim"]["body"] = "invented claim body"
|
|
path = tmp_path / "bad-claim-fixture.json"
|
|
path.write_text(json.dumps(fixture), encoding="utf-8")
|
|
|
|
with pytest.raises(canary.CanaryError, match="claim body must be an exact substring"):
|
|
canary.load_fixture(path)
|
|
|
|
|
|
def test_capture_sql_escapes_quotes_and_backslashes_from_fixture(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
fixture = json.loads(canary.DEFAULT_FIXTURE.read_text(encoding="utf-8"))
|
|
fixture["source"]["title"] = "O'Brien\\review"
|
|
fixture["source"]["metadata"]["note"] = "quoted ' value \\ path"
|
|
path = tmp_path / "quoted-fixture.json"
|
|
path.write_text(json.dumps(fixture), encoding="utf-8")
|
|
loaded, input_receipt = canary.load_fixture(path)
|
|
row_ids = canary.build_row_ids(input_receipt["artifact_sha256"])
|
|
|
|
sql = canary.build_capture_sql(loaded, input_receipt, row_ids)
|
|
|
|
assert canary.ap.sql_literal(fixture["source"]["title"]) in sql
|
|
assert canary.ap.sql_literal(
|
|
json.dumps(fixture["source"]["metadata"], sort_keys=True)
|
|
) in sql
|
|
|
|
|
|
def test_parent_normalizes_to_hash_bound_pending_proposal_with_embedded_row_links() -> None:
|
|
fixture, input_receipt, row_ids = _loaded()
|
|
parent = canary.build_parent_packet(fixture, input_receipt, row_ids)
|
|
child = canary.normalized_stage.prepare_normalized_child(parent)
|
|
payload = child["payload"]["apply_payload"]
|
|
|
|
assert child["status"] == "pending_review"
|
|
assert child["proposal_type"] == "approve_claim"
|
|
assert len(payload["claims"]) == 1
|
|
assert len(payload["sources"]) == 2
|
|
assert len(payload["evidence"]) == 2
|
|
assert input_receipt["source_content_sha256"] in {row["hash"] for row in payload["sources"]}
|
|
excerpts = "\n".join(row["excerpt"] for row in payload["sources"])
|
|
assert input_receipt["artifact_sha256"] in excerpts
|
|
assert row_ids["source_capture_id"] in excerpts
|
|
assert row_ids["claim_extraction_id"] in excerpts
|
|
assert row_ids["evidence_extraction_id"] in excerpts
|
|
|
|
|
|
def test_capture_and_stage_sql_never_mutate_canonical_public_tables() -> None:
|
|
fixture, input_receipt, row_ids = _loaded()
|
|
child = canary.normalized_stage.prepare_normalized_child(
|
|
canary.build_parent_packet(fixture, input_receipt, row_ids)
|
|
)
|
|
sql = "\n".join(
|
|
(
|
|
canary.build_schema_sql(),
|
|
canary.build_capture_sql(fixture, input_receipt, row_ids),
|
|
canary.normalized_stage.build_stage_sql(child),
|
|
)
|
|
).lower()
|
|
|
|
assert "insert into public." not in sql
|
|
assert "update public." not in sql
|
|
assert "delete from public." not in sql
|
|
assert "insert into kb_canary.source_captures" in sql
|
|
assert "insert into kb_canary.claim_extractions" in sql
|
|
assert "insert into kb_canary.evidence_extractions" in sql
|
|
assert "insert into kb_stage.kb_proposals" in sql
|
|
|
|
|
|
def test_check_evaluation_requires_every_row_link_and_staging_boundary() -> None:
|
|
fixture, input_receipt, row_ids = _loaded()
|
|
child = canary.normalized_stage.prepare_normalized_child(
|
|
canary.build_parent_packet(fixture, input_receipt, row_ids)
|
|
)
|
|
apply_payload = child["payload"]["apply_payload"]
|
|
readback = {
|
|
"source_capture": {
|
|
"id": row_ids["source_capture_id"],
|
|
"artifact_sha256": input_receipt["artifact_sha256"],
|
|
"content_sha256": input_receipt["source_content_sha256"],
|
|
"source_identity": input_receipt["source_identity"],
|
|
},
|
|
"claim_extraction": {
|
|
"id": row_ids["claim_extraction_id"],
|
|
"source_capture_id": row_ids["source_capture_id"],
|
|
"body": fixture["extraction"]["claim"]["body"],
|
|
"metadata": {"text": fixture["extraction"]["claim"]["text"]},
|
|
},
|
|
"evidence_extraction": {
|
|
"id": row_ids["evidence_extraction_id"],
|
|
"claim_extraction_id": row_ids["claim_extraction_id"],
|
|
"source_capture_id": row_ids["source_capture_id"],
|
|
"body": fixture["extraction"]["evidence"]["body"],
|
|
"metadata": fixture["extraction"]["evidence"]["metadata"],
|
|
},
|
|
"staged_proposal": {
|
|
"id": child["id"],
|
|
"status": "pending_review",
|
|
"source_ref": child["source_ref"],
|
|
"payload": {"apply_payload": apply_payload},
|
|
"reviewed_by_handle": None,
|
|
"reviewed_at": None,
|
|
"applied_by_handle": None,
|
|
"applied_at": None,
|
|
},
|
|
"counts": {
|
|
"source_captures": 1,
|
|
"claim_extractions": 1,
|
|
"evidence_extractions": 1,
|
|
"staged_proposals": 1,
|
|
},
|
|
}
|
|
|
|
checks = canary.evaluate_checks(fixture, input_receipt, row_ids, readback)
|
|
assert all(checks.values())
|
|
broken = copy.deepcopy(readback)
|
|
broken["evidence_extraction"]["claim_extraction_id"] = canary.stable_uuid("0" * 64, "wrong")
|
|
assert (
|
|
canary.evaluate_checks(fixture, input_receipt, row_ids, broken)["evidence_links_to_claim_and_source"] is False
|
|
)
|