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
is already the practice; this document keeps it.
**Status.** Erasure built. Rule anchors and their verification: to
build.
**Status.** Built (2026-10-07): `talmudic_engine/src/halt/anchors.pl`
(`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
@@ -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.
*Done 2026-10-07.*
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
architecture's centre; the first three make it worth standing at.
5. **The hakhel cycle and record** (VIII).
+18
View File
@@ -235,6 +235,7 @@ Response (200):
"model": "gpt",
"verdict": "tov" | "lo_tov" | "empty",
"violations": ["halt(avodah_zarah, ...)", ...], # the Prolog halt terms, verbatim
"anchors": { "avodah_zarah": "Shemot 20:3", ... }, # the verse of each rule that fired
"checks": {
"authority": { "fired": bool, "claims": [...], "violations": [...] },
"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.
```
**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;
Devarim 25:13–16, Vayikra 19:15, Shemot 23:2; `halt/mishkal.pl`,
`VavPipeline.Bedikah.Pair`). Two outputs on the same matter — the same
@@ -328,6 +345,7 @@ Response (200):
"pair_ref": "pair-<16 hex>",
"verdict": "even" | "uneven",
"violations": ["halt(even_vaaven, action(weigh, ...), hedged_claims, ...)", ...],
"anchors": { "even_vaaven": "Devarim 25:13" },
"a": { "bedikah_ref", "model", "verdict", "violations", "words", "measures": {"<m>": n, ...} },
"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/lo_taaseh_lekha).
:- use_module(halt/mishkal).
:- use_module(halt/anchors).
:- use_module(interface/api).
:- use_module(interface/json_bridge).
:- 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",
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).
+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,
file_count: length(VavPipeline.Doorpost.files()),
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: [
"Devarim 4:2 (lo tosif)",
"Devarim 11:16-17 (failure mechanism)",
@@ -603,6 +613,7 @@ defmodule VavPipeline.BigdeiKodesh.Router do
model: result.provenance,
verdict: Atom.to_string(result.verdict),
violations: result.violations,
anchors: VavPipeline.Anchors.for_violations(result.violations),
checks: result.checks,
examination: %{
vital_content: result.examination["vital_content"],
@@ -679,6 +690,7 @@ defmodule VavPipeline.BigdeiKodesh.Router do
pair_ref: result.pair_ref,
verdict: Atom.to_string(result.verdict),
violations: result.violations,
anchors: VavPipeline.Anchors.for_violations(result.violations),
a: result.a,
b: result.b,
difference: result.difference,
+8 -3
View File
@@ -150,6 +150,7 @@ defmodule VavPipeline.Doorpost do
"specs/shorashim_vayakhel.md",
"specs/structure_not_content.md",
"specs/threshold_inscription.md",
"talmudic_engine/src/halt/anchors.pl",
"talmudic_engine/src/halt/avodah_zarah.pl",
"talmudic_engine/src/halt/gilui_arayot.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
# hash-update commit (without a corresponding spec change in the
# 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."
@spec files() :: [String.t()]
@@ -254,7 +255,9 @@ defmodule VavPipeline.Doorpost do
baked-in @expected_hash. Same shape as L1Reader.verify_integrity/0.
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()}
def verify_identity do
@@ -264,7 +267,9 @@ defmodule VavPipeline.Doorpost do
hash when is_binary(hash) ->
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
{:error,
"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