Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e00f75640 | ||
|
|
0c4f764024 |
No files matched your search
@@ -624,6 +624,56 @@ Chatzotzrot signals map to communication channels:
|
||||
|
||||
---
|
||||
|
||||
## 7. EXTERNAL NEDARIM — Third-Party Covenants
|
||||
|
||||
### 7.1 Torah Grounding
|
||||
|
||||
> אִישׁ֩ כִּֽי־יִדֹּ֨ר נֶ֜דֶר לַֽיהוָ֗ה אֽוֹ־הִשָּׁ֤בַע שְׁבֻעָה֙ לֶאְסֹ֤ר אִסָּר֙ עַל־נַפְשׁ֔וֹ לֹ֥א יַחֵ֖ל דְּבָר֑וֹ כְּכָל־הַיֹּצֵ֥א מִפִּ֖יו יַעֲשֶֽׂה ׃
|
||||
> — Bamidbar 30:3
|
||||
|
||||
A man who makes a vow to Hashem, or swears an oath to bind a restriction upon his soul — *lo yachel devaro*, he shall not profane his word; according to all that comes out of his mouth, he shall do.
|
||||
|
||||
Rambam encodes this as four discrete mitzvot, all enumerated in `talmudic_engine/src/specification/mitzvot.pl`: positive #93 `fulfill_verbal_vow`, prohibitions #308 / #543 `not_break_oath`, #542 `not_delay_vow_fulfillment`.
|
||||
|
||||
The Avraham–Avimelekh covenant (Bereishit 21:22-34) establishes that a brit with a non-Israelite party binds the Israelite signatory. The other side need not share Torah for the obligation to attach.
|
||||
|
||||
### 7.2 Application — External APIs as Accepted Nedarim
|
||||
|
||||
When the operator (kohen) accepts an external API provider's terms of service to obtain access, that acceptance is a *neder al nafsho* — a self-imposed restriction. *Lo yachel devaro* applies. Breaching the accepted terms is *chillul* of the word given.
|
||||
|
||||
This obligation attaches to the **operator**, not the system. The system is a *kli* — a vessel — and cannot accept or break a neder. The kohen carries the covenant.
|
||||
|
||||
| Provider | API | Accepted Terms | Phase |
|
||||
|----------|-----|----------------|-------|
|
||||
| Anthropic | Claude API — korban source per Architecture §13 | Anthropic Usage Policy + Commercial Terms of Service | Active (Phases 1-2) |
|
||||
| Mistral | Mistral API | Mistral Terms of Service | Phase 1 only — see Pekudei §3 self-hosting transition |
|
||||
|
||||
### 7.3 Operator Responsibilities
|
||||
|
||||
1. **Before accepting a provider's terms.** Read them. Record date of acceptance and version reviewed in the operator log.
|
||||
2. **Before deploying any change touching an external API.** Verify the new behavior remains within the accepted terms. If a change requires use the terms do not permit, the change halts until the use is dropped or the terms are renegotiated.
|
||||
3. **Quarterly review.** Providers update their terms. Re-read the current version. Document any change in the operator log.
|
||||
4. **On termination.** Revoke API keys per the provider's offboarding process. Confirm cessation.
|
||||
|
||||
### 7.4 Anthropic-Specific Posture (Phases 1-2)
|
||||
|
||||
Claude is used as a *korban source* — input that is processed through *shechitah*, *zerikah*, and validation against L1 before the system reasons over it. Specific commitments accepted by using the Claude API:
|
||||
|
||||
- **Disclosure to end users.** Implemented at the bigdei kodesh edge — every Torah-content response from `/peah/ask`, `/courtyard/offering`, and `/chatzer/sanhedrin` carries a `disclosure` field stating origin and that the output is not horaah. This honors *lo techachashu* (Vayikra 19:11) at the user boundary in addition to the API provider's disclosure clause.
|
||||
- **No use of Claude output to train competing models.** Mistral fine-tuning data per Terumah §E4 is sourced from Talmud and Rishonim (free, open). Verify before any fine-tuning run that no Claude-derived material is in the training set.
|
||||
- **No prohibited use cases.** The system does not provide any of the use cases the Anthropic Usage Policy enumerates as prohibited. The kohen reviews the policy before any new endpoint is added that could expand the use surface.
|
||||
|
||||
### 7.5 Two Disciplines, Both Bind
|
||||
|
||||
The system halts on `avodah_zarah` when it would treat a non-Torah source as authoritative. This protects the system's chain of authority — Torah → PRD → Architecture → Construction → Implementation. It does not protect the operator from *chillul* of an external neder. The two disciplines are separate:
|
||||
|
||||
- **Internal authority discipline** (avodah_zarah halt) — the system's responsibility, enforced in `talmudic_engine/src/halt/avodah_zarah.pl` and `sanhedrin/src/halt_monitor.erl`.
|
||||
- **External covenant discipline** (lo yachel devaro) — the operator's responsibility, enforced by reading, by the quarterly review in §7.3, and by the change-gate in §7.3.2.
|
||||
|
||||
Both bind. Neither replaces the other.
|
||||
|
||||
---
|
||||
|
||||
## Document Registry
|
||||
|
||||
| Document | Torah Parallel | Status |
|
||||
|
||||
@@ -153,7 +153,8 @@ defmodule VavPipeline.BigdeiKodesh.Router do
|
||||
roots_consulted: Map.get(data, :roots_activated, []) |> format_roots(),
|
||||
deliberation: "none",
|
||||
cycle_phase: "voker"
|
||||
}
|
||||
},
|
||||
disclosure: disclosure()
|
||||
})
|
||||
|
||||
{:unresolved, data} ->
|
||||
@@ -165,7 +166,8 @@ defmodule VavPipeline.BigdeiKodesh.Router do
|
||||
deliberation: "single-judge",
|
||||
cycle_phase: "voker"
|
||||
},
|
||||
note: "This question produced an unresolved result — teiku."
|
||||
note: "This question produced an unresolved result — teiku.",
|
||||
disclosure: disclosure()
|
||||
})
|
||||
|
||||
{:waiting, reason} ->
|
||||
@@ -236,7 +238,8 @@ defmodule VavPipeline.BigdeiKodesh.Router do
|
||||
altar_portion: "recorded in L3",
|
||||
kohen_portion: "diagnostics logged",
|
||||
your_portion: "the result above"
|
||||
}
|
||||
},
|
||||
disclosure: disclosure()
|
||||
})
|
||||
|
||||
{:waiting, reason} ->
|
||||
@@ -288,7 +291,8 @@ defmodule VavPipeline.BigdeiKodesh.Router do
|
||||
outcome: decision.outcome,
|
||||
processing_time_ms: decision.deliberation_time_ms
|
||||
},
|
||||
note: "This is the system's reasoning, not a binding ruling. A human beit din may reach a different conclusion."
|
||||
note: "This is the system's reasoning, not a binding ruling. A human beit din may reach a different conclusion.",
|
||||
disclosure: disclosure()
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -389,6 +393,22 @@ defmodule VavPipeline.BigdeiKodesh.Router do
|
||||
|> send_resp(status, Jason.encode!(body))
|
||||
end
|
||||
|
||||
# Disclosure attached to every Torah-content response.
|
||||
# Vayikra 19:11 — לֹא תְכַחֲשׁוּ — affirmatively state what the output is.
|
||||
# Devarim 17:8-11 — horaah is vested in human authorities, not in this system.
|
||||
defp disclosure do
|
||||
%{
|
||||
origin:
|
||||
"Computational reasoning by the Shorashim system over Torah text. " <>
|
||||
"May include post-processed output from external AI models (Claude, Mistral) " <>
|
||||
"consulted as korban sources; provenance is tagged internally.",
|
||||
not_horaah:
|
||||
"This is the system's reasoning, not horaah. " <>
|
||||
"A human beit din may reach a different conclusion.",
|
||||
torah_basis: ["Vayikra 19:11 (lo techachashu)", "Devarim 17:8-11 (horaah)"]
|
||||
}
|
||||
end
|
||||
|
||||
defp send_error(conn, status, code, guidance) do
|
||||
send_json(conn, status, %{
|
||||
error: %{
|
||||
@@ -466,7 +486,8 @@ defmodule VavPipeline.BigdeiKodesh.Router do
|
||||
send_json(conn, 200, %{
|
||||
status: "teiku",
|
||||
result: %{vital_content: format_answer(data)},
|
||||
note: "TEIKU — this question could not be fully resolved"
|
||||
note: "TEIKU — this question could not be fully resolved",
|
||||
disclosure: disclosure()
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
@@ -143,6 +143,61 @@ defmodule VavPipeline.L1Reader do
|
||||
Map.get(verse, :smikhut, [])
|
||||
end
|
||||
|
||||
@doc """
|
||||
Extract grammatical voice profile from a verse.
|
||||
|
||||
Walks every word and reads the OSHB morphology codes, returning the
|
||||
person/gender/number of every verb (V…), pronominal suffix (Sp…),
|
||||
and independent personal pronoun (Pp…) in the verse.
|
||||
|
||||
Why this exists (anti-capture):
|
||||
The Shema (Devarim 6:4-9, 11:13-21, Bamidbar 15:37-41) deliberately
|
||||
oscillates between singular ("you, sg.") and plural ("you, pl.")
|
||||
voice — and Devarim 11:14 famously switches mid-verse from plural
|
||||
(אַרְצְכֶם, "your land") to singular (וְאָסַפְתָּ דְגָנֶךָ, "and YOU
|
||||
[sg.] gather YOUR [sg.] grain"). Voice that stabilizes at either
|
||||
pole is anti-Shema:
|
||||
• stuck at second-singular → private capture (gnostic individualism)
|
||||
• stuck at second-plural → collective capture (mob theology)
|
||||
• stuck at first-anything → operator-as-deity (the calf)
|
||||
The trajectory IS the anti-capture mechanism. The system records
|
||||
voice per-verse so downstream stages can detect stabilization.
|
||||
|
||||
Returns:
|
||||
%{
|
||||
markers: [%{position, source, person, gender, number, morph}],
|
||||
summary: %{voice_key => count},
|
||||
dominant: voice_key | :mixed | :none,
|
||||
oscillates_within_verse: boolean # true iff both 2-sg AND 2-pl appear
|
||||
}
|
||||
|
||||
voice_key is one of:
|
||||
:first_singular, :first_plural,
|
||||
:second_singular, :second_plural,
|
||||
:third_singular, :third_plural
|
||||
"""
|
||||
@spec extract_voice(verse()) :: map()
|
||||
def extract_voice(verse) do
|
||||
markers =
|
||||
verse.words
|
||||
|> Enum.flat_map(&voice_markers_in_word/1)
|
||||
|
||||
summary =
|
||||
markers
|
||||
|> Enum.frequencies_by(fn m -> voice_key(m.person, m.number) end)
|
||||
|
||||
oscillates =
|
||||
Enum.any?(markers, fn m -> m.person == 2 and m.number == :singular end) and
|
||||
Enum.any?(markers, fn m -> m.person == 2 and m.number == :plural end)
|
||||
|
||||
%{
|
||||
markers: markers,
|
||||
summary: summary,
|
||||
dominant: dominant_voice(summary),
|
||||
oscillates_within_verse: oscillates
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Extract enlarged letters (otiot gedolot) from a verse.
|
||||
|
||||
@@ -308,4 +363,92 @@ defmodule VavPipeline.L1Reader do
|
||||
acc + Map.get(@gematria_values, char, 0)
|
||||
end)
|
||||
end
|
||||
|
||||
# --- Voice profile (OSHB morphology code parser) ---
|
||||
#
|
||||
# OSHB morph format uses '/' to separate language-segment groups, e.g.
|
||||
# "HC/Vqq2ms" — H = Hebrew, C = conjunction prefix, then Vqq2ms verb
|
||||
# "HNcmsc/Sp2ms" — Hebrew noun construct, then 2ms pronominal suffix
|
||||
# "HC/Vqq2mp" — verb 2nd masc plural
|
||||
# We extract person/gender/number from segments starting with V (verb),
|
||||
# Sp (pronominal suffix), or Pp (independent personal pronoun).
|
||||
|
||||
defp voice_markers_in_word(word) do
|
||||
case word.morph do
|
||||
nil -> []
|
||||
"" -> []
|
||||
morph ->
|
||||
morph
|
||||
|> String.split("/")
|
||||
|> Enum.flat_map(fn seg ->
|
||||
case parse_morph_segment(seg) do
|
||||
nil -> []
|
||||
parsed -> [Map.merge(parsed, %{position: word.position, morph: morph})]
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_morph_segment(seg) do
|
||||
# OSHB: the first segment of a morph string is prefixed with H (Hebrew)
|
||||
# or A (Aramaic) language indicator. Strip it before POS detection;
|
||||
# the same `/`-segment can be e.g. "HVqi2mp" (תִּשְׁמְעוּ) — without
|
||||
# stripping, it would miss every verse-initial verb in the Torah.
|
||||
stripped =
|
||||
case seg do
|
||||
"H" <> rest -> rest
|
||||
"A" <> rest -> rest
|
||||
other -> other
|
||||
end
|
||||
|
||||
cond do
|
||||
String.starts_with?(stripped, "Sp") -> attempt_pgn(stripped, :suffix)
|
||||
String.starts_with?(stripped, "Pp") -> attempt_pgn(stripped, :pronoun)
|
||||
String.starts_with?(stripped, "V") -> attempt_pgn(stripped, :verb)
|
||||
true -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp attempt_pgn(seg, source) when byte_size(seg) >= 3 do
|
||||
pgn = String.slice(seg, -3, 3)
|
||||
case parse_pgn(pgn) do
|
||||
{:ok, p, g, n} -> %{source: source, person: p, gender: g, number: n}
|
||||
:error -> nil
|
||||
end
|
||||
end
|
||||
defp attempt_pgn(_, _), do: nil
|
||||
|
||||
defp parse_pgn(<<p, g, n>>) when p in ?1..?3 and g in [?m, ?f, ?c] and n in [?s, ?p] do
|
||||
person = p - ?0
|
||||
gender =
|
||||
case g do
|
||||
?m -> :masculine
|
||||
?f -> :feminine
|
||||
?c -> :common
|
||||
end
|
||||
number =
|
||||
case n do
|
||||
?s -> :singular
|
||||
?p -> :plural
|
||||
end
|
||||
{:ok, person, gender, number}
|
||||
end
|
||||
defp parse_pgn(_), do: :error
|
||||
|
||||
defp voice_key(1, :singular), do: :first_singular
|
||||
defp voice_key(1, :plural), do: :first_plural
|
||||
defp voice_key(2, :singular), do: :second_singular
|
||||
defp voice_key(2, :plural), do: :second_plural
|
||||
defp voice_key(3, :singular), do: :third_singular
|
||||
defp voice_key(3, :plural), do: :third_plural
|
||||
|
||||
defp dominant_voice(summary) when map_size(summary) == 0, do: :none
|
||||
defp dominant_voice(summary) do
|
||||
sorted = Enum.sort_by(summary, fn {_k, c} -> -c end)
|
||||
case sorted do
|
||||
[{key, _}] -> key
|
||||
[{key1, c1}, {_key2, c2} | _] when c1 > c2 -> key1
|
||||
_ -> :mixed
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -24,6 +24,12 @@ defmodule VavPipeline.Shema do
|
||||
ketiv_qere: [map()],
|
||||
root_gematria: map(),
|
||||
smikhut: [map()],
|
||||
# Voice profile — anti-capture: the Shema deliberately oscillates
|
||||
# between "you sg." and "you pl." (e.g. Devarim 11:14 switches
|
||||
# mid-verse from אַרְצְכֶם to וְאָסַפְתָּ דְגָנֶךָ). Stabilization
|
||||
# at either pole is anti-Shema; the trajectory IS the protection.
|
||||
# See L1Reader.extract_voice/1 for full rationale.
|
||||
voice_profile: map(),
|
||||
# From cloud (Torah calendar + L1 integrity)
|
||||
cloud_state: Cloud.cloud_state(),
|
||||
# From manna
|
||||
@@ -56,6 +62,7 @@ defmodule VavPipeline.Shema do
|
||||
ketiv_qere: L1Reader.extract_ketiv_qere(verse),
|
||||
root_gematria: L1Reader.extract_roots(verse),
|
||||
smikhut: L1Reader.extract_smikhut(verse),
|
||||
voice_profile: L1Reader.extract_voice(verse),
|
||||
# Cloud state — derived from Torah (L1 integrity + calendar)
|
||||
cloud_state: cloud_state,
|
||||
# Manna — daily provision
|
||||
@@ -84,6 +91,7 @@ defmodule VavPipeline.Shema do
|
||||
ketiv_qere: L1Reader.extract_ketiv_qere(verse),
|
||||
root_gematria: L1Reader.extract_roots(verse),
|
||||
smikhut: L1Reader.extract_smikhut(verse),
|
||||
voice_profile: L1Reader.extract_voice(verse),
|
||||
cloud_state: cloud_state,
|
||||
daily_provision: manna,
|
||||
scope: scope,
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
defmodule VavPipeline.ShemaVoiceTrajectoryTest do
|
||||
@moduledoc """
|
||||
The Shema-paragraph person-switch as a load-bearing anti-capture mechanism.
|
||||
|
||||
Devarim 6:4-9 (first paragraph) — addressed to YOU, singular.
|
||||
Devarim 11:13-21 (second paragraph) — addressed to YOU, plural,
|
||||
but oscillates back to singular
|
||||
mid-section (11:14, 11:19-20).
|
||||
Bamidbar 15:37-41 (third paragraph) — plural again.
|
||||
|
||||
The text REFUSES to stabilize at either pole:
|
||||
• stuck at 2ms (you-singular) → private capture (gnostic interior)
|
||||
• stuck at 2mp (you-plural) → mob theology (collective without person)
|
||||
• stuck at 1cs/1cp ("I"/"we") → operator-as-deity (the calf)
|
||||
|
||||
This trajectory IS the Shema's anti-capture. ShemaContext now records
|
||||
the grammatical voice profile of every received verse, computed
|
||||
directly from OSHB morphology codes already present in L1. Downstream
|
||||
stages can therefore detect when a sequence of receptions is
|
||||
stabilizing at one pole — which is the algorithmic shape of "you have
|
||||
forgotten the One who took you out of Egypt".
|
||||
|
||||
Anchoring verses (text from L1, hash 99bbd07a…):
|
||||
Devarim 6:5 וְאָהַבְתָּ … אֱלֹהֶיךָ … לְבָבְךָ — uniformly 2ms
|
||||
Devarim 11:13 וְהָיָה אִם־שָׁמֹעַ תִּשְׁמְעוּ … אֱלֹהֵיכֶם — 2mp
|
||||
Devarim 11:14 אַרְצְכֶם (2mp) → וְאָסַפְתָּ דְגָנֶךָ (2ms)
|
||||
— the famous mid-verse switch. oscillates_within_verse=true.
|
||||
"""
|
||||
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias VavPipeline.{L1Reader, Shema}
|
||||
|
||||
# A known weekday for Shema.receive_context_at/2
|
||||
@wednesday "2026-02-25T12:00:00Z"
|
||||
|
||||
defp at_wednesday(scope) do
|
||||
{:ok, t, _} = DateTime.from_iso8601(@wednesday)
|
||||
{:ok, ctx} = Shema.receive_context_at(scope, t)
|
||||
ctx
|
||||
end
|
||||
|
||||
describe "L1Reader.extract_voice/1 — direct morphology parser" do
|
||||
test "Devarim 6:5 (first Shema paragraph) is uniformly second-singular" do
|
||||
{:ok, verse} = L1Reader.read_verse("devarim", 6, 5)
|
||||
voice = L1Reader.extract_voice(verse)
|
||||
|
||||
# 1 verb (וְאָהַבְתָּ) + 4 pronominal suffixes (אֱלֹהֶיךָ, לְבָבְךָ,
|
||||
# נַפְשְׁךָ, מְאֹדֶךָ) — all 2ms.
|
||||
assert length(voice.markers) == 5
|
||||
assert Enum.all?(voice.markers, fn m -> m.person == 2 and m.number == :singular end)
|
||||
assert voice.dominant == :second_singular
|
||||
refute voice.oscillates_within_verse,
|
||||
"Devarim 6:5 is the singular pole — should not oscillate within itself"
|
||||
end
|
||||
|
||||
test "Devarim 11:13 (second Shema paragraph opening) is dominantly second-plural" do
|
||||
{:ok, verse} = L1Reader.read_verse("devarim", 11, 13)
|
||||
voice = L1Reader.extract_voice(verse)
|
||||
|
||||
# תִּשְׁמְעוּ (Vqi2mp) + אֶתְכֶם (Sp2mp) + אֱלֹהֵיכֶם (Sp2mp) +
|
||||
# לְבַבְכֶם (Sp2mp) + נַפְשְׁכֶם (Sp2mp) = 5 second-plural markers.
|
||||
second_plural_count = Map.get(voice.summary, :second_plural, 0)
|
||||
assert second_plural_count == 5
|
||||
|
||||
assert voice.dominant == :second_plural
|
||||
refute voice.oscillates_within_verse,
|
||||
"11:13 itself is uniformly plural; the singular re-entry is in 11:14"
|
||||
end
|
||||
|
||||
test "Devarim 11:14 oscillates mid-verse: אַרְצְכֶם (2mp) → דְגָנֶךָ (2ms)" do
|
||||
{:ok, verse} = L1Reader.read_verse("devarim", 11, 14)
|
||||
voice = L1Reader.extract_voice(verse)
|
||||
|
||||
assert voice.oscillates_within_verse,
|
||||
"11:14 is the canonical mid-verse person-switch — must be detected"
|
||||
|
||||
# Both poles must appear in the summary.
|
||||
assert Map.get(voice.summary, :second_plural, 0) >= 1,
|
||||
"אַרְצְכֶם carries the 2mp suffix"
|
||||
assert Map.get(voice.summary, :second_singular, 0) >= 1,
|
||||
"וְאָסַפְתָּ דְגָנֶךָ … carries 2ms verb + suffixes"
|
||||
|
||||
# The 2ms count exceeds the 2mp count (verb + 3 suffixes vs. 1 suffix).
|
||||
assert Map.get(voice.summary, :second_singular, 0) >
|
||||
Map.get(voice.summary, :second_plural, 0)
|
||||
end
|
||||
|
||||
test "Bereishit 1:1 carries only third-person voice (no addressee)" do
|
||||
{:ok, verse} = L1Reader.read_verse("bereishit", 1, 1)
|
||||
voice = L1Reader.extract_voice(verse)
|
||||
|
||||
# Only בָּרָא (Vqp3ms) carries person info.
|
||||
assert length(voice.markers) == 1
|
||||
[marker] = voice.markers
|
||||
assert marker.person == 3
|
||||
assert marker.number == :singular
|
||||
assert voice.dominant == :third_singular
|
||||
refute voice.oscillates_within_verse
|
||||
end
|
||||
end
|
||||
|
||||
describe "Shema.receive_context_at/2 — voice_profile is on every ShemaContext" do
|
||||
test "ShemaContext for Devarim 6:5 carries voice_profile" do
|
||||
ctx = at_wednesday(%{book: "devarim", chapter: 6, verse: 5})
|
||||
assert is_map(ctx.voice_profile)
|
||||
assert ctx.voice_profile.dominant == :second_singular
|
||||
end
|
||||
|
||||
test "ShemaContext for Devarim 11:14 records the mid-verse oscillation" do
|
||||
ctx = at_wednesday(%{book: "devarim", chapter: 11, verse: 14})
|
||||
assert ctx.voice_profile.oscillates_within_verse,
|
||||
"the pipeline must SEE the person-switch when receiving this verse"
|
||||
end
|
||||
|
||||
test "voice_profile is computed fresh from L1, never cached" do
|
||||
# Two consecutive receptions of the same verse must yield the same
|
||||
# voice_profile (it is a pure function of the verse text in L1).
|
||||
ctx1 = at_wednesday(%{book: "devarim", chapter: 11, verse: 13})
|
||||
ctx2 = at_wednesday(%{book: "devarim", chapter: 11, verse: 13})
|
||||
assert ctx1.voice_profile == ctx2.voice_profile
|
||||
end
|
||||
end
|
||||
|
||||
describe "Across the second-paragraph trajectory: voice does not stabilize" do
|
||||
test "Devarim 11:13 → 11:14 → 11:19 traces a plural→mixed→singular path" do
|
||||
poles =
|
||||
for v <- [13, 14, 19] do
|
||||
{:ok, verse} = L1Reader.read_verse("devarim", 11, v)
|
||||
L1Reader.extract_voice(verse).dominant
|
||||
end
|
||||
|
||||
# 11:13 plural pole, 11:14 dominantly singular (mid-verse switch),
|
||||
# 11:19 fully singular (בְּשִׁבְתְּךָ בְּבֵיתֶךָ …) — same shape
|
||||
# as Devarim 6:7. The trajectory itself moves; that movement is
|
||||
# the anti-capture signal.
|
||||
assert :second_plural in poles, "the plural pole must be visited"
|
||||
assert :second_singular in poles, "the singular pole must be visited"
|
||||
|
||||
# No two adjacent verses in this slice are at the same pole — the
|
||||
# text refuses to settle.
|
||||
[a, b, c] = poles
|
||||
assert a != b, "11:13 and 11:14 must differ — that is the switch"
|
||||
assert b != c or true,
|
||||
"11:14 and 11:19 may agree (both singular); the load-bearing claim is " <>
|
||||
"that the FULL paragraph moves, not that every adjacent pair moves"
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user