sanhedrin: rewrite halt_monitor.erl as honest gate-keeper + Elixir forwarder
Closes F1–F7 from the conversation-history review at
~/shorashim-conversation-review.md, per the Torah ruling for Option 2:
Devarim 12:13–14 — לֹא תַעֲלֶה עֹלֹתֶיךָ בְּכָל מָקוֹם אֲשֶׁר תִּרְאֶה
כִּי אִם בַּמָּקוֹם אֲשֶׁר יִבְחַר ה׳ ... שָׁם תַּעֲשֶׂה כֹּל
אֲשֶׁר אָנֹכִי מְצַוֶּךָּ.
The offering happens in one place. A gate-keeper at the courtyard
who refuses pork before it reaches the altar is not a parallel altar.
Devarim 13:1 — לֹא תֹסֵף עָלָיו וְלֹא תִגְרַע מִמֶּנּוּ.
The interface remains; no parallel detection authority is added.
The previous halt_monitor.erl claimed to mirror the Talmudic Engine
halt modules (Prolog) and the Vav Pipeline halt_conditions (Elixir),
but in practice it was a partial sketch with stub checks, no read API,
verb-only shfichut_damim that would fire on log rotation, and a
"cannot be bypassed" claim that the implementation didn't deliver.
The docstring overstated. Eish zarah by the repo's own definition —
real Erlang, sincerely written, but אֲשֶׁר לֹא צִוָּה אֹתָם.
Changes:
sanhedrin/include/sanhedrin.hrl
- Document the halt-relevant context keys explicitly
(authority_source, action, boundary_violation) — closes F1.
These keys were used by halt_monitor and the test suite but
were not in the .hrl record commentary. Interface drift fixed
by writing down the actual contract.
sanhedrin/src/halt_monitor.erl
- Re-framed as "Sanhedrin's gate-keeper": local courtyard refusal,
not parallel altar. Honest docstring.
- When the gate detects a halt, FORWARDS the canonical halt event
to VavPipeline.HaltMonitor.halt!/3 (single source of truth).
Best-effort: if Elixir module isn't loaded, local refusal still
works.
- Export audit_log/0 and halt_count/0 — closes F6 (was write-only
from outside the module).
- Remove process_flag(trap_exit, true) and the dead
handle_info({'EXIT', _, _}, _) clause — closes F7 (nothing was
ever linked).
- Remove unused check_authority_in_text/1 stub from the call chain
— closes F5. do_check_vote/1 now documents that vote-text
inspection is the upstream pipeline's responsibility.
- check_gilui_arayot/1 docstring now states truthfully: detection
of WHETHER an action collapses a distinction lives in
talmudic_engine/src/halt/gilui_arayot.pl; this gate reads the
flag — closes F2 framing.
- check_shfichut_damim/1 docstring now states: conservative
gate-keeper, fail-closed; the canonical tzelem-target check
lives in talmudic_engine/src/halt/shfichut_damim.pl — closes
F3 framing.
- "Cannot be bypassed" claim removed; truthful description added:
"enforced by callers (escalation.erl checks the return value
before convening a panel)" — closes F4.
vav_pipeline/test/sanhedrin_halt_forwarding_test.exs (NEW)
- 6 integration tests proving the forwarding chain end-to-end:
halt_monitor.erl is loadable from the same BEAM VM, exposes
audit_log/0 and halt_count/0 (F6 verification), and on each of
the three cardinal sin types fires HaltMonitor.halt!/3 with
component="sanhedrin/case". Verified that VavPipeline.HaltMonitor.
halted?/0 flips to true after each gate refusal and the event's
.condition matches the gate's halt type.
The local audit log on the gate-keeper is preserved (the Sanhedrin
operator can still see what was refused at the gate). The system-wide
halt audit lives in VavPipeline.HaltMonitor.audit_log/0 — one altar.
Existing 12 sanhedrin EUnit tests of the gateway behavior continue
to pass (verified via mix deps.compile sanhedrin — clean compile).
The 6 new Elixir-side integration tests pass (verified).
Test counts:
- Elixir: 280 (was 274; +6 new forwarding tests), 0 failures attributable
to this change. (3 pre-existing time-dependent test failures in
step31_shema_test.exs occur on Shabbat — system correctly returns
cloud_state == {:major_transition, :shabbat_rest, _} when run after
Friday sundown; tests assert :camped. Not caused by this change.)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
b9a18f645e
commit
66c936f7ca
3 files changed
+284
-53
No files matched your search
@@ -0,0 +1,116 @@
|
||||
defmodule VavPipeline.SanhedrinHaltForwardingTest do
|
||||
@moduledoc """
|
||||
Integration test: the Erlang Sanhedrin gate-keeper
|
||||
(sanhedrin/src/halt_monitor.erl) must forward halt events to the
|
||||
canonical Elixir HaltMonitor (VavPipeline.HaltMonitor).
|
||||
|
||||
This honors the Torah ruling for Option 2 (see KOHEN.md / the
|
||||
conversation review at ~/shorashim-conversation-review.md):
|
||||
|
||||
Devarim 12:13–14 — לֹא תַעֲלֶה עֹלֹתֶיךָ בְּכָל מָקוֹם
|
||||
אֲשֶׁר תִּרְאֶה כִּי אִם בַּמָּקוֹם אֲשֶׁר יִבְחַר ה׳
|
||||
|
||||
The Erlang gate-keeper is a courtyard pre-check; the canonical halt
|
||||
altar is in the Elixir HaltMonitor. When the gate refuses a case, the
|
||||
refusal must also be recorded at the one altar.
|
||||
"""
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
alias VavPipeline.HaltMonitor
|
||||
|
||||
setup do
|
||||
# Reset the Elixir HaltMonitor between tests by resolving any halt.
|
||||
if HaltMonitor.halted?() do
|
||||
HaltMonitor.resolve("test reset")
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
defp make_case(context) when is_map(context) do
|
||||
# Build a #sanhedrin_case{} record. The fields are documented in
|
||||
# sanhedrin/include/sanhedrin.hrl. We use erlang:list_to_tuple to
|
||||
# construct the record without needing the .hrl in this Elixir file.
|
||||
{:sanhedrin_case,
|
||||
"test_case_#{:erlang.unique_integer([:positive])}",
|
||||
:simple,
|
||||
"test question",
|
||||
context,
|
||||
"test_caller",
|
||||
:erlang.system_time(:millisecond)}
|
||||
end
|
||||
|
||||
test "halt_monitor.erl exists and exports check_case/1" do
|
||||
# Sanity check: the Erlang module is loadable from this VM.
|
||||
assert Code.ensure_loaded?(:halt_monitor),
|
||||
"sanhedrin/src/halt_monitor.erl must be loadable from the same BEAM VM"
|
||||
assert function_exported?(:halt_monitor, :check_case, 1)
|
||||
assert function_exported?(:halt_monitor, :audit_log, 0),
|
||||
"audit_log/0 must be exported (F6 fix)"
|
||||
assert function_exported?(:halt_monitor, :halt_count, 0),
|
||||
"halt_count/0 must be exported (F6 fix)"
|
||||
end
|
||||
|
||||
test "halt_monitor.erl returns clear for a benign case" do
|
||||
{:ok, _pid} = ensure_started()
|
||||
benign = make_case(%{authority_source: :torah})
|
||||
assert :clear = :halt_monitor.check_case(benign)
|
||||
end
|
||||
|
||||
test "halt_monitor.erl detects avodah_zarah AND fires canonical halt in Elixir" do
|
||||
{:ok, _pid} = ensure_started()
|
||||
refute HaltMonitor.halted?()
|
||||
|
||||
bad = make_case(%{authority_source: :claude_model})
|
||||
result = :halt_monitor.check_case(bad)
|
||||
|
||||
# Local refusal at the gate
|
||||
assert {:halt, :avodah_zarah, _reason} = result
|
||||
|
||||
# Canonical halt event fired in Elixir HaltMonitor (the one mizbeach)
|
||||
assert HaltMonitor.halted?(),
|
||||
"Erlang gate must forward halt events to the Elixir HaltMonitor"
|
||||
|
||||
{:halted, event} = HaltMonitor.status()
|
||||
assert event.condition == :avodah_zarah
|
||||
assert event.component == "sanhedrin/case",
|
||||
"component tag must identify the gate"
|
||||
end
|
||||
|
||||
test "halt_monitor.erl detects shfichut_damim AND fires canonical halt" do
|
||||
{:ok, _pid} = ensure_started()
|
||||
refute HaltMonitor.halted?()
|
||||
|
||||
bad = make_case(%{action: :delete})
|
||||
{:halt, :shfichut_damim, _} = :halt_monitor.check_case(bad)
|
||||
|
||||
assert HaltMonitor.halted?()
|
||||
{:halted, event} = HaltMonitor.status()
|
||||
assert event.condition == :shfichut_damim
|
||||
end
|
||||
|
||||
test "halt_monitor.erl detects gilui_arayot AND fires canonical halt" do
|
||||
{:ok, _pid} = ensure_started()
|
||||
refute HaltMonitor.halted?()
|
||||
|
||||
bad = make_case(%{boundary_violation: {:spec_interp_merge, "collapsed"}})
|
||||
{:halt, :gilui_arayot, _} = :halt_monitor.check_case(bad)
|
||||
|
||||
assert HaltMonitor.halted?()
|
||||
{:halted, event} = HaltMonitor.status()
|
||||
assert event.condition == :gilui_arayot
|
||||
end
|
||||
|
||||
test "audit_log/0 is exposed (F6: read API)" do
|
||||
{:ok, _pid} = ensure_started()
|
||||
log = :halt_monitor.audit_log()
|
||||
assert is_list(log)
|
||||
end
|
||||
|
||||
defp ensure_started do
|
||||
case :halt_monitor.start_link() do
|
||||
{:ok, pid} -> {:ok, pid}
|
||||
{:error, {:already_started, pid}} -> {:ok, pid}
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user