"""Round-trip + validation tests for the Solution Pattern schema (T01).""" import os import sys import pytest sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from session_memory.curate.schema import ( # noqa: E402 Provenance, Resolution, Scope, SolutionPattern, ) def _sample() -> SolutionPattern: src = "success:clean_pass:outcome" return SolutionPattern( id=SolutionPattern.make_id(src), name="Run tests before declaring success", version="1.0.0", polarity="success", problem="Sessions that run tests and finish with no retries resolve cheaply.", resolutions=[Resolution(summary="Always run the suite", steps=["edit", "test", "commit"])], scope=Scope(flavors=["claude", "grok"]), provenance=Provenance(source_key=src, evidence={"frequency": 18, "cross_flavor": True}), rendering_hints={"claude": {"target": "CLAUDE.md"}, "codex": {"target": "AGENTS.md"}}, status="approved", distribution_ready=True, ) def test_round_trip_is_lossless(): p = _sample() again = SolutionPattern.from_json(p.to_json()) assert again.to_dict() == p.to_dict() assert again.resolutions[0].steps == ["edit", "test", "commit"] assert again.scope.flavors == ["claude", "grok"] assert again.provenance.evidence["cross_flavor"] is True def test_serialization_is_deterministic(): p = _sample() assert p.to_json() == p.to_json() assert SolutionPattern.from_json(p.to_json()).to_json() == p.to_json() def test_make_id_is_stable_and_slugged(): assert SolutionPattern.make_id("success:clean_pass:outcome") == "sp-success-clean_pass-outcome" # same source key -> same id regardless of later wording assert SolutionPattern.make_id("problem:abandoned:outcome") == SolutionPattern.make_id( "problem:abandoned:outcome" ) def test_bump_version(): assert SolutionPattern.bump_version("1.0.0") == "1.0.1" assert SolutionPattern.bump_version("1.2.3", "minor") == "1.3.0" assert SolutionPattern.bump_version("1.2.3", "major") == "2.0.0" def test_rejects_unknown_polarity(): with pytest.raises(ValueError): SolutionPattern(id="x", name="n", version="1.0.0", polarity="meh", problem="p") def test_rejects_unknown_status(): with pytest.raises(ValueError): SolutionPattern(id="x", name="n", version="1.0.0", polarity="problem", problem="p", status="bogus") def test_rejects_unknown_flavor_in_hints_and_scope(): with pytest.raises(ValueError): SolutionPattern(id="x", name="n", version="1.0.0", polarity="problem", problem="p", rendering_hints={"gpt": {}}) with pytest.raises(ValueError): Scope(flavors=["gpt"])