peah: hear the verse the question is standing in (kohen Day 7, tablet 30)

Every Hebrew question was answered against Bereishit 1:1 —
extract_scope_from_question/1 ignored its argument. ויאמר אלהים יהי אור
(1:3) and ויהי ערב ויהי בקר (1:5) came back sourced from 1:1 with roots
"not in this verse". The grounding check passed by construction.

- L1Index: inverted index consonants → verses over l1/torah, built in
  handle_continue right after start (5853 verses, ~1 s), read-only after.
- ScopeResolver: explicit reference (bereishit/Genesis/בראשית 1:3) first;
  then quoted Torah — most question words in a verse, ties to the verse
  where they stand together in order, then Torah order; else default.
  A reference to a verse L1 lacks is a 422 KIYOR_VALIDATION_FAILED with
  the correction, not a silent 1:1.
- Router: processing.scope reports verse + resolved_by; a default scope
  carries a note saying the verse was assumed, not heard.
- test/tablet30_scope_test.exs: the five Day-7 offerings through the
  real router land on 1:1, 1:1, 1:3, 1:5, 1:1; Shema → Devarim 6:4;
  reference, invalid reference, default confession. 14 tests.
- KOHEN.md Day 7: what to expect in sources[0].ref.

454 tests, 0 failures on seeds 0 1 2 3 42 99. Seed 191243 fails
LivenessTest before and after this change — pre-existing, not touched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Scott KarpandClaude Fable 5.1 committed 2026-10-04 15:13:26 +00:00
1 parent d6d4475da3
commit c795225709
6 files changed
+626 -16

No files matched your search

@@ -314,16 +314,34 @@ defmodule VavPipeline.BigdeiKodesh.Router do
})
:available ->
# Pe'ah uses minchah protocol — simplest offering
scope = extract_scope_from_question(question)
# Pe'ah uses minchah protocol — simplest offering.
# The verse is heard from the question (tablet 30), not assumed.
case VavPipeline.ScopeResolver.resolve(question) do
{:error, {:invalid_reference, ref}} ->
send_error(conn, 422, "KIYOR_VALIDATION_FAILED", %{
issue: "INVALID_SCOPE: #{ref} is not a verse in L1",
correction:
"Name a verse that exists — chapter and verse within the five books " <>
"(for example \"bereishit 1:1\" or \"devarim 6:4\").",
resubmit: true
})
input = %{
source: "peah",
verse_scope: scope,
content: question
}
{:ok, scope, resolved_by} ->
process_peah(conn, question, scope, resolved_by)
end
end
end
case VavPipeline.process(input) do
defp process_peah(conn, question, scope, resolved_by) do
input = %{
source: "peah",
verse_scope: scope,
content: question
}
scope_report = scope_report(scope, resolved_by)
case VavPipeline.process(input) do
{:ok, data} ->
send_json(conn, 200, %{
answer: format_answer(data),
@@ -331,7 +349,8 @@ defmodule VavPipeline.BigdeiKodesh.Router do
processing: %{
roots_consulted: Map.get(data, :roots_activated, []) |> format_roots(),
deliberation: "none",
cycle_phase: "voker"
cycle_phase: "voker",
scope: scope_report
},
disclosure: disclosure()
})
@@ -343,7 +362,8 @@ defmodule VavPipeline.BigdeiKodesh.Router do
processing: %{
roots_consulted: Map.get(data, :roots_activated, []) |> format_roots(),
deliberation: "single-judge",
cycle_phase: "voker"
cycle_phase: "voker",
scope: scope_report
},
note: "This question produced an unresolved result — teiku.",
disclosure: disclosure()
@@ -379,7 +399,6 @@ defmodule VavPipeline.BigdeiKodesh.Router do
correction: "Contact system operators",
resubmit: false
})
end
end
end
@@ -808,10 +827,21 @@ defmodule VavPipeline.BigdeiKodesh.Router do
defp format_since(nil), do: "all_time"
defp format_since(%DateTime{} = dt), do: DateTime.to_iso8601(dt)
defp extract_scope_from_question(_question) do
# Default scope for pe'ah — Bereishit 1:1
# In production, this would parse the question for verse references
%{book: "bereishit", chapter: 1, verse: 1}
# How the verse was chosen, said out loud in the response. A default
# scope is a confession, not a grounding (tablet 30).
defp scope_report(scope, :default) do
%{
verse: scope_verse(scope),
resolved_by: "default",
note:
"The question named no verse and quoted no Torah the index could find, " <>
"so the default scope was used. Roots are read against it, not against " <>
"the question's source."
}
end
defp scope_report(scope, resolved_by) do
%{verse: scope_verse(scope), resolved_by: to_string(resolved_by)}
end
defp parse_scope(nil), do: %{book: "bereishit", chapter: 1, verse: 1}