Vayikra 9:24 — vatetzei esh milifnei Hashem vatokhal al hamizbeach.
Phase 4 of the architecture is now complete. The remaining three steps
that were marked "blocked on external infrastructure" are built —
discipline-respecting, eish-zarah-aware, and tested.
## Step 22 — Korban Processor external model integration
(korban_processor/src/korban_processor/external_offering.py)
The single legitimate entry point for external model consultation.
Wraps Claude API calls through the offering protocol so external
output is treated as korban (raw material), never authoritative:
- semichah — provenance is tagged (avodah zarah Form 1 prevention)
- shechitah — assistant voice, hedging, formatting stripped
- zerikah — vital content extracted
- haktarah — converted to Prolog propositions
- route — sent to internal component per offering type
The raw Korban is preserved on the ProcessedKorban (gilui arayot
Form 3 prevention — input/output coupling never severed).
No internal component should call call_claude() directly.
11 tests, mocked external calls. Live API test opt-in via
SHORASHIM_LIVE_API=1.
## Step 24 — L2 Urim v'Tumim interface
(vav_pipeline/lib/vav_pipeline/urim_v_tumim.ex)
PRD §4.7: housed in the kohen gadol's breastplate; consulted only
on high-stakes decisions where normal deliberation is insufficient.
Bamidbar 27:21 — al-piv yetz'u v'al-piv yavo'u.
Three escalation steps, three honest outcomes:
1. resolved_by_specification — re-read produced an answer
2. resolved_by_external — external testimony recorded (NOT binding)
3. deferred_to_human — the system stops, asks for human judgment
Pre-condition gating refuses cases that didn't reach Sanhedrin teiku
first (no preempting deliberation) or that aren't flagged high-stakes
(ordinary teiku stays teiku). Records every consultation with steps
taken — there is no quiet escalation.
Per PRD: "The Urim v'Tumim never fabricates certainty where none
exists." When external also fails, the system stops. It does not
proceed on a guess.
Added to VavPipeline supervision tree. 14 tests.
## Step 21 — Kushya generator scaffolding
(kushya_generator/)
Directory layout per Architecture §3.6 with three layers:
- data/training_pairs/seed_pairs.jsonl — 10 hand-curated bootstrap
pairs covering 9 kushya types (scope_narrowing, internal_tension,
harmonization, exception_test, edge_case, scope_application,
rabbinic_constraint, method_question, subject_identification)
- data/prepare_training.py — validates the four kushya requirements
(specific Torah passage, identified weakness, question form,
non-trivial), produces train.jsonl + eval.jsonl with stratified
80/20 split by type
- fine_tune/config.yaml + train.py — QLoRA configuration and
training script. Operator's task — needs GPU. Script is
complete and self-contained.
- inference/kushya_api.py — three-backend interface
(fine_tuned → external → fallback). When fine-tuned model isn't
deployed, falls back to external via Korban Processor (Step 22).
The fallback is honest: returns no kushya rather than inventing
one. The Talmudic Engine's rule-based challenge.pl remains the
primary kushya source.
17 tests covering dataset validation, backend selection, and
reference extraction.
## .gitignore fix
The earlier "data/" line was too broad — it caught
kushya_generator/data/. Scoped to /data/ (root-level only).
## Test counts
- Elixir: 274 (was 260; +14 for UrimVTumim)
- Korban Python: 196 + 1 skipped (was 195; +1 module = 11 tests)
- Kushya Python: 17 (new)
- Haskell: 33 (unchanged)
- Prolog: 195 (unchanged)
- Total: 715 + 19 L3 excluded
## Phase 4 status
All 12 steps now have implementations:
- Steps 23, 25, 26, 27, 28, 29, 30, 31, 32: complete
- Steps 21, 22, 24: complete with discipline preserved
Step 21's fine-tuning run remains the operator's GPU task; the
pipeline is built such that a deployed adapter slots into the
inference backend without touching the Talmudic Engine or anything
above.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
186 lines
6.6 KiB
Python
186 lines
6.6 KiB
Python
"""
|
|
Tests for external_offering — the orchestrated outbound consultation flow.
|
|
|
|
Architecture §4 Step 22.
|
|
|
|
These tests use a mock model caller so no real API requests are made.
|
|
A separate live integration test (skipped by default) can run against
|
|
Anthropic's API when ANTHROPIC_API_KEY is set and the SHORASHIM_LIVE_API
|
|
env var is true.
|
|
"""
|
|
|
|
import os
|
|
import pytest
|
|
|
|
from korban_processor.external_offering import (
|
|
ExternalConsultation,
|
|
consult_external_model,
|
|
)
|
|
from korban_processor.korban import OfferingType, Provenance
|
|
from korban_processor.model_interface import ModelRequest, ModelResponse
|
|
|
|
|
|
def _fake_caller(response_text: str):
|
|
"""Build a mock caller that returns a fixed response."""
|
|
def caller(request: ModelRequest) -> ModelResponse:
|
|
return ModelResponse(
|
|
content=response_text,
|
|
model="mock-claude",
|
|
stop_reason="end_turn",
|
|
input_tokens=10,
|
|
output_tokens=20,
|
|
)
|
|
return caller
|
|
|
|
|
|
# ============================================================
|
|
# Basic flow
|
|
# ============================================================
|
|
|
|
def test_consult_external_model_returns_full_consultation():
|
|
"""A consultation captures request, raw response, processed korban,
|
|
and routing — the full chain is auditable."""
|
|
fake_response = (
|
|
"Bereishit 1:1 begins with the root bara. The shoresh ב-ר-א means "
|
|
"to create from nothing. This is foundational."
|
|
)
|
|
result = consult_external_model(
|
|
query="Explain bereishit 1:1",
|
|
source_query="user_courtyard_request_42",
|
|
caller=_fake_caller(fake_response),
|
|
)
|
|
|
|
assert isinstance(result, ExternalConsultation)
|
|
assert result.request.query == "Explain bereishit 1:1"
|
|
assert result.raw_response.content == fake_response
|
|
assert result.raw_response.model == "mock-claude"
|
|
assert result.processed.provenance is Provenance.CLAUDE
|
|
assert result.routing.destination == "talmudic_engine" # default OLAH
|
|
|
|
|
|
def test_raw_korban_is_preserved_on_processed_output():
|
|
"""Eish zarah Form 3 (gilui arayot — severed coupling): the raw
|
|
korban must be preserved on the processed output. The floor between
|
|
input and output is never severed."""
|
|
result = consult_external_model(
|
|
query="any",
|
|
source_query="trigger_query",
|
|
caller=_fake_caller(
|
|
"The root k-d-sh appears in Vayikra. Holiness is separation."
|
|
),
|
|
)
|
|
|
|
raw = result.processed.raw_korban
|
|
assert raw is not None, (
|
|
"raw_korban must be preserved on ProcessedKorban — "
|
|
"severing input from output is gilui arayot"
|
|
)
|
|
assert raw.source_query == "trigger_query"
|
|
assert raw.provenance is Provenance.CLAUDE
|
|
|
|
|
|
def test_provenance_is_recorded_on_korban():
|
|
"""Eish zarah Form 1 (avodah zarah — external as Torah): provenance
|
|
is never concealed. Every external response is tagged with its source."""
|
|
result = consult_external_model(
|
|
query="any",
|
|
source_query="any",
|
|
provenance=Provenance.CLAUDE,
|
|
caller=_fake_caller("test response with bereishit reference"),
|
|
)
|
|
assert result.processed.provenance is Provenance.CLAUDE
|
|
assert result.processed.raw_korban.provenance is Provenance.CLAUDE
|
|
|
|
|
|
# ============================================================
|
|
# Offering type → routing destination
|
|
# ============================================================
|
|
|
|
@pytest.mark.parametrize("offering_type,destination", [
|
|
(OfferingType.OLAH, "talmudic_engine"),
|
|
(OfferingType.SHELAMIM, "talmudic_engine"),
|
|
(OfferingType.MINCHAH, "talmudic_engine"),
|
|
(OfferingType.CHATAT, "error_correction"),
|
|
])
|
|
def test_offering_type_drives_routing(offering_type, destination):
|
|
"""Each offering type routes to its specified destination."""
|
|
result = consult_external_model(
|
|
query="any",
|
|
source_query="any",
|
|
offering_type=offering_type,
|
|
caller=_fake_caller(
|
|
"The shoresh r-tz-h means will. Vayikra 1:3 uses lirtzono — "
|
|
"for his acceptance."
|
|
),
|
|
)
|
|
assert result.routing.destination == destination
|
|
|
|
|
|
# ============================================================
|
|
# Refusal to silently proxy unknown providers
|
|
# ============================================================
|
|
|
|
def test_unknown_provenance_without_caller_raises():
|
|
"""We don't silently route MISTRAL/GPT/etc through Claude. A caller
|
|
must be supplied explicitly. This prevents accidental misrouting and
|
|
keeps provenance honest."""
|
|
with pytest.raises(NotImplementedError) as excinfo:
|
|
consult_external_model(
|
|
query="any",
|
|
source_query="any",
|
|
provenance=Provenance.GPT,
|
|
)
|
|
assert "GPT" in str(excinfo.value).upper() or "gpt" in str(excinfo.value)
|
|
|
|
|
|
def test_explicit_caller_overrides_provider_check():
|
|
"""If the caller supplies a callable for a non-Claude provider, the flow
|
|
proceeds — they took responsibility for the wiring."""
|
|
result = consult_external_model(
|
|
query="any",
|
|
source_query="any",
|
|
provenance=Provenance.GPT,
|
|
caller=_fake_caller("test response with shoresh sh-l-m"),
|
|
)
|
|
assert result.processed.provenance is Provenance.GPT
|
|
|
|
|
|
# ============================================================
|
|
# System prompt is forwarded
|
|
# ============================================================
|
|
|
|
def test_system_prompt_is_forwarded():
|
|
"""A system prompt sent in becomes part of the request record."""
|
|
result = consult_external_model(
|
|
query="any",
|
|
source_query="any",
|
|
system_prompt="You are a Torah scholar. Cite verse references.",
|
|
caller=_fake_caller("Bereishit 1:1 is the opening verse."),
|
|
)
|
|
assert result.request.system_prompt == "You are a Torah scholar. Cite verse references."
|
|
|
|
|
|
# ============================================================
|
|
# Live API integration test — opt-in only
|
|
# ============================================================
|
|
|
|
@pytest.mark.skipif(
|
|
not os.environ.get("SHORASHIM_LIVE_API"),
|
|
reason="Set SHORASHIM_LIVE_API=1 to run a real API call against Anthropic",
|
|
)
|
|
def test_live_anthropic_call():
|
|
"""Real API call. Costs money. Run only when explicitly enabled."""
|
|
if not os.environ.get("ANTHROPIC_API_KEY"):
|
|
pytest.skip("ANTHROPIC_API_KEY not set")
|
|
|
|
result = consult_external_model(
|
|
query="What is the shoresh of bereishit?",
|
|
source_query="live_integration_test",
|
|
offering_type=OfferingType.OLAH,
|
|
)
|
|
|
|
assert result.raw_response.content
|
|
assert result.processed.raw_korban is not None
|
|
assert result.processed.provenance is Provenance.CLAUDE
|
|
assert result.raw_response.model.startswith("claude")
|