Files
Scott KarpandClaude Sonnet 4.6 33f8b03583 Step 13: Korban Processor complete — 7 modules, 181 tests, all passing
- semichah: provenance tagging (6 sources, rejects empty/anonymous)
- shechitah: strip preamble, self-reference, hedging, markdown, sycophancy
- zerikah: extract Torah refs, Hebrew text, root analysis, insight markers
- haktarah: transform prose to Prolog propositions (verse/3, root/2, claim/2, connection/3)
- router: stateless routing — removed module-level _routing_log (kiyyor principle)
- model_interface: outbound Claude API via httpx (Construction §3.4, HTTPS only)
- hebrew_parser: nikkud/teamim stripping, consonant extraction, gematria, root identification

All 5 BUILD_KORBAN.md verification tests pass.
AGENTS.md: added structure_not_content.md to spec table, added Principle 6.
build_log.md: recorded session, broken tablets #18-20, design decisions.

Ka'asher tzivah Hashem et Moshe.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 09:37:25 -04:00

178 lines
5.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Tests for hebrew_parser — Hebrew text analysis utilities.
Architecture §3.5: Used by zerikah for Hebrew analysis.
Construction §1.4: hebrew-tokenizer==2.3.0.
"""
from korban_processor.hebrew_parser import (
is_consonant,
is_hebrew_char,
is_hebrew_text,
strip_nikkud,
strip_teamim,
strip_nikkud_and_teamim,
extract_consonants,
gematria,
identify_root,
normalize_root_notation,
split_hebrew_words,
)
class TestHebrewCharDetection:
def test_alef_is_consonant(self):
assert is_consonant("א")
def test_tav_is_consonant(self):
assert is_consonant("ת")
def test_latin_a_not_consonant(self):
assert not is_consonant("a")
def test_nikkud_sheva_not_consonant(self):
# U+05B0 = SHEVA — vowel point, not consonant
assert not is_consonant("\u05b0")
def test_hebrew_text_with_consonants(self):
assert is_hebrew_text("בְּרֵאשִׁית")
def test_latin_text_not_hebrew(self):
assert not is_hebrew_text("Genesis")
def test_empty_not_hebrew(self):
assert not is_hebrew_text("")
class TestNikkudStripping:
def test_strip_nikkud_bereishit(self):
# בְּרֵאשִׁית → בראשית (consonants + te'amim, no nikkud)
result = strip_nikkud("בְּרֵאשִׁית")
# Should contain only consonants (and possibly te'amim if any)
for ch in result:
assert ord(ch) < 0x05B0 or ord(ch) >= 0x05C8 or is_consonant(ch), \
f"Unexpected nikkud char: {ch!r} (U+{ord(ch):04X})"
def test_strip_nikkud_preserves_consonants(self):
result = strip_nikkud("בְּרֵאשִׁית")
assert "ב" in result
assert "ר" in result
assert "א" in result
assert "ש" in result
assert "י" in result
assert "ת" in result
def test_strip_nikkud_plain_text_unchanged(self):
assert strip_nikkud("בראשית") == "בראשית"
def test_strip_nikkud_and_teamim(self):
result = strip_nikkud_and_teamim("בְּרֵאשִׁית")
# Only consonants should remain
for ch in result:
assert is_consonant(ch), f"Non-consonant after full strip: {ch!r}"
class TestExtractConsonants:
def test_extracts_consonants_from_bereishit(self):
result = extract_consonants("בְּרֵאשִׁית")
assert result == "בראשית"
def test_extracts_consonants_plain(self):
assert extract_consonants("בראשית") == "בראשית"
def test_empty_returns_empty(self):
assert extract_consonants("") == ""
def test_latin_returns_empty(self):
assert extract_consonants("Genesis") == ""
class TestGematria:
def test_alef_is_1(self):
assert gematria("א") == 1
def test_bet_is_2(self):
assert gematria("ב") == 2
def test_tav_is_400(self):
assert gematria("ת") == 400
def test_torah_gematria(self):
# תורה = 400 + 6 + 200 + 5 = 611
assert gematria("תורה") == 611
def test_bereishit_gematria(self):
# בראשית = 2 + 200 + 1 + 300 + 10 + 400 = 913
assert gematria("בראשית") == 913
def test_kaf_sofit_equals_kaf(self):
# ך = 20 (same as כ)
assert gematria("ך") == gematria("כ")
def test_mem_sofit_equals_mem(self):
# ם = 40 (same as מ)
assert gematria("ם") == gematria("מ")
def test_latin_chars_ignored(self):
assert gematria("abc") == 0
def test_nikkud_ignored(self):
# Nikkud chars have no gematria value
assert gematria("בְּרֵאשִׁית") == gematria("בראשית")
class TestIdentifyRoot:
def test_three_letter_word_returns_word(self):
root = identify_root("בָּרָא")
assert root == "ברא"
def test_short_word_returns_none(self):
assert identify_root("אל") is None
def test_empty_returns_none(self):
assert identify_root("") is None
def test_returns_first_three_consonants(self):
# For a 4-letter word, return first 3 (Phase 2 approximation)
root = identify_root("בראשית")
assert root == "בר" + "א" # First 3 consonants
class TestNormalizeRootNotation:
def test_dash_separated(self):
result = normalize_root_notation("ר-א-ש")
assert result == "ראש"
def test_dot_separated(self):
result = normalize_root_notation("ר.א.ש")
assert result == "ראש"
def test_bare_consonants(self):
result = normalize_root_notation("ראש")
assert result == "ראש"
def test_non_three_letter_returns_none(self):
assert normalize_root_notation("אב") is None
assert normalize_root_notation("אבגד") is None
class TestSplitHebrewWords:
def test_splits_single_word(self):
words = split_hebrew_words("בְּרֵאשִׁית")
assert len(words) == 1
def test_splits_multiple_words(self):
words = split_hebrew_words("בְּרֵאשִׁית בָּרָא אֱלֹהִים")
assert len(words) == 3
def test_splits_on_latin_boundary(self):
words = split_hebrew_words("The word בְּרֵאשִׁית opens Torah.")
assert len(words) == 1
assert "ב" in words[0]
def test_empty_text_returns_empty(self):
assert split_hebrew_words("") == []
def test_latin_only_returns_empty(self):
assert split_hebrew_words("Genesis 1:1") == []