defmodule VavPipeline.AreiMiklatTest do @moduledoc """ Tests for the Arei Miklat (Cities of Refuge) protection protocol. Bamidbar 35:11 — V'hikritem lakhem arim, arei miklat tihyeinah lakhem. Devarim 19:3 — Takhin lekha haderekh — prepare the road. """ use ExUnit.Case, async: false alias VavPipeline.AreiMiklat @test_incident %{ id: "incident_001", type: :unintentional_harm, description: "Korban processor returned malformed output to user", affected_party: "user_42", processing_path: ["korban_processor", "sanhedrin", "output_formatter"] } # ============================================================ # Refuge entry — Bamidbar 35:11 # ============================================================ describe "enter_refuge" do test "component enters refuge and is recorded" do {:ok, record} = AreiMiklat.enter_refuge("korban_processor", @test_incident) assert record.component_id == "korban_processor" assert record.status == :in_refuge assert record.incident.type == :unintentional_harm assert record.entered_at != nil assert record.released_at == nil assert record.release_judgment == nil end test "component in refuge is detectable" do AreiMiklat.enter_refuge("test_component_a", @test_incident) assert AreiMiklat.in_refuge?("test_component_a") refute AreiMiklat.in_refuge?("nonexistent_component") end test "cannot enter refuge twice" do AreiMiklat.enter_refuge("double_entry_test", @test_incident) assert {:error, :already_in_refuge} = AreiMiklat.enter_refuge("double_entry_test", @test_incident) end test "refuge entry appears in audit trail" do AreiMiklat.enter_refuge("audit_test_component", @test_incident) trail = AreiMiklat.audit_trail() entry = Enum.find(trail, &(&1.event == :refuge_entry and &1.component_id == "audit_test_component")) assert entry != nil assert entry.timestamp != nil end test "chatzotzrot assembly_leaders signal is sent on refuge entry" do # Subscribe to kohanim group to receive assembly_leaders signals VavPipeline.Chatzotzrot.subscribe(:kohanim) AreiMiklat.enter_refuge("signal_test_component", @test_incident) assert_receive {:chatzotzrot, %{signal_type: :assembly_leaders}} end test "refuge entry records detected_at if not provided" do incident = Map.delete(@test_incident, :detected_at) {:ok, record} = AreiMiklat.enter_refuge("detected_at_test", incident) assert record.incident.detected_at != nil end end # ============================================================ # Affected party protection — Bamidbar 35:12 # ============================================================ describe "protect_affected" do test "affected party's processing path is blocked" do AreiMiklat.protect_affected("user_42", @test_incident) assert AreiMiklat.path_blocked?( "user_42", ["korban_processor", "sanhedrin", "output_formatter"] ) end test "unrelated path is not blocked" do AreiMiklat.protect_affected("user_43", @test_incident) refute AreiMiklat.path_blocked?("user_43", ["shoresh_engine", "talmudic_engine"]) end test "protection appears in audit trail" do AreiMiklat.protect_affected("user_audit", @test_incident) trail = AreiMiklat.audit_trail() entry = Enum.find(trail, &(&1.event == :affected_party_protected and &1.party_id == "user_audit")) assert entry != nil end test "protection is listed" do AreiMiklat.protect_affected("listed_user", @test_incident) protections = AreiMiklat.list_protections() assert Enum.any?(protections, &(&1.party_id == "listed_user")) end end # ============================================================ # Release — ad mot hakohen hagadol (Bamidbar 35:25) # ============================================================ describe "release" do test "release with sanhedrin_deliberation succeeds" do AreiMiklat.enter_refuge("release_test", @test_incident) assert AreiMiklat.in_refuge?("release_test") judgment = %{ authority: :sanhedrin_deliberation, reason: "Processing path corrected — output validation added", grounding: "Devarim 19:6 — the road has been prepared" } {:ok, released} = AreiMiklat.release("release_test", judgment) assert released.status == :released assert released.released_at != nil assert released.release_judgment.authority == :sanhedrin_deliberation refute AreiMiklat.in_refuge?("release_test") end test "release without sanhedrin authority is rejected" do AreiMiklat.enter_refuge("unauthorized_release", @test_incident) judgment = %{ authority: :operator_decision, reason: "Operator wants it back" } assert {:error, :unauthorized_release} = AreiMiklat.release("unauthorized_release", judgment) assert AreiMiklat.in_refuge?("unauthorized_release") end test "release of non-refugee returns error" do assert {:error, :not_in_refuge} = AreiMiklat.release("never_entered", %{authority: :sanhedrin_deliberation, reason: "test"}) end test "release appears in audit trail" do AreiMiklat.enter_refuge("release_audit", @test_incident) AreiMiklat.release("release_audit", %{ authority: :sanhedrin_deliberation, reason: "Era ended" }) trail = AreiMiklat.audit_trail() release_entry = Enum.find(trail, &(&1.event == :refuge_release and &1.component_id == "release_audit")) assert release_entry != nil assert release_entry.judgment.reason == "Era ended" end end # ============================================================ # Listing # ============================================================ describe "listing" do test "list_refugees returns current refugees" do AreiMiklat.enter_refuge("listed_refugee", @test_incident) refugees = AreiMiklat.list_refugees() assert Enum.any?(refugees, &(&1.component_id == "listed_refugee")) end end end