defmodule VavPipeline.L3.CouplingTraceTest do @moduledoc """ Tests for the Elixir-side L1-grounded coupling-trace validator. This module mirrors the Prolog is_l1_grounded_coupling/1 check in talmudic_engine/src/halt/avodah_zarah.pl. The two MUST stay aligned — if Prolog adds a new recognized coupling shape, this module's l1_grounded?/1 must add it too. These tests are the canary: they fail loudly if either side drifts. See ~/shorashim-conversation-review.md Pass 2 finding L (Elixir half). """ use ExUnit.Case, async: true alias VavPipeline.L3.CouplingTrace describe "l1_grounded?/1 — three valid anchor shapes (mirror Prolog)" do test "verse anchor with Hebrew root subject" do assert CouplingTrace.l1_grounded?("coupled(root(בער), verse(shemot, 35, 3))") end test "verse anchor with Latinized root subject" do assert CouplingTrace.l1_grounded?("coupled(root(brk), verse(bereishit, 1, 1))") end test "mitzvah anchor (Rambam-derived, no via_verse)" do assert CouplingTrace.l1_grounded?("coupled(domain(creation), mitzvah(5))") end test "mitzvah anchor with via_verse (3-arg form)" do assert CouplingTrace.l1_grounded?( "coupled(root(shm), mitzvah(7), via_verse(devarim, 6, 4))" ) end end describe "l1_grounded?/1 — ungrounded shapes that must fail" do test "prior_decision anchor — the canonical fake-tzivah case" do refute CouplingTrace.l1_grounded?("coupled(self, prior_decision(d1))") end test "system_view anchor" do refute CouplingTrace.l1_grounded?("coupled(consensus, system_view(s1))") end test "interpretation/1 — explicit self-citation" do refute CouplingTrace.l1_grounded?("coupled(root(x), interpretation(prior_one))") end test "consensus anchor without recognized inner term" do refute CouplingTrace.l1_grounded?("coupled(any, consensus(c1))") end test "mitzvah-via-something-other-than-via_verse fails" do refute CouplingTrace.l1_grounded?( "coupled(root(x), mitzvah(7), via_decision(d1))" ) end end describe "l1_grounded?/1 — malformed input is not grounded" do test "missing closing paren" do refute CouplingTrace.l1_grounded?("coupled(root(x), verse(b, 1, 1)") end test "wrong functor" do refute CouplingTrace.l1_grounded?("derived(root(x), verse(b, 1, 1))") end test "single arg" do refute CouplingTrace.l1_grounded?("coupled(root(x))") end test "four args" do refute CouplingTrace.l1_grounded?( "coupled(a, mitzvah(1), via_verse(b, 1, 1), extra)" ) end test "empty string" do refute CouplingTrace.l1_grounded?("") end test "non-string input" do refute CouplingTrace.l1_grounded?(nil) refute CouplingTrace.l1_grounded?(42) end end describe "validate/1 — list-level checks" do test "empty list passes" do assert :ok = CouplingTrace.validate([]) end test "all-grounded list passes" do traces = [ "coupled(root(brk), verse(bereishit, 1, 1))", "coupled(root(qdsh), verse(vayikra, 11, 44))", "coupled(domain(creation), mitzvah(5))" ] assert :ok = CouplingTrace.validate(traces) end test "any ungrounded entry fails — and the offending string is reported" do traces = [ "coupled(root(brk), verse(bereishit, 1, 1))", "coupled(self, prior_decision(d1))" ] assert {:error, :ungrounded, "coupled(self, prior_decision(d1))"} = CouplingTrace.validate(traces) end test "first ungrounded entry is reported (Enum.find semantics)" do traces = [ "coupled(root(x), system_view(s1))", "coupled(any, consensus(c1))" ] assert {:error, :ungrounded, "coupled(root(x), system_view(s1))"} = CouplingTrace.validate(traces) end end describe "parser robustness — nested parens in subject must not break splitting" do test "subject with nested parens (root(בער)) parses cleanly" do # The parser must not split on the comma inside root(...) ... # actually root() has no comma; let's stress with a more complex # subject form just in case. assert CouplingTrace.l1_grounded?( "coupled(complex_subject(a, b, c), verse(shemot, 1, 1))" ) end test "subject with deeply nested parens" do assert CouplingTrace.l1_grounded?( "coupled(outer(middle(inner(x))), mitzvah(99))" ) end test "extra whitespace around args is tolerated" do assert CouplingTrace.l1_grounded?( "coupled( root(brk) , verse(bereishit, 1, 1) )" ) end end end