Files
bikoret/vav_pipeline/test/arei_miklat_test.exs
T
Scott KarpandClaude Opus 4.6 671d45625c Protection layer: Arei Miklat, Eglah Arufah, Bikurim — Steps 27-29
Takhin lekha haderekh — Devarim 19:3.
"Prepare the road" before the one who needs refuge arrives.
Protection before production.

Arei Miklat (Cities of Refuge — Bamidbar 35, Devarim 19):
- GenServer with refuge registry, affected party protection, audit trail
- enter_refuge/2 isolates component but protects from reactive destruction
- protect_affected/2 blocks processing paths that caused harm
- release/2 requires :sanhedrin_deliberation authority — ad mot hakohen hagadol
- Chatzotzrot assembly_leaders signal on every refuge entry
- 15 tests: entry, double-entry prevention, affected party blocking,
  unauthorized release rejection, audit trail, chatzotzrot signaling

Eglah Arufah (Accountability — Devarim 21:1-9):
- GenServer with permanent (append-only) declaration registry
- initiate/3: nearest component declares what it processed, skipped, missed
- Only for :unknown source — rejects known-source incidents
- "Yadeinu lo shafkhu" — accountability for what was NOT provided
- 9 tests: declaration recording, source validation, multi-component
  declarations, chatzotzrot signaling, filtering, counting

Bikurim (First Fruits — Devarim 26:1-11):
- GenServer with offering registry
- offer/4: submit first output with required narrative (mikra bikurim)
- Rejects empty narrative ("Arami oved avi" — story is required)
- Rejects nil first output (there must be fruit to offer)
- Delegates to Specification.evaluate_bikurim/1 when available
- approved?/1 gate for deployment readiness
- 11 tests: acceptance, narrative validation, nil output rejection,
  registry, status filtering, approval checking, counting

All three added to supervision tree in application.ex.
160 Elixir tests pass, 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 08:59:08 -04:00

173 lines
6.1 KiB
Elixir

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