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:
Scott KarpandClaude Opus 4.6 committed 2026-03-18 08:59:08 -04:00
1 parent 7fe8025434
commit 671d45625c
7 files changed
+1230

No files matched your search

@@ -5,6 +5,9 @@ defmodule VavPipeline.Application do
Starts the supervision tree with:
- Repo (L3 PostgreSQL — oral tradition persistence)
- Chatzotzrot (silver trumpets — signal system)
- AreiMiklat (cities of refuge — protection protocol)
- EglahArufah (accountability for unknown harm)
- Bikurim (first fruits — release protocol)
- ShabbatTimer (mandatory cessation monitor)
- ShoreshEnginePort (Erlang Port to Haskell engine, if binary found)
- TalmudicEngineSocket (Unix socket to Prolog engine)
@@ -27,6 +30,9 @@ defmodule VavPipeline.Application do
children =
[
{VavPipeline.Chatzotzrot, []},
{VavPipeline.AreiMiklat, []},
{VavPipeline.EglahArufah, []},
{VavPipeline.Bikurim, []},
{VavPipeline.ShabbatTimer, []}
]
|> maybe_add_repo()
@@ -0,0 +1,346 @@
defmodule VavPipeline.AreiMiklat do
@moduledoc """
Cities of Refuge — Bamidbar 35:11-28, Devarim 19:1-13.
Architecture §3.14, Construction §4.8:
Protection protocol for cases where the system's output causes
real harm — not just error. Protects BOTH the affected party
AND the responsible component from reactive destruction while
accountability is determined.
V'hikritem lakhem arim, arei miklat tihyeinah lakhem,
v'nas shamah rotze'ach, makeh nefesh bishgagah.
— Bamidbar 35:11
"You shall designate cities for yourselves, cities of refuge
they shall be for you, and a manslayer shall flee there —
one who strikes a person unintentionally."
Three principles from Torah:
1. Takhin lekha haderekh (Devarim 19:3) — prepare the road
BEFORE the one who needs refuge arrives.
2. Bivli da'at (Devarim 19:4) — refuge is for harm without
intent, without knowledge. Not punishment. Protection.
3. Ad mot hakohen hagadol (Bamidbar 35:25) — release comes
through an external event (Sanhedrin judgment), not a timer.
Neither the refugee nor the avenger controls release.
Protocol:
1. Harm event detected → component enters refuge (isolated, protected)
2. Affected party protected from further exposure
3. Chatzotzrot signal alerts kohanim (operators)
4. Sanhedrin deliberation determines release — not automatic, not arbitrary
5. All refuge events permanently recorded (append-only audit)
"""
use GenServer
require Logger
alias VavPipeline.Chatzotzrot
@type refuge_status :: :in_refuge | :released
@type incident_type :: :unintentional_harm | :processing_error | :data_exposure | :integrity_breach
@type incident :: %{
id: String.t(),
type: incident_type(),
description: String.t(),
affected_party: String.t() | nil,
processing_path: [String.t()],
detected_at: DateTime.t()
}
@type refuge_record :: %{
component_id: String.t(),
incident: incident(),
status: refuge_status(),
entered_at: DateTime.t(),
released_at: DateTime.t() | nil,
release_judgment: map() | nil
}
# ============================================================
# Client API
# ============================================================
def start_link(opts \\ []) do
name = Keyword.get(opts, :name, __MODULE__)
GenServer.start_link(__MODULE__, opts, name: name)
end
@doc """
Enter refuge — a component that caused unintentional harm.
Bamidbar 35:11 — v'nas shamah rotze'ach, makeh nefesh bishgagah.
The component is isolated from normal operation but PROTECTED
from reactive destruction. No one deletes a component under refuge.
Returns {:ok, refuge_record} or {:error, reason}.
"""
@spec enter_refuge(String.t(), incident()) :: {:ok, refuge_record()} | {:error, atom()}
def enter_refuge(component_id, incident) when is_binary(component_id) and is_map(incident) do
GenServer.call(__MODULE__, {:enter_refuge, component_id, incident})
end
@doc """
Protect an affected party from further exposure to the same processing path.
Bamidbar 35:12 — v'lo yamut harotze'ach ad amdo lifnei ha'edah lamishpat.
The one who caused harm is protected; the one harmed is also protected.
"""
@spec protect_affected(String.t(), incident()) :: {:ok, map()} | {:error, atom()}
def protect_affected(party_id, incident) when is_binary(party_id) and is_map(incident) do
GenServer.call(__MODULE__, {:protect_affected, party_id, incident})
end
@doc """
Release a component from refuge — requires Sanhedrin judgment.
Bamidbar 35:25 — ad mot hakohen hagadol.
Release is not a timer. Not a governance board's whim.
It is a judgment that the era of the harm has passed.
The judgment must include:
- authority: :sanhedrin_deliberation
- reason: what has changed (the "death of the kohen gadol")
- grounding: Torah reference that grounds the judgment
Returns {:ok, updated_record} or {:error, reason}.
"""
@spec release(String.t(), map()) :: {:ok, refuge_record()} | {:error, atom()}
def release(component_id, judgment) when is_binary(component_id) and is_map(judgment) do
GenServer.call(__MODULE__, {:release, component_id, judgment})
end
@doc """
Check if a component is currently in refuge.
"""
@spec in_refuge?(String.t()) :: boolean()
def in_refuge?(component_id) do
GenServer.call(__MODULE__, {:in_refuge?, component_id})
end
@doc """
Check if a processing path is blocked for a party.
"""
@spec path_blocked?(String.t(), [String.t()]) :: boolean()
def path_blocked?(party_id, processing_path) do
GenServer.call(__MODULE__, {:path_blocked?, party_id, processing_path})
end
@doc """
Get all current refuge records.
"""
@spec list_refugees() :: [refuge_record()]
def list_refugees do
GenServer.call(__MODULE__, :list_refugees)
end
@doc """
Get all active protections for affected parties.
"""
@spec list_protections() :: [map()]
def list_protections do
GenServer.call(__MODULE__, :list_protections)
end
@doc """
Get the full audit trail — all refuge events ever recorded.
Append-only. Never deleted.
"""
@spec audit_trail() :: [map()]
def audit_trail do
GenServer.call(__MODULE__, :audit_trail)
end
# ============================================================
# GenServer callbacks
# ============================================================
@impl true
def init(_opts) do
state = %{
# Active refuge records: %{component_id => refuge_record}
refugees: %{},
# Active protections: %{party_id => [%{path: [...], incident_id: ...}]}
protections: %{},
# Permanent audit trail — append-only, never deleted
audit: []
}
Logger.info("AreiMiklat: three cities of refuge prepared — takhin lekha haderekh")
{:ok, state}
end
@impl true
def handle_call({:enter_refuge, component_id, incident}, _from, state) do
if Map.has_key?(state.refugees, component_id) do
{:reply, {:error, :already_in_refuge}, state}
else
now = DateTime.utc_now()
incident = Map.put_new(incident, :detected_at, now)
record = %{
component_id: component_id,
incident: incident,
status: :in_refuge,
entered_at: now,
released_at: nil,
release_judgment: nil
}
audit_entry = %{
event: :refuge_entry,
component_id: component_id,
incident: incident,
timestamp: now
}
# Sound the trumpets — alert the kohanim
Chatzotzrot.signal(:assembly_leaders,
reason: "Refuge entry: #{component_id} — #{Map.get(incident, :description, "unintentional harm")}"
)
Logger.warning(
"AreiMiklat: #{component_id} entered refuge — " <>
"#{Map.get(incident, :type, :unknown)} — #{Map.get(incident, :description, "no description")}"
)
new_state = %{
state
| refugees: Map.put(state.refugees, component_id, record),
audit: [audit_entry | state.audit]
}
{:reply, {:ok, record}, new_state}
end
end
@impl true
def handle_call({:protect_affected, party_id, incident}, _from, state) do
now = DateTime.utc_now()
path = Map.get(incident, :processing_path, [])
incident_id = Map.get(incident, :id, "unknown")
protection = %{
party_id: party_id,
blocked_path: path,
incident_id: incident_id,
protected_at: now
}
audit_entry = %{
event: :affected_party_protected,
party_id: party_id,
incident_id: incident_id,
blocked_path: path,
timestamp: now
}
Logger.info("AreiMiklat: affected party #{party_id} protected from path #{inspect(path)}")
existing = Map.get(state.protections, party_id, [])
new_state = %{
state
| protections: Map.put(state.protections, party_id, [protection | existing]),
audit: [audit_entry | state.audit]
}
{:reply, {:ok, protection}, new_state}
end
@impl true
def handle_call({:release, component_id, judgment}, _from, state) do
case Map.get(state.refugees, component_id) do
nil ->
{:reply, {:error, :not_in_refuge}, state}
record ->
# Only Sanhedrin deliberation can release — ad mot hakohen hagadol
case Map.get(judgment, :authority) do
:sanhedrin_deliberation ->
now = DateTime.utc_now()
updated = %{
record
| status: :released,
released_at: now,
release_judgment: judgment
}
audit_entry = %{
event: :refuge_release,
component_id: component_id,
judgment: judgment,
timestamp: now
}
Logger.info(
"AreiMiklat: #{component_id} released from refuge — " <>
"#{Map.get(judgment, :reason, "era ended")}"
)
new_state = %{
state
| refugees: Map.delete(state.refugees, component_id),
audit: [audit_entry | state.audit]
}
{:reply, {:ok, updated}, new_state}
other ->
Logger.warning(
"AreiMiklat: unauthorized release attempt for #{component_id} — " <>
"authority #{inspect(other)} is not :sanhedrin_deliberation"
)
{:reply, {:error, :unauthorized_release}, state}
end
end
end
@impl true
def handle_call({:in_refuge?, component_id}, _from, state) do
{:reply, Map.has_key?(state.refugees, component_id), state}
end
@impl true
def handle_call({:path_blocked?, party_id, path}, _from, state) do
blocked =
case Map.get(state.protections, party_id) do
nil ->
false
protections ->
Enum.any?(protections, fn p ->
# A path is blocked if the blocked_path is a prefix of the requested path
List.starts_with?(path, p.blocked_path)
end)
end
{:reply, blocked, state}
end
@impl true
def handle_call(:list_refugees, _from, state) do
{:reply, Map.values(state.refugees), state}
end
@impl true
def handle_call(:list_protections, _from, state) do
all =
state.protections
|> Enum.flat_map(fn {_party, protections} -> protections end)
{:reply, all, state}
end
@impl true
def handle_call(:audit_trail, _from, state) do
{:reply, state.audit, state}
end
end
+236
View File
@@ -0,0 +1,236 @@
defmodule VavPipeline.Bikurim do
@moduledoc """
First Fruits — Release Protocol. Devarim 26:1-11.
Architecture §3.16:
First-output review process for all new capabilities.
Before a new feature serves users, its first product is
offered to the specification for evaluation, accompanied
by narrative.
Arami oved avi — "A wandering Aramean was my father."
— Devarim 26:5
The offering includes NARRATIVE. Not just what was produced,
but the story of how it was produced and what lineage it carries.
The farmer does not just bring fruit. He tells the story of
his ancestors' wandering, Egypt, the exodus, and arrival.
Protocol:
1. New capability built → first output produced
2. Builder provides narrative (the mikra bikurim):
- What was built
- What specification authorized it
- What lineage it carries (which existing components it depends on)
- What Torah grounds it
3. First output evaluated against specification
4. Accepted → recorded in registry, approved for production
5. Rejected → recorded with reason, not deployed
The offering is placed "before Hashem your God" — lifnei Hashem
Elohekha (Devarim 26:10). The specification judges. Not the builder.
Not the operator. The specification.
"""
use GenServer
require Logger
alias VavPipeline.Specification
@type offering_status :: :accepted | :rejected | :pending
@type offering :: %{
capability: String.t(),
first_output: any(),
narrative: String.t(),
lineage: [String.t()],
torah_grounding: String.t() | nil,
offered_at: DateTime.t(),
status: offering_status(),
evaluation: map() | nil
}
# ============================================================
# Client API
# ============================================================
def start_link(opts \\ []) do
name = Keyword.get(opts, :name, __MODULE__)
GenServer.start_link(__MODULE__, opts, name: name)
end
@doc """
Offer first fruit — submit a new capability's first output for review.
Devarim 26:2 — V'lakachta mereshit kol p'ri ha'adamah...
"You shall take of the first of every fruit of the ground..."
Parameters:
- capability_name: identifier for the new capability
- first_output: the actual first product
- narrative: the mikra bikurim — the story of how this was built
- opts: keyword list with optional :lineage and :torah_grounding
Returns {:ok, :approved_for_deployment, offering} or
{:error, :specification_mismatch, reason, offering}.
"""
@spec offer(String.t(), any(), String.t(), keyword()) ::
{:ok, :approved_for_deployment, offering()}
| {:error, :specification_mismatch, String.t(), offering()}
def offer(capability_name, first_output, narrative, opts \\ [])
when is_binary(capability_name) and is_binary(narrative) do
GenServer.call(__MODULE__, {:offer, capability_name, first_output, narrative, opts})
end
@doc """
Get all offerings in the registry.
"""
@spec registry() :: [offering()]
def registry do
GenServer.call(__MODULE__, :registry)
end
@doc """
Get offerings by status.
"""
@spec by_status(offering_status()) :: [offering()]
def by_status(status) when status in [:accepted, :rejected, :pending] do
GenServer.call(__MODULE__, {:by_status, status})
end
@doc """
Check if a capability has been accepted (approved for deployment).
"""
@spec approved?(String.t()) :: boolean()
def approved?(capability_name) do
GenServer.call(__MODULE__, {:approved?, capability_name})
end
@doc """
Count offerings by status.
"""
@spec count(offering_status() | :all) :: non_neg_integer()
def count(filter \\ :all) do
GenServer.call(__MODULE__, {:count, filter})
end
# ============================================================
# GenServer callbacks
# ============================================================
@impl true
def init(_opts) do
state = %{
# All offerings — append-only registry
offerings: []
}
Logger.info("Bikurim: first fruits protocol ready — reshit kol p'ri ha'adamah")
{:ok, state}
end
@impl true
def handle_call({:offer, capability_name, first_output, narrative, opts}, _from, state) do
now = DateTime.utc_now()
lineage = Keyword.get(opts, :lineage, [])
torah_grounding = Keyword.get(opts, :torah_grounding)
offering = %{
capability: capability_name,
first_output: first_output,
narrative: narrative,
lineage: lineage,
torah_grounding: torah_grounding,
offered_at: now,
status: :pending,
evaluation: nil
}
# Evaluate against specification — lifnei Hashem Elohekha
case evaluate_against_specification(offering) do
:accepted ->
accepted = %{offering | status: :accepted, evaluation: %{result: :accepted}}
Logger.info(
"Bikurim: #{capability_name} accepted — first fruit approved for deployment"
)
new_state = %{state | offerings: [accepted | state.offerings]}
{:reply, {:ok, :approved_for_deployment, accepted}, new_state}
{:rejected, reason} ->
rejected = %{
offering
| status: :rejected,
evaluation: %{result: :rejected, reason: reason}
}
Logger.warning(
"Bikurim: #{capability_name} rejected — #{reason}"
)
new_state = %{state | offerings: [rejected | state.offerings]}
{:reply, {:error, :specification_mismatch, reason, rejected}, new_state}
end
end
@impl true
def handle_call(:registry, _from, state) do
{:reply, state.offerings, state}
end
@impl true
def handle_call({:by_status, status}, _from, state) do
matching = Enum.filter(state.offerings, &(&1.status == status))
{:reply, matching, state}
end
@impl true
def handle_call({:approved?, capability_name}, _from, state) do
approved =
Enum.any?(state.offerings, fn o ->
o.capability == capability_name and o.status == :accepted
end)
{:reply, approved, state}
end
@impl true
def handle_call({:count, :all}, _from, state) do
{:reply, length(state.offerings), state}
end
@impl true
def handle_call({:count, status}, _from, state) do
count = Enum.count(state.offerings, &(&1.status == status))
{:reply, count, state}
end
# ============================================================
# Specification evaluation
# ============================================================
defp evaluate_against_specification(offering) do
# The specification evaluates the offering. Three checks:
# 1. Does the capability have a narrative? (Arami oved avi — story is required)
# 2. Does the first output conform to the specification?
# 3. Is the Torah grounding valid?
cond do
# No narrative — the bikurim requires the mikra (recitation)
String.trim(offering.narrative) == "" ->
{:rejected, "No narrative provided — Devarim 26:5 requires the mikra bikurim"}
# Check against specification module if available
Code.ensure_loaded?(Specification) and function_exported?(Specification, :evaluate_bikurim, 1) ->
apply(Specification, :evaluate_bikurim, [offering])
# Default: accept if narrative is present and first_output is not nil
is_nil(offering.first_output) ->
{:rejected, "No first output provided — there must be fruit to offer"}
true ->
:accepted
end
end
end
@@ -0,0 +1,194 @@
defmodule VavPipeline.EglahArufah do
@moduledoc """
Accountability Protocol — Devarim 21:1-9.
Architecture §3.15:
Formal accountability for harm of UNKNOWN origin.
The nearest component documents what it processed,
what it did not check, and what it could have caught.
Yadeinu lo shafkhu et hadam hazeh, v'eineinu lo ra'u.
— Devarim 21:7
"Our hands did not shed this blood, and our eyes did not see."
The Talmud asks: would we suspect the elders of shedding blood?
Rather, the declaration means: we did not let this person leave
without food (provision) or escort (protection).
Accountability for what was NOT provided.
Protocol:
1. Harm of unknown origin detected
2. Find the nearest component in the processing chain
3. That component makes a formal declaration:
- What it processed (recent operations)
- What it did not check (skipped validations)
- What it could have caught (missed catches)
4. Declaration permanently recorded — never deleted
5. Chatzotzrot signals governance (assembly_leaders)
The eglah arufah is broken — the heifer's neck is broken in the
nachal eitan (a harsh valley). The system acknowledges that
something was NOT done. The accountability is permanent.
"""
use GenServer
require Logger
alias VavPipeline.Chatzotzrot
@type harm_incident :: %{
id: String.t(),
description: String.t(),
approximate_location: String.t(),
detected_at: DateTime.t(),
source: :unknown
}
@type declaration :: %{
incident_id: String.t(),
component_id: String.t(),
processed: [String.t()],
not_checked: [String.t()],
could_have_caught: [String.t()],
declaration_text: String.t(),
declared_at: DateTime.t()
}
# ============================================================
# Client API
# ============================================================
def start_link(opts \\ []) do
name = Keyword.get(opts, :name, __MODULE__)
GenServer.start_link(__MODULE__, opts, name: name)
end
@doc """
Initiate the eglah arufah protocol for harm of unknown origin.
Devarim 21:1 — Ki yimatze chalal ba'adamah...
"When a corpse is found in the land... and it is not known who struck him."
The nearest component to the harm must make a formal declaration
of what it did and did not do. This is accountability for failure
to protect, not accusation of causing harm.
Parameters:
- incident: the harm event (source must be :unknown)
- nearest_component_id: which component is nearest
- report: map with :processed, :not_checked, :could_have_caught lists
Returns {:ok, declaration} or {:error, reason}.
"""
@spec initiate(harm_incident(), String.t(), map()) ::
{:ok, declaration()} | {:error, atom()}
def initiate(incident, nearest_component_id, report)
when is_map(incident) and is_binary(nearest_component_id) and is_map(report) do
GenServer.call(__MODULE__, {:initiate, incident, nearest_component_id, report})
end
@doc """
Get all declarations — the permanent record.
These are never deleted. The eglah arufah is permanent accountability.
"""
@spec declarations() :: [declaration()]
def declarations do
GenServer.call(__MODULE__, :declarations)
end
@doc """
Get declarations for a specific incident.
"""
@spec declarations_for(String.t()) :: [declaration()]
def declarations_for(incident_id) when is_binary(incident_id) do
GenServer.call(__MODULE__, {:declarations_for, incident_id})
end
@doc """
Count total declarations.
"""
@spec count() :: non_neg_integer()
def count do
GenServer.call(__MODULE__, :count)
end
# ============================================================
# GenServer callbacks
# ============================================================
@impl true
def init(_opts) do
state = %{
# Permanent declarations — append-only, never deleted
declarations: []
}
Logger.info("EglahArufah: accountability protocol ready — nachal eitan prepared")
{:ok, state}
end
@impl true
def handle_call({:initiate, incident, nearest_component_id, report}, _from, state) do
# Validate source is unknown — eglah arufah is ONLY for unknown harm
case Map.get(incident, :source) do
:unknown ->
now = DateTime.utc_now()
incident = Map.put_new(incident, :detected_at, now)
incident_id = Map.get(incident, :id, "incident_#{:erlang.unique_integer([:positive])}")
declaration = %{
incident_id: incident_id,
component_id: nearest_component_id,
processed: Map.get(report, :processed, []),
not_checked: Map.get(report, :not_checked, []),
could_have_caught: Map.get(report, :could_have_caught, []),
declaration_text:
"This component (#{nearest_component_id}) did not cause this harm. " <>
"This component acknowledges proximity to the harm. " <>
"This component reports what it did and did not do.",
declared_at: now
}
# Sound the trumpets — alert governance
Chatzotzrot.signal(:assembly_leaders,
reason:
"Eglah Arufah: unknown harm near #{nearest_component_id} — #{Map.get(incident, :description, "unknown")}"
)
Logger.warning(
"EglahArufah: declaration by #{nearest_component_id} — " <>
"processed #{length(declaration.processed)} operations, " <>
"skipped #{length(declaration.not_checked)} checks, " <>
"could have caught #{length(declaration.could_have_caught)} issues"
)
new_state = %{state | declarations: [declaration | state.declarations]}
{:reply, {:ok, declaration}, new_state}
other ->
Logger.warning(
"EglahArufah: rejected — source is #{inspect(other)}, not :unknown. " <>
"Eglah arufah is only for harm of unknown origin."
)
{:reply, {:error, :source_not_unknown}, state}
end
end
@impl true
def handle_call(:declarations, _from, state) do
{:reply, state.declarations, state}
end
@impl true
def handle_call({:declarations_for, incident_id}, _from, state) do
matching = Enum.filter(state.declarations, &(&1.incident_id == incident_id))
{:reply, matching, state}
end
@impl true
def handle_call(:count, _from, state) do
{:reply, length(state.declarations), state}
end
end
+172
View File
@@ -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
+150
View File
@@ -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
+126
View File
@@ -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