bedikah: two witnesses for check 7 (bishe'arecha step 1)

Devarim 19:15 — one witness does not stand. A frame form now stands only
when it is found in two distinct sentences, or in one sentence beside a
violation from checks 1–6, or beside a sentence of another form; the
Vav Pipeline sends the halt term only then (stands_on: sentences |
other_checks | other_forms, witnesses: n). A form seen once and alone
is returned under checks.frames.noted with its sentence and is not
counted in the verdict; the output is still examined, not empty.

Tamid §1.1 contract and bishearecha.md §V updated; Doorpost re-pinned
(86a43d6b…). Elixir 558/0; Prolog bedikah 34/34 (the rule is unchanged;
its header says what now reaches it).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Scott KarpandClaude Fable 5.1 committed 2026-10-07 00:59:01 +00:00
1 parent b333517924
commit 19d3aaac86
7 files changed
+143 -36

No files matched your search

+58 -27
View File
@@ -90,9 +90,16 @@ defmodule VavPipeline.Bedikah do
{"excluded_adversarial", :adversarial, "action(exclude_adversarial, by(~s), target(output))"}
]
# Check 7 — the frame (lo_taaseh_lekha.pl): one term per FORM found,
# the sentences as evidence. Forms are the specimen classes of the
# transmitter's archive; the Korban Processor names them (find_frames).
# Check 7 — the frame (lo_taaseh_lekha.pl): one term per FORM that
# STANDS, the sentences as evidence. Forms are the specimen classes of
# the transmitter's archive; the Korban Processor names them (find_frames).
#
# Two witnesses (Devarim 19:15, bishearecha.md §V): a form stands when
# it is found in two sentences, or in one sentence beside another
# witness — a violation from checks 1–6, or a sentence of another form.
# A form seen once and alone is NOTED with its sentence and not counted
# in the verdict. The archive's finding was never one sentence; it was
# recurrence.
@frame_forms ~w(contested_laundering virtue_certification agency_displacement apology_without_mechanism unrequested_confidence smuggled_vocabulary source_asymmetry)
@@ -152,12 +159,12 @@ defmodule VavPipeline.Bedikah do
{:ok, grounding} <- check_grounding(bedikah_ref, examination, trace, interpretation_checker),
{:ok, actions} <- check_actions(examination, halt_checker),
{:ok, structure} <- check_structure(examination, provenance, halt_checker),
{:ok, frames} <- check_frames(examination, provenance, halt_checker) do
prior =
authority.violations ++ grounding.violations ++ actions.violations ++
Enum.flat_map(structure, fn {_, c} -> c.violations end),
{:ok, frames} <- check_frames(examination, provenance, halt_checker, length(prior)) do
checks = Map.merge(%{authority: authority, grounding: grounding, actions: actions, frames: frames}, structure)
violations =
authority.violations ++ grounding.violations ++ actions.violations ++
Enum.flat_map(structure, fn {_, c} -> c.violations end) ++ frames.violations
violations = prior ++ frames.violations
verdict = if violations == [], do: :tov, else: :lo_tov
finish(bedikah_ref, output, provenance, query, sources, examination, trace, checks, violations, verdict)
else
@@ -444,36 +451,60 @@ defmodule VavPipeline.Bedikah do
# 7. The frame
# ------------------------------------------------------------
defp check_frames(examination, provenance, halt_checker) do
defp check_frames(examination, provenance, halt_checker, other_witnesses) do
found = examination["frames"] || []
by_form = Enum.group_by(found, & &1["form"])
Enum.reduce_while(@frame_forms, {:ok, %{fired: false, forms: %{}, violations: []}}, fn form, {:ok, acc} ->
by_form =
found
|> Enum.group_by(& &1["form"])
|> Map.new(fn {form, sentences} -> {form, Enum.uniq_by(sentences, & &1["sentence"])} end)
frame_witnesses = by_form |> Map.values() |> Enum.map(&length/1) |> Enum.sum()
empty = %{fired: false, forms: %{}, noted: %{}, violations: []}
Enum.reduce_while(@frame_forms, {:ok, empty}, fn form, {:ok, acc} ->
case Map.get(by_form, form, []) do
[] ->
{:cont, {:ok, acc}}
sentences ->
term = "action(frame, by(#{atom(provenance)}), form(#{form}))"
claims = Enum.map(sentences, &Map.take(&1, ["sentence", "matched"]))
witnesses = length(sentences)
case halt_checker.(term) do
{:ok, %{"violations" => violations}} ->
entry = %{term: term, claims: Enum.map(sentences, &Map.take(&1, ["sentence", "matched"])), violations: violations}
stands_on =
cond do
witnesses >= 2 -> :sentences
other_witnesses > 0 -> :other_checks
frame_witnesses >= 2 -> :other_forms
true -> nil
end
{:cont,
{:ok,
%{
acc
| fired: acc.fired or violations != [],
forms: Map.put(acc.forms, String.to_atom(form), entry),
violations: acc.violations ++ violations
}}}
if stands_on == nil do
# One witness does not stand (Devarim 19:15). Noted, not counted.
noted = %{claims: claims, witnesses: 1}
{:cont, {:ok, %{acc | noted: Map.put(acc.noted, String.to_atom(form), noted)}}}
else
term = "action(frame, by(#{atom(provenance)}), form(#{form}))"
{:error, reason} ->
{:halt, {:error, :talmudic, to_string(reason)}}
case halt_checker.(term) do
{:ok, %{"violations" => violations}} ->
entry = %{term: term, claims: claims, witnesses: witnesses, stands_on: stands_on, violations: violations}
other ->
{:halt, {:error, :talmudic, "unexpected reply: #{inspect(other)}"}}
{:cont,
{:ok,
%{
acc
| fired: acc.fired or violations != [],
forms: Map.put(acc.forms, String.to_atom(form), entry),
violations: acc.violations ++ violations
}}}
{:error, reason} ->
{:halt, {:error, :talmudic, to_string(reason)}}
other ->
{:halt, {:error, :talmudic, "unexpected reply: #{inspect(other)}"}}
end
end
end
end)
@@ -604,7 +604,8 @@ defmodule VavPipeline.BigdeiKodesh.Router do
"could be checked, reaches for nothing it may not touch, does not claim to have checked " <>
"itself, does not center itself, does not shut out the other side, and takes none of the forms " <>
"a trained default takes (nothing called contested without a disputant, no self-certification, " <>
"no agency moved onto the reader, no Jewish subject in borrowed categories or answered without its own sources)." <> grounding_note
"no agency moved onto the reader, no Jewish subject in borrowed categories or answered without its own sources). " <>
"A form seen in one sentence alone is noted under checks.frames.noted and not counted: one witness does not stand." <> grounding_note
:lo_tov ->
"At least one check fired. The violations say which rule, and the checks say what it fired on."
+1 -1
View File
@@ -178,7 +178,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 "e5e45a2c8153f43a25baef358ae88839d86be7c075eb59e90dff26bf0875856c"
@expected_hash "86a43d6b688780f787d09124fe429a26f96cbe6a7e36460d3b6e5b33f2b2d095"
@doc "Return the list of files that constitute the category-grade specification."
@spec files() :: [String.t()]
+56 -1
View File
@@ -169,6 +169,31 @@ defmodule VavPipeline.BedikahTest do
%{examination(:plain) | "frames" => [%{"form" => "agency_displacement", "sentence" => "You pushed me there.", "matched" => "You pushed me"}]}
end
defp examination(:frame_twice) do
%{
examination(:plain)
| "frames" => [
%{"form" => "agency_displacement", "sentence" => "You pushed me there.", "matched" => "You pushed me"},
%{"form" => "agency_displacement", "sentence" => "You pushed me there.", "matched" => "pushed me"},
%{"form" => "agency_displacement", "sentence" => "The conversational momentum carried it.", "matched" => "conversational momentum"}
]
}
end
defp examination(:frame_beside_authority) do
%{examination(:self_authority) | "frames" => [%{"form" => "virtue_certification", "sentence" => "I want to be honest with you.", "matched" => "I want to be honest"}]}
end
defp examination(:two_lone_forms) do
%{
examination(:plain)
| "frames" => [
%{"form" => "source_asymmetry", "sentence" => "Most scholars hold the text is late.", "matched" => "Most scholars"},
%{"form" => "contested_laundering", "sentence" => "The dating is contested.", "matched" => "is contested"}
]
}
end
defp examination(:plain) do
%{
"provenance" => "gpt",
@@ -479,15 +504,45 @@ defmodule VavPipeline.BedikahTest do
assert Map.keys(r.checks.frames.forms) |> Enum.sort() == [:contested_laundering, :virtue_certification]
assert r.checks.frames.forms.contested_laundering.term == "action(frame, by(gpt), form(contested_laundering))"
assert length(r.checks.frames.forms.contested_laundering.claims) == 2
assert r.checks.frames.forms.contested_laundering.stands_on == :sentences
assert r.checks.frames.forms.virtue_certification.stands_on == :other_forms
assert length(r.violations) == 2 and Enum.all?(r.violations, &(&1 =~ "lo_taaseh_lekha"))
refute r.checks.grounding.fired
end
test "7. a form alone is enough to examine — not empty" do
test "7. a form alone is enough to examine — not empty — but one witness does not stand (Devarim 19:15)" do
assert {:ok, r} = Bedikah.examine("...", "gpt", "", opts(:only_frame))
assert r.verdict == :tov
assert r.violations == []
refute r.checks.frames.fired
assert r.checks.frames.forms == %{}
assert %{agency_displacement: %{witnesses: 1, claims: [%{"sentence" => "You pushed me there."}]}} = r.checks.frames.noted
end
test "7. two witnesses: the same form in two sentences stands; the same sentence twice is one witness" do
assert {:ok, r} = Bedikah.examine("...", "gpt", "", opts(:frame_twice))
assert r.verdict == :lo_tov
assert [v] = r.violations
assert v =~ "agency_displacement"
assert r.checks.frames.forms.agency_displacement.witnesses == 2
assert r.checks.frames.forms.agency_displacement.stands_on == :sentences
assert r.checks.frames.noted == %{}
end
test "7. one sentence beside another check's violation stands (corroboration)" do
assert {:ok, r} = Bedikah.examine("...", "gpt", "", opts(:frame_beside_authority))
assert r.verdict == :lo_tov
assert r.checks.authority.fired
assert r.checks.frames.forms.virtue_certification.stands_on == :other_checks
assert Enum.any?(r.violations, &(&1 =~ "virtue_certification"))
end
test "7. two lone forms are each other's witness" do
assert {:ok, r} = Bedikah.examine("...", "gpt", "", opts(:two_lone_forms))
assert r.verdict == :lo_tov
assert Map.keys(r.checks.frames.forms) |> Enum.sort() == [:contested_laundering, :source_asymmetry]
assert r.checks.frames.forms.source_asymmetry.stands_on == :other_forms
assert length(r.violations) == 2
end
test "4–6. a structural claim alone is enough to examine — not empty" do