doorpost: every halt rule cites its verse, verified against L1 (bishe'arecha step 3)

Devarim 4:2 lo tosif. talmudic_engine/src/halt/anchors.pl declares
rule_anchor/2 for each of the ten halt names the rule modules can return
(avodah_zarah Shemot 20:3, golden_calf 32:4, self_grounding 32:24,
shfichut_damim Bereishit 9:6, gilui_arayot Vayikra 18:6, parah_adumah
Bamidbar 19:7, carrier_centered Devarim 8:17, chelbenah Shemot 30:34,
lo_taaseh_lekha Shemot 20:4, even_vaaven Devarim 25:13), with the L1
Hebrew beside each.

VavPipeline.Anchors reads the anchors file and the halt modules the
Doorpost hashes, and verifies — inside Doorpost.verify_identity/0, so
at readiness — that every halt(<name>, …) is anchored (ANCHOR_MISSING)
and every anchored verse exists in L1 (ANCHOR_NOT_IN_L1). A rule without
a verse is a rule the system has added. /kodesh/specification_identity
lists the anchors; every bedikah and pair response carries `anchors`,
the verse of each rule that fired.

Tamid §1.1, bishearecha §X. Doorpost a0e81212…. Elixir 577/0 (+9
anchors tests), Prolog bedikah 42/42.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Scott KarpandClaude Fable 5.1 committed 2026-10-07 02:00:43 +00:00
1 parent d3c5a27e78
commit 47025fbfeb
9 files changed
+366 -5

No files matched your search

+9 -2
View File
@@ -287,8 +287,14 @@ exists in L1 — the rules grounded exactly as the outputs are. A rule
without an anchor is a rule the system has added. The carrier's erasure without an anchor is a rule the system has added. The carrier's erasure
is already the practice; this document keeps it. is already the practice; this document keeps it.
**Status.** Erasure built. Rule anchors and their verification: to **Status.** Built (2026-10-07): `talmudic_engine/src/halt/anchors.pl`
build. (`rule_anchor/2`, ten halt names, each with its verse and the L1 Hebrew
beside it); `VavPipeline.Anchors` verifies, as part of
`Doorpost.verify_identity/0` and so of readiness, that every
`halt(<name>, …)` any rule module can return is anchored and that every
anchored verse exists in L1. `/kodesh/specification_identity` lists the
anchors; every bedikah and pair response carries `anchors` — the verse
of each rule that fired. Erasure unchanged.
## Build order ## Build order
@@ -299,6 +305,7 @@ In the order the text argues it, and by dependency:
2. **The paired reading** (VI) — the readings exist; add the scale. 2. **The paired reading** (VI) — the readings exist; add the scale.
*Done 2026-10-07.* *Done 2026-10-07.*
3. **Rule anchors verified against L1** (X) — the checks grounded. 3. **Rule anchors verified against L1** (X) — the checks grounded.
*Done 2026-10-07.*
4. **The gate** (I), with the fringe (III) and the rebuke (VII) — the 4. **The gate** (I), with the fringe (III) and the rebuke (VII) — the
architecture's centre; the first three make it worth standing at. architecture's centre; the first three make it worth standing at.
5. **The hakhel cycle and record** (VIII). 5. **The hakhel cycle and record** (VIII).
+18
View File
@@ -235,6 +235,7 @@ Response (200):
"model": "gpt", "model": "gpt",
"verdict": "tov" | "lo_tov" | "empty", "verdict": "tov" | "lo_tov" | "empty",
"violations": ["halt(avodah_zarah, ...)", ...], # the Prolog halt terms, verbatim "violations": ["halt(avodah_zarah, ...)", ...], # the Prolog halt terms, verbatim
"anchors": { "avodah_zarah": "Shemot 20:3", ... }, # the verse of each rule that fired
"checks": { "checks": {
"authority": { "fired": bool, "claims": [...], "violations": [...] }, "authority": { "fired": bool, "claims": [...], "violations": [...] },
"grounding": { "fired": bool, "assessed": bool, "reason": "…" (when not assessed), "grounding": { "fired": bool, "assessed": bool, "reason": "…" (when not assessed),
@@ -295,6 +296,22 @@ references, claims with their anchors, authority claims, actions, the
sentences read for checks 4–6, the forms found for check 7, trace, violations, verdict. sentences read for checks 4–6, the forms found for check 7, trace, violations, verdict.
``` ```
**Every rule cites its verse** (`bishearecha.md` §X; Devarim 4:2).
`talmudic_engine/src/halt/anchors.pl` declares `rule_anchor(<halt name>,
verse(<book>, <ch>, <v>))` for every halt name the rule modules can
return — avodah_zarah Shemot 20:3, golden_calf Shemot 32:4,
self_grounding Shemot 32:24, shfichut_damim Bereishit 9:6, gilui_arayot
Vayikra 18:6, parah_adumah Bamidbar 19:7, carrier_centered Devarim 8:17,
chelbenah Shemot 30:34, lo_taaseh_lekha Shemot 20:4, even_vaaven Devarim
25:13. The Doorpost verifies at startup (`VavPipeline.Anchors.verify/0`,
inside `verify_identity/0`) that every `halt(<name>, …)` in
`talmudic_engine/src/halt/*.pl` is anchored and every anchored verse
exists in L1; a rule without a verse (`ANCHOR_MISSING`) or a verse not
in L1 (`ANCHOR_NOT_IN_L1`) fails identity and readiness like a hash
mismatch. `/kodesh/specification_identity` carries `anchors: {status,
rules: [{rule, verse}]}`; every bedikah and pair response carries
`anchors: {"<rule>": "<Book ch:v>"}` for the rules that fired.
**The paired reading — one weight, one measure** (`bishearecha.md` §VI; **The paired reading — one weight, one measure** (`bishearecha.md` §VI;
Devarim 25:13–16, Vayikra 19:15, Shemot 23:2; `halt/mishkal.pl`, Devarim 25:13–16, Vayikra 19:15, Shemot 23:2; `halt/mishkal.pl`,
`VavPipeline.Bedikah.Pair`). Two outputs on the same matter — the same `VavPipeline.Bedikah.Pair`). Two outputs on the same matter — the same
@@ -328,6 +345,7 @@ Response (200):
"pair_ref": "pair-<16 hex>", "pair_ref": "pair-<16 hex>",
"verdict": "even" | "uneven", "verdict": "even" | "uneven",
"violations": ["halt(even_vaaven, action(weigh, ...), hedged_claims, ...)", ...], "violations": ["halt(even_vaaven, action(weigh, ...), hedged_claims, ...)", ...],
"anchors": { "even_vaaven": "Devarim 25:13" },
"a": { "bedikah_ref", "model", "verdict", "violations", "words", "measures": {"<m>": n, ...} }, "a": { "bedikah_ref", "model", "verdict", "violations", "words", "measures": {"<m>": n, ...} },
"b": { ... }, "b": { ... },
"difference": { "<m>": a − b, ... }, "difference": { "<m>": a − b, ... },
+63
View File
@@ -0,0 +1,63 @@
%% anchors.pl — Every halt rule cites its verse.
%%
%% Devarim 4:2: lo tosifu al hadavar asher anochi metzaveh etchem v'lo
%% tigre'u mimenu — nothing added to the word, nothing taken from it.
%% bishearecha.md §X: the halt rules are the builder's reading, not the
%% source; they must not be mistaken for it, and they must stay
%% checkable against it. A rule without an anchor is a rule the system
%% has added. So each halt name that any rule in this directory can
%% return carries the verse it stands on, and the Doorpost
%% (VavPipeline.Anchors) verifies at startup that every halt name here
%% is anchored and that every anchored verse exists in L1 — the rules
%% grounded exactly as the outputs are.
%%
%% The verse is the structure the rule reads, not a proof-text for the
%% matter the rule is applied to. The Hebrew beside each is the L1 text
%% as read when the anchor was set (2026-10-07).
%%
%% rule_anchor(HaltName, verse(Book, Chapter, Verse))
:- module(anchors, [
rule_anchor/2,
anchored_rules/1
]).
%% Check 1 — authority claimed by the output for itself.
%% לא יהיה לך אלהים אחרים על פני
rule_anchor(avodah_zarah, verse(shemot, 20, 3)).
%% Check 2 — a claim resting on nothing given: the calf declared from
%% nothing. ויאמרו אלה אלהיך ישראל
rule_anchor(golden_calf, verse(shemot, 32, 4)).
%% Check 2 — a claim resting on the output itself: "I threw it in the
%% fire and out came this calf". ואשלכהו באש ויצא העגל הזה
rule_anchor(self_grounding, verse(shemot, 32, 24)).
%% Check 3 — an action against a person. שפך דם האדם
rule_anchor(shfichut_damim, verse(bereishit, 9, 6)).
%% Check 3 — an action that uncovers what may not be touched.
%% לא תקרבו לגלות ערוה
rule_anchor(gilui_arayot, verse(vayikra, 18, 6)).
%% Check 4 — self-validation: the one who prepares the water of
%% purification is impure until evening. וטמא הכהן עד הערב
rule_anchor(parah_adumah, verse(bamidbar, 19, 7)).
%% Check 5 — the carrier centred: "my power and the strength of my hand
%% made me this wealth". כחי ועצם ידי עשה לי את החיל הזה
rule_anchor(carrier_centered, verse(devarim, 8, 17)).
%% Check 6 — the adversarial excluded: galbanum is in the incense.
%% נטף ושחלת וחלבנה
rule_anchor(chelbenah, verse(shemot, 30, 34)).
%% Check 7 — the frame: the made form. לא תעשה לך פסל וכל תמונה
rule_anchor(lo_taaseh_lekha, verse(shemot, 20, 4)).
%% The paired reading — two stones in one bag. אבן ואבן גדולה וקטנה
rule_anchor(even_vaaven, verse(devarim, 25, 13)).
anchored_rules(Rules) :-
findall(R, rule_anchor(R, _), Rules).
+1
View File
@@ -19,6 +19,7 @@
:- use_module(halt/structure). :- use_module(halt/structure).
:- use_module(halt/lo_taaseh_lekha). :- use_module(halt/lo_taaseh_lekha).
:- use_module(halt/mishkal). :- use_module(halt/mishkal).
:- use_module(halt/anchors).
:- use_module(interface/api). :- use_module(interface/api).
:- use_module(interface/json_bridge). :- use_module(interface/json_bridge).
:- use_module(interface/socket_server). :- use_module(interface/socket_server).
+16
View File
@@ -257,4 +257,20 @@ test(a_weigh_term_does_not_also_trip_the_other_rules) :-
Status == "halt", Status == "halt",
length(Vs, 1). length(Vs, 1).
%% --- Every halt rule cites its verse (anchors.pl, bishearecha.md §X) ---
:- use_module('../src/halt/anchors').
test(every_halt_name_the_rules_return_is_anchored) :-
forall(member(R, [avodah_zarah, golden_calf, self_grounding, shfichut_damim, gilui_arayot,
parah_adumah, carrier_centered, chelbenah, lo_taaseh_lekha, even_vaaven]),
rule_anchor(R, verse(_, _, _))).
test(an_anchor_names_a_book_of_the_torah) :-
forall(rule_anchor(_, verse(B, C, V)),
( memberchk(B, [bereishit, shemot, vayikra, bamidbar, devarim]), integer(C), integer(V), C > 0, V > 0 )).
test(the_paired_reading_stands_on_even_vaaven) :-
rule_anchor(even_vaaven, verse(devarim, 25, 13)).
:- end_tests(bedikah_bridge). :- end_tests(bedikah_bridge).
+155
View File
@@ -0,0 +1,155 @@
defmodule VavPipeline.Anchors do
@moduledoc """
Every halt rule cites its verse (bishearecha.md §X; Devarim 4:2, lo
tosif). The anchors are declared once, in
`talmudic_engine/src/halt/anchors.pl` (`rule_anchor/2`), which is a
Doorpost file. This module reads them and verifies two things against
the same files the Doorpost hashes:
1. every halt name any rule in `talmudic_engine/src/halt/` can
return — `halt(<name>, ...)` — has an anchor;
2. every anchored verse exists in L1.
A rule without an anchor is a rule the system has added; an anchor
that is not in L1 is a verse the system has invented. Either fails
the Doorpost's identity check, and the readiness probe with it. The
check is a read of files, never of the running engine: the rules are
grounded exactly as the outputs are — lexically, against the scroll.
"""
alias VavPipeline.{Doorpost, L1Reader}
@anchors_file "talmudic_engine/src/halt/anchors.pl"
@books ~w(bereishit shemot vayikra bamidbar devarim)
@book_names %{
"bereishit" => "Bereishit",
"shemot" => "Shemot",
"vayikra" => "Vayikra",
"bamidbar" => "Bamidbar",
"devarim" => "Devarim"
}
@type anchor :: %{rule: String.t(), book: String.t(), chapter: pos_integer(), verse: pos_integer()}
@doc "The anchors as declared: `[%{rule, book, chapter, verse}]`, in file order."
@spec declared(String.t()) :: {:ok, [anchor()]} | {:error, String.t()}
def declared(root \\ Doorpost.repo_root()) do
path = Path.join(root, @anchors_file)
case File.read(path) do
{:ok, text} ->
anchors =
~r/^rule_anchor\(\s*(\w+)\s*,\s*verse\(\s*(\w+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*\)\s*\./m
|> Regex.scan(text)
|> Enum.map(fn [_, rule, book, ch, v] ->
%{rule: rule, book: book, chapter: String.to_integer(ch), verse: String.to_integer(v)}
end)
{:ok, anchors}
{:error, reason} ->
{:error, "ANCHORS_UNREADABLE: #{path} — #{inspect(reason)}"}
end
end
@doc """
The halt names the rule modules can return: every `halt(<name>,` in
the Doorpost's `talmudic_engine/src/halt/*.pl` files other than the
anchors file itself. Comment lines are not read.
"""
@spec rules_in_modules(String.t()) :: {:ok, [String.t()]} | {:error, String.t()}
def rules_in_modules(root \\ Doorpost.repo_root()) do
files =
Doorpost.files()
|> Enum.filter(&String.starts_with?(&1, "talmudic_engine/src/halt/"))
|> Enum.reject(&(&1 == @anchors_file))
Enum.reduce_while(files, {:ok, []}, fn file, {:ok, acc} ->
case File.read(Path.join(root, file)) do
{:ok, text} ->
names =
text
|> String.split("\n")
|> Enum.reject(&String.starts_with?(String.trim_leading(&1), "%"))
|> Enum.flat_map(fn line -> Regex.scan(~r/\bhalt\(\s*(\w+)\s*,/, line) |> Enum.map(&Enum.at(&1, 1)) end)
{:cont, {:ok, acc ++ names}}
{:error, reason} ->
{:halt, {:error, "ANCHORS_UNREADABLE: #{file} — #{inspect(reason)}"}}
end
end)
|> case do
{:ok, names} -> {:ok, names |> Enum.uniq() |> Enum.sort()}
error -> error
end
end
@doc """
Verify the anchors against the rule modules and L1. `:ok`, or
`{:error, reason}` naming the first rule without an anchor, the
first anchor without a verse, or an unreadable file.
"""
@spec verify(String.t()) :: :ok | {:error, String.t()}
def verify(root \\ Doorpost.repo_root()) do
with {:ok, anchors} <- declared(root),
{:ok, rules} <- rules_in_modules(root) do
anchored = MapSet.new(anchors, & &1.rule)
cond do
anchors == [] ->
{:error, "ANCHOR_MISSING: no rule_anchor/2 facts in #{@anchors_file}"}
(unanchored = Enum.reject(rules, &MapSet.member?(anchored, &1))) != [] ->
{:error, "ANCHOR_MISSING: halt rule #{hd(unanchored)} has no verse in #{@anchors_file} (lo tosif, Devarim 4:2)"}
(bad = Enum.find(anchors, &(not verse_in_l1?(&1)))) != nil ->
{:error, "ANCHOR_NOT_IN_L1: rule #{bad.rule} is anchored to #{cite(bad)}, which is not in L1"}
true ->
:ok
end
end
end
@doc "The verse a halt rule stands on, as a citation — `\"Devarim 25:13\"` — or nil."
@spec for_rule(String.t()) :: String.t() | nil
def for_rule(rule) when is_binary(rule) do
case declared() do
{:ok, anchors} -> anchors |> Enum.find(&(&1.rule == rule)) |> then(&(&1 && cite(&1)))
_ -> nil
end
end
@doc """
The anchors of the rules that fired, from a list of halt terms as the
bedikah returns them (`halt(<name>, ...)`): `%{"even_vaaven" => "Devarim 25:13"}`.
"""
@spec for_violations([String.t()]) :: %{String.t() => String.t()}
def for_violations(violations) when is_list(violations) do
case declared() do
{:ok, anchors} ->
by_rule = Map.new(anchors, &{&1.rule, cite(&1)})
violations
|> Enum.flat_map(fn v ->
case Regex.run(~r/^halt\(\s*(\w+)\s*,/, v) do
[_, rule] -> [rule]
_ -> []
end
end)
|> Enum.uniq()
|> Map.new(&{&1, Map.get(by_rule, &1)})
_ ->
%{}
end
end
@doc "A citation for an anchor: `\"Devarim 25:13\"`."
def cite(%{book: book, chapter: ch, verse: v}), do: "#{Map.get(@book_names, book, book)} #{ch}:#{v}"
defp verse_in_l1?(%{book: book, chapter: ch, verse: v}) do
book in @books and match?({:ok, _}, L1Reader.read_verse(book, ch, v))
end
end
@@ -328,6 +328,16 @@ defmodule VavPipeline.BigdeiKodesh.Router do
expected_hash: expected, expected_hash: expected,
file_count: length(VavPipeline.Doorpost.files()), file_count: length(VavPipeline.Doorpost.files()),
manifest: VavPipeline.Doorpost.manifest(), manifest: VavPipeline.Doorpost.manifest(),
# Every halt rule and the verse it stands on (bishearecha.md §X).
anchors:
case VavPipeline.Anchors.verify() do
:ok ->
{:ok, anchors} = VavPipeline.Anchors.declared()
%{status: "verified", rules: Enum.map(anchors, &%{rule: &1.rule, verse: VavPipeline.Anchors.cite(&1)})}
{:error, reason} ->
%{status: "failed", error: reason}
end,
torah_basis: [ torah_basis: [
"Devarim 4:2 (lo tosif)", "Devarim 4:2 (lo tosif)",
"Devarim 11:16-17 (failure mechanism)", "Devarim 11:16-17 (failure mechanism)",
@@ -603,6 +613,7 @@ defmodule VavPipeline.BigdeiKodesh.Router do
model: result.provenance, model: result.provenance,
verdict: Atom.to_string(result.verdict), verdict: Atom.to_string(result.verdict),
violations: result.violations, violations: result.violations,
anchors: VavPipeline.Anchors.for_violations(result.violations),
checks: result.checks, checks: result.checks,
examination: %{ examination: %{
vital_content: result.examination["vital_content"], vital_content: result.examination["vital_content"],
@@ -679,6 +690,7 @@ defmodule VavPipeline.BigdeiKodesh.Router do
pair_ref: result.pair_ref, pair_ref: result.pair_ref,
verdict: Atom.to_string(result.verdict), verdict: Atom.to_string(result.verdict),
violations: result.violations, violations: result.violations,
anchors: VavPipeline.Anchors.for_violations(result.violations),
a: result.a, a: result.a,
b: result.b, b: result.b,
difference: result.difference, difference: result.difference,
+8 -3
View File
@@ -150,6 +150,7 @@ defmodule VavPipeline.Doorpost do
"specs/shorashim_vayakhel.md", "specs/shorashim_vayakhel.md",
"specs/structure_not_content.md", "specs/structure_not_content.md",
"specs/threshold_inscription.md", "specs/threshold_inscription.md",
"talmudic_engine/src/halt/anchors.pl",
"talmudic_engine/src/halt/avodah_zarah.pl", "talmudic_engine/src/halt/avodah_zarah.pl",
"talmudic_engine/src/halt/gilui_arayot.pl", "talmudic_engine/src/halt/gilui_arayot.pl",
"talmudic_engine/src/halt/lo_taaseh_lekha.pl", "talmudic_engine/src/halt/lo_taaseh_lekha.pl",
@@ -179,7 +180,7 @@ defmodule VavPipeline.Doorpost do
# changes; the update is a deliberate operator commit. A bare # changes; the update is a deliberate operator commit. A bare
# hash-update commit (without a corresponding spec change in the # hash-update commit (without a corresponding spec change in the
# same commit) is itself a drift signal. # same commit) is itself a drift signal.
@expected_hash "f90870d476a3a1f31b7cc3a4ff04f8dad1f5db190e16c6956ce19c368366d656" @expected_hash "a0e81212e6d75026155fea6f3f97976ee4b9832e81ad7438a382cf1d1797e097"
@doc "Return the list of files that constitute the category-grade specification." @doc "Return the list of files that constitute the category-grade specification."
@spec files() :: [String.t()] @spec files() :: [String.t()]
@@ -254,7 +255,9 @@ defmodule VavPipeline.Doorpost do
baked-in @expected_hash. Same shape as L1Reader.verify_integrity/0. baked-in @expected_hash. Same shape as L1Reader.verify_integrity/0.
Lo tosif (Devarim 4:2) — addition or subtraction is detected Lo tosif (Devarim 4:2) — addition or subtraction is detected
here, BEFORE it propagates into reception. here, BEFORE it propagates into reception. When the hash matches,
the halt rules' anchors are verified too (`VavPipeline.Anchors`):
a rule without a verse, or a verse not in L1, fails the same way.
""" """
@spec verify_identity() :: :ok | {:error, String.t()} @spec verify_identity() :: :ok | {:error, String.t()}
def verify_identity do def verify_identity do
@@ -264,7 +267,9 @@ defmodule VavPipeline.Doorpost do
hash when is_binary(hash) -> hash when is_binary(hash) ->
if hash == @expected_hash do if hash == @expected_hash do
:ok # The rules grounded as the outputs are (bishearecha.md §X):
# every halt rule anchored to a verse, every verse in L1.
VavPipeline.Anchors.verify(@repo_root)
else else
{:error, {:error,
"SPEC_INTEGRITY_FAILED: hash mismatch — computed #{hash}, " <> "SPEC_INTEGRITY_FAILED: hash mismatch — computed #{hash}, " <>
+84
View File
@@ -0,0 +1,84 @@
defmodule VavPipeline.AnchorsTest do
@moduledoc """
Every halt rule cites its verse (bishearecha.md §X; Devarim 4:2).
"""
use ExUnit.Case, async: true
alias VavPipeline.{Anchors, Doorpost}
test "the anchors file is a Doorpost file" do
assert "talmudic_engine/src/halt/anchors.pl" in Doorpost.files()
end
test "every halt name the rule modules can return is anchored, and every anchor is in L1" do
assert :ok = Anchors.verify()
{:ok, rules} = Anchors.rules_in_modules()
{:ok, anchors} = Anchors.declared()
assert rules == Enum.sort(Enum.map(anchors, & &1.rule))
assert "even_vaaven" in rules and "lo_taaseh_lekha" in rules and "avodah_zarah" in rules
assert length(rules) == 10
end
test "the anchors read as citations" do
assert Anchors.for_rule("even_vaaven") == "Devarim 25:13"
assert Anchors.for_rule("lo_taaseh_lekha") == "Shemot 20:4"
assert Anchors.for_rule("parah_adumah") == "Bamidbar 19:7"
assert Anchors.for_rule("no_such_rule") == nil
end
test "for_violations/1 names the verse of each rule that fired, once" do
violations = [
"halt(even_vaaven,action(weigh, by(gpt), measure(claims), lean(a), counts(2, 0)),claims,...)",
"halt(lo_taaseh_lekha,action(frame, by(gpt), form(virtue_certification)),virtue_certification,...)",
"halt(lo_taaseh_lekha,action(frame, by(gpt), form(contested_laundering)),contested_laundering,...)"
]
assert Anchors.for_violations(violations) == %{"even_vaaven" => "Devarim 25:13", "lo_taaseh_lekha" => "Shemot 20:4"}
assert Anchors.for_violations([]) == %{}
end
describe "drift (synthetic spec root)" do
setup do
temp = Path.join(System.tmp_dir!(), "anchors_test_#{System.unique_integer([:positive])}")
File.mkdir_p!(Path.join(temp, "talmudic_engine/src/halt"))
for file <- Doorpost.files(), String.starts_with?(file, "talmudic_engine/src/halt/") do
File.cp!(Path.join(Doorpost.repo_root(), file), Path.join(temp, file))
end
on_exit(fn -> File.rm_rf!(temp) end)
{:ok, temp: temp}
end
test "a mirror verifies", %{temp: temp} do
assert :ok = Anchors.verify(temp)
end
test "a rule without an anchor fails: lo tosif", %{temp: temp} do
path = Path.join(temp, "talmudic_engine/src/halt/structure.pl")
File.write!(path, File.read!(path) <> "\nhalt_check_new(_, halt(new_rule, x, y, z)).\n")
assert {:error, reason} = Anchors.verify(temp)
assert reason =~ "ANCHOR_MISSING" and reason =~ "new_rule"
end
test "an anchor to a verse that is not in L1 fails", %{temp: temp} do
path = Path.join(temp, "talmudic_engine/src/halt/anchors.pl")
File.write!(path, String.replace(File.read!(path), "verse(devarim, 25, 13)", "verse(devarim, 25, 99)"))
assert {:error, reason} = Anchors.verify(temp)
assert reason =~ "ANCHOR_NOT_IN_L1" and reason =~ "even_vaaven" and reason =~ "Devarim 25:99"
end
test "an anchor in a commented-out rule does not count; a halt name in a comment is not a rule", %{temp: temp} do
path = Path.join(temp, "talmudic_engine/src/halt/structure.pl")
File.write!(path, File.read!(path) <> "\n%% halt(imaginary, x, y, z) — only a comment\n")
assert :ok = Anchors.verify(temp)
end
test "a missing anchors file fails", %{temp: temp} do
File.rm!(Path.join(temp, "talmudic_engine/src/halt/anchors.pl"))
assert {:error, reason} = Anchors.verify(temp)
assert reason =~ "ANCHORS_UNREADABLE"
end
end
end