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 test "Pesach is a festival" do # 15 Nisan 5787 = 2 April 2026 {:ok, pesach, _} = DateTime.from_iso8601("2026-04-02T12:00:00Z") assert VavPipeline.Cloud.festival?(pesach) == true end test "Rosh Hashanah is a festival" do # 1 Tishrei 5787 = 12 September 2026 {:ok, rosh_hashanah, _} = DateTime.from_iso8601("2026-09-12T12:00:00Z") assert VavPipeline.Cloud.festival?(rosh_hashanah) == true end test "Yom Kippur is a festival" do # 10 Tishrei 5787 = 21 September 2026 {:ok, yom_kippur, _} = DateTime.from_iso8601("2026-09-21T12:00:00Z") assert VavPipeline.Cloud.festival?(yom_kippur) == true end test "regular weekday is not a festival" do {:ok, tuesday, _} = DateTime.from_iso8601("2026-03-10T12:00:00Z") assert VavPipeline.Cloud.festival?(tuesday) == false end test "festival triggers major transition" do {:ok, pesach, _} = DateTime.from_iso8601("2026-04-02T12:00:00Z") {:ok, state} = VavPipeline.Cloud.check_at(pesach) assert {:major_transition, :festival_rest, %{festival: :pesach}} = state 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 — tekiah_teruah (Architecture §3.12)" do signal = VavPipeline.Chatzotzrot.signal(:breaking_camp) assert signal.signal_type == :breaking_camp assert signal.pattern == :tekiah_teruah assert signal.details.urgency == :immediate end test "assembly_all signal — tekiah (Architecture §3.12)" do signal = VavPipeline.Chatzotzrot.signal(:assembly_all) assert signal.signal_type == :assembly_all assert signal.pattern == :tekiah end test "assembly_leaders signal — teruah (Architecture §3.12)" do signal = VavPipeline.Chatzotzrot.signal(:assembly_leaders) assert signal.signal_type == :assembly_leaders assert signal.pattern == :teruah end test "moadim signal — tekiah_tekiah (Architecture §3.12)" do signal = VavPipeline.Chatzotzrot.signal(:moadim) assert signal.pattern == :tekiah_tekiah end test "war signal — teruah_teruah (Architecture §3.12)" do signal = VavPipeline.Chatzotzrot.signal(:war) assert signal.pattern == :teruah_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