Files
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

151 lines
5.0 KiB
Elixir

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