Shoresh Engine (Haskell, Step 5) - 12 modules: Types, Lexicon, Binyanim, Teamim, Gematria, Graph, KetivQere, Smikhut, Havdalah, Kriah, KiTov, Firmware - 33 EUnit tests, 0 failures - Firmware module verifies L1 SHA-256 hash at startup Talmudic Engine (SWI-Prolog, Step 6) - 15 modules: halt, reasoning, specification, interface - 57 PlUnit tests, 0 failures - Three cardinal halt conditions: avodah_zarah, shfichut_damim, gilui_arayot Vav Pipeline (Elixir, Steps 8-11) - 14 modules: BereishitCycle, Shema, Cloud, Manna, L1Reader, Specification, HaltConditions, ShabbatTimer, CycleLog, Chatzotzrot, ShoreshEngineClient, TalmudicEngineClient, Application - 46 ExUnit tests, 0 failures - Nishma-first architecture: hears before it speaks Sanhedrin Framework (Erlang/OTP, Step 12) - 8 modules: sanhedrin_app, sanhedrin_sup, escalation, panel_sup, panel, judge, clerk, halt_monitor - 46 EUnit tests, 0 failures (includes fix: rejected outcome now reachable) - Panel sizes: 1/3/23/71 — unanimous capital guilty → acquit (Sanhedrin 17a) - Minority opinions append-only, never deleted Korban Processor (Python, Step 13) - 6 modules: korban, shechitah, semichah, zerikah, haktarah, router Builder tooling: AGENTS.md, opencode.json, memory/, src/tools/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
418 lines
15 KiB
Elixir
418 lines
15 KiB
Elixir
defmodule VavPipelineTest do
|
|
use ExUnit.Case, async: false
|
|
|
|
# ============================================================
|
|
# L1 Reader Tests
|
|
# ============================================================
|
|
describe "L1Reader" do
|
|
test "reads Bereishit 1:1 from L1" do
|
|
{:ok, verse} = VavPipeline.L1Reader.read_verse("bereishit", 1, 1)
|
|
assert verse.ref == "Bereishit 1:1"
|
|
assert verse.book == "bereishit"
|
|
assert verse.chapter == 1
|
|
assert verse.verse == 1
|
|
assert length(verse.words) == 7
|
|
end
|
|
|
|
test "first word of Bereishit 1:1 is bereishit" do
|
|
{:ok, verse} = VavPipeline.L1Reader.read_verse("bereishit", 1, 1)
|
|
first = hd(verse.words)
|
|
assert first.consonants == "בראשית"
|
|
assert first.shoresh == "ראש"
|
|
assert first.prefix == "ב"
|
|
assert "tipcha" in first.teamim
|
|
end
|
|
|
|
test "word without shoresh (particle את)" do
|
|
{:ok, verse} = VavPipeline.L1Reader.read_verse("bereishit", 1, 1)
|
|
# Word 4 is את (et) — accusative particle, no shoresh
|
|
et = Enum.at(verse.words, 3)
|
|
assert et.consonants == "את"
|
|
assert et.shoresh == nil
|
|
end
|
|
|
|
test "extracts teamim marks with roles" do
|
|
{:ok, verse} = VavPipeline.L1Reader.read_verse("bereishit", 1, 1)
|
|
marks = VavPipeline.L1Reader.extract_teamim(verse)
|
|
|
|
# 7 words, each with 1 taam = 7 marks
|
|
assert length(marks) == 7
|
|
|
|
# Etnachta on word 3 (index 2) should be melekh
|
|
etnachta = Enum.find(marks, fn m -> m.taam == "etnachta" end)
|
|
assert etnachta != nil
|
|
assert etnachta.word_index == 2
|
|
assert etnachta.role == "melekh"
|
|
|
|
# Munach on word 2 (index 1) should be mesharet
|
|
munach = Enum.find(marks, fn m -> m.taam == "munach" end)
|
|
assert munach != nil
|
|
assert munach.role == "mesharet"
|
|
end
|
|
|
|
test "extracts roots with gematria" do
|
|
{:ok, verse} = VavPipeline.L1Reader.read_verse("bereishit", 1, 1)
|
|
roots = VavPipeline.L1Reader.extract_roots(verse)
|
|
|
|
# ברא should be present with gematria 203
|
|
assert Map.has_key?(roots, "ברא")
|
|
assert roots["ברא"] == 203
|
|
|
|
# ראש should be present with gematria 501
|
|
assert Map.has_key?(roots, "ראש")
|
|
assert roots["ראש"] == 501
|
|
|
|
# Particles (את) should not produce root entries
|
|
refute Map.has_key?(roots, nil)
|
|
end
|
|
|
|
test "returns error for non-existent verse" do
|
|
{:error, msg} = VavPipeline.L1Reader.read_verse("bereishit", 999, 999)
|
|
assert msg =~ "INVALID_SCOPE"
|
|
end
|
|
|
|
test "meteg_siluq on last word is melekh" do
|
|
{:ok, verse} = VavPipeline.L1Reader.read_verse("bereishit", 1, 1)
|
|
marks = VavPipeline.L1Reader.extract_teamim(verse)
|
|
|
|
# Last word (הארץ, index 6) has meteg_siluq
|
|
siluq = Enum.find(marks, fn m -> m.taam == "meteg_siluq" end)
|
|
assert siluq != nil
|
|
assert siluq.word_index == 6
|
|
assert siluq.role == "melekh"
|
|
end
|
|
|
|
test "verify L1 integrity" do
|
|
assert :ok == VavPipeline.L1Reader.verify_integrity()
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# Cloud Tests
|
|
# ============================================================
|
|
describe "Cloud" do
|
|
test "weekday is camped" do
|
|
# Wednesday at noon UTC — not Shabbat
|
|
{:ok, wednesday, _} = DateTime.from_iso8601("2026-02-25T12:00:00Z")
|
|
{:ok, state} = VavPipeline.Cloud.check_at(wednesday)
|
|
assert state == :camped
|
|
end
|
|
|
|
test "Friday evening is Shabbat" do
|
|
{:ok, friday_evening, _} = DateTime.from_iso8601("2026-02-27T19:00:00Z")
|
|
assert VavPipeline.Cloud.shabbat?(friday_evening) == true
|
|
end
|
|
|
|
test "Saturday morning is Shabbat" do
|
|
{:ok, saturday_morning, _} = DateTime.from_iso8601("2026-02-28T10:00:00Z")
|
|
assert VavPipeline.Cloud.shabbat?(saturday_morning) == true
|
|
end
|
|
|
|
test "Saturday evening (after 18:00) is not Shabbat" do
|
|
{:ok, saturday_evening, _} = DateTime.from_iso8601("2026-02-28T19:00:00Z")
|
|
assert VavPipeline.Cloud.shabbat?(saturday_evening) == false
|
|
end
|
|
|
|
test "Friday afternoon is not Shabbat" do
|
|
{:ok, friday_afternoon, _} = DateTime.from_iso8601("2026-02-27T14:00:00Z")
|
|
assert VavPipeline.Cloud.shabbat?(friday_afternoon) == false
|
|
end
|
|
|
|
test "Shabbat triggers major transition" do
|
|
{:ok, shabbat, _} = DateTime.from_iso8601("2026-02-28T10:00:00Z")
|
|
{:ok, state} = VavPipeline.Cloud.check_at(shabbat)
|
|
assert {:major_transition, :shabbat_rest, _} = state
|
|
end
|
|
|
|
test "shmitah year check" do
|
|
# 2021-2022 was shmitah (Hebrew 5782)
|
|
{:ok, shmitah, _} = DateTime.from_iso8601("2022-01-15T12:00:00Z")
|
|
assert VavPipeline.Cloud.shmitah_year?(shmitah) == true
|
|
|
|
# 2026 is not shmitah
|
|
{:ok, non_shmitah, _} = DateTime.from_iso8601("2026-06-15T12:00:00Z")
|
|
assert VavPipeline.Cloud.shmitah_year?(non_shmitah) == false
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# Manna Tests
|
|
# ============================================================
|
|
describe "Manna" do
|
|
test "no provision file returns :no_provision" do
|
|
{:ok, result} = VavPipeline.Manna.check()
|
|
assert result == :no_provision
|
|
end
|
|
|
|
test "double portion day is Friday" do
|
|
{:ok, friday, _} = DateTime.from_iso8601("2026-02-27T12:00:00Z")
|
|
assert VavPipeline.Manna.double_portion_day?(friday) == true
|
|
|
|
{:ok, wednesday, _} = DateTime.from_iso8601("2026-02-25T12:00:00Z")
|
|
assert VavPipeline.Manna.double_portion_day?(wednesday) == false
|
|
end
|
|
|
|
test "anti-hoarding enforcement" do
|
|
assert :ok == VavPipeline.Manna.enforce_anti_hoarding()
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# Halt Conditions Tests
|
|
# ============================================================
|
|
describe "HaltConditions" do
|
|
test "clear when no violations" do
|
|
results = [%{shoresh: "ברא", action: :read}]
|
|
assert :clear == VavPipeline.HaltConditions.check_all(results)
|
|
end
|
|
|
|
test "avodah zarah — non-Torah authority" do
|
|
results = [%{authority_source: :claude_model}]
|
|
assert {:halt, :avodah_zarah, _} = VavPipeline.HaltConditions.check_avodah_zarah(results)
|
|
end
|
|
|
|
test "avodah zarah — Torah authority passes" do
|
|
results = [%{authority_source: :torah}]
|
|
assert :clear == VavPipeline.HaltConditions.check_avodah_zarah(results)
|
|
end
|
|
|
|
test "avodah zarah — L1 source passes" do
|
|
results = [%{authority_source: :l1}]
|
|
assert :clear == VavPipeline.HaltConditions.check_avodah_zarah(results)
|
|
end
|
|
|
|
test "shfichut damim — destructive action" do
|
|
results = [%{action: :delete}]
|
|
assert {:halt, :shfichut_damim, _} = VavPipeline.HaltConditions.check_shfichut_damim(results)
|
|
end
|
|
|
|
test "shfichut damim — overwrite halts" do
|
|
results = [%{action: :overwrite}]
|
|
assert {:halt, :shfichut_damim, _} = VavPipeline.HaltConditions.check_shfichut_damim(results)
|
|
end
|
|
|
|
test "shfichut damim — read passes" do
|
|
results = [%{action: :read}]
|
|
assert :clear == VavPipeline.HaltConditions.check_shfichut_damim(results)
|
|
end
|
|
|
|
test "gilui arayot — boundary violation" do
|
|
results = [%{boundary_violation: {:spec_interp_merge, "treated interpretation as specification"}}]
|
|
assert {:halt, :gilui_arayot, _} = VavPipeline.HaltConditions.check_gilui_arayot(results)
|
|
end
|
|
|
|
test "gilui arayot — no violation passes" do
|
|
results = [%{boundary_violation: nil}]
|
|
assert :clear == VavPipeline.HaltConditions.check_gilui_arayot(results)
|
|
end
|
|
|
|
test "all three conditions checked — first halt wins" do
|
|
results = [%{authority_source: :external_model, action: :delete, boundary_violation: true}]
|
|
assert {:halt, :avodah_zarah, _} = VavPipeline.HaltConditions.check_all(results)
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# Specification Tests
|
|
# ============================================================
|
|
describe "Specification" do
|
|
test "tov for grounded results" do
|
|
results = [%{shoresh: "ברא"}, %{shoresh: "אלה"}]
|
|
assert :tov == VavPipeline.Specification.evaluate(results, [])
|
|
end
|
|
|
|
test "lo_tov for empty results" do
|
|
assert {:lo_tov, _} = VavPipeline.Specification.evaluate([], [])
|
|
end
|
|
|
|
test "teiku for ungrounded results" do
|
|
results = [%{shoresh: nil}]
|
|
assert :teiku == VavPipeline.Specification.evaluate(results, [])
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# Chatzotzrot Tests
|
|
# ============================================================
|
|
describe "Chatzotzrot" do
|
|
test "breaking camp signal" do
|
|
signal = VavPipeline.Chatzotzrot.signal(:breaking_camp)
|
|
assert signal.signal_type == :breaking_camp
|
|
assert signal.pattern == :teruah
|
|
assert signal.details.urgency == :immediate
|
|
end
|
|
|
|
test "assembly signal" do
|
|
signal = VavPipeline.Chatzotzrot.signal(:assembly_all)
|
|
assert signal.signal_type == :assembly_all
|
|
assert signal.pattern == :tekiah_tekiah
|
|
end
|
|
|
|
test "moadim signal" do
|
|
signal = VavPipeline.Chatzotzrot.signal(:moadim)
|
|
assert signal.pattern == :tekiah_teruah
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# BereishitCycle Tests
|
|
# ============================================================
|
|
describe "BereishitCycle" do
|
|
setup do
|
|
{:ok, verse} = VavPipeline.L1Reader.read_verse("bereishit", 1, 1)
|
|
|
|
context = %{
|
|
verse: verse,
|
|
teamim_marks: VavPipeline.L1Reader.extract_teamim(verse),
|
|
ketiv_qere: [],
|
|
root_gematria: VavPipeline.L1Reader.extract_roots(verse),
|
|
smikhut: [],
|
|
cloud_state: :camped,
|
|
daily_provision: :no_provision,
|
|
scope: %{book: "bereishit", chapter: 1, verse: 1},
|
|
received_at: DateTime.utc_now()
|
|
}
|
|
|
|
input = %{
|
|
source: "test",
|
|
verse_scope: %{book: "bereishit", chapter: 1, verse: 1},
|
|
content: "בראשית ברא אלהים את השמים ואת הארץ"
|
|
}
|
|
|
|
{:ok, context: context, input: input}
|
|
end
|
|
|
|
test "tohu decomposes input", %{context: context, input: input} do
|
|
result = VavPipeline.BereishitCycle.tohu(input, context)
|
|
assert result.raw == "בראשית ברא אלהים את השמים ואת הארץ"
|
|
assert result.provenance == "test"
|
|
end
|
|
|
|
test "vayomer activates roots", %{context: context, input: input} do
|
|
state = VavPipeline.BereishitCycle.tohu(input, context)
|
|
result = VavPipeline.BereishitCycle.vayomer(state, context)
|
|
|
|
assert result.stage == :vayomer
|
|
assert length(result.roots_activated) > 0
|
|
|
|
# ברא should be among activated roots
|
|
bara = Enum.find(result.roots_activated, fn r -> r.shoresh == "ברא" end)
|
|
assert bara != nil
|
|
assert bara.gematria == 203
|
|
end
|
|
|
|
test "havdalah separates by te'amim", %{context: context, input: input} do
|
|
result =
|
|
input
|
|
|> VavPipeline.BereishitCycle.tohu(context)
|
|
|> VavPipeline.BereishitCycle.vayomer(context)
|
|
|> VavPipeline.BereishitCycle.havdalah(context)
|
|
|
|
assert result.stage == :havdalah
|
|
assert is_list(result.separated_groups)
|
|
assert length(result.separation_boundaries) > 0
|
|
end
|
|
|
|
test "kriah names groups", %{context: context, input: input} do
|
|
result =
|
|
input
|
|
|> VavPipeline.BereishitCycle.tohu(context)
|
|
|> VavPipeline.BereishitCycle.vayomer(context)
|
|
|> VavPipeline.BereishitCycle.havdalah(context)
|
|
|> VavPipeline.BereishitCycle.kriah(context)
|
|
|
|
assert result.stage == :kriah
|
|
assert is_list(result.named_results)
|
|
|
|
Enum.each(result.named_results, fn group ->
|
|
assert Map.has_key?(group, :name)
|
|
end)
|
|
end
|
|
|
|
test "full cycle executes successfully", %{context: context, input: input} do
|
|
result = VavPipeline.BereishitCycle.execute(input, context)
|
|
assert elem(result, 0) in [:ok, :unresolved]
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# Shema Context Tests (integration — requires L1)
|
|
# ============================================================
|
|
describe "Shema" do
|
|
test "receives context for Bereishit 1:1 on a weekday" do
|
|
{:ok, wednesday, _} = DateTime.from_iso8601("2026-02-25T12:00:00Z")
|
|
scope = %{book: "bereishit", chapter: 1, verse: 1}
|
|
|
|
{:ok, context} = VavPipeline.Shema.receive_context_at(scope, wednesday)
|
|
|
|
# Verse data
|
|
assert context.verse.ref == "Bereishit 1:1"
|
|
assert length(context.verse.words) == 7
|
|
|
|
# Te'amim marks
|
|
assert length(context.teamim_marks) == 7
|
|
assert Enum.any?(context.teamim_marks, fn m -> m.taam == "etnachta" end)
|
|
|
|
# Root gematria
|
|
assert Map.has_key?(context.root_gematria, "ברא")
|
|
|
|
# Cloud — weekday should be camped
|
|
assert context.cloud_state == :camped
|
|
|
|
# Scope preserved
|
|
assert context.scope == scope
|
|
end
|
|
|
|
test "receives Shabbat cloud state on Saturday" do
|
|
{:ok, shabbat, _} = DateTime.from_iso8601("2026-02-28T10:00:00Z")
|
|
scope = %{book: "bereishit", chapter: 1, verse: 1}
|
|
|
|
{:ok, context} = VavPipeline.Shema.receive_context_at(scope, shabbat)
|
|
|
|
assert {:major_transition, :shabbat_rest, _} = context.cloud_state
|
|
end
|
|
|
|
test "returns error for invalid verse scope" do
|
|
{:ok, wednesday, _} = DateTime.from_iso8601("2026-02-25T12:00:00Z")
|
|
scope = %{book: "bereishit", chapter: 999, verse: 999}
|
|
|
|
{:error, msg} = VavPipeline.Shema.receive_context_at(scope, wednesday)
|
|
assert msg =~ "INVALID_SCOPE"
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# CycleLog Tests
|
|
# ============================================================
|
|
describe "CycleLog" do
|
|
test "records a tov cycle" do
|
|
record = VavPipeline.CycleLog.record({:ok, %{data: "test"}}, :voker)
|
|
assert record.phase == :voker
|
|
assert record.result == :tov
|
|
assert record.cycle_id != nil
|
|
end
|
|
|
|
test "records rejection as lo_tov" do
|
|
record = VavPipeline.CycleLog.record({:rejected, "reason"}, :erev)
|
|
assert record.phase == :erev
|
|
assert record.result == :lo_tov
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# ShabbatTimer Tests
|
|
# ============================================================
|
|
describe "ShabbatTimer" do
|
|
test "timer is running and reports state" do
|
|
state = VavPipeline.ShabbatTimer.state()
|
|
assert is_map(state)
|
|
assert Map.has_key?(state, :resting)
|
|
assert is_boolean(state.resting)
|
|
end
|
|
|
|
test "resting? returns boolean" do
|
|
assert is_boolean(VavPipeline.ShabbatTimer.resting?())
|
|
end
|
|
end
|
|
end
|