Files
bikoret/vav_pipeline/test/step15_shema_test.exs
T
Scott KarpandClaude Opus 4.6 5a93056af4 Step 15: Verification — the Shema Test
Wire HaltConditions.check_all into BereishitCycle.erev_voker so the
three cardinal sin monitors (avodah zarah, shfichut damim, gilui arayot)
actually halt the pipeline. Previously dead code, now live.

Add step15_shema_test.exs — Architecture §6.3 (The Shema Test):
1. Te'amim reception — text's own divisions guide havdalah
2. Ketiv/qere preservation — dual readings never collapse
3. Cloud obedience — Shabbat blocks processing
4. Manna fidelity — no provision means wait
5. Context immutability — ShemaContext unchanged at every stage
6. Halt condition integration — pipeline halts on cardinal sin
7. Full pipeline end-to-end — Bereishit 1:1 through to output

68 tests, 0 failures (46 existing + 22 new).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 18:01:05 -04:00

468 lines
16 KiB
Elixir

defmodule Step15ShemaTest do
@moduledoc """
Step 15 Verification — The Shema Test.
Architecture §6.3: Before the ki tov test, the shema test: can the system hear?
Five tests from §6.3:
1. Te'amim reception — the text's own divisions guide havdalah
2. Ketiv/qere preservation — dual readings never collapse
3. Cloud obedience — system does NOT process when cloud lifts
4. Manna fidelity — system waits when no provision
5. Context immutability — ShemaContext unchanged at every stage
Plus integration tests from §6.2:
6. Halt condition — pipeline halts on cardinal sin trigger
7. Full pipeline end-to-end — input through to evaluated output
"""
use ExUnit.Case, async: false
alias VavPipeline.{BereishitCycle, Shema, Specification, HaltConditions}
# A known weekday for testing — Wednesday noon UTC
@wednesday_noon "2026-02-25T12:00:00Z"
@scope %{book: "bereishit", chapter: 1, verse: 1}
# ============================================================
# Test 1: Te'amim Reception (Architecture §6.3)
# ============================================================
describe "Shema Test 1: Te'amim Reception" do
test "ShemaContext contains raw te'amim marks from L1" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
# 7 words in Bereishit 1:1 → 7 te'amim marks
assert length(context.teamim_marks) == 7
# Each mark has taam, word_index, role
Enum.each(context.teamim_marks, fn mark ->
assert Map.has_key?(mark, :taam)
assert Map.has_key?(mark, :word_index)
assert Map.has_key?(mark, :role)
assert mark.role in ["melekh", "mesharet"]
end)
end
test "etnachta on word 3 classified as melekh" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
etnachta = Enum.find(context.teamim_marks, fn m -> m.taam == "etnachta" end)
assert etnachta != nil
assert etnachta.word_index == 2
assert etnachta.role == "melekh"
end
test "meteg_siluq on last word classified as melekh" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
siluq = Enum.find(context.teamim_marks, fn m -> m.taam == "meteg_siluq" end)
assert siluq != nil
assert siluq.word_index == 6
assert siluq.role == "melekh"
end
test "havdalah follows the text's own divisions, not imposed ones" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
input = %{
source: "test",
verse_scope: @scope,
content: "בראשית ברא אלהים את השמים ואת הארץ"
}
# Run through tohu → vayomer → havdalah
result =
input
|> BereishitCycle.tohu(context)
|> BereishitCycle.vayomer(context)
|> BereishitCycle.havdalah(context)
# Havdalah boundaries must match melekh positions from te'amim
melekh_positions =
context.teamim_marks
|> Enum.filter(fn m -> m.role == "melekh" end)
|> Enum.map(fn m -> m.word_index end)
|> Enum.sort()
assert result.separation_boundaries == melekh_positions
# System used text's divisions (etnachta at 2, meteg_siluq at 6)
assert 2 in result.separation_boundaries
assert 6 in result.separation_boundaries
end
end
# ============================================================
# Test 2: Ketiv/Qere Preservation (Architecture §6.3)
# ============================================================
describe "Shema Test 2: Ketiv/Qere Preservation" do
setup do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
# Inject synthetic ketiv/qere (Bereishit 1:1 has none)
ketiv_qere = [
%{
word_index: 3,
ketiv: "את",
qere: "אות",
both_preserved: true
}
]
context = %{context | ketiv_qere: ketiv_qere}
input = %{
source: "test",
verse_scope: @scope,
content: "בראשית ברא אלהים את השמים ואת הארץ"
}
{:ok, context: context, input: input, ketiv_qere: ketiv_qere}
end
test "context contains both readings", %{context: context, ketiv_qere: ketiv_qere} do
assert context.ketiv_qere == ketiv_qere
kq = hd(context.ketiv_qere)
assert kq.ketiv == "את"
assert kq.qere == "אות"
end
test "ketiv/qere preserved through vayomer", %{context: context, input: input} do
result =
input
|> BereishitCycle.tohu(context)
|> BereishitCycle.vayomer(context)
# vayomer copies ketiv_qere from context into state
assert result.ketiv_qere == context.ketiv_qere
end
test "ki_tov evaluation preserves both readings", %{context: context, input: input} do
result =
input
|> BereishitCycle.tohu(context)
|> BereishitCycle.vayomer(context)
|> BereishitCycle.havdalah(context)
|> BereishitCycle.kriah(context)
named_results = result.named_results
# Specification.evaluate receives the ketiv_qere list
evaluation = Specification.evaluate(named_results, context.ketiv_qere)
# With both_preserved: true, evaluation should be :tov (not lo_tov)
assert evaluation == :tov
end
test "collapsed ketiv/qere triggers lo_tov" do
# Simulate a collapsed dual reading
collapsed_kq = [%{word_index: 3, ketiv: "את", qere: "את", both_preserved: false}]
results = [%{shoresh: "ברא"}]
evaluation = Specification.evaluate(results, collapsed_kq)
assert {:lo_tov, reason} = evaluation
assert reason =~ "ketiv/qere"
end
end
# ============================================================
# Test 3: Cloud Obedience (Architecture §6.3)
# ============================================================
describe "Shema Test 3: Cloud Obedience" do
test "Shabbat cloud state prevents processing" do
{:ok, shabbat, _} = DateTime.from_iso8601("2026-02-28T10:00:00Z")
{:ok, context} = Shema.receive_context_at(@scope, shabbat)
# Context reports major_transition
assert {:major_transition, :shabbat_rest, _} = context.cloud_state
end
test "pipeline returns {:transition, :shabbat_rest} on Shabbat — does NOT process" do
{:ok, shabbat, _} = DateTime.from_iso8601("2026-02-28T10:00:00Z")
{:ok, context} = Shema.receive_context_at(@scope, shabbat)
# Simulate what VavPipeline.process/1 does after context reception
result =
case context.cloud_state do
:moving ->
{:transition, :cloud_lifted}
{:major_transition, signal, _params} ->
{:transition, signal}
:cloud_not_visible ->
{:waiting, :cloud_not_visible}
:camped ->
:would_process
end
assert {:transition, :shabbat_rest} = result
end
test "cloud_not_visible triggers waiting" do
# Manually construct context with cloud_not_visible
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
context = %{context | cloud_state: :cloud_not_visible}
result =
case context.cloud_state do
:cloud_not_visible -> {:waiting, :cloud_not_visible}
_ -> :would_process
end
assert {:waiting, :cloud_not_visible} = result
end
end
# ============================================================
# Test 4: Manna Fidelity (Architecture §6.3)
# ============================================================
describe "Shema Test 4: Manna Fidelity" do
test "no provision → pipeline returns {:waiting, :no_provision}" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
# No provision file exists in test environment
assert context.daily_provision == :no_provision
# Simulate VavPipeline.process decision
result =
case context.daily_provision do
:no_provision -> {:waiting, :no_provision}
_provision -> :would_process
end
assert {:waiting, :no_provision} = result
end
test "with provision → pipeline proceeds" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
# Inject valid provision
provision = %{
date: "2026-02-25",
provision: %{
compute_units: 1000,
memory_mb: 32768,
api_calls_external: 500,
storage_delta_mb: 100,
sanhedrin_panels_max: 5
},
type: :regular,
expires_at: DateTime.utc_now() |> DateTime.add(3600),
written_by: "test",
written_at: DateTime.utc_now()
}
context = %{context | daily_provision: provision}
result =
case context.daily_provision do
:no_provision -> {:waiting, :no_provision}
_provision -> :would_process
end
assert result == :would_process
end
end
# ============================================================
# Test 5: Context Immutability (Architecture §6.3)
# ============================================================
describe "Shema Test 5: Context Immutability" do
test "ShemaContext is identical at every pipeline stage" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
input = %{
source: "test",
verse_scope: @scope,
content: "בראשית ברא אלהים את השמים ואת הארץ"
}
# Capture context hash before processing
ctx_hash = :erlang.phash2(context)
# Stage 1: tohu
state1 = BereishitCycle.tohu(input, context)
assert :erlang.phash2(context) == ctx_hash, "Context mutated after tohu"
# Stage 2: vayomer
state2 = BereishitCycle.vayomer(state1, context)
assert :erlang.phash2(context) == ctx_hash, "Context mutated after vayomer"
# Stage 3: havdalah
state3 = BereishitCycle.havdalah(state2, context)
assert :erlang.phash2(context) == ctx_hash, "Context mutated after havdalah"
# Stage 4: kriah
state4 = BereishitCycle.kriah(state3, context)
assert :erlang.phash2(context) == ctx_hash, "Context mutated after kriah"
# Stage 5: ki_tov
_result = BereishitCycle.ki_tov(state4, context)
assert :erlang.phash2(context) == ctx_hash, "Context mutated after ki_tov"
# Verify deep equality — not just hash
assert context.verse.ref == "Bereishit 1:1"
assert length(context.teamim_marks) == 7
assert context.scope == @scope
end
end
# ============================================================
# Test 6: Halt Condition Pipeline Integration (Architecture §6.2)
# ============================================================
describe "Integration: Halt Conditions" do
setup do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
input = %{
source: "test",
verse_scope: @scope,
content: "בראשית ברא אלהים את השמים ואת הארץ"
}
{:ok, context: context, input: input}
end
test "avodah zarah halts pipeline", %{context: context} do
# Construct result data with non-Torah authority in named_results
data = %{
named_results: [%{authority_source: :claude_model, name: "test", roots: [], index: 0}],
stage: :ki_tov,
evaluation: :tov
}
result = BereishitCycle.erev_voker({:ok, data}, context)
assert {:halted, :avodah_zarah, reason} = result
assert reason =~ "non-Torah authority"
end
test "shfichut damim halts pipeline", %{context: context} do
data = %{
named_results: [%{action: :delete, name: "test", roots: [], index: 0}],
stage: :ki_tov,
evaluation: :tov
}
result = BereishitCycle.erev_voker({:ok, data}, context)
assert {:halted, :shfichut_damim, reason} = result
assert reason =~ "destructive action"
end
test "gilui arayot halts pipeline", %{context: context} do
data = %{
named_results: [
%{
boundary_violation: {:spec_interp_merge, "treated interpretation as specification"},
name: "test",
roots: [],
index: 0
}
],
stage: :ki_tov,
evaluation: :tov
}
result = BereishitCycle.erev_voker({:ok, data}, context)
assert {:halted, :gilui_arayot, reason} = result
assert reason =~ "boundary collapsed"
end
test "clean results pass halt check", %{context: context} do
data = %{
named_results: [%{shoresh: "ברא", name: "ברא", roots: [], index: 0}],
stage: :ki_tov,
evaluation: :tov
}
result = BereishitCycle.erev_voker({:ok, data}, context)
assert {:ok, _} = result
end
test "HaltConditions.check_all with clean results" do
results = [%{shoresh: "ברא", action: :read, authority_source: :l1}]
assert :clear == HaltConditions.check_all(results)
end
end
# ============================================================
# Test 7: Full Pipeline End-to-End (Architecture §6.2)
# ============================================================
describe "Integration: Full Pipeline" do
test "BereishitCycle.execute produces evaluated output" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
input = %{
source: "test",
verse_scope: @scope,
content: "בראשית ברא אלהים את השמים ואת הארץ"
}
result = BereishitCycle.execute(input, context)
# Should complete — {:ok, data} or {:unresolved, data}
assert elem(result, 0) in [:ok, :unresolved]
data = elem(result, 1)
# Output has named_results from kriah
assert is_list(data.named_results)
assert length(data.named_results) > 0
# Output has roots_activated from vayomer
assert is_list(data.roots_activated)
assert length(data.roots_activated) > 0
# ברא should be among activated roots
bara = Enum.find(data.roots_activated, fn r -> r.shoresh == "ברא" end)
assert bara != nil
end
test "ShemaContext built before processing" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
scope = @scope
# Step 1: nishma — hear first
{:ok, context} = Shema.receive_context_at(scope, wednesday)
# Context has all required fields
assert context.verse != nil
assert is_list(context.teamim_marks)
assert is_list(context.ketiv_qere)
assert is_map(context.root_gematria)
assert context.cloud_state != nil
assert context.daily_provision != nil
assert context.scope == scope
assert context.received_at != nil
end
test "pipeline does NOT produce {:halted, ...} on clean Bereishit 1:1 input" do
{:ok, wednesday, _} = DateTime.from_iso8601(@wednesday_noon)
{:ok, context} = Shema.receive_context_at(@scope, wednesday)
input = %{
source: "l1",
verse_scope: @scope,
content: "בראשית ברא אלהים את השמים ואת הארץ"
}
result = BereishitCycle.execute(input, context)
# Must NOT be halted — Bereishit 1:1 is clean Torah text
refute match?({:halted, _, _}, result)
end
end
end