"""IMP-33 u6 — AI fallback cache gate tests. Verifies the IMP-46 gate contract: * ``read_proposal`` is a stub (returns None until IMP-46). * ``save_proposal`` enforces both gates before any write attempt. * Storage itself raises NotImplementedError (IMP-46 marker). """ from __future__ import annotations import pytest from src.phase_z2_ai_fallback.cache import ( AiFallbackCacheGateError, read_proposal, save_proposal, ) from src.phase_z2_ai_fallback.schema import AiFallbackProposal, ProposalKind def _proposal() -> AiFallbackProposal: return AiFallbackProposal( proposal_kind=ProposalKind.BUILDER_OPTIONS_PATCH, payload={"item_parser": "bullet_v2"}, rationale="u6-test", ) def test_read_proposal_returns_none_for_any_key(): assert read_proposal("frame=foo|cardinality=3") is None def test_read_proposal_rejects_empty_key(): with pytest.raises(ValueError): read_proposal("") def test_save_rejects_when_visual_check_failed(): with pytest.raises(AiFallbackCacheGateError) as exc: save_proposal( "k", _proposal(), visual_check_passed=False, user_approved=True ) assert "visual_check_passed" in str(exc.value) def test_save_rejects_when_user_not_approved(): with pytest.raises(AiFallbackCacheGateError) as exc: save_proposal( "k", _proposal(), visual_check_passed=True, user_approved=False ) assert "user_approved" in str(exc.value) def test_save_rejects_when_both_gates_false(): with pytest.raises(AiFallbackCacheGateError): save_proposal( "k", _proposal(), visual_check_passed=False, user_approved=False ) def test_save_raises_not_implemented_when_both_gates_pass(): with pytest.raises(NotImplementedError) as exc: save_proposal( "k", _proposal(), visual_check_passed=True, user_approved=True ) assert "IMP-46" in str(exc.value) def test_save_rejects_empty_key(): with pytest.raises(ValueError): save_proposal( "", _proposal(), visual_check_passed=True, user_approved=True ) def test_save_rejects_non_proposal_object(): with pytest.raises(TypeError): save_proposal( "k", {"proposal_kind": "builder_options_patch"}, # type: ignore[arg-type] visual_check_passed=True, user_approved=True, ) def test_gate_error_is_not_notimplementederror(): with pytest.raises(AiFallbackCacheGateError): save_proposal( "k", _proposal(), visual_check_passed=False, user_approved=True ) assert not issubclass(AiFallbackCacheGateError, NotImplementedError)