244 lines
9.5 KiB
Python
244 lines
9.5 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
from collections.abc import Sequence
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from ops.audit_kb_rebuild_coverage import (
|
|
CommandResult,
|
|
audit_database,
|
|
build_audit_sql,
|
|
build_report,
|
|
)
|
|
|
|
|
|
def aggregate_fixture() -> dict[str, Any]:
|
|
return {
|
|
"identity": {"database": "teleo", "transaction_read_only": "on", "server_version_num": "160004"},
|
|
"canonical_counts": {"claims": 10, "sources": 8, "claim_evidence": 12, "claim_edges": 9},
|
|
"staging_counts": {
|
|
"canonical_mappings": 17,
|
|
"import_runs": 1,
|
|
"inventory_items": 20,
|
|
"staged_claims": 11,
|
|
"staged_sources": 8,
|
|
"staged_claim_sources": 13,
|
|
"staged_claim_edges": 10,
|
|
"kb_proposals": 4,
|
|
},
|
|
"mappings": {
|
|
"claims": {
|
|
"rows": 9,
|
|
"legacy_keys": 9,
|
|
"target_ids": 9,
|
|
"missing_canonical_targets": 0,
|
|
"with_first_run_staged_row": 9,
|
|
"canonical_target_rows_covered": 9,
|
|
"canonical_target_rows_unmapped": 1,
|
|
"staged_distinct_keys": 10,
|
|
"staged_distinct_keys_unmapped": 1,
|
|
},
|
|
"sources": {
|
|
"rows": 8,
|
|
"legacy_keys": 8,
|
|
"target_ids": 8,
|
|
"missing_canonical_targets": 0,
|
|
"with_first_run_staged_row": 7,
|
|
"canonical_target_rows_covered": 8,
|
|
"canonical_target_rows_unmapped": 0,
|
|
"staged_distinct_keys": 8,
|
|
"staged_distinct_keys_unmapped": 0,
|
|
},
|
|
"unsupported_target_rows": 0,
|
|
},
|
|
"claim_parity": {
|
|
"compared_fields": ["type", "text_from_title"],
|
|
"eligible_rows": 9,
|
|
"exact_projection_rows": 9,
|
|
"field_matches": {"type": 9, "text_from_title": 9},
|
|
"projection_limits": {"staged_body_nonempty": 9},
|
|
},
|
|
"source_parity": {
|
|
"compared_fields": ["source_type", "hash"],
|
|
"eligible_rows": 7,
|
|
"exact_projection_rows": 6,
|
|
"field_matches": {"source_type": 7, "hash": 6},
|
|
"projection_limits": {"staged_title_nonempty": 7},
|
|
},
|
|
"claim_evidence_reconstruction": {
|
|
"compared_fields": ["claim_id", "source_id", "role", "weight"],
|
|
"not_replayed_fields": ["created_by", "created_at"],
|
|
"staged_rows": 13,
|
|
"rows_with_mapped_claim": 12,
|
|
"rows_with_mapped_source": 13,
|
|
"rows_with_both_mapped_endpoints": 12,
|
|
"distinct_projected_rows": 11,
|
|
"projected_rows_present_in_canonical": 11,
|
|
"canonical_rows_covered": 11,
|
|
"canonical_rows_total": 12,
|
|
},
|
|
"claim_edge_reconstruction": {
|
|
"compared_fields": ["from_claim", "to_claim", "edge_type"],
|
|
"not_replayed_fields": ["id", "weight", "created_by", "created_at", "duplicate_multiplicity"],
|
|
"staged_rows": 10,
|
|
"resolution_state_resolved_rows": 9,
|
|
"resolved_rows_with_from_mapping": 9,
|
|
"resolved_rows_with_to_mapping": 8,
|
|
"resolved_rows_with_both_mapped_endpoints": 8,
|
|
"distinct_projected_rows": 8,
|
|
"projected_rows_present_in_canonical": 8,
|
|
"canonical_rows_covered": 8,
|
|
"canonical_rows_total": 9,
|
|
},
|
|
"later_and_unmapped": {
|
|
"latest_import_completed_at": "2026-01-01T00:00:00+00:00",
|
|
"canonical_created_after_latest_import": {
|
|
"claims": 1,
|
|
"sources": 0,
|
|
"claim_evidence": 1,
|
|
"claim_edges": 1,
|
|
},
|
|
"canonical_without_mapping": {"claims": 1, "sources": 0},
|
|
"canonical_relations_not_reconstructible": {"claim_evidence": 1, "claim_edges": 1},
|
|
"staged_distinct_keys_without_mapping": {"claims": 1, "sources": 0},
|
|
},
|
|
"proposal_apply_payload": {
|
|
"total_rows": 4,
|
|
"status_counts": {"applied": 2, "pending_review": 2},
|
|
"with_apply_payload_key": 2,
|
|
"with_valid_apply_payload": 2,
|
|
"applied_rows": 2,
|
|
"applied_with_valid_apply_payload": 1,
|
|
},
|
|
"import_runs": [
|
|
{
|
|
"id": "run-id",
|
|
"label": "fixture-run",
|
|
"repo_path": "/workspace",
|
|
"inventory_path": "/inventory/fixture.jsonl",
|
|
"started_at": "2026-01-01T00:00:00+00:00",
|
|
"completed_at": "2026-01-01T00:01:00+00:00",
|
|
"inventory_items": 20,
|
|
"staged_claims": 11,
|
|
"staged_sources": 8,
|
|
"staged_claim_sources": 13,
|
|
"staged_claim_edges": 10,
|
|
}
|
|
],
|
|
}
|
|
|
|
|
|
def test_sql_is_guarded_and_read_only() -> None:
|
|
sql = build_audit_sql()
|
|
|
|
assert "BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY" in sql
|
|
assert "current_setting('transaction_read_only')" in sql
|
|
assert "expected_schema_absent" in sql
|
|
assert "\\if :schema_ok" in sql
|
|
assert sql.count("ROLLBACK;") >= 2
|
|
assert not re.search(r"\b(INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE|COPY)\b", sql, re.IGNORECASE)
|
|
|
|
|
|
def test_report_separates_snapshot_recovery_from_source_recompile_and_calculates_gaps() -> None:
|
|
report = build_report(aggregate_fixture(), container="teleo-test", database="teleo")
|
|
semantic = report["source_derived_recompile_readiness"]
|
|
|
|
assert report["audit_status"] == "complete"
|
|
assert report["exact_snapshot_recovery"]["verified_by_this_database_only_auditor"] is False
|
|
assert report["exact_snapshot_recovery"]["current_state_counts"]["canonical"]["claims"] == 10
|
|
assert semantic["status"] == "partial"
|
|
assert semantic["canonical_mappings"]["claims"]["canonical_coverage"] == {
|
|
"covered": 9,
|
|
"total": 10,
|
|
"gap": 1,
|
|
"percent": 90.0,
|
|
}
|
|
assert semantic["canonical_mappings"]["sources"]["first_run_stage_origin_coverage"]["percent"] == 87.5
|
|
assert semantic["claim_evidence_from_staged_claim_sources"]["canonical_reconstruction_coverage"]["percent"] == 91.67
|
|
assert semantic["claim_evidence_from_staged_claim_sources"]["not_replayed_fields"] == [
|
|
"created_by",
|
|
"created_at",
|
|
]
|
|
assert "duplicate_multiplicity" in semantic["claim_edges_from_resolved_staged_claim_edges"]["not_replayed_fields"]
|
|
assert semantic["proposal_apply_payload_coverage"]["applied_proposal_payload_coverage"]["percent"] == 50.0
|
|
gap_codes = {gap["code"] for gap in semantic["explicit_gaps"]}
|
|
assert "canonical_claims_without_mapping" in gap_codes
|
|
assert "source_mappings_without_first_run_stage" in gap_codes
|
|
assert "mapped_source_projection_mismatch" in gap_codes
|
|
assert "canonical_claim_evidence_not_reconstructible" in gap_codes
|
|
assert "canonical_claim_edges_not_reconstructible" in gap_codes
|
|
assert "applied_proposals_without_valid_apply_payload" in gap_codes
|
|
assert semantic["import_run_metadata"][0]["inventory_path"] == "/inventory/fixture.jsonl"
|
|
assert report["safety"]["contains_private_bodies_or_source_excerpts"] is False
|
|
|
|
|
|
def test_audit_uses_named_container_database_and_injected_runner() -> None:
|
|
captured: dict[str, Any] = {}
|
|
|
|
def fake_runner(command: Sequence[str], stdin: str, timeout: int) -> CommandResult:
|
|
captured.update(command=list(command), stdin=stdin, timeout=timeout)
|
|
return CommandResult(0, json.dumps(aggregate_fixture()) + "\n", "")
|
|
|
|
report = audit_database(
|
|
container="teleo-local",
|
|
database="teleo",
|
|
db_user="postgres",
|
|
timeout=45,
|
|
runner=fake_runner,
|
|
)
|
|
|
|
assert captured["command"] == [
|
|
"docker",
|
|
"exec",
|
|
"-i",
|
|
"teleo-local",
|
|
"psql",
|
|
"-X",
|
|
"-U",
|
|
"postgres",
|
|
"-d",
|
|
"teleo",
|
|
"-Atq",
|
|
"-v",
|
|
"ON_ERROR_STOP=1",
|
|
]
|
|
assert captured["timeout"] == 45
|
|
assert "READ ONLY" in captured["stdin"]
|
|
assert report["target"]["container"] == "teleo-local"
|
|
assert report["safety"]["transaction_read_only_readback"] == "on"
|
|
|
|
|
|
def test_missing_schema_fails_closed_with_structured_json() -> None:
|
|
def fake_runner(_command: Sequence[str], _stdin: str, _timeout: int) -> CommandResult:
|
|
payload = {
|
|
"status": "error",
|
|
"error": "expected_schema_absent",
|
|
"missing_relations": ["kb_stage.canonical_mappings"],
|
|
"missing_columns": ["kb_stage.canonical_mappings.legacy_key"],
|
|
}
|
|
return CommandResult(3, json.dumps(payload) + "\n", "")
|
|
|
|
report = audit_database(container="empty-postgres", database="teleo", runner=fake_runner)
|
|
|
|
assert report["audit_status"] == "error"
|
|
assert report["error"] == "expected_schema_absent"
|
|
assert report["details"]["missing_relations"] == ["kb_stage.canonical_mappings"]
|
|
assert report["details"]["missing_columns"] == ["kb_stage.canonical_mappings.legacy_key"]
|
|
assert "source_derived_recompile_readiness" not in report
|
|
|
|
|
|
def test_invalid_docker_identifier_is_rejected_before_runner() -> None:
|
|
called = False
|
|
|
|
def fake_runner(_command: Sequence[str], _stdin: str, _timeout: int) -> CommandResult:
|
|
nonlocal called
|
|
called = True
|
|
return CommandResult(0, "{}", "")
|
|
|
|
with pytest.raises(ValueError, match="container must match"):
|
|
audit_database(container="--privileged", database="teleo", runner=fake_runner)
|
|
|
|
assert called is False
|