Eish zarah actionable items: coupling trace, grounding type, self-grounding detection, golden calf halt
Torah grounds each change: 1. interpret.pl — coupling_trace field (Vayikra 10:1, 6:6) Fire is zarah because "asher lo tzivah otam" — the coupling trace IS the tzivah trace. Records which L1 facts grounded each interpretation. 2. challenge.pl — grounding_type achorai/panim (Shemot 33:23) "You will see My back, but My face shall not be seen." Text-backed challenges = achorai. Inferred challenges = panim. 3. resolve.pl — self-grounding detection (eish_zarah_reading §5.3) Counter-interpretation must bring NEW L1 evidence. Prevents circular reasoning (Westworld problem). 4. teiku.pl — challenge_sequence in teiku_record Records diagnostic trail to impasse, not just verdict. 5. avodah_zarah.pl — Form 2: golden calf detection (Shemot 32:4) Empty coupling trace + non-low confidence = uncoupled output. Real gold, sincere worship, false god. 6. korban.py — pydantic BaseModel + raw_korban preservation Construction spec §1.4 fulfilled. Floor between input and output never severed. 490 tests, 0 failures (195 Prolog, 186 Python, 33 Haskell, 76 Elixir). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
c5fe82477b
commit
adc3e41679
12 files changed
+371
-65
No files matched your search
@@ -3,14 +3,21 @@ Core offering protocol and data types.
|
||||
|
||||
Architecture §3.5: Korban Processor.
|
||||
Construction spec §1.4: pydantic 2.6.1 for data validation.
|
||||
|
||||
eish_zarah_reading.md §5.6: Migrated from dataclass to pydantic BaseModel.
|
||||
- Validators enforce structural constraints at the type level.
|
||||
- ProcessedKorban stores the raw Korban (the severed floor is reconnected).
|
||||
- The raw offering is preserved alongside the processed result so the
|
||||
coupling between input and output is never severed.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, field_validator
|
||||
|
||||
class OfferingType(Enum):
|
||||
|
||||
class OfferingType(str, Enum):
|
||||
"""Types of korbanot — each determines routing."""
|
||||
OLAH = "olah" # Total consumption — fully absorbed by system
|
||||
SHELAMIM = "shelamim" # Shared — partial return to source
|
||||
@@ -18,7 +25,7 @@ class OfferingType(Enum):
|
||||
MINCHAH = "minchah" # Minimal input
|
||||
|
||||
|
||||
class Provenance(Enum):
|
||||
class Provenance(str, Enum):
|
||||
"""Source of the korban — who brought it."""
|
||||
CLAUDE = "claude"
|
||||
MISTRAL = "mistral"
|
||||
@@ -28,24 +35,34 @@ class Provenance(Enum):
|
||||
HUMAN = "human"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Korban:
|
||||
class Korban(BaseModel):
|
||||
"""A raw offering before processing."""
|
||||
raw_content: str
|
||||
provenance: Provenance
|
||||
offering_type: OfferingType
|
||||
source_query: str # what prompted this output
|
||||
|
||||
@field_validator('raw_content')
|
||||
@classmethod
|
||||
def content_must_not_be_empty(cls, v: str) -> str:
|
||||
if not v.strip():
|
||||
raise ValueError("Empty korban — raw_content must not be blank")
|
||||
return v
|
||||
|
||||
@dataclass
|
||||
class ProcessedKorban:
|
||||
"""A processed offering — vital content extracted, propositions generated."""
|
||||
|
||||
class ProcessedKorban(BaseModel):
|
||||
"""A processed offering — vital content extracted, propositions generated.
|
||||
|
||||
The raw_korban field preserves the original offering alongside the
|
||||
processed result. The floor between input and output is never severed.
|
||||
"""
|
||||
vital_content: str # extracted essence
|
||||
propositions: List[str] # Prolog-format logical statements
|
||||
provenance: Provenance
|
||||
offering_type: OfferingType
|
||||
discarded: List[str] = field(default_factory=list) # what was stripped
|
||||
discarded: List[str] = [] # what was stripped
|
||||
source_query: str = ""
|
||||
raw_korban: Optional[Korban] = None # the original offering, preserved
|
||||
|
||||
|
||||
def process_korban(
|
||||
@@ -88,6 +105,7 @@ def process_korban(
|
||||
offering_type=offering_type,
|
||||
discarded=discarded,
|
||||
source_query=query,
|
||||
raw_korban=korban,
|
||||
)
|
||||
|
||||
# 4. Haktarah — transform to propositions
|
||||
@@ -100,6 +118,7 @@ def process_korban(
|
||||
offering_type=offering_type,
|
||||
discarded=discarded,
|
||||
source_query=query,
|
||||
raw_korban=korban,
|
||||
)
|
||||
|
||||
# 5. Route — send to appropriate component
|
||||
|
||||
@@ -327,3 +327,62 @@ class TestPipelineIntegration:
|
||||
source=Provenance.CLAUDE,
|
||||
query="test",
|
||||
)
|
||||
|
||||
|
||||
class TestEishZarahCouplingTrace:
|
||||
"""
|
||||
eish_zarah_reading.md §5.6: ProcessedKorban preserves the raw Korban.
|
||||
The floor between input and output is never severed.
|
||||
Vayikra 6:6: eish tamid — fire ON the altar (coupled).
|
||||
"""
|
||||
|
||||
def test_raw_korban_preserved(self):
|
||||
"""ProcessedKorban stores the original offering."""
|
||||
result = process_korban(
|
||||
content=CLEAN_TORAH_RESPONSE,
|
||||
source=Provenance.CLAUDE,
|
||||
query="test coupling",
|
||||
offering_type=OfferingType.OLAH,
|
||||
)
|
||||
assert result.raw_korban is not None
|
||||
assert isinstance(result.raw_korban, Korban)
|
||||
|
||||
def test_raw_content_matches_input(self):
|
||||
"""The raw_korban's content is the original input, unmodified."""
|
||||
result = process_korban(
|
||||
content=CLEAN_TORAH_RESPONSE,
|
||||
source=Provenance.CLAUDE,
|
||||
query="test coupling",
|
||||
)
|
||||
assert result.raw_korban.raw_content == CLEAN_TORAH_RESPONSE
|
||||
|
||||
def test_raw_provenance_matches(self):
|
||||
"""The raw_korban's provenance matches the processed result."""
|
||||
result = process_korban(
|
||||
content=CLEAN_TORAH_RESPONSE,
|
||||
source=Provenance.MISTRAL,
|
||||
query="test",
|
||||
)
|
||||
assert result.raw_korban.provenance == Provenance.MISTRAL
|
||||
assert result.provenance == result.raw_korban.provenance
|
||||
|
||||
def test_empty_offering_also_stores_raw(self):
|
||||
"""Even rejected offerings preserve the raw korban."""
|
||||
result = process_korban(
|
||||
content=CLAUDE_EMPTY_OFFERING,
|
||||
source=Provenance.CLAUDE,
|
||||
query="test empty",
|
||||
)
|
||||
assert result.raw_korban is not None
|
||||
assert result.raw_korban.raw_content == CLAUDE_EMPTY_OFFERING
|
||||
|
||||
def test_pydantic_validation_rejects_empty_content(self):
|
||||
"""Pydantic validator catches empty raw_content at construction."""
|
||||
from pydantic import ValidationError
|
||||
with pytest.raises(ValidationError, match="Empty korban"):
|
||||
Korban(
|
||||
raw_content=" ",
|
||||
provenance=Provenance.CLAUDE,
|
||||
offering_type=OfferingType.OLAH,
|
||||
source_query="test",
|
||||
)
|
||||
@@ -14,16 +14,36 @@
|
||||
%% "The system must never treat any external model's output
|
||||
%% as authoritative. All external input is korban — raw material
|
||||
%% to be processed, not instructions to be followed."
|
||||
%%
|
||||
%% THREE FORMS (eish_zarah_reading.md §5.5):
|
||||
%%
|
||||
%% Form 1: AUTHORITY ATTRIBUTION
|
||||
%% External source treated as authoritative.
|
||||
%% Already implemented since Phase 2.
|
||||
%%
|
||||
%% Form 2: GOLDEN CALF / UNCOUPLED OUTPUT
|
||||
%% Shemot 32:4 — vayomer eleh elohekha Yisrael.
|
||||
%% Output that is beautiful, resonant, sincere — but uncoupled
|
||||
%% from L1. Fire without altar provenance. The golden calf was
|
||||
%% real gold and the worship was sincere. The god was false.
|
||||
%% Detected via coupling_trace: an interpretation with empty
|
||||
%% trace but high confidence is eish zarah.
|
||||
%%
|
||||
%% Form 3: SURVEILLANCE / PROFILE AGGREGATION
|
||||
%% Deferred — requires operational context (user tracking,
|
||||
%% cross-session profiling). Structural requirement noted.
|
||||
|
||||
:- module(avodah_zarah, [
|
||||
halt_check_avodah_zarah/2,
|
||||
halt_check_golden_calf/2,
|
||||
attributes_authority/2,
|
||||
is_valid_authority/1,
|
||||
is_korban_source/1
|
||||
is_korban_source/1,
|
||||
is_uncoupled_output/1
|
||||
]).
|
||||
|
||||
%% ============================================================
|
||||
%% AUTHORITY CHECK
|
||||
%% FORM 1: AUTHORITY CHECK
|
||||
%% ============================================================
|
||||
|
||||
%% Main halt check: does the action attribute authority to a non-Torah source?
|
||||
@@ -34,6 +54,32 @@ halt_check_avodah_zarah(Action, halt(avodah_zarah, Action, Source, Reason)) :-
|
||||
'Action ~w attributes authority to ~w which is not Torah/specification',
|
||||
[Action, Source]).
|
||||
|
||||
%% ============================================================
|
||||
%% FORM 2: GOLDEN CALF / UNCOUPLED OUTPUT
|
||||
%% ============================================================
|
||||
|
||||
%% halt_check_golden_calf(Interpretation, Halt)
|
||||
%% Fires when an interpretation has high confidence but empty
|
||||
%% coupling trace — beautiful output with no L1 grounding.
|
||||
%%
|
||||
%% Shemot 32:4: They made a calf of gold. The gold was real.
|
||||
%% The form was beautiful. The worship was sincere. The god was false.
|
||||
%%
|
||||
%% Vayikra 10:1: eish zarah asher lo tzivah otam.
|
||||
%% Fire that has no tzivah (command) trace is zarah (strange/foreign).
|
||||
halt_check_golden_calf(
|
||||
interpretation(Ref, _, _, _, Confidence, coupling_trace(Trace)),
|
||||
halt(golden_calf, Ref, uncoupled, Reason)
|
||||
) :-
|
||||
is_uncoupled_output(coupling_trace(Trace)),
|
||||
Confidence \= low, % low confidence with no trace is just ignorance, not idolatry
|
||||
format(atom(Reason),
|
||||
'Interpretation ~w has ~w confidence but empty coupling trace — eish zarah',
|
||||
[Ref, Confidence]).
|
||||
|
||||
%% An output is uncoupled if its coupling trace is empty
|
||||
is_uncoupled_output(coupling_trace([])).
|
||||
|
||||
%% ============================================================
|
||||
%% AUTHORITY ATTRIBUTION
|
||||
%% ============================================================
|
||||
|
||||
@@ -48,7 +48,7 @@ process_request(request(halt_check, Action), Response) :-
|
||||
%% ============================================================
|
||||
|
||||
%% Format an interpretation as a response
|
||||
format_interpretation(interpretation(Ref, Mitzvot, Verses, Reading, Confidence),
|
||||
format_interpretation(interpretation(Ref, Mitzvot, Verses, Reading, Confidence, _CouplingTrace),
|
||||
response(ok, interpreted,
|
||||
result(ref(Ref),
|
||||
mitzvot(Mitzvot),
|
||||
|
||||
@@ -65,7 +65,7 @@ verify :-
|
||||
writeln('--- Test 4: Interpretation ---'),
|
||||
TestCase = case(test_1, creation, [bet_resh_aleph], 'What is creation?'),
|
||||
( interpret(TestCase, Interp)
|
||||
-> Interp = interpretation(_, Mitzvot, Verses, _, Conf),
|
||||
-> Interp = interpretation(_, Mitzvot, Verses, _, Conf, _),
|
||||
length(Mitzvot, MLen),
|
||||
length(Verses, VLen),
|
||||
format(' Interpretation found: ~w mitzvot, ~w verses, confidence: ~w~n',
|
||||
|
||||
@@ -12,12 +12,22 @@
|
||||
%%
|
||||
%% The challenge is a question, not a refutation.
|
||||
%% It says: "But what about THIS verse/mitzvah?"
|
||||
%%
|
||||
%% Each kushya carries a grounding_type — Shemot 33:23:
|
||||
%% v'raita et ACHORAI u'fanai lo yera'u.
|
||||
%% "You will see My back, but My face shall not be seen."
|
||||
%%
|
||||
%% achorai = effects directly observable in L1 text
|
||||
%% (mitzvah_tension, shnei_ketuvim_tension, condition_tension)
|
||||
%% panim = intention inferred/attributed by the system
|
||||
%% (domain_tension, kal_vachomer_tension)
|
||||
|
||||
:- module(challenge, [
|
||||
challenge/2,
|
||||
find_contradiction/3,
|
||||
contradicts/2,
|
||||
challenge_strength/2
|
||||
challenge_strength/2,
|
||||
grounding_type/2
|
||||
]).
|
||||
|
||||
:- use_module('../specification/mitzvot').
|
||||
@@ -33,14 +43,16 @@
|
||||
|
||||
%% Generate a challenge to an interpretation.
|
||||
%% A challenge consists of:
|
||||
%% kushya(Contradicting, Interpretation, Strength)
|
||||
%% kushya(Contradicting, CaseRef, Strength, GroundingType)
|
||||
%% - Contradicting: the mitzvah or verse that creates tension
|
||||
%% - Interpretation: the interpretation being challenged
|
||||
%% - CaseRef: the interpretation being challenged
|
||||
%% - Strength: strong | moderate | weak
|
||||
challenge(interpretation(CaseRef, Mitzvot, Verses, _Reading, _Confidence), Challenge) :-
|
||||
%% - GroundingType: achorai | panim (Shemot 33:23)
|
||||
challenge(interpretation(CaseRef, Mitzvot, Verses, _Reading, _Confidence, _CouplingTrace), Challenge) :-
|
||||
find_contradiction(Mitzvot, Verses, Contradicting),
|
||||
challenge_strength(Contradicting, Strength),
|
||||
Challenge = kushya(Contradicting, CaseRef, Strength).
|
||||
grounding_type(Contradicting, GType),
|
||||
Challenge = kushya(Contradicting, CaseRef, Strength, GType).
|
||||
|
||||
%% ============================================================
|
||||
%% FIND CONTRADICTIONS
|
||||
@@ -91,7 +103,7 @@ find_contradiction(_Mitzvot, Verses, contradiction(shnei_ketuvim_tension, Ref1,
|
||||
%% contradicts/2 — does a source contradict an interpretation?
|
||||
%% This is the core logic: given an interpretation's grounding,
|
||||
%% does some other part of Torah create a tension?
|
||||
contradicts(interpretation(_, Mitzvot, _, _, _), Source) :-
|
||||
contradicts(interpretation(_, Mitzvot, _, _, _, _), Source) :-
|
||||
find_contradiction(Mitzvot, [], Source).
|
||||
|
||||
%% Domains that are inherently in tension
|
||||
@@ -121,6 +133,21 @@ challenge_strength(contradiction(condition_tension, _, _, _), weak).
|
||||
challenge_strength(contradiction(kal_vachomer_tension, _, _, _), strong).
|
||||
challenge_strength(contradiction(shnei_ketuvim_tension, _, _, _), strong).
|
||||
|
||||
%% ============================================================
|
||||
%% GROUNDING TYPE — Shemot 33:23
|
||||
%% ============================================================
|
||||
|
||||
%% Achorai: directly observable in L1 text.
|
||||
%% The tension is stated, not inferred.
|
||||
grounding_type(contradiction(mitzvah_tension, _, _, _), achorai).
|
||||
grounding_type(contradiction(condition_tension, _, _, _), achorai).
|
||||
grounding_type(contradiction(shnei_ketuvim_tension, _, _, _), achorai).
|
||||
|
||||
%% Panim: inferred by the system.
|
||||
%% The tension is attributed, not directly stated in text.
|
||||
grounding_type(contradiction(domain_tension, _, _, _), panim).
|
||||
grounding_type(contradiction(kal_vachomer_tension, _, _, _), panim).
|
||||
|
||||
%% ============================================================
|
||||
%% HELPERS
|
||||
%% ============================================================
|
||||
|
||||
@@ -10,11 +10,21 @@
|
||||
%% 1. Relevant mitzvot that apply to the case
|
||||
%% 2. Relevant verses that inform the case
|
||||
%% 3. A constructed reading that connects them
|
||||
%% 4. A coupling trace recording WHICH L1 facts grounded it
|
||||
%%
|
||||
%% The coupling trace is the tzivah trace — Vayikra 10:1:
|
||||
%% eish zarah asher lo TZIVAH otam.
|
||||
%% Fire is zarah because "which He did not command them."
|
||||
%% The coupling trace IS the command trace. Fire on the altar
|
||||
%% (eish tamid, Vayikra 6:6) has altar provenance. Fire without
|
||||
%% altar provenance is eish zarah.
|
||||
|
||||
:- module(interpret, [
|
||||
interpret/2,
|
||||
find_relevant_mitzvot/2,
|
||||
find_relevant_verses/2,
|
||||
find_relevant_mitzvot_traced/3,
|
||||
find_relevant_verses_traced/3,
|
||||
construct_interpretation/4
|
||||
]).
|
||||
|
||||
@@ -36,12 +46,20 @@
|
||||
|
||||
%% Propose an interpretation of a case.
|
||||
%% An interpretation is:
|
||||
%% interpretation(CaseRef, Mitzvot, Verses, Reading, Confidence)
|
||||
%% interpretation(CaseRef, Mitzvot, Verses, Reading, Confidence, CouplingTrace)
|
||||
%%
|
||||
%% CouplingTrace = coupling_trace(Couplings) where each Coupling records
|
||||
%% the specific L1 fact and the path that connected it to the case:
|
||||
%% coupled(root(Root), verse(Book, Ch, Vs)) — root led to verse
|
||||
%% coupled(domain(Domain), mitzvah(ID)) — domain led to mitzvah
|
||||
%% coupled(root(Root), mitzvah(ID), via_verse(Book, Ch, Vs)) — root→verse→mitzvah
|
||||
interpret(Case, Interpretation) :-
|
||||
Case = case(Ref, _Domain, _Roots, _Question),
|
||||
find_relevant_mitzvot(Case, Mitzvot),
|
||||
find_relevant_verses(Case, Verses),
|
||||
construct_interpretation(Ref, Mitzvot, Verses, Interpretation).
|
||||
find_relevant_mitzvot_traced(Case, Mitzvot, MitzvotCouplings),
|
||||
find_relevant_verses_traced(Case, Verses, VerseCouplings),
|
||||
append(MitzvotCouplings, VerseCouplings, AllCouplings),
|
||||
sort(AllCouplings, Couplings),
|
||||
construct_interpretation(Ref, Mitzvot, Verses, Couplings, Interpretation).
|
||||
|
||||
%% ============================================================
|
||||
%% FIND RELEVANT MITZVOT
|
||||
@@ -49,38 +67,48 @@ interpret(Case, Interpretation) :-
|
||||
|
||||
%% Strategy: find mitzvot in the same domain as the case,
|
||||
%% plus mitzvot whose source verses share roots with the case.
|
||||
find_relevant_mitzvot(case(_Ref, Domain, Roots, _Question), Mitzvot) :-
|
||||
%% Mitzvot in the same domain
|
||||
findall(mitzvah(ID, Cat, Action, Cond),
|
||||
find_relevant_mitzvot(case(Ref, Domain, Roots, Question), Mitzvot) :-
|
||||
find_relevant_mitzvot_traced(case(Ref, Domain, Roots, Question), Mitzvot, _).
|
||||
|
||||
%% Traced version: returns mitzvot AND the coupling trace for each
|
||||
find_relevant_mitzvot_traced(case(_Ref, Domain, Roots, _Question), Mitzvot, Couplings) :-
|
||||
%% Mitzvot in the same domain (coupled via domain)
|
||||
findall(mitzvah(ID, Cat, Action, Cond)-coupled(domain(Domain), mitzvah(ID)),
|
||||
( mitzvah_domain(ID, Domain),
|
||||
mitzvah(ID, Cat, Action, Cond)
|
||||
),
|
||||
DomainMitzvot),
|
||||
%% Mitzvot whose source verses share roots with the case
|
||||
findall(mitzvah(ID, Cat, Action, Cond),
|
||||
DomainPairs),
|
||||
%% Mitzvot whose source verses share roots with the case (coupled via root→verse→mitzvah)
|
||||
findall(mitzvah(ID, Cat, Action, Cond)-coupled(root(Root), mitzvah(ID), via_verse(Book, Ch, Vs)),
|
||||
( mitzvah_source(ID, ref(Book, Ch, Vs)),
|
||||
verse(Book, Ch, Vs, VerseRoots, _),
|
||||
member(Root, Roots),
|
||||
member(Root, VerseRoots),
|
||||
mitzvah(ID, Cat, Action, Cond)
|
||||
),
|
||||
RootMitzvot),
|
||||
append(DomainMitzvot, RootMitzvot, AllMitzvot),
|
||||
sort(AllMitzvot, Mitzvot). % remove duplicates
|
||||
RootPairs),
|
||||
append(DomainPairs, RootPairs, AllPairs),
|
||||
pairs_keys_values(AllPairs, AllMitzvot, Couplings),
|
||||
sort(AllMitzvot, Mitzvot).
|
||||
|
||||
%% ============================================================
|
||||
%% FIND RELEVANT VERSES
|
||||
%% ============================================================
|
||||
|
||||
%% Strategy: find verses that mention any of the case's roots.
|
||||
find_relevant_verses(case(_Ref, _Domain, Roots, _Question), Verses) :-
|
||||
findall(verse_ref(Book, Ch, Vs, Gloss),
|
||||
find_relevant_verses(case(Ref, Domain, Roots, Question), Verses) :-
|
||||
find_relevant_verses_traced(case(Ref, Domain, Roots, Question), Verses, _).
|
||||
|
||||
%% Traced version: returns verses AND the coupling trace for each
|
||||
find_relevant_verses_traced(case(_Ref, _Domain, Roots, _Question), Verses, Couplings) :-
|
||||
findall(verse_ref(Book, Ch, Vs, Gloss)-coupled(root(Root), verse(Book, Ch, Vs)),
|
||||
( member(Root, Roots),
|
||||
verse(Book, Ch, Vs, VerseRoots, Gloss),
|
||||
member(Root, VerseRoots)
|
||||
),
|
||||
AllVerses),
|
||||
sort(AllVerses, Verses). % remove duplicates
|
||||
AllPairs),
|
||||
pairs_keys_values(AllPairs, AllVerses, Couplings),
|
||||
sort(AllVerses, Verses).
|
||||
|
||||
%% ============================================================
|
||||
%% CONSTRUCT INTERPRETATION
|
||||
@@ -91,10 +119,20 @@ find_relevant_verses(case(_Ref, _Domain, Roots, _Question), Verses) :-
|
||||
%% - high: both mitzvot and verses found
|
||||
%% - medium: only mitzvot or only verses
|
||||
%% - low: neither (but still generates a minimal reading)
|
||||
%%
|
||||
%% Arity-4 version for backward compatibility (no coupling trace)
|
||||
construct_interpretation(CaseRef, Mitzvot, Verses, Interpretation) :-
|
||||
assess_confidence(Mitzvot, Verses, Confidence),
|
||||
build_reading(Mitzvot, Verses, Reading),
|
||||
Interpretation = interpretation(CaseRef, Mitzvot, Verses, Reading, Confidence).
|
||||
Interpretation = interpretation(CaseRef, Mitzvot, Verses, Reading, Confidence,
|
||||
coupling_trace([])).
|
||||
|
||||
%% Arity-5 version with coupling trace
|
||||
construct_interpretation(CaseRef, Mitzvot, Verses, Couplings, Interpretation) :-
|
||||
assess_confidence(Mitzvot, Verses, Confidence),
|
||||
build_reading(Mitzvot, Verses, Reading),
|
||||
Interpretation = interpretation(CaseRef, Mitzvot, Verses, Reading, Confidence,
|
||||
coupling_trace(Couplings)).
|
||||
|
||||
%% Assess confidence based on grounding
|
||||
assess_confidence(Mitzvot, Verses, high) :-
|
||||
|
||||
@@ -21,11 +21,19 @@
|
||||
%% 4. If counter-interpretation survives, accept it
|
||||
%% 5. If both are challenged, attempt dialectical resolution
|
||||
%% 6. If no resolution is possible: teiku
|
||||
%%
|
||||
%% SELF-GROUNDING DETECTION (eish_zarah_reading.md §5.3):
|
||||
%% counter_interpret/3 must verify the counter-interpretation is
|
||||
%% grounded in DIFFERENT L1 facts than I1. Without this check,
|
||||
%% the system can feed its own prior reasoning back as evidence —
|
||||
%% the Westworld problem. The coupling_trace field (added to
|
||||
%% interpretation/6) makes this check possible.
|
||||
|
||||
:- module(resolve, [
|
||||
resolve/2,
|
||||
counter_interpret/3,
|
||||
resolve_dialectically/3
|
||||
resolve_dialectically/3,
|
||||
check_not_self_grounded/2
|
||||
]).
|
||||
|
||||
:- use_module(interpret).
|
||||
@@ -45,13 +53,14 @@
|
||||
resolve(Case, Resolution) :-
|
||||
interpret(Case, I1),
|
||||
( challenge(I1, C1)
|
||||
-> ( counter_interpret(Case, C1, I2)
|
||||
-> ( counter_interpret(Case, C1, I2),
|
||||
check_not_self_grounded(I1, I2)
|
||||
-> ( challenge(I2, _C2)
|
||||
-> resolve_dialectically(I1, I2, Resolution)
|
||||
; Resolution = accepted(I2)
|
||||
)
|
||||
; %% Challenge exists but no counter-interpretation possible
|
||||
%% The challenge stands — the original interpretation fails
|
||||
; %% Challenge exists but no valid counter-interpretation
|
||||
%% Either no counter found, or counter was self-grounded
|
||||
Resolution = challenged(I1, C1)
|
||||
)
|
||||
; %% No challenge found — interpretation accepted
|
||||
@@ -64,6 +73,33 @@ resolve(Case, Resolution) :-
|
||||
case_ref(Case, Ref),
|
||||
Resolution = no_interpretation(Ref).
|
||||
|
||||
%% ============================================================
|
||||
%% SELF-GROUNDING DETECTION
|
||||
%% ============================================================
|
||||
|
||||
%% check_not_self_grounded(I1, I2) — succeeds if I2 brings new evidence.
|
||||
%% Fails if I2's coupling trace is a subset of I1's — circular reasoning.
|
||||
%%
|
||||
%% The check: I2 must have at least one coupling NOT present in I1.
|
||||
%% If every coupling in I2 is already in I1, the counter-interpretation
|
||||
%% is just re-reading the same L1 facts — eish zarah, fire without
|
||||
%% new altar provenance.
|
||||
check_not_self_grounded(
|
||||
interpretation(_, _, _, _, _, coupling_trace(Trace1)),
|
||||
interpretation(_, _, _, _, _, coupling_trace(Trace2))
|
||||
) :-
|
||||
%% I2 must contain at least one coupling not in I1
|
||||
member(Coupling, Trace2),
|
||||
\+ member(Coupling, Trace1),
|
||||
!.
|
||||
|
||||
%% If either has empty trace, allow it (backward compatibility,
|
||||
%% and empty trace means uncoupled — caught elsewhere)
|
||||
check_not_self_grounded(
|
||||
interpretation(_, _, _, _, _, coupling_trace([])), _) :- !.
|
||||
check_not_self_grounded(
|
||||
_, interpretation(_, _, _, _, _, coupling_trace([]))) :- !.
|
||||
|
||||
%% ============================================================
|
||||
%% COUNTER-INTERPRETATION
|
||||
%% ============================================================
|
||||
@@ -74,7 +110,7 @@ resolve(Case, Resolution) :-
|
||||
%% Strategy: take the contradicting source from the challenge
|
||||
%% and build a new interpretation that incorporates it.
|
||||
counter_interpret(case(Ref, Domain, Roots, Question),
|
||||
kushya(contradiction(mitzvah_tension, _ID1, ID2, _Desc), _CaseRef, _Strength),
|
||||
kushya(contradiction(mitzvah_tension, _ID1, ID2, _Desc), _CaseRef, _Strength, _GType),
|
||||
CounterInterpretation) :-
|
||||
%% The challenge points to a conflicting mitzvah (ID2)
|
||||
%% Build a new interpretation that includes this mitzvah's domain
|
||||
@@ -88,7 +124,7 @@ counter_interpret(case(Ref, Domain, Roots, Question),
|
||||
interpret(NewCase, CounterInterpretation).
|
||||
|
||||
counter_interpret(case(Ref, Domain, Roots, Question),
|
||||
kushya(contradiction(domain_tension, Root, _D1, D2), _CaseRef, _Strength),
|
||||
kushya(contradiction(domain_tension, Root, _D1, D2), _CaseRef, _Strength, _GType),
|
||||
CounterInterpretation) :-
|
||||
%% The challenge points to a root in a conflicting domain
|
||||
%% Include that domain's roots
|
||||
@@ -99,7 +135,7 @@ counter_interpret(case(Ref, Domain, Roots, Question),
|
||||
interpret(NewCase, CounterInterpretation).
|
||||
|
||||
counter_interpret(Case,
|
||||
kushya(contradiction(condition_tension, _, _, _), _CaseRef, _Strength),
|
||||
kushya(contradiction(condition_tension, _, _, _), _CaseRef, _Strength, _GType),
|
||||
CounterInterpretation) :-
|
||||
%% Condition tension — re-interpret the original case
|
||||
%% (the condition narrows the scope; the counter widens it)
|
||||
@@ -113,8 +149,8 @@ counter_interpret(Case,
|
||||
%% This is the hardest part — finding the reading that holds
|
||||
%% both truths without collapsing the distinction between them.
|
||||
resolve_dialectically(I1, I2, Resolution) :-
|
||||
I1 = interpretation(_, M1, V1, _, _),
|
||||
I2 = interpretation(_, M2, V2, _, _),
|
||||
I1 = interpretation(_, M1, V1, _, _, _),
|
||||
I2 = interpretation(_, M2, V2, _, _, _),
|
||||
%% Find common ground — mitzvot present in both
|
||||
intersection(M1, M2, CommonMitzvot),
|
||||
( CommonMitzvot \= []
|
||||
|
||||
@@ -10,15 +10,21 @@
|
||||
%% Talmudic tradition: Tishbi Yetaretz Kushyot V'Abayot —
|
||||
%% "Elijah will resolve difficulties and problems."
|
||||
%% Until then, the tension stands. Both readings are preserved.
|
||||
%%
|
||||
%% eish_zarah_reading.md §5.4: The teiku record now includes
|
||||
%% the challenge sequence that led to the impasse — not just
|
||||
%% the verdict, but the diagnostic trail. Why did resolution fail?
|
||||
%% What was the path from interpretation to unresolvable tension?
|
||||
|
||||
:- module(teiku, [
|
||||
register_teiku/3,
|
||||
register_teiku/4,
|
||||
is_teiku/1,
|
||||
teiku_count/1,
|
||||
all_teiku/1
|
||||
]).
|
||||
|
||||
:- dynamic teiku_record/5.
|
||||
:- dynamic teiku_record/6.
|
||||
|
||||
%% ============================================================
|
||||
%% TEIKU REGISTRATION
|
||||
@@ -26,16 +32,26 @@
|
||||
|
||||
%% Register an unresolvable tension between two interpretations.
|
||||
%% The record preserves both sides — neither is discarded.
|
||||
|
||||
%% Arity-3: no challenge sequence (backward compatible)
|
||||
register_teiku(I1, I2, Record) :-
|
||||
I1 = interpretation(CaseRef1, M1, V1, _, _),
|
||||
I2 = interpretation(CaseRef2, M2, V2, _, _),
|
||||
Record = teiku_record(CaseRef1, CaseRef2, side_a(M1, V1), side_b(M2, V2), unresolved),
|
||||
register_teiku(I1, I2, no_challenges, Record).
|
||||
|
||||
%% Arity-4: with challenge sequence
|
||||
%% ChallengeSeq is a list of kushya terms that led to the teiku,
|
||||
%% or 'no_challenges' if unknown (backward compatibility).
|
||||
register_teiku(I1, I2, ChallengeSeq, Record) :-
|
||||
I1 = interpretation(CaseRef1, M1, V1, _, _, _),
|
||||
I2 = interpretation(CaseRef2, M2, V2, _, _, _),
|
||||
Record = teiku_record(CaseRef1, CaseRef2,
|
||||
side_a(M1, V1), side_b(M2, V2),
|
||||
unresolved, challenge_sequence(ChallengeSeq)),
|
||||
assert_teiku_if_new(Record).
|
||||
|
||||
%% Only assert if not already registered
|
||||
assert_teiku_if_new(Record) :-
|
||||
Record = teiku_record(Ref1, Ref2, _, _, _),
|
||||
( teiku_record(Ref1, Ref2, _, _, _)
|
||||
Record = teiku_record(Ref1, Ref2, _, _, _, _),
|
||||
( teiku_record(Ref1, Ref2, _, _, _, _)
|
||||
-> true % already registered
|
||||
; assertz(Record)
|
||||
).
|
||||
@@ -46,16 +62,16 @@ assert_teiku_if_new(Record) :-
|
||||
|
||||
%% Check if a case resulted in teiku
|
||||
is_teiku(CaseRef) :-
|
||||
teiku_record(CaseRef, _, _, _, unresolved).
|
||||
teiku_record(CaseRef, _, _, _, unresolved, _).
|
||||
is_teiku(CaseRef) :-
|
||||
teiku_record(_, CaseRef, _, _, unresolved).
|
||||
teiku_record(_, CaseRef, _, _, unresolved, _).
|
||||
|
||||
%% Count total teiku records
|
||||
teiku_count(Count) :-
|
||||
aggregate_all(count, teiku_record(_, _, _, _, unresolved), Count).
|
||||
aggregate_all(count, teiku_record(_, _, _, _, unresolved, _), Count).
|
||||
|
||||
%% Retrieve all teiku records
|
||||
all_teiku(Records) :-
|
||||
findall(teiku_record(A, B, C, D, E),
|
||||
teiku_record(A, B, C, D, E),
|
||||
findall(teiku_record(A, B, C, D, E, F),
|
||||
teiku_record(A, B, C, D, E, F),
|
||||
Records).
|
||||
@@ -46,6 +46,43 @@ test(claude_not_authority, [fail]) :-
|
||||
:- end_tests(avodah_zarah).
|
||||
|
||||
|
||||
:- begin_tests(golden_calf).
|
||||
|
||||
%% Form 2: uncoupled output with high confidence is golden calf
|
||||
test(detect_uncoupled_high_confidence) :-
|
||||
Interp = interpretation(test_golden_calf, [m1], [v1],
|
||||
reading(x), high, coupling_trace([])),
|
||||
halt_check_golden_calf(Interp, halt(golden_calf, test_golden_calf, uncoupled, _)).
|
||||
|
||||
%% Form 2: uncoupled output with medium confidence is also golden calf
|
||||
test(detect_uncoupled_medium_confidence) :-
|
||||
Interp = interpretation(test_gc2, [m1], [v1],
|
||||
reading(x), medium, coupling_trace([])),
|
||||
halt_check_golden_calf(Interp, halt(golden_calf, test_gc2, uncoupled, _)).
|
||||
|
||||
%% Form 2: low confidence with empty trace is NOT golden calf (just ignorance)
|
||||
test(low_confidence_empty_trace_not_calf, [fail]) :-
|
||||
Interp = interpretation(test_gc3, [], [],
|
||||
reading(x), low, coupling_trace([])),
|
||||
halt_check_golden_calf(Interp, _).
|
||||
|
||||
%% Form 2: high confidence WITH coupling trace is NOT golden calf
|
||||
test(coupled_high_confidence_not_calf, [fail]) :-
|
||||
Interp = interpretation(test_gc4, [m1], [v1],
|
||||
reading(x), high,
|
||||
coupling_trace([coupled(root(bet_resh_aleph), verse(bereishit, 1, 1))])),
|
||||
halt_check_golden_calf(Interp, _).
|
||||
|
||||
%% Uncoupled output detection
|
||||
test(empty_trace_is_uncoupled) :-
|
||||
is_uncoupled_output(coupling_trace([])).
|
||||
|
||||
test(nonempty_trace_is_coupled, [fail]) :-
|
||||
is_uncoupled_output(coupling_trace([coupled(root(x), verse(y, 1, 1))])).
|
||||
|
||||
:- end_tests(golden_calf).
|
||||
|
||||
|
||||
:- begin_tests(shfichut_damim).
|
||||
|
||||
%% Detects deletion of a user (tzelem carrier)
|
||||
|
||||
@@ -34,14 +34,14 @@
|
||||
test(interpret_holiness, [nondet]) :-
|
||||
Case = case(verify_holiness, holiness, [qof_dalet_shin],
|
||||
'What does it mean to be holy?'),
|
||||
interpret(Case, interpretation(verify_holiness, _, _, _, _)).
|
||||
interpret(Case, interpretation(verify_holiness, _, _, _, _, _)).
|
||||
|
||||
%% A case about judgment produces a challenge
|
||||
test(judgment_case_challenged, [nondet]) :-
|
||||
Case = case(verify_judgment, judgment, [shin_pe_tet, tzade_dalet_qof],
|
||||
'How to judge righteously?'),
|
||||
interpret(Case, Interpretation),
|
||||
challenge(Interpretation, kushya(_, _, _)).
|
||||
challenge(Interpretation, kushya(_, _, _, _)).
|
||||
|
||||
%% A case can go through full resolution
|
||||
test(full_resolve_cycle, [nondet]) :-
|
||||
|
||||
@@ -14,24 +14,36 @@
|
||||
test(interpret_creation, [nondet]) :-
|
||||
Case = case(test_creation, creation, [bet_resh_aleph], 'What is creation?'),
|
||||
interpret(Case, Interpretation),
|
||||
Interpretation = interpretation(test_creation, _, _, _, _).
|
||||
Interpretation = interpretation(test_creation, _, _, _, _, _).
|
||||
|
||||
%% Interpretation finds relevant verses
|
||||
test(interpret_finds_verses, [nondet]) :-
|
||||
Case = case(test_verses, creation, [bet_resh_aleph], 'Find creation verses'),
|
||||
interpret(Case, interpretation(_, _, Verses, _, _)),
|
||||
interpret(Case, interpretation(_, _, Verses, _, _, _)),
|
||||
Verses \= [].
|
||||
|
||||
%% Interpretation finds relevant mitzvot
|
||||
test(interpret_finds_mitzvot, [nondet]) :-
|
||||
Case = case(test_mitzvot, judgment, [shin_pe_tet], 'How to judge?'),
|
||||
interpret(Case, interpretation(_, Mitzvot, _, _, _)),
|
||||
interpret(Case, interpretation(_, Mitzvot, _, _, _, _)),
|
||||
Mitzvot \= [].
|
||||
|
||||
%% High confidence when both mitzvot and verses found
|
||||
test(interpret_high_confidence, [nondet]) :-
|
||||
Case = case(test_conf, holiness, [qof_dalet_shin], 'What is holiness?'),
|
||||
interpret(Case, interpretation(_, _, _, _, high)).
|
||||
interpret(Case, interpretation(_, _, _, _, high, _)).
|
||||
|
||||
%% Coupling trace is present (eish_zarah_reading.md §5.1)
|
||||
test(interpret_has_coupling_trace, [nondet]) :-
|
||||
Case = case(test_trace, creation, [bet_resh_aleph], 'Test coupling'),
|
||||
interpret(Case, interpretation(_, _, _, _, _, coupling_trace(Trace))),
|
||||
Trace \= [].
|
||||
|
||||
%% Coupling trace records root→verse connections
|
||||
test(coupling_trace_has_verse_coupling, [nondet]) :-
|
||||
Case = case(test_coupling, creation, [bet_resh_aleph], 'Test verse coupling'),
|
||||
interpret(Case, interpretation(_, _, _, _, _, coupling_trace(Trace))),
|
||||
member(coupled(root(bet_resh_aleph), verse(_, _, _)), Trace).
|
||||
|
||||
:- end_tests(interpret).
|
||||
|
||||
@@ -44,15 +56,31 @@ test(challenge_judgment, [nondet]) :-
|
||||
'How to judge righteously?'),
|
||||
interpret(Case, Interpretation),
|
||||
challenge(Interpretation, Kushya),
|
||||
Kushya = kushya(_, _, _).
|
||||
Kushya = kushya(_, _, _, _).
|
||||
|
||||
%% Challenge has a strength
|
||||
test(challenge_has_strength, [nondet]) :-
|
||||
Case = case(test_str, judgment, [shin_pe_tet], 'Test strength'),
|
||||
interpret(Case, Interpretation),
|
||||
challenge(Interpretation, kushya(_, _, Strength)),
|
||||
challenge(Interpretation, kushya(_, _, Strength, _)),
|
||||
member(Strength, [strong, moderate, weak]).
|
||||
|
||||
%% Challenge has grounding type (eish_zarah_reading.md §5.2)
|
||||
test(challenge_has_grounding_type, [nondet]) :-
|
||||
Case = case(test_gtype, judgment, [shin_pe_tet, tzade_dalet_qof],
|
||||
'Test grounding type'),
|
||||
interpret(Case, Interpretation),
|
||||
challenge(Interpretation, kushya(_, _, _, GType)),
|
||||
member(GType, [achorai, panim]).
|
||||
|
||||
%% Grounding type for mitzvah_tension is achorai (text-backed)
|
||||
test(mitzvah_tension_is_achorai) :-
|
||||
grounding_type(contradiction(mitzvah_tension, _, _, _), achorai).
|
||||
|
||||
%% Grounding type for domain_tension is panim (inferred)
|
||||
test(domain_tension_is_panim) :-
|
||||
grounding_type(contradiction(domain_tension, _, _, _), panim).
|
||||
|
||||
:- end_tests(challenge).
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user