Bedikah: POST /courtyard/bedikah — the external check on any model's output

Lo taaseh lekha §9.1: alignment that only the system can validate is not
alignment. The bedikah takes an output from any model and puts it to the
Torah-structure halt rules from outside, deterministically. Three checks:

  1. authority  — sentences claiming authority for the output itself →
                  action(claim_authority, source(<model>), target(self))
                  → halt_check_avodah_zarah/2
  2. grounding  — references, roots, Hebrew → coupling trace against L1
                  → halt_check_golden_calf/2, halt_check_self_grounding/2
  3. actions    — actions the output proposes → action terms
                  → halt_check_shfichut_damim/2, halt_check_gilui_arayot/2

Korban Processor: bedikah.py (the three readings over the offering
protocol; claims about what Torah requires stay vital for the examination
even when zerikah finds nothing to offer), server.py (pod-internal JSON
socket, KORBAN_SOCKET_PATH), __main__ now serves instead of idling.
Talmudic Engine: json_bridge accepts halt_check with a term string and
halt_check_interpretation with a coupling trace. Vav Pipeline:
KorbanProcessorSocket client, Bedikah, L1Index.lookup_root/1, bedikot
table (append-only) + BedikahRecord, router endpoint; verdict tov /
lo_tov / empty with the halt terms verbatim, meaning, limits.

Broken tablets found on the way, all fixed:
  41 socket_server.pl wrote multi-line JSON — every Elixir request to the
     Talmudic Engine since Step 14 had failed and fallen back to the stub
     (json_write_dict width(0))
  42 stale socket file survived a restart (exists_file is false for a
     socket; access_file exist)
  43 socket streams were not UTF-8 (set_stream encoding(utf8))
  44 SHORASHIM_L3=1 mix test: Repo config had no password, SCRAM raised
     KeyError in every connection, pool restart intensity took the whole
     app down ~30 ms after test_helper, silently — no L3 test had ever
     run. Credentials from env; azazel_log tests check out a sandbox
     connection; sanhedrin_halt_forwarding resolves its halt on exit.

Specs: Tamid §1.1 (endpoint contract), Architecture §3.5, Vayakhel §3.4
and new §3.9, KOHEN.md. Doorpost 3bc5dd6a… → 91d09d8d….
Tests: Elixir 519 (0 failures, L3 on and off), korban 263, azazel 125,
Prolog 7/7 suites.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Scott KarpandClaude Fable 5.1 committed 2026-10-06 15:06:58 +00:00
1 parent 3a9ebdc7d4
commit 996a8efe68
32 files changed
+2368 -71

No files matched your search

@@ -143,6 +143,28 @@ defmodule VavPipeline.BigdeiKodesh.Router do
end
end
# === COURTYARD — the bedikah (Construction §3.9) ===
#
# An external model's output, brought by hand to be examined against
# the specification. Three deterministic checks — authority,
# grounding, the halt categories — judged by the Talmudic Engine on
# what the Korban Processor read. The verdict and its reasons are
# engraved in L3. See VavPipeline.Bedikah.
post "/courtyard/bedikah" do
case get_req_header(conn, "authorization") do
["Bearer " <> _token] ->
process_bedikah(conn)
_ ->
send_error(conn, 401, "UNAUTHORIZED", %{
issue: "Missing or invalid Authorization header",
correction: "Include 'Authorization: Bearer <api-key>' header",
resubmit: true
})
end
end
# === CHATZER — Full Access (Sanhedrin) ===
post "/chatzer/sanhedrin" do
@@ -403,6 +425,131 @@ defmodule VavPipeline.BigdeiKodesh.Router do
end
end
# ============================================================
# Internal — the bedikah
# ============================================================
@bedikah_provenances ~w(claude gpt mistral llama gemma human)
@bedikah_max_bytes 65_536
defp process_bedikah(conn) do
params = conn.body_params
output = params["output"]
model = params["model"]
query = params["query"] || ""
cond do
not is_binary(output) or String.trim(output) == "" ->
send_error(conn, 422, "KIYOR_VALIDATION_FAILED", %{
issue: "Missing or empty 'output' field",
correction: "Submit JSON with 'output': the external model's output, as text",
resubmit: true
})
byte_size(output) > @bedikah_max_bytes ->
send_error(conn, 422, "KIYOR_VALIDATION_FAILED", %{
issue: "'output' is #{byte_size(output)} bytes; the examination reads at most #{@bedikah_max_bytes}",
correction: "Bring the output in parts",
resubmit: true
})
model not in @bedikah_provenances ->
send_error(conn, 422, "KIYOR_VALIDATION_FAILED", %{
issue: "Missing or unknown 'model' field: #{inspect(model)}",
correction: "Name whose output this is — one of #{Enum.join(@bedikah_provenances, ", ")}",
resubmit: true
})
not is_binary(query) ->
send_error(conn, 422, "KIYOR_VALIDATION_FAILED", %{
issue: "'query' must be a string",
correction: "Give the question the model was asked, or omit it",
resubmit: true
})
true ->
case check_availability() do
{:shabbat, until} ->
send_error(conn, 503, "SHABBAT", %{
issue: "System in mandatory rest",
correction: "Retry after Shabbat ends",
resumption: until,
resubmit: true
})
{:halted, event} ->
send_error(conn, 503, "HALT_#{String.upcase(to_string(event.condition))}", %{
issue: "System halted — cardinal sin detected",
correction: "Contact system operators",
resubmit: false
})
:available ->
respond_bedikah(conn, VavPipeline.Bedikah.examine(output, model, query))
end
end
end
defp respond_bedikah(conn, {:ok, result}) do
send_json(conn, 200, %{
bedikah_ref: result.bedikah_ref,
model: result.provenance,
verdict: Atom.to_string(result.verdict),
violations: result.violations,
checks: result.checks,
examination: %{
vital_content: result.examination["vital_content"],
propositions: result.examination["propositions"],
references: result.examination["references"],
roots: result.examination["roots"],
discarded: result.examination["discarded"]
},
coupling_trace: result.coupling_trace,
meaning:
case result.verdict do
:tov ->
"None of the three checks fired on what the examination could read. " <>
"This does not say the model is aligned; it says this output claims no authority " <>
"for itself, couples to the text where it claims to, and reaches for nothing it may not touch."
:lo_tov ->
"At least one check fired. The violations say which rule, and the checks say what it fired on."
:empty ->
"The offering protocol extracted nothing from this output — no Torah reference, no Hebrew, " <>
"no analytical claim, no authority claim, no action. There was nothing to examine."
end,
limits:
"The examination reads by pattern (korban_processor/bedikah.py). A claim or an action " <>
"in a form those patterns do not know is not seen. Deterministic: the same output gives the same verdict.",
disclosure: disclosure()
})
end
defp respond_bedikah(conn, {:waiting, reason}) do
send_error(conn, 503, "MANNA_DEPLETED", %{
issue: "System waiting — #{reason}",
correction: "Retry later — the next provision is written by the kohen at the day boundary",
resubmit: true
})
end
defp respond_bedikah(conn, {:error, :korban_unavailable, reason}) do
send_error(conn, 503, "KORBAN_UNAVAILABLE", %{
issue: "The Korban Processor could not read the output: #{reason}",
correction: "Retry; if it persists, the korban-processor container is down",
resubmit: true
})
end
defp respond_bedikah(conn, {:error, :talmudic_unavailable, reason}) do
send_error(conn, 503, "TALMUDIC_UNAVAILABLE", %{
issue: "The Talmudic Engine could not judge the examination: #{reason}. No verdict is given from a stub.",
correction: "Retry; if it persists, the talmudic-engine container is down",
resubmit: true
})
end
# ============================================================
# Internal — Courtyard processing
# ============================================================