"""test_graph_projection.py — T18 §18Q/§18P: read-only graph projection + the self-scaffolded upgrade proof record.""" from __future__ import annotations import sys from pathlib import Path REPO = Path(__file__).resolve().parent.parent sys.path.insert(0, str(REPO / "src")) from rune import graph_projection as gp # noqa: E402 from rune import structural_model as sm # noqa: E402 SELF = REPO / "store" / "scaffold" def _self_model(): return sm.StructuralModel(SELF, "scaffolding") def test_18q_projection_is_versioned_and_complete(): m = _self_model() j = gp.project_json(m) assert j["schema_version"] == gp.PROJECTION_SCHEMA_VERSION == 1 assert j["node_count"] >= 25 and j["edge_count"] >= 30 # no internal storage layout leaked: only curated ext keys for n in j["nodes"]: assert set(n.keys()) <= {"id", "kind", "maturity", "name", "ext"} assert set((n.get("ext") or {}).keys()) <= {"source", "bounded_adapter"} def test_18q_dot_and_mermaid_render_parse(): m = _self_model() dot = gp.project_dot(m) assert dot.startswith("digraph") and dot.count("->") >= 30 mm = gp.project_mermaid(m) assert mm.startswith("graph LR") and mm.count("-->") >= 30 # DOT/Mermaid ids are safe (quoted / mangled) even with ':' in ids assert '"component:scaffold"' in dot # quoted DOT ids assert " component:scaffold " not in mm # mangled in mermaid def test_18q_projection_is_read_only(): m = _self_model() before = (SELF / "structural.json").read_text() gp.project_json(m); gp.project_dot(m); gp.project_mermaid(m) assert (SELF / "structural.json").read_text() == before def test_18p_upgrade_proof_artifacts_exist(): rec = REPO / "store/scaffold/programmes" # programme records live contract_docs = (SELF / "current.json").read_text() assert "18q-graph-projection" in contract_docs assert "closed" in contract_docs wsr = REPO / "store/evidence/t18/18P_workspace_record.json" import json r = json.loads(wsr.read_text()) assert r["stages_completed"][:4] == ["base_verified", "worktree_created", "construction", "verified"] assert r["construction_base"] # started from a verified base SHA # the projection output exists and matches the live model j = json.loads((REPO / "store/evidence/t18/projection/" "structural_graph.json").read_text()) assert any(n["id"] == "component:graph_projection" for n in j["nodes"])