Files
bikoret/scripts/build_engine_verses.py
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

112 lines
4.4 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""build_engine_verses.py — the Talmudic Engine's verse facts, derived from L1.
Architecture §3.4: verse(Book, Chapter, Verse, HebrewRoots, Gloss) is "the
reasoning layer's view of the specification — not a replacement for L1".
Until 2026-10-19 that view was 32 hand-written verses, so any root the
engine knew lit the same handful and every reading cited the same list.
This script writes talmudic_engine/src/specification/l1_verses.pl from
l1/torah — every verse, its roots as the engine names them
(Hebrew shoresh → letter names, finals folded: ברא → bet_resh_aleph), the
consonantal text as the gloss — and records the SHA-256 of the L1 files it
read in the header, so the facts can be checked against the scroll.
scripts/build_engine_verses.py # write the facts
scripts/build_engine_verses.py --check # exit 1 if the facts do not match L1 as it stands
Devarim 4:2 — nothing added, nothing taken: the engine reads the scroll's
roots, not the builder's memory of them.
"""
import argparse, hashlib, json, os, sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
L1 = os.path.join(ROOT, "l1", "torah")
OUT = os.path.join(ROOT, "talmudic_engine", "src", "specification", "l1_verses.pl")
BOOKS = ["bereishit", "shemot", "vayikra", "bamidbar", "devarim"]
NAMES = {
"א": "aleph", "ב": "bet", "ג": "gimel", "ד": "dalet", "ה": "he", "ו": "vav", "ז": "zayin",
"ח": "chet", "ט": "tet", "י": "yod", "כ": "kaf", "ך": "kaf", "ל": "lamed", "מ": "mem", "ם": "mem",
"נ": "nun", "ן": "nun", "ס": "samekh", "ע": "ayin", "פ": "pe", "ף": "pe", "צ": "tsadi", "ץ": "tsadi",
"ק": "qof", "ר": "resh", "ש": "shin", "ת": "tav",
}
def root_atom(shoresh):
if not shoresh:
return None
names = [NAMES.get(c) for c in shoresh]
if not names or any(n is None for n in names):
return None
return "_".join(names)
def quote(s):
return "'" + s.replace("\\", "\\\\").replace("'", "\\'") + "'"
def verse_files():
out = []
for book in BOOKS:
bdir = os.path.join(L1, book)
for ch in sorted((d for d in os.listdir(bdir) if d.isdigit()), key=int):
cdir = os.path.join(bdir, ch)
for f in sorted((f for f in os.listdir(cdir) if f.endswith(".json") and f[:-5].isdigit()), key=lambda x: int(x[:-5])):
out.append((book, int(ch), int(f.split(".")[0]), os.path.join(cdir, f)))
return out
def build():
h = hashlib.sha256()
facts = []
nverses = nroots = 0
for book, ch, vs, path in verse_files():
data = open(path, "rb").read()
h.update(f"{book}/{ch}/{vs}\n".encode())
h.update(data)
d = json.loads(data)
roots = []
for w in d.get("words", []):
a = root_atom(w.get("shoresh"))
if a and a not in roots:
roots.append(a)
gloss = " ".join(w.get("consonants", "") for w in d.get("words", []) if w.get("consonants"))
facts.append(f"verse({book}, {ch}, {vs}, [{', '.join(roots)}], {quote(gloss)}).")
nverses += 1
nroots += len(roots)
header = f"""%% l1_verses.pl — GENERATED by scripts/build_engine_verses.py from l1/torah.
%% Do not edit: regenerate. verse(Book, Chapter, Verse, Roots, Gloss) for
%% every verse of L1; Roots are the engine's letter-name atoms derived from
%% each word's shoresh (finals folded), once per verse in word order; Gloss
%% is the consonantal text. Included by torah_text.pl.
%%
%% l1_sha256: {h.hexdigest()}
%% verses: {nverses} root_occurrences: {nroots}
"""
return header + "\n".join(facts) + "\n", h.hexdigest(), nverses
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--check", action="store_true")
a = ap.parse_args()
text, digest, n = build()
if a.check:
try:
current = open(OUT, encoding="utf-8").read()
except FileNotFoundError:
print(f"engine verses: {OUT} missing — run scripts/build_engine_verses.py", file=sys.stderr)
sys.exit(1)
if current != text:
print(f"engine verses: {OUT} does not match L1 (l1_sha256 now {digest[:12]}…) — regenerate", file=sys.stderr)
sys.exit(1)
print(f"engine verses: match L1 ({n} verses, l1_sha256 {digest[:12]}…)")
return
with open(OUT, "w", encoding="utf-8") as f:
f.write(text)
print(f"wrote {OUT}: {n} verses, l1_sha256 {digest[:12]}…")
if __name__ == "__main__":
main()