defmodule VavPipeline.UrimVTumimTest do @moduledoc """ Tests for L2 — Urim v'Tumim (Architecture §2, PRD §4.7). The Urim v'Tumim is the decision oracle interface, consulted only on high-stakes teiku cases the Sanhedrin cannot resolve. It NEVER fabricates certainty — it returns one of three honest outcomes: 1. resolved_by_specification — re-read produced an answer 2. resolved_by_external — external testimony recorded (not binding) 3. deferred_to_human — the system stops, human judgment required Bamidbar 27:21 — al-piv yetz'u v'al-piv yavo'u. By the Urim's word the people go out and come in. Not the system's word. """ use ExUnit.Case, async: false alias VavPipeline.UrimVTumim setup do # Reset state by replacing hooks with defaults each test. GenServer.call(UrimVTumim, {:set_hook, :specification_consult, &UrimVTumim.default_specification_consult/1}) GenServer.call(UrimVTumim, {:set_hook, :external_consult, &UrimVTumim.default_external_consult/1}) :ok end defp valid_input(overrides \\ %{}) do Map.merge( %{ case_id: "case_#{:rand.uniform(1_000_000)}", question: "When two principles conflict, which takes precedence?", context: %{torah_refs: ["Shemot 35:3", "Vayikra 18:5"]}, stakes: :high, sanhedrin_teiku: true }, overrides ) end # ============================================================ # Pre-condition gating # ============================================================ describe "pre-condition gating" do test "refuses cases that did not reach Sanhedrin teiku first" do # Urim is consulted AFTER teiku, never instead of Sanhedrin. input = valid_input(%{sanhedrin_teiku: false}) assert {:error, :not_eligible} = UrimVTumim.consult(input) end test "refuses ordinary-stakes cases" do # Only national-importance cases escalate to the Urim. input = valid_input(%{stakes: :ordinary}) assert {:error, :not_eligible} = UrimVTumim.consult(input) end test "refuses missing case_id" do input = valid_input() |> Map.delete(:case_id) assert {:error, _} = UrimVTumim.consult(input) end test "refuses empty question" do input = valid_input(%{question: ""}) assert {:error, :invalid_input} = UrimVTumim.consult(input) end end # ============================================================ # Outcome 1: resolved by specification # ============================================================ describe "specification re-read" do test "specification consult resolves the case" do GenServer.call(UrimVTumim, {:set_hook, :specification_consult, fn _input -> {:resolved, %{verses: ["Shemot 35:3"], reading: "Shabbat is absolute"}} end }) input = valid_input() assert {:ok, {:resolved_by_specification, evidence}} = UrimVTumim.consult(input) assert evidence.reading == "Shabbat is absolute" end test "specification resolution is recorded with steps_taken=[:specification]" do GenServer.call(UrimVTumim, {:set_hook, :specification_consult, fn _input -> {:resolved, %{ok: true}} end }) input = valid_input() {:ok, _} = UrimVTumim.consult(input) {:ok, record} = UrimVTumim.get_record(input.case_id) assert record.steps_taken == [:specification] end end # ============================================================ # Outcome 2: resolved by external (testimony, not ruling) # ============================================================ describe "external consultation" do setup do GenServer.call(UrimVTumim, {:set_hook, :external_consult, fn _input -> {:ok, %{ provenance: :claude, reading: "Pikuach nefesh overrides — testimony only", propositions: ["overrides(pikuach_nefesh, shabbat_lo_taaseh)"] }} end }) :ok end test "external consultation succeeds when specification fails" do input = valid_input() assert {:ok, {:resolved_by_external, consultation}} = UrimVTumim.consult(input) assert consultation.provenance == :claude end test "steps_taken records both specification attempt and external consult" do input = valid_input() {:ok, _} = UrimVTumim.consult(input) {:ok, record} = UrimVTumim.get_record(input.case_id) assert record.steps_taken == [:specification, :external] end end # ============================================================ # Outcome 3: deferred to human (the honest refusal) # ============================================================ describe "deferral to human" do test "defers when both specification and external fail" do # Both hooks return their default failure modes. input = valid_input() assert {:ok, {:deferred_to_human, reason}} = UrimVTumim.consult(input) assert is_binary(reason) assert reason =~ "Human judgment required" end test "deferred record has steps_taken with :deferred at the end" do input = valid_input() {:ok, _} = UrimVTumim.consult(input) {:ok, record} = UrimVTumim.get_record(input.case_id) assert record.steps_taken == [:specification, :external, :deferred] end test "the Urim refuses to fabricate certainty (PRD 4.7)" do # When both consultations fail, the Urim does NOT return any # invented answer — it deliberately stops and asks for human judgment. input = valid_input() {:ok, outcome} = UrimVTumim.consult(input) assert match?({:deferred_to_human, _}, outcome) end end # ============================================================ # Records & stats # ============================================================ describe "records and stats" do test "consultations are recorded in chronological order" do before_count = length(UrimVTumim.records()) input1 = valid_input(%{case_id: "rec_test_1"}) input2 = valid_input(%{case_id: "rec_test_2"}) {:ok, _} = UrimVTumim.consult(input1) {:ok, _} = UrimVTumim.consult(input2) records = UrimVTumim.records() assert length(records) >= before_count + 2 ids = Enum.map(records, & &1.case_id) assert "rec_test_1" in ids assert "rec_test_2" in ids end test "stats track outcomes" do stats = UrimVTumim.stats() assert is_integer(stats.total) assert is_integer(stats.resolved_by_specification) assert is_integer(stats.resolved_by_external) assert is_integer(stats.deferred_to_human) assert stats.total == stats.resolved_by_specification + stats.resolved_by_external + stats.deferred_to_human end test "get_record returns :not_found for unknown case_id" do assert :not_found = UrimVTumim.get_record("nonexistent_xyz") end end end