summaryrefslogtreecommitdiff
path: root/tests/test_kernel_models.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_kernel_models.py')
-rw-r--r--tests/test_kernel_models.py138
1 files changed, 138 insertions, 0 deletions
diff --git a/tests/test_kernel_models.py b/tests/test_kernel_models.py
new file mode 100644
index 0000000..864d6d5
--- /dev/null
+++ b/tests/test_kernel_models.py
@@ -0,0 +1,138 @@
+from __future__ import annotations
+
+import pytest
+
+from gap_pipeline.kernel_models import (
+ DiffusedProof,
+ JudgeVerdict,
+ MethodPlan,
+ ProofDAG,
+ RenderedVariant,
+ ReplacementPlan,
+)
+
+
+def branched_dag() -> ProofDAG:
+ return ProofDAG.model_validate(
+ {
+ "nodes": [
+ {"node_id": "n1", "claim": "first fact", "dependencies": []},
+ {"node_id": "n2", "claim": "left branch", "dependencies": ["n1"]},
+ {"node_id": "n3", "claim": "right branch", "dependencies": ["n1"]},
+ {
+ "node_id": "n4",
+ "claim": "combine branches",
+ "dependencies": ["n2", "n3"],
+ },
+ ],
+ "terminal_node_id": "n4",
+ }
+ )
+
+
+def test_proof_dag_supports_real_branching() -> None:
+ dag = branched_dag()
+ assert dag.nodes[-1].dependencies == ["n2", "n3"]
+
+
+def test_replacement_must_reference_a_real_dag_node() -> None:
+ replacements = ReplacementPlan.model_validate(
+ {
+ "changes": [
+ {
+ "slot_id": "s1",
+ "source_node_id": "n9",
+ "description": "constant",
+ "original_value": "1",
+ "replacement_value": "2",
+ "guard_condition": "positive",
+ "guard_justification": "2 is positive",
+ }
+ ],
+ "closure_statement": "No undeclared changes.",
+ }
+ )
+ with pytest.raises(ValueError, match="unknown nodes"):
+ replacements.validate_against(branched_dag())
+
+
+def test_diffusion_preserves_dependencies_and_methods() -> None:
+ dag = branched_dag()
+ methods = MethodPlan.model_validate(
+ {
+ "nodes": [
+ {"node_id": node.node_id, "method_label": f"method {node.node_id}"}
+ for node in dag.nodes
+ ]
+ }
+ )
+ diffused = DiffusedProof.model_validate(
+ {
+ "nodes": [
+ {
+ "node_id": node.node_id,
+ "dependencies": node.dependencies,
+ "method_label": f"method {node.node_id}",
+ "instantiated_claim": f"new {node.claim}",
+ "justification": "valid re-instantiation",
+ }
+ for node in dag.nodes
+ ],
+ "terminal_node_id": "n4",
+ "terminal_answer": "answer",
+ }
+ )
+ assert diffused.validate_against(dag, methods) is diffused
+
+ broken = diffused.model_copy(deep=True)
+ broken.nodes[-1].dependencies = ["n3"]
+ with pytest.raises(ValueError, match="dependencies changed"):
+ broken.validate_against(dag, methods)
+
+
+def test_rendered_solution_must_expose_every_node() -> None:
+ dag = branched_dag()
+ methods = MethodPlan.model_validate(
+ {
+ "nodes": [
+ {"node_id": node.node_id, "method_label": f"method {node.node_id}"}
+ for node in dag.nodes
+ ]
+ }
+ )
+ diffused = DiffusedProof.model_validate(
+ {
+ "nodes": [
+ {
+ "node_id": node.node_id,
+ "dependencies": node.dependencies,
+ "method_label": f"method {node.node_id}",
+ "instantiated_claim": f"new {node.claim}",
+ "justification": "valid",
+ }
+ for node in dag.nodes
+ ],
+ "terminal_node_id": "n4",
+ "terminal_answer": "answer",
+ }
+ ).validate_against(dag, methods)
+ variant = RenderedVariant(
+ question="New problem",
+ solution="[n1] first [n2] left [n3] right",
+ node_order=dag.node_ids(),
+ terminal_answer="answer",
+ )
+ with pytest.raises(ValueError, match="missing node markers.*n4"):
+ variant.validate_against(dag, diffused)
+
+
+def test_accept_verdict_normalizes_explicit_none_sentinel() -> None:
+ verdict = JudgeVerdict(
+ verdict="accept",
+ step_by_step_check="n1 valid",
+ replacement_check="s1 valid",
+ blocking_issues="None detected.",
+ patch_suggestion="N/A",
+ )
+ assert verdict.blocking_issues == ""
+ assert verdict.patch_suggestion == ""