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>
This commit is contained in:
1 parent
7fe8025434
commit
671d45625c
7 files changed
+1230
No files matched your search
@@ -0,0 +1,172 @@
|
||||
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
|
||||
Reference in new issue
Block a user