- 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>
113 lines
4.4 KiB
Python
113 lines
4.4 KiB
Python
"""
|
|
Tests for router — output routing based on offering type.
|
|
|
|
Architecture §3.5: Route to appropriate component based on offering type.
|
|
|
|
Kiyyor principle (structure_not_content.md):
|
|
Stateless — no module-level routing log, no state between calls.
|
|
"""
|
|
|
|
from korban_processor.korban import ProcessedKorban, OfferingType, Provenance
|
|
from korban_processor.router import route, RoutingResult
|
|
|
|
|
|
_DEFAULT_PROPOSITIONS = ["verse(bereishit, 1, 1)", 'root("ראש", hebrew)']
|
|
|
|
|
|
def make_processed(
|
|
offering_type: OfferingType,
|
|
propositions: list[str] | None = None,
|
|
) -> ProcessedKorban:
|
|
props = _DEFAULT_PROPOSITIONS if propositions is None else propositions
|
|
return ProcessedKorban(
|
|
vital_content="The root ר-א-ש means beginning. Bereishit 1:1.",
|
|
propositions=props,
|
|
provenance=Provenance.CLAUDE,
|
|
offering_type=offering_type,
|
|
discarded=[],
|
|
source_query="test query",
|
|
)
|
|
|
|
|
|
class TestRoutingResults:
|
|
def test_olah_routes_to_talmudic_engine(self):
|
|
processed = make_processed(OfferingType.OLAH)
|
|
result = route(processed, OfferingType.OLAH)
|
|
assert result.destination == "talmudic_engine"
|
|
assert result.returned_to_source is False
|
|
|
|
def test_shelamim_routes_to_talmudic_engine_with_return(self):
|
|
processed = make_processed(OfferingType.SHELAMIM)
|
|
result = route(processed, OfferingType.SHELAMIM)
|
|
assert result.destination == "talmudic_engine"
|
|
assert result.returned_to_source is True
|
|
|
|
def test_chatat_routes_to_error_correction(self):
|
|
processed = make_processed(OfferingType.CHATAT)
|
|
result = route(processed, OfferingType.CHATAT)
|
|
assert result.destination == "error_correction"
|
|
assert result.returned_to_source is False
|
|
|
|
def test_minchah_routes_to_talmudic_engine(self):
|
|
processed = make_processed(OfferingType.MINCHAH)
|
|
result = route(processed, OfferingType.MINCHAH)
|
|
assert result.destination == "talmudic_engine"
|
|
assert result.returned_to_source is False
|
|
|
|
def test_returns_routing_result_instance(self):
|
|
processed = make_processed(OfferingType.OLAH)
|
|
result = route(processed, OfferingType.OLAH)
|
|
assert isinstance(result, RoutingResult)
|
|
|
|
def test_propositions_sent_count_is_correct(self):
|
|
propositions = ["verse(bereishit, 1, 1)", 'root("ראש", hebrew)', 'claim("a", "b")']
|
|
processed = make_processed(OfferingType.OLAH, propositions)
|
|
result = route(processed, OfferingType.OLAH)
|
|
assert result.propositions_sent == 3
|
|
|
|
def test_zero_propositions(self):
|
|
processed = make_processed(OfferingType.OLAH, [])
|
|
result = route(processed, OfferingType.OLAH)
|
|
assert result.propositions_sent == 0
|
|
|
|
|
|
class TestRouterStateless:
|
|
"""
|
|
BUILD_KORBAN verification §4:
|
|
Kiyyor principle — no state leaks between calls.
|
|
No module-level routing log.
|
|
"""
|
|
|
|
def test_no_module_level_routing_log(self):
|
|
"""router.py must not have a module-level _routing_log accumulator."""
|
|
import korban_processor.router as router_module
|
|
assert not hasattr(router_module, "_routing_log"), (
|
|
"router.py has module-level _routing_log — violates kiyyor principle"
|
|
)
|
|
|
|
def test_successive_calls_independent(self):
|
|
"""Second call returns correct result regardless of first call."""
|
|
p1 = make_processed(OfferingType.OLAH, ["prop1"])
|
|
p2 = make_processed(OfferingType.CHATAT, ["prop2", "prop3"])
|
|
|
|
result1 = route(p1, OfferingType.OLAH)
|
|
result2 = route(p2, OfferingType.CHATAT)
|
|
|
|
assert result1.destination == "talmudic_engine"
|
|
assert result1.propositions_sent == 1
|
|
assert result2.destination == "error_correction"
|
|
assert result2.propositions_sent == 2
|
|
|
|
def test_same_input_same_output(self):
|
|
"""Identical input always produces identical output — no accumulated state."""
|
|
processed = make_processed(OfferingType.SHELAMIM, ["verse(bereishit, 1, 1)"])
|
|
|
|
result1 = route(processed, OfferingType.SHELAMIM)
|
|
# Run an unrelated routing between
|
|
route(make_processed(OfferingType.CHATAT, []), OfferingType.CHATAT)
|
|
result2 = route(processed, OfferingType.SHELAMIM)
|
|
|
|
assert result1.destination == result2.destination
|
|
assert result1.propositions_sent == result2.propositions_sent
|
|
assert result1.returned_to_source == result2.returned_to_source
|