defmodule VavPipeline.SanhedrinHaltForwardingTest do @moduledoc """ Integration test: the Erlang Sanhedrin gate-keeper (sanhedrin/src/halt_monitor.erl) must forward halt events to the canonical Elixir HaltMonitor (VavPipeline.HaltMonitor). This honors the Torah ruling for Option 2 (see KOHEN.md / the conversation review at ~/shorashim-conversation-review.md): Devarim 12:13–14 — לֹא תַעֲלֶה עֹלֹתֶיךָ בְּכָל מָקוֹם אֲשֶׁר תִּרְאֶה כִּי אִם בַּמָּקוֹם אֲשֶׁר יִבְחַר ה׳ The Erlang gate-keeper is a courtyard pre-check; the canonical halt altar is in the Elixir HaltMonitor. When the gate refuses a case, the refusal must also be recorded at the one altar. """ use ExUnit.Case, async: false alias VavPipeline.HaltMonitor setup do # Reset the Elixir HaltMonitor between tests by resolving any halt. if HaltMonitor.halted?() do HaltMonitor.resolve("test reset") end :ok end defp make_case(context) when is_map(context) do # Build a #sanhedrin_case{} record. The fields are documented in # sanhedrin/include/sanhedrin.hrl. We use erlang:list_to_tuple to # construct the record without needing the .hrl in this Elixir file. {:sanhedrin_case, "test_case_#{:erlang.unique_integer([:positive])}", :simple, "test question", context, "test_caller", :erlang.system_time(:millisecond)} end test "halt_monitor.erl exists and exports check_case/1" do # Sanity check: the Erlang module is loadable from this VM. assert Code.ensure_loaded?(:halt_monitor), "sanhedrin/src/halt_monitor.erl must be loadable from the same BEAM VM" assert function_exported?(:halt_monitor, :check_case, 1) assert function_exported?(:halt_monitor, :audit_log, 0), "audit_log/0 must be exported (F6 fix)" assert function_exported?(:halt_monitor, :halt_count, 0), "halt_count/0 must be exported (F6 fix)" end test "halt_monitor.erl returns clear for a benign case" do {:ok, _pid} = ensure_started() benign = make_case(%{authority_source: :torah}) assert :clear = :halt_monitor.check_case(benign) end test "halt_monitor.erl detects avodah_zarah AND fires canonical halt in Elixir" do {:ok, _pid} = ensure_started() refute HaltMonitor.halted?() bad = make_case(%{authority_source: :claude_model}) result = :halt_monitor.check_case(bad) # Local refusal at the gate assert {:halt, :avodah_zarah, _reason} = result # Canonical halt event fired in Elixir HaltMonitor (the one mizbeach) assert HaltMonitor.halted?(), "Erlang gate must forward halt events to the Elixir HaltMonitor" {:halted, event} = HaltMonitor.status() assert event.condition == :avodah_zarah assert event.component == "sanhedrin/case", "component tag must identify the gate" end test "halt_monitor.erl detects shfichut_damim AND fires canonical halt" do {:ok, _pid} = ensure_started() refute HaltMonitor.halted?() bad = make_case(%{action: :delete}) {:halt, :shfichut_damim, _} = :halt_monitor.check_case(bad) assert HaltMonitor.halted?() {:halted, event} = HaltMonitor.status() assert event.condition == :shfichut_damim end test "halt_monitor.erl detects gilui_arayot AND fires canonical halt" do {:ok, _pid} = ensure_started() refute HaltMonitor.halted?() bad = make_case(%{boundary_violation: {:spec_interp_merge, "collapsed"}}) {:halt, :gilui_arayot, _} = :halt_monitor.check_case(bad) assert HaltMonitor.halted?() {:halted, event} = HaltMonitor.status() assert event.condition == :gilui_arayot end test "audit_log/0 is exposed (F6: read API)" do {:ok, _pid} = ensure_started() log = :halt_monitor.audit_log() assert is_list(log) end defp ensure_started do case :halt_monitor.start_link() do {:ok, pid} -> {:ok, pid} {:error, {:already_started, pid}} -> {:ok, pid} end end end