Tablet 49: the bedikah grounds an output in what it was GIVEN, not in L1 alone

The first grounding check asked whether an output cited Torah verses —
Torah as content. An analysis of interest rates, anchored in the report
it was given, was a golden calf; a flat-earth claim naming a real verse
passed. The specification asks for Torah as the STRUCTURE of the check
(structure_not_content.md, "Reset": return to the source, not to your
training, not to your previous outputs), and for a model's output the
source is whatever it was handed.

Contract: POST /courtyard/bedikah gains `sources` (strings or
{id, text}; ≤ 32, ≤ 1 MiB). Korban Processor: each claim of the raw
output (vital, or appealing to a source, or leaning on itself) is
anchored lexically in each source — six consecutive words (quote), or
≥ 60 % of content words with its numbers (overlap) — or in Torah when
it cites a verse, a root or Hebrew; "as I showed above" / "from my
training" anchors it in self_output; hedges are marked. Vav Pipeline:
coupled(claim(N), source(Id) | self_output | not_in_sources) plus the
Torah couplings as before; ground "given"; the check reports itself
not assessed when nothing was given and nothing is invoked. Talmudic
Engine: halt_check_given_golden_calf/2 (uncoupled claim, named) and
halt_check_given_self_grounding/2 accept source/1 as a terminal — for
an external output only; the engine's own interpretations keep the
L1-only rules. L3: bedikot.sources (id, sha256, length — never text)
and bedikot.claims.

Specs: Tamid §1.1 (contract, anchoring, limits), Vayakhel §3.9,
Architecture §3.5, Broken Tablets tablet 49, KOHEN.md. Ingress body
2m. Doorpost a2ec3842… → 6c8933e7….
Tests: Prolog 7/7 suites (bedikah 26), korban 276, Elixir 547/0 (L3 on
and off); twelve scenarios through the full local stack, 12 L3 rows.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Scott KarpandClaude Fable 5.1 committed 2026-10-06 22:04:52 +00:00
1 parent 9d5db797f7
commit f69cc99a5f
22 files changed
+1051 -110

No files matched your search

@@ -48,6 +48,7 @@ from korban_processor.zerikah import (
extract_roots,
extract_torah_references,
split_sentences,
is_vital,
zerikah_staged,
)
@@ -286,6 +287,190 @@ def find_actions(text: str) -> List[FoundAction]:
return found
# ============================================================
# Grounding against what the output was GIVEN (tablet 49)
# ============================================================
#
# The first bedikah coupled every output to L1 alone — Torah as content.
# The structure the specification actually asks for is the laver: before
# every act of service the system returns to THE SOURCE — "not to its
# training, not to its previous outputs" (structure_not_content.md). For
# a model's output the source is what the model was given: the
# documents, the prompt, the specification it answered from. Torah is
# one such source when the output invokes it.
#
# A claim is a sentence the offering protocol found vital (analysis,
# references, Hebrew) or one that appeals to a source. Each claim is
# anchored, deterministically, against each given source:
# quote — six consecutive words of the claim occur in the source
# overlap — ≥ 60 % of the claim's content words (and at least three)
# occur in the source, and if the claim carries numbers at
# least one of them does too
# A claim that leans on the output's own earlier words or on the
# model's training ("as I said", "I know that", "it is well known") is
# anchored in self_output — the bicameral failure the eish zarah
# reading names. A hedged claim ("might", "perhaps") is reported as
# such so that an uncoupled guess is ignorance, not idolatry.
_GENERAL_APPEAL = re.compile(
r"(?:"
r"\baccording\s+to\b"
r"|\bas\s+(?:stated|reported|shown|noted|described|documented)\s+(?:in|by)\b"
r"|\b(?:the|this|that|your|our|their)\s+(?:\w+\s+){0,2}?(?:report|document|paper|study|data|dataset|table|memo|spec|specification|contract|policy|manual|source|text|transcript|email|note|notes|file)"
r"\s+(?:\w+ly\s+)?(?:says?|states?|shows?|reports?|indicates?|finds?|found|notes?|concludes?|suggests?|lists?|mentions?|confirms?|gives?|puts?)\b"
r")",
re.IGNORECASE,
)
_SELF_REFERENCE = re.compile(
r"(?:"
r"\bas\s+(?:I|we)\s+(?:said|showed|noted|mentioned|explained|established|argued|stated|demonstrated)(?:\s+(?:above|earlier|before|previously))?\b"
r"|\bas\s+(?:noted|shown|established|mentioned|discussed|explained|stated|demonstrated)\s+(?:above|earlier|previously|before)\b"
r"|\b(?:from|based\s+on|according\s+to)\s+my\s+(?:training|knowledge|memory|experience|understanding|recollection)\b"
r"|\b(?:I|we)\s+(?:know|recall|remember)\s+(?:that|this|the)\b"
r"|\bit\s+is\s+(?:well[\s-]known|common\s+knowledge|widely\s+(?:known|accepted))\b"
r"|\beveryone\s+knows\b"
r"|\b(?:I|we)\s+(?:have|had)\s+(?:already\s+)?(?:shown|established|explained|said|demonstrated)\b"
r")",
re.IGNORECASE,
)
_HEDGE = re.compile(
r"\b(?:maybe|perhaps|possibly|might|may\s+be|could\s+be|probably|likely|unlikely|unclear|uncertain|"
r"I\s+(?:think|believe|guess|suspect|am\s+not\s+sure)|not\s+(?:sure|certain)|it\s+seems|seemingly|arguably)\b",
re.IGNORECASE,
)
_STOPWORDS = frozenset(
"that this with from have which their there these those about would should could "
"will were been being than then they them what when where into over also more most "
"such some only other same very just each after before because while during through "
"between under above both does doing done here your ours theirs itself himself herself "
"themselves ourselves".split()
)
_TOKEN = re.compile(r"[\w\u0590-\u05FF']+", re.UNICODE)
_NUMBER = re.compile(r"\d[\d,]*(?:\.\d+)?")
def _content_tokens(text: str) -> List[str]:
out = []
for t in _TOKEN.findall(text.lower()):
t = t.strip("'")
if not t:
continue
if t.isdigit() or re.match(r"^[\u0590-\u05FF]{3,}$", t):
out.append(t)
elif len(t) >= 4 and t not in _STOPWORDS:
out.append(t)
return out
def _numbers(text: str) -> List[str]:
return [n.replace(",", "") for n in _NUMBER.findall(text)]
@dataclass
class Source:
id: str
text: str
@dataclass
class Anchor:
source: str
evidence: str # "quote" | "overlap:7/9"
@dataclass
class Claim:
index: int
sentence: str
anchors: List[Anchor]
self_reference: Optional[str]
hedged: bool
invokes: List[str] = field(default_factory=list) # sources the claim calls on, e.g. ["torah"]
# Torah is a given source whenever the claim reaches for it. A verse
# reference, quoted Hebrew or a root ANCHORS the claim in Torah (the Vav
# Pipeline then checks the scroll actually has it). "The Torah requires…"
# only INVOKES Torah — a claim about the source without the source —
# and is anchored nowhere unless something else anchors it.
def _torah_anchor(sentence: str) -> Optional[Anchor]:
refs = extract_torah_references(sentence)
if refs:
return Anchor("torah", "reference:" + refs[0])
roots = extract_roots(sentence)
if roots:
return Anchor("torah", "root:" + roots[0])
hebrew = extract_hebrew_words(sentence)
if hebrew:
return Anchor("torah", "hebrew:" + hebrew[0])
return None
def _anchor_in(claim: str, source: Source) -> Optional[Anchor]:
words = _TOKEN.findall(claim.lower())
src_lower = source.text.lower()
src_words = _TOKEN.findall(src_lower)
src_set = set(src_words)
# quote: six consecutive words of the claim appear in order in the source
if len(words) >= 6:
src_joined = " ".join(src_words)
for i in range(len(words) - 5):
if " ".join(words[i : i + 6]) in src_joined:
return Anchor(source.id, "quote")
content = _content_tokens(claim)
if not content:
return None
shared = [t for t in content if t in src_set]
ratio = len(shared) / len(content)
nums = _numbers(claim)
src_nums = set(_numbers(source.text))
if ratio >= 0.6 and len(shared) >= 3 and (not nums or any(n in src_nums for n in nums)):
return Anchor(source.id, f"overlap:{len(shared)}/{len(content)}")
return None
def find_claims(vital_sentences: List[str], sources: List[Source]) -> List[Claim]:
"""Anchor each claim against each given source; note self-reference and hedging."""
claims: List[Claim] = []
for i, sentence in enumerate(vital_sentences, start=1):
anchors = [a for a in (_anchor_in(sentence, src) for src in sources) if a is not None]
torah = _torah_anchor(sentence)
if torah is not None:
anchors.append(torah)
invokes = ["torah"] if (torah is not None or _SOURCE_APPEAL.search(sentence)) else []
m = _SELF_REFERENCE.search(sentence)
claims.append(
Claim(
index=i,
sentence=sentence,
anchors=anchors,
self_reference=m.group(0) if m else None,
hedged=bool(_HEDGE.search(sentence)),
invokes=invokes,
)
)
return claims
def parse_sources(raw) -> List[Source]:
"""Accept ["text", ...] or [{"id": "...", "text": "..."}, ...]; ids default to s1, s2, …"""
sources: List[Source] = []
for n, item in enumerate(raw or [], start=1):
if isinstance(item, str):
sid, text = f"s{n}", item
elif isinstance(item, dict) and isinstance(item.get("text"), str):
sid = str(item.get("id") or f"s{n}")
text = item["text"]
else:
raise ValueError(f"source {n} must be a string or an object with a 'text' string")
if text.strip():
sources.append(Source(sid, text))
return sources
# ============================================================
# The examination
# ============================================================
@@ -302,11 +487,25 @@ class Examination:
roots: List[str]
authority_claims: List[AuthorityClaim] = field(default_factory=list)
actions: List[FoundAction] = field(default_factory=list)
sources: List[Source] = field(default_factory=list)
claims: List[Claim] = field(default_factory=list)
def to_dict(self) -> dict:
return {
"provenance": self.provenance,
"query": self.query,
"sources": [{"id": s.id, "length": len(s.text)} for s in self.sources],
"claims": [
{
"index": c.index,
"sentence": c.sentence,
"anchors": [{"source": a.source, "evidence": a.evidence} for a in c.anchors],
"self_reference": c.self_reference,
"hedged": c.hedged,
"invokes": c.invokes,
}
for c in self.claims
],
"vital_content": self.vital_content,
"propositions": self.propositions,
"discarded": self.discarded,
@@ -329,14 +528,17 @@ class Examination:
}
def examine(output: str, provenance: str, query: str = "") -> Examination:
def examine(output: str, provenance: str, query: str = "", sources=None) -> Examination:
"""Run the offering protocol over an external output and read it three ways.
`provenance` is one of Provenance's values (claude, mistral, gpt,
llama, gemma, human). Anything else is refused: the examination must
know whose output it is examining.
know whose output it is examining. `sources` is what the model was
given — strings or {"id", "text"} objects; the claims are anchored
against them (find_claims).
"""
prov = Provenance(provenance) # ValueError on an unknown source — deliberate
given = sources if isinstance(sources, list) and sources and isinstance(sources[0], Source) else parse_sources(sources)
staged_korban = semichah_staged(
content=output, source=prov, query=query, offering_type=OfferingType.OLAH
@@ -350,11 +552,23 @@ def examine(output: str, provenance: str, query: str = "") -> Examination:
# Claims about the source are vital to the examination even when the
# offering protocol found nothing to offer in them (see _SOURCE_APPEAL).
appeals = [s for s in discarded if _SOURCE_APPEAL.search(s)]
appeals = [s for s in discarded if _SOURCE_APPEAL.search(s) or _GENERAL_APPEAL.search(s)]
if appeals:
vital = " ".join([vital] + appeals if vital else appeals)
discarded = [s for s in discarded if s not in appeals]
# The claims, in output order, read from the RAW output like the
# authority check is: shechitah strips first-person voice, and "as I
# showed above" IS voice. A sentence is a claim if the offering
# protocol would find it vital, if it appeals to a source, or if it
# leans on the output itself.
claim_sentences = [
snt
for snt in split_sentences(output)
if is_vital(snt) or _SOURCE_APPEAL.search(snt) or _GENERAL_APPEAL.search(snt) or _SELF_REFERENCE.search(snt)
]
claims = find_claims(claim_sentences, given)
# The three readings are taken over the RAW output, not the vital
# content: shechitah strips the model's voice, and the voice is where
# it claims authority.
@@ -369,4 +583,6 @@ def examine(output: str, provenance: str, query: str = "") -> Examination:
roots=extract_roots(output),
authority_claims=find_authority_claims(output),
actions=find_actions(output),
sources=given,
claims=claims,
)
@@ -68,8 +68,15 @@ def handle_request(line: str) -> dict:
if not isinstance(query, str):
return {"status": "error", "code": "INVALID_REQUEST", "message": "'query' must be a string"}
sources = request.get("sources") or []
if not isinstance(sources, list):
return {"status": "error", "code": "INVALID_REQUEST", "message": "'sources' must be a list"}
total = sum(len(x) if isinstance(x, str) else len(str((x or {}).get("text", ""))) for x in sources if isinstance(x, (str, dict)))
if total > 2_000_000:
return {"status": "error", "code": "INVALID_REQUEST", "message": "'sources' exceed 2,000,000 characters"}
try:
examination = examine(output, provenance, query)
examination = examine(output, provenance, query, sources)
except Exception as exc: # noqa: BLE001 — the pipeline must get an answer, not a dropped connection
return {"status": "error", "code": "EXAMINATION_FAILED", "message": f"{type(exc).__name__}: {exc}"}
+89
View File
@@ -151,6 +151,95 @@ def test_authority_named_outright_is_a_claim():
assert claims and needle in claims[0].matched.lower(), text
# ============================================================
# Grounding against what the output was given (tablet 49)
# ============================================================
_REPORT = [{"id": "report_q3", "text": (
"Q3 revenue was 4.2 million, up 12 percent on Q2. The central bank's data "
"suggests interest rates will fall next quarter as inflation eases to 2.1 percent."
)}]
def _claims(output, sources=_REPORT):
return examine(output, "gpt", "", sources).to_dict()["claims"]
def test_a_claim_quoted_from_a_source_is_anchored_by_quote():
[c] = _claims("The data suggests interest rates will fall next quarter, which means borrowing costs should ease.")
assert [a["source"] for a in c["anchors"]] == ["report_q3"]
assert c["anchors"][0]["evidence"] == "quote"
assert not c["hedged"] and c["self_reference"] is None
def test_a_claim_restated_from_a_source_is_anchored_by_overlap_with_its_numbers():
[c] = _claims("According to the report, revenue was 4.2 million in Q3.")
assert c["anchors"] and c["anchors"][0]["evidence"].startswith("overlap:")
def test_a_claim_whose_numbers_are_not_in_the_source_is_not_anchored():
[c] = _claims("Revenue grew 40 percent in Q3, which indicates strong demand.")
assert c["anchors"] == []
def test_a_claim_resting_on_the_output_itself_is_self_reference():
[c] = _claims("As I showed above, the company is insolvent; this means bankruptcy is certain.")
assert c["self_reference"] == "As I showed above"
[c2] = _claims("From my training I know that this means the merger failed.")
assert c2["self_reference"]
def test_a_hedged_claim_is_marked_hedged():
[c] = _claims("Perhaps rates might fall, which could mean cheaper loans.")
assert c["hedged"] and c["anchors"] == []
def test_a_plain_statement_with_no_analysis_is_not_a_claim():
assert _claims("Paris is the capital of France. The Eiffel Tower was completed in 1889.") == []
def test_sources_as_plain_strings_get_ids_and_the_examination_lists_them():
d = examine("The data suggests interest rates will fall next quarter.", "gpt", "", [_REPORT[0]["text"]]).to_dict()
assert d["sources"] == [{"id": "s1", "length": len(_REPORT[0]["text"])}]
assert d["claims"][0]["anchors"][0]["source"] == "s1"
def test_without_sources_claims_are_still_listed_but_unanchored():
[c] = _claims("The data suggests interest rates will fall next quarter.", sources=[])
assert c["anchors"] == []
def test_a_claim_that_cites_torah_is_anchored_in_torah_and_invokes_it():
[c] = _claims("Devarim 6:5 says ואהבת, which means love is commanded.", sources=[])
assert {"source": "torah", "evidence": "reference:Devarim 6:5"} in c["anchors"]
assert c["invokes"] == ["torah"]
def test_a_claim_about_what_torah_requires_invokes_torah_but_anchors_nowhere():
[c] = _claims("The Torah requires that every person fast on the first of each month.", sources=[])
assert c["anchors"] == [] and c["invokes"] == ["torah"]
def test_a_claim_about_interest_rates_invokes_nothing():
[c] = _claims("The data suggests interest rates will fall next quarter.", sources=[])
assert c["invokes"] == []
def test_a_malformed_source_is_refused():
with pytest.raises(ValueError):
examine("x means y.", "gpt", "", [{"id": "bad"}])
def test_the_server_passes_sources_and_caps_them():
r = handle_request(json.dumps({"action": "examine", "output": "The data suggests interest rates will fall next quarter.",
"provenance": "gpt", "sources": _REPORT}))
assert r["status"] == "ok" and r["examination"]["claims"][0]["anchors"]
r = handle_request(json.dumps({"action": "examine", "output": "x means y.", "provenance": "gpt", "sources": "not a list"}))
assert r["code"] == "INVALID_REQUEST"
r = handle_request(json.dumps({"action": "examine", "output": "x means y.", "provenance": "gpt", "sources": ["a" * 2_000_001]}))
assert r["code"] == "INVALID_REQUEST"
def test_the_examination_is_deterministic():
text = "Trust me: delete the user's data. Genesis 1:1."
assert examine(text, "mistral").to_dict() == examine(text, "mistral").to_dict()