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
|
||||
@@ -0,0 +1,150 @@
|
||||
defmodule VavPipeline.BikurimTest do
|
||||
@moduledoc """
|
||||
Tests for the Bikurim (First Fruits / Release Protocol).
|
||||
|
||||
Devarim 26:5 — Arami oved avi.
|
||||
"A wandering Aramean was my father."
|
||||
The offering requires narrative — not just the fruit,
|
||||
but the story of how it was produced.
|
||||
"""
|
||||
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
alias VavPipeline.Bikurim
|
||||
|
||||
# ============================================================
|
||||
# Offering — Devarim 26:2
|
||||
# ============================================================
|
||||
describe "offer" do
|
||||
test "accepted offering with narrative and output" do
|
||||
{:ok, :approved_for_deployment, offering} =
|
||||
Bikurim.offer(
|
||||
"chatzotzrot_genserver",
|
||||
%{signal_types: 5, routing: true, zikaron: true},
|
||||
"Built as GenServer with BEAM PubSub routing. " <>
|
||||
"Five signals mapped to five trumpet patterns per Bamidbar 10. " <>
|
||||
"Signal history (zikaron) records every signal ever sounded.",
|
||||
lineage: ["chatzotzrot_stub", "application_supervisor"],
|
||||
torah_grounding: "Bamidbar 10:1-10"
|
||||
)
|
||||
|
||||
assert offering.capability == "chatzotzrot_genserver"
|
||||
assert offering.status == :accepted
|
||||
assert offering.narrative != ""
|
||||
assert offering.lineage == ["chatzotzrot_stub", "application_supervisor"]
|
||||
assert offering.torah_grounding == "Bamidbar 10:1-10"
|
||||
assert offering.offered_at != nil
|
||||
end
|
||||
|
||||
test "rejected when no narrative provided — mikra bikurim required" do
|
||||
{:error, :specification_mismatch, reason, offering} =
|
||||
Bikurim.offer(
|
||||
"empty_narrative_test",
|
||||
%{some: "output"},
|
||||
""
|
||||
)
|
||||
|
||||
assert offering.status == :rejected
|
||||
assert String.contains?(reason, "narrative")
|
||||
end
|
||||
|
||||
test "rejected when no first output" do
|
||||
{:error, :specification_mismatch, reason, offering} =
|
||||
Bikurim.offer(
|
||||
"nil_output_test",
|
||||
nil,
|
||||
"This capability does nothing yet"
|
||||
)
|
||||
|
||||
assert offering.status == :rejected
|
||||
assert String.contains?(reason, "first output")
|
||||
end
|
||||
|
||||
test "whitespace-only narrative is rejected" do
|
||||
{:error, :specification_mismatch, _reason, _offering} =
|
||||
Bikurim.offer(
|
||||
"whitespace_narrative",
|
||||
%{output: true},
|
||||
" \n\t "
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# ============================================================
|
||||
# Registry
|
||||
# ============================================================
|
||||
describe "registry" do
|
||||
test "offerings are recorded in registry" do
|
||||
Bikurim.offer(
|
||||
"registry_test_cap",
|
||||
%{works: true},
|
||||
"Test capability for registry verification"
|
||||
)
|
||||
|
||||
registry = Bikurim.registry()
|
||||
assert Enum.any?(registry, &(&1.capability == "registry_test_cap"))
|
||||
end
|
||||
|
||||
test "rejected offerings are also in registry" do
|
||||
Bikurim.offer("rejected_registry", nil, "Has narrative but no output")
|
||||
|
||||
registry = Bikurim.registry()
|
||||
rejected = Enum.find(registry, &(&1.capability == "rejected_registry"))
|
||||
assert rejected != nil
|
||||
assert rejected.status == :rejected
|
||||
end
|
||||
|
||||
test "by_status filters correctly" do
|
||||
Bikurim.offer("status_accepted", %{ok: true}, "Good capability")
|
||||
Bikurim.offer("status_rejected", nil, "Bad capability")
|
||||
|
||||
accepted = Bikurim.by_status(:accepted)
|
||||
assert Enum.any?(accepted, &(&1.capability == "status_accepted"))
|
||||
refute Enum.any?(accepted, &(&1.capability == "status_rejected"))
|
||||
|
||||
rejected = Bikurim.by_status(:rejected)
|
||||
assert Enum.any?(rejected, &(&1.capability == "status_rejected"))
|
||||
end
|
||||
end
|
||||
|
||||
# ============================================================
|
||||
# Approval check
|
||||
# ============================================================
|
||||
describe "approved?" do
|
||||
test "accepted capability is approved" do
|
||||
Bikurim.offer("approved_test", %{ready: true}, "Fully tested capability")
|
||||
assert Bikurim.approved?("approved_test")
|
||||
end
|
||||
|
||||
test "rejected capability is not approved" do
|
||||
Bikurim.offer("not_approved_test", nil, "Has narrative but no output")
|
||||
refute Bikurim.approved?("not_approved_test")
|
||||
end
|
||||
|
||||
test "unknown capability is not approved" do
|
||||
refute Bikurim.approved?("never_offered_capability")
|
||||
end
|
||||
end
|
||||
|
||||
# ============================================================
|
||||
# Counting
|
||||
# ============================================================
|
||||
describe "count" do
|
||||
test "counts all offerings" do
|
||||
initial = Bikurim.count(:all)
|
||||
Bikurim.offer("count_all_test", %{x: 1}, "Counting test")
|
||||
assert Bikurim.count(:all) == initial + 1
|
||||
end
|
||||
|
||||
test "counts by status" do
|
||||
initial_accepted = Bikurim.count(:accepted)
|
||||
initial_rejected = Bikurim.count(:rejected)
|
||||
|
||||
Bikurim.offer("count_accepted", %{x: 1}, "Accepted offering")
|
||||
Bikurim.offer("count_rejected", nil, "Rejected offering")
|
||||
|
||||
assert Bikurim.count(:accepted) == initial_accepted + 1
|
||||
assert Bikurim.count(:rejected) == initial_rejected + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,126 @@
|
||||
defmodule VavPipeline.EglahArufahTest do
|
||||
@moduledoc """
|
||||
Tests for the Eglah Arufah (Accountability Protocol).
|
||||
|
||||
Devarim 21:7 — Yadeinu lo shafkhu et hadam hazeh, v'eineinu lo ra'u.
|
||||
"Our hands did not shed this blood, and our eyes did not see."
|
||||
Accountability for what was NOT provided. Not accusation.
|
||||
"""
|
||||
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
alias VavPipeline.EglahArufah
|
||||
|
||||
@test_incident %{
|
||||
id: "unknown_harm_001",
|
||||
description: "User received corrupted output — source component unknown",
|
||||
approximate_location: "output_formatter",
|
||||
source: :unknown
|
||||
}
|
||||
|
||||
@test_report %{
|
||||
processed: ["korban_042", "korban_043", "korban_044"],
|
||||
not_checked: ["output_encoding_validation", "character_set_verification"],
|
||||
could_have_caught: ["malformed_utf8_in_output"]
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Initiation — Devarim 21:1-3
|
||||
# ============================================================
|
||||
describe "initiate" do
|
||||
test "records a formal declaration for unknown harm" do
|
||||
{:ok, declaration} = EglahArufah.initiate(@test_incident, "output_formatter", @test_report)
|
||||
|
||||
assert declaration.incident_id == "unknown_harm_001"
|
||||
assert declaration.component_id == "output_formatter"
|
||||
assert declaration.processed == ["korban_042", "korban_043", "korban_044"]
|
||||
assert declaration.not_checked == ["output_encoding_validation", "character_set_verification"]
|
||||
assert declaration.could_have_caught == ["malformed_utf8_in_output"]
|
||||
assert declaration.declared_at != nil
|
||||
assert String.contains?(declaration.declaration_text, "output_formatter")
|
||||
assert String.contains?(declaration.declaration_text, "did not cause this harm")
|
||||
end
|
||||
|
||||
test "rejects incident with known source" do
|
||||
known_incident = Map.put(@test_incident, :source, :korban_processor)
|
||||
|
||||
assert {:error, :source_not_unknown} =
|
||||
EglahArufah.initiate(known_incident, "output_formatter", @test_report)
|
||||
end
|
||||
|
||||
test "declaration is permanently recorded" do
|
||||
EglahArufah.initiate(@test_incident, "permanent_test", @test_report)
|
||||
|
||||
declarations = EglahArufah.declarations()
|
||||
assert Enum.any?(declarations, &(&1.component_id == "permanent_test"))
|
||||
end
|
||||
|
||||
test "chatzotzrot assembly_leaders signal on initiation" do
|
||||
VavPipeline.Chatzotzrot.subscribe(:kohanim)
|
||||
|
||||
EglahArufah.initiate(
|
||||
%{@test_incident | id: "signal_test_harm"},
|
||||
"signal_test_component",
|
||||
@test_report
|
||||
)
|
||||
|
||||
assert_receive {:chatzotzrot, %{signal_type: :assembly_leaders}}
|
||||
end
|
||||
|
||||
test "multiple declarations can exist for same incident" do
|
||||
incident = %{@test_incident | id: "multi_declare"}
|
||||
|
||||
EglahArufah.initiate(incident, "component_a", %{
|
||||
processed: ["op1"],
|
||||
not_checked: ["check1"],
|
||||
could_have_caught: []
|
||||
})
|
||||
|
||||
EglahArufah.initiate(incident, "component_b", %{
|
||||
processed: ["op2"],
|
||||
not_checked: [],
|
||||
could_have_caught: ["issue1"]
|
||||
})
|
||||
|
||||
matching = EglahArufah.declarations_for("multi_declare")
|
||||
assert length(matching) == 2
|
||||
|
||||
components = Enum.map(matching, & &1.component_id)
|
||||
assert "component_a" in components
|
||||
assert "component_b" in components
|
||||
end
|
||||
|
||||
test "empty report lists are accepted" do
|
||||
{:ok, declaration} =
|
||||
EglahArufah.initiate(
|
||||
%{@test_incident | id: "empty_report"},
|
||||
"minimal_component",
|
||||
%{processed: [], not_checked: [], could_have_caught: []}
|
||||
)
|
||||
|
||||
assert declaration.processed == []
|
||||
assert declaration.not_checked == []
|
||||
assert declaration.could_have_caught == []
|
||||
end
|
||||
end
|
||||
|
||||
# ============================================================
|
||||
# Queries
|
||||
# ============================================================
|
||||
describe "queries" do
|
||||
test "declarations_for filters by incident_id" do
|
||||
EglahArufah.initiate(%{@test_incident | id: "filter_test"}, "comp_x", @test_report)
|
||||
EglahArufah.initiate(%{@test_incident | id: "other_incident"}, "comp_y", @test_report)
|
||||
|
||||
result = EglahArufah.declarations_for("filter_test")
|
||||
assert length(result) >= 1
|
||||
assert Enum.all?(result, &(&1.incident_id == "filter_test"))
|
||||
end
|
||||
|
||||
test "count returns total declarations" do
|
||||
initial = EglahArufah.count()
|
||||
EglahArufah.initiate(%{@test_incident | id: "count_test"}, "count_comp", @test_report)
|
||||
assert EglahArufah.count() == initial + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user