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:
Scott KarpandClaude Opus 4.6 committed 2026-04-24 17:31:37 -04:00
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