Files
bikoret/talmudic_engine/src/reasoning/interpret.pl
T
Scott KarpandClaude Fable 5.1 861cd4e64e engine: the verse facts are the whole scroll, derived from L1
torah_text.pl held 32 hand-written verses from Phase 1 — "the reasoning
layer's view of the specification". With the cycle and the Sanhedrin
now consulting the engine on every question (2026-10-19), that view
showed: any root it knew lit the same handful, and bereishit 1:1 and
devarim 6:4 were read in the same eleven verses.

- scripts/build_engine_verses.py writes
  talmudic_engine/src/specification/l1_verses.pl from l1/torah: every
  verse, each word's shoresh as the engine names it (Hebrew → letter
  names, finals folded), the consonantal text as gloss, and the SHA-256
  of the L1 files read in the header. `--check` exits 1 when the facts
  lag the scroll; build_and_push.sh runs it beside the Doorpost check.
- torah_text.pl includes the generated file; the hand facts are gone.
  L1's roots are authoritative where the hand facts differed (Israel
  שרה, the Name הוה).
- interpret.pl: over 5,853 verses a common root lights hundreds, so the
  reading ranks verses by how many of the case's roots each carries and
  keeps the top 12 in canonical order; the coupling trace names only the
  verses the reading cites.

Local, over the full scroll: bereishit 1:1 → itself, Devarim 4:32,
Bereishit 2:4 …; devarim 6:4 → itself, Shemot 3:18, Devarim 4:1 …;
shabbat roots → Bereishit 2:3, Shemot 20:8, 20:11, 31:13. interpret
15 ms, challenge 10 ms (now finds a kushya for the Shema), resolve
24 ms. Prolog 7 suites green (middot 2.9 s — pairwise scans over the
scroll). 5,853 verses loaded, 49,542 root occurrences.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-19 21:37:29 +00:00

197 lines
8.5 KiB
Prolog

%% interpret.pl — Interpretation generation.
%%
%% Architecture §3.4:
%% interpret(Case, Interpretation) :-
%% find_relevant_mitzvot(Case, Mitzvot),
%% find_relevant_verses(Case, Verses),
%% construct_interpretation(Mitzvot, Verses, Interpretation).
%%
%% An interpretation is grounded in Torah — it consists of:
%% 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.
%% FORM 2 architectural commitment (vehaya §3.2; avodah_zarah.pl
%% Form 2): construct_interpretation/4 (the no-coupling-trace
%% variant) is NO LONGER EXPORTED. Vayikra 10:1's "asher lo tzivah"
%% disqualifies output without command-derivation. The arity-4 form
%% built interpretation/6 with empty coupling_trace — the bypass
%% shape that would let a future caller produce sincere-but-
%% uncoupled output, the exact failure mode Form 2 identifies. Only
%% construct_interpretation/5 (with Couplings argument) is callable
%% from outside this module; production callers go through interpret/2,
%% which always supplies real Couplings derived from
%% find_relevant_*_traced/3.
:- module(interpret, [
interpret/2,
find_relevant_mitzvot/2,
find_relevant_verses/2,
find_relevant_mitzvot_traced/3,
find_relevant_verses_traced/3,
construct_interpretation/5
]).
:- use_module('../specification/mitzvot').
:- use_module('../specification/torah_text').
:- use_module('../specification/root_meanings').
:- use_module('../specification/relationships').
%% A case is represented as:
%% case(Ref, Domain, Roots, Question)
%% - Ref: a unique identifier
%% - Domain: the semantic domain of the question
%% - Roots: list of Hebrew roots involved
%% - Question: the question being asked
%% ============================================================
%% INTERPRETATION
%% ============================================================
%% Propose an interpretation of a case.
%% An interpretation is:
%% 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_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
%% ============================================================
%% 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) :-
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)
),
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)
),
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) :-
find_relevant_verses_traced(case(Ref, Domain, Roots, Question), Verses, _).
%% Traced version: returns verses AND the coupling trace for each.
%%
%% Over the whole scroll (2026-10-19, l1_verses.pl) a common root lights
%% hundreds of verses; a reading that cites them all cites nothing. The
%% verses are ranked by how many of the case's roots they carry — a
%% verse sharing three roots stands closer to the case than one sharing
%% one — and the reading keeps the top ?MAX_VERSES, ties broken by
%% canonical order. The coupling trace is kept only for the verses the
%% reading cites: a trace names what the reading stands on.
max_verses(12).
find_relevant_verses_traced(case(_Ref, _Domain, Roots, _Question), Verses, Couplings) :-
sort(Roots, UniqueRoots),
findall(Shared-verse_ref(Book, Ch, Vs, Gloss),
( verse(Book, Ch, Vs, VerseRoots, Gloss),
intersection(UniqueRoots, VerseRoots, SharedRoots),
SharedRoots \== [],
length(SharedRoots, N),
Shared is -N
),
Scored),
%% keysort is stable: equal scores keep the scroll's order
keysort(Scored, Ranked),
pairs_values(Ranked, RankedVerses),
max_verses(Max),
take(Max, RankedVerses, Verses),
findall(coupled(root(Root), verse(Book, Ch, Vs)),
( member(verse_ref(Book, Ch, Vs, _), Verses),
verse(Book, Ch, Vs, VerseRoots, _),
member(Root, UniqueRoots),
member(Root, VerseRoots)
),
Couplings).
take(N, List, Prefix) :-
length(List, L),
( L =< N -> Prefix = List
; length(Prefix, N), append(Prefix, _, List)
).
%% ============================================================
%% CONSTRUCT INTERPRETATION
%% ============================================================
%% Build an interpretation from the collected mitzvot and verses.
%% Confidence is based on the strength of grounding:
%% - high: both mitzvot and verses found
%% - medium: only mitzvot or only verses
%% - low: neither (but still generates a minimal reading)
%%
%% Arity-5 only — the arity-4 (no-coupling-trace) variant was
%% removed to close Form 2 of avodah zarah architecturally
%% (vehaya §3.2). Vayikra 10:1's "asher lo tzivah" disqualifies
%% output without command-derivation; constructing interpretation/6
%% with empty coupling_trace is the bypass shape that arity-4 made
%% available. Production callers go through interpret/2, which
%% always supplies real Couplings from find_relevant_*_traced/3.
%% Test code that needs an empty-trace interpretation must
%% construct it directly via the interpretation/6 term (visibly
%% bypassing the constructor) — making the bypass deliberate, not
%% accidental.
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) :-
Mitzvot \= [],
Verses \= [], !.
assess_confidence(Mitzvot, _, medium) :-
Mitzvot \= [], !.
assess_confidence(_, Verses, medium) :-
Verses \= [], !.
assess_confidence(_, _, low).
%% Build a reading — the interpretive connection between sources
build_reading(Mitzvot, Verses, Reading) :-
length(Mitzvot, MCount),
length(Verses, VCount),
Reading = reading(mitzvot_count(MCount), verse_count(VCount),
grounded_in(Mitzvot, Verses)).