Files
bikoret/korban_processor/test/test_external_offering.py
T
Scott KarpandClaude Fable 5.1 c0d0555aed the name: Bikoret — code, contracts, images
Headers X-Bikoret-Key / -Rebuke / -Verdict / -Bedikah; the `bikoret`
object and the "— bikoret …" fringe on a gate reply; environment
variables BIKORET_*; the image user and paths (/home/bikoret,
/tmp/bikoret, /var/lib/bikoret/manna, /etc/bikoret/secrets,
/opt/bikoret/spec); the tmp-bikoret pod volume; local databases
bikoret_dev/_test. Kubernetes resource names, the shorashim_app role and
the domain are unchanged (Tamid §1.1, "the names that still carry the
old word"). Doorpost c963c4fe…. Elixir 604/0, L3 10/0, korban 295,
Prolog bedikah 44/44. Gitea repo renamed heaviness510/bikoret (old URL
redirects).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 22:13:36 +00:00

317 lines
12 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 BIKORET_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."
# ============================================================
# Empty-vital → Azazel disposal routing (commit 9, properties 1 + 6)
# ============================================================
# Property 1 at runtime: an empty-vital korban is routed to disposal,
# not silently dropped. The disposal record IS the permanent
# acknowledgment that the system received this input and could not
# metabolize it.
import json
import pathlib
import tempfile
from azazel_processor import AzazelRecord
def _empty_vital_response():
"""A model response that contains no extractable Torah content
(no Torah refs, no Hebrew, no insight markers, no roots).
zerikah will return empty vital for this."""
return "ok thanks. let me know if you want me to do anything else."
def test_empty_vital_korban_is_routed_to_azazel():
with tempfile.TemporaryDirectory(prefix="azazel-pending-") as d:
pending = pathlib.Path(d)
result = consult_external_model(
query="anything",
source_query="empty_vital_test_001",
caller=_fake_caller(_empty_vital_response()),
azazel_kohen_gadol="kohen-gadol-test",
azazel_shaliach_id="ish-itti-test",
azazel_pending_l3_dir=pending,
)
# The processed korban is empty (zerikah returned no vital)
assert result.processed.vital_content == ""
# The disposal_record field is now populated
assert result.disposal_record is not None
assert isinstance(result.disposal_record, AzazelRecord)
assert result.disposal_record.shaliach == "ish-itti-test"
assert result.disposal_record.authorized_by == "kohen-gadol-test"
assert result.disposal_record.triggering_call == (
"external_offering.consult_external_model"
)
# A pending-l3 file was dropped for AzazelIngest to pick up
files = list(pending.glob("*.json"))
assert len(files) == 1
body = json.loads(files[0].read_text())
assert body["case_ref"] == result.disposal_record.case_ref
assert body["routing"] == "eretz_gezerah"
assert body["shaliach"] == "ish-itti-test"
# The vidui is on the pending file (operator-internal channel)
assert body["vidui"]["confessor"] == "kohen-gadol-test"
assert body["vidui"]["chatot"] # non-empty
def test_processable_response_does_not_create_disposal_record():
"""The companion to the above: an offering with extractable Torah
content goes through the processing channel and the disposal_record
field stays None."""
with tempfile.TemporaryDirectory(prefix="azazel-pending-") as d:
result = consult_external_model(
query="explain bereishit 1:1",
source_query="processable_test_001",
caller=_fake_caller(
"Bereishit 1:1 — the shoresh ב-ר-א means to create. The verse "
"indicates beginnings."
),
azazel_pending_l3_dir=pathlib.Path(d),
)
assert result.disposal_record is None
assert result.processed.vital_content != ""
# No file was dropped — nothing for AzazelIngest to pick up
assert list(pathlib.Path(d).glob("*.json")) == []
def test_pending_l3_file_does_not_contain_payload():
"""Property 10 follow-through: the file the orchestrator drops
for the Elixir bridge contains the vidui (what was disposed) but
not the disposed thing itself. The model's actual response text
must not appear in the pending-l3 file."""
secret_phrase = "this-string-must-not-leak-to-the-pending-l3-file"
with tempfile.TemporaryDirectory(prefix="azazel-pending-") as d:
pending = pathlib.Path(d)
consult_external_model(
query="any",
source_query="leak_check_001",
caller=_fake_caller(secret_phrase), # response is just the secret
azazel_pending_l3_dir=pending,
)
files = list(pending.glob("*.json"))
assert len(files) == 1
body_text = files[0].read_text()
assert secret_phrase not in body_text
def test_case_ref_is_content_addressable():
"""Audit can verify the routing was for a specific input by
recomputing the case_ref. Property 7's audit-trail half — the
routing decision is owned and traceable."""
response = _empty_vital_response()
with tempfile.TemporaryDirectory(prefix="azazel-pending-") as d:
pending = pathlib.Path(d)
result1 = consult_external_model(
query="any",
source_query="audit_test_001",
caller=_fake_caller(response),
azazel_pending_l3_dir=pending,
)
# Same content + same source_query → same case_ref
with tempfile.TemporaryDirectory(prefix="azazel-pending-") as d:
pending = pathlib.Path(d)
result2 = consult_external_model(
query="different-query", # query is not in the case_ref
source_query="audit_test_001",
caller=_fake_caller(response),
azazel_pending_l3_dir=pending,
)
assert result1.disposal_record.case_ref == result2.disposal_record.case_ref
# ============================================================
# Live API integration test — opt-in only
# ============================================================
@pytest.mark.skipif(
not os.environ.get("BIKORET_LIVE_API"),
reason="Set BIKORET_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")