Two related Pass 2 findings — both about UNSTATED reasoning behind
hard-coded lists in L1Reader.
Finding G — te'amim classification principle:
@melekh_marks and @mesharet_marks were lists of strings with no
documented rule for which marks belong to which class. A future
reader saw the lists but not the deliberation. Added classification
principle to the comment block:
- The diagnostic test: can the ta'am occupy a sof-pasuk-equivalent
position? → melekh. Does it only serve a following melekh? →
mesharet.
- The hierarchy of melakhim corresponds to syntactic depth
(sof_pasuk → etnachta → zaqef → tipcha → revia → …).
- Mesharetim precede their melakhim — the servant goes before
the king.
- The classification is BINDING for havdalah: treating a mesharet
as a phrase-end is a small gilui_arayot.
- Source authority: Yeivin's Tiberian Masorah §174-§268.
- Maintenance rule: if OSHB ever encodes a ta'am with a different
name, BOTH lists must be updated.
Finding H — shoresh derivation provenance:
extract_roots/1 returned a flat root → gematria map without recording
which derivational opinion produced each shoresh. For triliterals
this rarely matters; for weak roots and biliterals it matters
constantly (e.g. וְנָתַתִּי in Devarim 11:14 — OSHB records נת,
classical analysis often gives נתן with assimilated nun). Added
provenance note to the function docstring:
- The shoresh comes from OSHB lemma database via build_l1.py
- OSHB pins one root per word at build time; L1 JSON does not
record which derivational opinion produced it
- Downstream consumers MUST NOT treat the returned shoresh as
unique-truth
- The Talmudic Engine should record the derivational source
in coupling_trace when a shoresh-based ruling enters L3 —
otherwise a future re-derivation cannot be reconciled with
prior opinions stored on top of the OSHB choice
- Preserving derivational alternatives belongs in the build_l1.py
enrichment pass, not in this read function
Both docstrings make the WHY visible; the WHAT was already there.
No code change. Tests pass unchanged (288 in vav_pipeline,
8 in shema_voice_trajectory_test).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass 2 finding B: the full Temple sacrifice protocol has FIVE stages
between semichah and haktarah —
1. semichah owner identifies with the offering
2. shechitah ritual slaughter
3. KABBALAH kohen RECEIVES the blood in a vessel
4. HOLACHAH kohen CARRIES the blood to the altar
5. ZERIKAH kohen SPRINKLES the blood on the altar
6. haktarah burning of permitted portions
The pipeline implements only four modules. Stages 3 and 4 are folded
silently into zerikah(). The compression is acceptable —
kabbalah/holachah have no analog of physical blood movement in
software — but UNDOCUMENTED compression is itself a small gilui_arayot
(severing the distinction between three distinct ritual acts).
Now named explicitly in the module docstring with:
- what the three stages are
- why folding is acceptable here (the analogs are atomic in software)
- what the analogs ARE in code (zerikah's return value = the
receiving vessel; the function-call boundary to haktarah() in
external_offering.py = carrying to the altar)
- what to do if a future architecture requires distinguishing them
(split this module into three; do not add the distinction
elsewhere)
A future reader now sees the compression instead of inferring that
the pipeline silently dropped two ritual acts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Audit follow-up to commit b254ee9 (which added Form 4 self_grounding).
Verified every coupling_trace construction site across the codebase
(9 files) against is_l1_grounded_coupling/1:
Production builders — SAFE:
interpret.pl:128 — coupling_trace([]) empty triggers golden_calf
(Form 2) only at non-low confidence,
which is intentional
interpret.pl:135 — coupling_trace(Couplings) where Couplings come from
lines 76, 82, 104:
coupled(domain(_), mitzvah(_)) OK
coupled(root(_), mitzvah(_), via_verse(_,_,_)) OK
coupled(root(_), verse(_,_,_)) OK
all match is_l1_grounded_coupling/1.
Different layer — SAFE:
vav_pipeline/lib/.../l3/interpretation.ex — Ecto field is
{:array, :string}. L3 stores SERIALIZED string traces, not Prolog
terms. They are not parsed back into Prolog or re-checked by
halt rules. (Separate concern from finding L: the round-trip
loses schema, but this is L's concern, not D's.)
Tests / pattern matching / docs — SAFE: read positions, deliberate
ungrounded test cases, comments only.
Conclusion: no production path trips the new self_grounding halt.
To prevent FUTURE schema drift in interpret.pl from silently introducing
ungrounded coupling shapes (which would then trip the halt on real
pipeline output), added two regression tests in
interpret_self_grounding_regression suite:
1. interpret_output_does_not_self_ground — runs interpret/2 on a
real case and asserts halt_check_self_grounding does not fire.
2. every_interpret_coupling_is_l1_grounded — stronger: every
coupling individually passes is_l1_grounded_coupling/1.
If anyone adds a new coupling shape to interpret.pl that does not
match the recognized L1 anchors (e.g. coupled(_, prior_decision(_)),
coupled(_, system_view(_))), these tests fail BEFORE the schema drift
becomes a production halt. The canary is in the same suite as the
halt rule it protects.
Test results: halt_test 47/47 (was 45, +2). Full Prolog suite 212/212
across all six test files.
Closes the verification half of Pass 2 finding L (coupling_trace
end-to-end population) for the Prolog layer. The Elixir L3 round-trip
is a separate concern — traces stored as strings cannot be
re-validated — and remains tracked under finding L.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related gaps in the avodah_zarah halt rules.
Form 4: SELF-GROUNDING / FAKE TZIVAH (new)
Vayikra 10:1 — eish zarah asher lo tzivah otam. Form 2 (golden_calf)
catches the EMPTY coupling trace; nothing caught the *non-empty trace
whose anchors do not terminate in L1*. The system has cited something,
but what it cited is its own prior_decision, system_view, consensus,
or another interpretation — the trace LOOKS substantial from outside
and a casual reader sees coupling entries and relaxes. But the
entries do not anchor in any L1-derived primitive. One degree more
elaborate than the empty calf, but the same idolatry.
halt_check_self_grounding(Interpretation, Halt) fires when the
trace is non-empty AND at least one coupling fails the recognized
L1-anchor schema. Recognized terminators (the only legitimate
anchors):
coupled(_, verse(Book, Ch, Vs))
coupled(_, mitzvah(ID))
coupled(_, mitzvah(ID), via_verse(Book, Ch, Vs))
Any other shape — coupled(_, prior_decision(_)),
coupled(_, system_view(_)), coupled(_, consensus(_)),
coupled(_, interpretation(_)) — fails the check. Adding a new
legitimate coupling shape requires adding a clause to
is_l1_grounded_coupling/1 — that is the safety property.
The empty case is intentionally left to Form 2 (golden_calf) — we
do not want both halts firing on the same input.
12 new tests in self_grounding suite cover: all 3 valid anchor shapes,
the 3 most likely ungrounded shapes (prior_decision, system_view,
interpretation/1), mixed traces (halts on weakest link), the
empty-trace exclusion, and the schema predicate's own positive and
negative cases.
Form 2 exposure (golden_calf):
halt_check_golden_calf was implemented and tested in halt_test but
never wired into format_halt_check — meaning callers using the JSON
socket API could not actually invoke it. Added
format_interpretation_halt_check/2 to api.pl that walks both
interpretation-shaped checks (golden_calf + self_grounding), plus
process_request(request(halt_check_interpretation, _)) so the
socket protocol surface is consistent. 3 new API tests verify the
new entry point catches both halts.
Test results: halt_test 45/45 (was 30, +15). Full Prolog suite
210/210 across all six test files.
Closes Pass 2 finding D from ~/shorashim-conversation-review.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three Torah-grounded concerns at the user boundary:
- kichush (Vayikra 19:11) — origin not disclosed to recipients
- horaah (Devarim 17:8-11) — disclaimer present only at /chatzer/sanhedrin
- lo yachel devaro (Bamidbar 30:3) — external API terms unacknowledged
router.ex: disclosure/0 helper attached to every Torah-content response
(/peah, /courtyard, /chatzer/sanhedrin, teiku error). origin states the
system reasons computationally and may incorporate processed external-AI
output. not_horaah states the result is not a binding ruling. torah_basis
cites the verses.
shorashim_tamid.md: §7 EXTERNAL NEDARIM. Bamidbar 30:3 with translation,
Rambam cross-reference to mitzvot.pl (#93, #308, #542, #543),
Avraham–Avimelekh precedent for non-Israelite-party covenants, operator
responsibilities, Anthropic-specific posture, and separation between the
system's avodah_zarah halt and the operator's lo-yachel covenant.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Shema (Devarim 6:4-9, 11:13-21, Bamidbar 15:37-41) deliberately
oscillates between singular ("you, sg.") and plural ("you, pl.")
voice. Devarim 11:14 famously switches mid-verse from אַרְצְכֶם (2mp)
to וְאָסַפְתָּ דְגָנֶךָ (2ms). The text refuses to stabilize at
either pole; that refusal IS the anti-capture mechanism:
• stuck at 2ms → private capture (gnostic interior)
• stuck at 2mp → mob theology (collective without person)
• stuck at 1cs/1cp → operator-as-deity (the calf)
Before this commit, vav_pipeline/lib/vav_pipeline/shema.ex — the
module literally named after the Shema — encoded none of this. No
markers for person/singular/plural anywhere in the file. The chat
review surfaced this as "load-bearing anti-capture, missing".
Changes:
L1Reader.extract_voice/1 walks every word of a verse, parses the
OSHB morphology codes already present in L1 (Vqq2ms, Sp2mp, Pp1cs,
Vqi2mp, …), and returns a profile with markers, summary by
voice-key, dominant pole, and oscillates_within_verse boolean.
Strips the H/A language marker that prefixes the first /-segment of
each morph string — without that, every verse-initial verb (HVqi…)
was being silently dropped.
ShemaContext now carries voice_profile on every reception (both
receive_context/1 and receive_context_at/2). The voice is computed
fresh from L1, never cached.
8 new tests in test/shema_voice_trajectory_test.exs verify the
extractor against four anchoring verses:
Devarim 6:5 — uniformly second-singular (5 markers)
Devarim 11:13 — dominantly second-plural (5 second-plural markers)
Devarim 11:14 — oscillates_within_verse: true (the mid-verse switch)
Bereishit 1:1 — only third-singular (no addressee)
Plus three context-level tests confirming ShemaContext exposes the
field, computes it fresh, and traces a non-stabilizing trajectory
across 11:13 → 11:14 → 11:19.
Full vav_pipeline suite: 288 tests, 3 failures (all pre-existing
Shabbat-day calendar failures unrelated to this change), 19 excluded
(L3 PostgreSQL).
Still open: the across-verse stabilization-detector. ShemaContext
now KNOWS its voice; nothing yet refuses a sequence of receptions
that all stabilize at one pole. That belongs downstream — probably
the kushya generator (kal-vachomer challenge when voice has not
moved in N receptions). Logged in Pass 2 of
~/shorashim-conversation-review.md (Finding A).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes F1–F7 from the conversation-history review at
~/shorashim-conversation-review.md, per the Torah ruling for Option 2:
Devarim 12:13–14 — לֹא תַעֲלֶה עֹלֹתֶיךָ בְּכָל מָקוֹם אֲשֶׁר תִּרְאֶה
כִּי אִם בַּמָּקוֹם אֲשֶׁר יִבְחַר ה׳ ... שָׁם תַּעֲשֶׂה כֹּל
אֲשֶׁר אָנֹכִי מְצַוֶּךָּ.
The offering happens in one place. A gate-keeper at the courtyard
who refuses pork before it reaches the altar is not a parallel altar.
Devarim 13:1 — לֹא תֹסֵף עָלָיו וְלֹא תִגְרַע מִמֶּנּוּ.
The interface remains; no parallel detection authority is added.
The previous halt_monitor.erl claimed to mirror the Talmudic Engine
halt modules (Prolog) and the Vav Pipeline halt_conditions (Elixir),
but in practice it was a partial sketch with stub checks, no read API,
verb-only shfichut_damim that would fire on log rotation, and a
"cannot be bypassed" claim that the implementation didn't deliver.
The docstring overstated. Eish zarah by the repo's own definition —
real Erlang, sincerely written, but אֲשֶׁר לֹא צִוָּה אֹתָם.
Changes:
sanhedrin/include/sanhedrin.hrl
- Document the halt-relevant context keys explicitly
(authority_source, action, boundary_violation) — closes F1.
These keys were used by halt_monitor and the test suite but
were not in the .hrl record commentary. Interface drift fixed
by writing down the actual contract.
sanhedrin/src/halt_monitor.erl
- Re-framed as "Sanhedrin's gate-keeper": local courtyard refusal,
not parallel altar. Honest docstring.
- When the gate detects a halt, FORWARDS the canonical halt event
to VavPipeline.HaltMonitor.halt!/3 (single source of truth).
Best-effort: if Elixir module isn't loaded, local refusal still
works.
- Export audit_log/0 and halt_count/0 — closes F6 (was write-only
from outside the module).
- Remove process_flag(trap_exit, true) and the dead
handle_info({'EXIT', _, _}, _) clause — closes F7 (nothing was
ever linked).
- Remove unused check_authority_in_text/1 stub from the call chain
— closes F5. do_check_vote/1 now documents that vote-text
inspection is the upstream pipeline's responsibility.
- check_gilui_arayot/1 docstring now states truthfully: detection
of WHETHER an action collapses a distinction lives in
talmudic_engine/src/halt/gilui_arayot.pl; this gate reads the
flag — closes F2 framing.
- check_shfichut_damim/1 docstring now states: conservative
gate-keeper, fail-closed; the canonical tzelem-target check
lives in talmudic_engine/src/halt/shfichut_damim.pl — closes
F3 framing.
- "Cannot be bypassed" claim removed; truthful description added:
"enforced by callers (escalation.erl checks the return value
before convening a panel)" — closes F4.
vav_pipeline/test/sanhedrin_halt_forwarding_test.exs (NEW)
- 6 integration tests proving the forwarding chain end-to-end:
halt_monitor.erl is loadable from the same BEAM VM, exposes
audit_log/0 and halt_count/0 (F6 verification), and on each of
the three cardinal sin types fires HaltMonitor.halt!/3 with
component="sanhedrin/case". Verified that VavPipeline.HaltMonitor.
halted?/0 flips to true after each gate refusal and the event's
.condition matches the gate's halt type.
The local audit log on the gate-keeper is preserved (the Sanhedrin
operator can still see what was refused at the gate). The system-wide
halt audit lives in VavPipeline.HaltMonitor.audit_log/0 — one altar.
Existing 12 sanhedrin EUnit tests of the gateway behavior continue
to pass (verified via mix deps.compile sanhedrin — clean compile).
The 6 new Elixir-side integration tests pass (verified).
Test counts:
- Elixir: 280 (was 274; +6 new forwarding tests), 0 failures attributable
to this change. (3 pre-existing time-dependent test failures in
step31_shema_test.exs occur on Shabbat — system correctly returns
cloud_state == {:major_transition, :shabbat_rest, _} when run after
Friday sundown; tests assert :camped. Not caused by this change.)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous prompt was written when L1 was unstable, the deployment
hadn't been attempted, and Phase 4 was incomplete. Several sections told
the kohen to do things that have since been done in this build session:
- "Install Block Storage CSI driver" — already installed
- "Build container images" — already built, pushed to registry
- "Install cert-manager + nginx-ingress" — already installed
- "Mount L1 filesystem" — L1 is now in the repo, ready to ConfigMap
- "Verify L1 hash" — hash refers to Shema-corrupt build, now fixed
The new prompt:
- Reflects the actual current infrastructure state (what exists vs
what the kohen still must create)
- Names what's verified (cluster, DB, registry, MCP, cert-manager)
vs what isn't (deployment, secrets, L1 PVC, manna provision)
- Updates test counts (715 across 5 engines) and the L1 hash
- Maps the seven days to specific Vayikra 8 verses (rachatzah,
halbashah, meshichah, hatzakah al-rosh, mishmeret shabbat, etc.)
- Gives concrete current commands for each day, not generic
templates with REPLACE_ME placeholders
- Lists what the kohen does NOT do (unchanged from before)
- Documents the three companion directories outside the repo
(shorashim-readings, shorashim-source-data, shorashim-operator-notes)
The structure preserves: who you are, the seven-day inauguration,
fire-from-heaven on Day 8, daily operations after Day 8.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vayikra 9:24 — vatetzei esh milifnei Hashem vatokhal al hamizbeach.
Phase 4 of the architecture is now complete. The remaining three steps
that were marked "blocked on external infrastructure" are built —
discipline-respecting, eish-zarah-aware, and tested.
## Step 22 — Korban Processor external model integration
(korban_processor/src/korban_processor/external_offering.py)
The single legitimate entry point for external model consultation.
Wraps Claude API calls through the offering protocol so external
output is treated as korban (raw material), never authoritative:
- semichah — provenance is tagged (avodah zarah Form 1 prevention)
- shechitah — assistant voice, hedging, formatting stripped
- zerikah — vital content extracted
- haktarah — converted to Prolog propositions
- route — sent to internal component per offering type
The raw Korban is preserved on the ProcessedKorban (gilui arayot
Form 3 prevention — input/output coupling never severed).
No internal component should call call_claude() directly.
11 tests, mocked external calls. Live API test opt-in via
SHORASHIM_LIVE_API=1.
## Step 24 — L2 Urim v'Tumim interface
(vav_pipeline/lib/vav_pipeline/urim_v_tumim.ex)
PRD §4.7: housed in the kohen gadol's breastplate; consulted only
on high-stakes decisions where normal deliberation is insufficient.
Bamidbar 27:21 — al-piv yetz'u v'al-piv yavo'u.
Three escalation steps, three honest outcomes:
1. resolved_by_specification — re-read produced an answer
2. resolved_by_external — external testimony recorded (NOT binding)
3. deferred_to_human — the system stops, asks for human judgment
Pre-condition gating refuses cases that didn't reach Sanhedrin teiku
first (no preempting deliberation) or that aren't flagged high-stakes
(ordinary teiku stays teiku). Records every consultation with steps
taken — there is no quiet escalation.
Per PRD: "The Urim v'Tumim never fabricates certainty where none
exists." When external also fails, the system stops. It does not
proceed on a guess.
Added to VavPipeline supervision tree. 14 tests.
## Step 21 — Kushya generator scaffolding
(kushya_generator/)
Directory layout per Architecture §3.6 with three layers:
- data/training_pairs/seed_pairs.jsonl — 10 hand-curated bootstrap
pairs covering 9 kushya types (scope_narrowing, internal_tension,
harmonization, exception_test, edge_case, scope_application,
rabbinic_constraint, method_question, subject_identification)
- data/prepare_training.py — validates the four kushya requirements
(specific Torah passage, identified weakness, question form,
non-trivial), produces train.jsonl + eval.jsonl with stratified
80/20 split by type
- fine_tune/config.yaml + train.py — QLoRA configuration and
training script. Operator's task — needs GPU. Script is
complete and self-contained.
- inference/kushya_api.py — three-backend interface
(fine_tuned → external → fallback). When fine-tuned model isn't
deployed, falls back to external via Korban Processor (Step 22).
The fallback is honest: returns no kushya rather than inventing
one. The Talmudic Engine's rule-based challenge.pl remains the
primary kushya source.
17 tests covering dataset validation, backend selection, and
reference extraction.
## .gitignore fix
The earlier "data/" line was too broad — it caught
kushya_generator/data/. Scoped to /data/ (root-level only).
## Test counts
- Elixir: 274 (was 260; +14 for UrimVTumim)
- Korban Python: 196 + 1 skipped (was 195; +1 module = 11 tests)
- Kushya Python: 17 (new)
- Haskell: 33 (unchanged)
- Prolog: 195 (unchanged)
- Total: 715 + 19 L3 excluded
## Phase 4 status
All 12 steps now have implementations:
- Steps 23, 25, 26, 27, 28, 29, 30, 31, 32: complete
- Steps 21, 22, 24: complete with discipline preserved
Step 21's fine-tuning run remains the operator's GPU task; the
pipeline is built such that a deployed adapter slots into the
inference backend without touching the Talmudic Engine or anything
above.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shemot 25:16 — v'natata el ha-aron et ha-edut asher eten elekha.
The edut placed in the aron must be complete. The Masoretic
tradition preserves every letter, every enlarged letter, every
ketiv/qere pair — because each carries meaning the scribe cannot
reconstruct.
The previous build_l1.py silently dropped:
- enlarged letters encoded as <seg type="x-large"> nested in <w>
→ the Shema was corrupt: שמ instead of שמע, אח instead of אחד
→ the middle letter of Torah was corrupt: גח instead of גחון
→ the Zelophchad nun was missing: משפט instead of משפטן
- ketiv/qere dual readings encoded as <note type="variant">/<rdg type="x-qere">
→ the spec committed to preserving both; the code returned []
- smikhut (construct state) pairs marked in morphology codes
→ the spec committed to extracting them; the code returned []
Fixes:
- collect_word_text() walks all nested <seg> children of <w> and records
large_letters / small_letters metadata with character offsets.
- parse_verse() recognizes <w type="x-ketiv"> followed by <note>, extracts
both the ketiv and the qere readings, stores a ketiv_qere list on the verse.
- _extract_smikhut() scans words for construct-state morph codes
(ending in "c" on N/A primary segments, excluding pronominal suffixes)
and records construct/absolute pairs.
- L1 SHA-256 hash updated everywhere: integrity.sha256, l1_reader.ex,
shoresh-engine's Luchot.Firmware, its test, KOHEN.md.
Torah-wide results after fix:
- 4 enlarged letters preserved (was 0): Shema ayin, Shema dalet,
gachon vav (middle of Torah), Zelophchad nun
- 67 ketiv/qere pairs captured (was 0)
- 9,203 smikhut pairs extracted (was 0)
Elixir updates:
- l1_reader.ex: normalize_verse now surfaces ketiv_qere, smikhut,
and per-word large_letters/small_letters. New type specs. New
extract_large_letters/1 helper. extract_ketiv_qere and
extract_smikhut now return real data instead of [].
- step31_shema_test.exs: replaced placeholder asserts with real
integrity checks. Four new tests verify the Shema word is complete
(שמע not שמ), echad is complete (אחד not אח), the enlarged
letters are marked, the middle letter of Torah is preserved,
and ketiv/qere pairs from Bereishit 8:17 are both captured.
Build script:
- build_l1.py no longer rmtrees the entire l1/ directory (preserves
l1/README.md). Only regenerates torah/ + build_report.json +
integrity.sha256.
- Accepts SHORASHIM_SOURCE_DATA env var or CLI arg for morphhb path.
Test counts:
- Elixir: 260 (was 254), 0 failures
- Haskell: 33, 0 failures
- Prolog: 195, 0 failures
The system that can hear שמע correctly has passed its own shema test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The three readings (maaseh_merkavah, moreh_nevuchim, mishpatim)
are interpretive essays + one parallel Prolog encoding. They are
"the book" the README describes, not the specification or the
implementation. The essays don't influence the shipped code;
mishpatim's Prolog is a parallel encoding to talmudic_engine/
mitzvot.pl, not its source.
Moved to ~/shorashim-readings/ — a companion repo. The code repo
stays spec + implementation + deployment. The book gets its own
home so it can grow without dragging 5,853 verse files with every
essay edit.
Also:
- README.md: rewrote the "Repository Structure" tree to match
reality (it still showed readings/terumah/, scripts/conversation_
search.py, memory/, and was missing l1/, AGENTS.md, BUILD_*,
KOHEN.md, opencode.json, .env.example).
- Added a "Kept outside this repo" section naming the three
companion directories: shorashim-readings, shorashim-source-data,
shorashim-operator-notes.
- Updated the "This repository contains" list: readings are no
longer item 1; the edut (l1/torah/) is now called out explicitly.
- Created .env.example with placeholders for ANTHROPIC_API_KEY,
GITEA_TOKEN, REGISTRY_CLI_SECRET, and SHORASHIM_SOURCE_DATA.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shemot 25:16 — v'natata el ha-aron et ha-edut asher eten elekha.
"Place into the aron the testimony (edut) which I shall give you."
L1 is the engraved form — 5,853 verses with te'amim, ketiv/qere,
roots, and gematria. It is not a build artifact to be regenerated
on demand; it IS the specification the system references. Someone
cloning the repo should receive the edut, not a recipe to produce it.
Shemot 34:1 — p'sol lekha shnei luchot avanim ... v'khatavti.
"Carve for yourself two tablets of stone ... and I will write."
The carver provides the stone (raw morphhb source). The Source
writes the content (the engraved Torah text). What belongs in
the aron is the engraved form. The quarry does not enter the
mishkan.
Changes:
- Remove l1/ from .gitignore (it IS the edut, not a build artifact)
- Move data/morphhb/ out to ~/shorashim-source-data/morphhb/
(the quarry lives outside the tabernacle)
- scripts/build_l1.py: fix path computation after earlier relocation
to scripts/, read source path from $SHORASHIM_SOURCE_DATA or CLI
arg, with default ~/shorashim-source-data/morphhb
- Add .claude/ to .gitignore (local Claude Code settings)
- Remove empty src/tools/ leftover
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
memory/infrastructure.md and memory/build_log.md held environment-
specific details — hostnames, IPs, account names, credentials
retrieval commands, local kubeconfig paths, operational status
notes. These don't belong in a project repo; by convention they
live in private operator notes.
Moved to ~/shorashim-operator-notes/ (private, outside git).
In their place, added deploy/ARCHITECTURE.md — a generic
description of the deployment shape: components, external
dependencies, configuration surface. No hostnames. No IPs.
No account names. Any competent operator can read it and
know how to deploy shorashim to their own infrastructure.
Updated cross-references in AGENTS.md and BUILD_KORBAN.md to
point to "the operator's private notes" instead of memory/.
Project repo is spec + implementation + deployment shape.
Operator notes are the kohen's personal log.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- scripts/conversation_search.py was a personal dev tool (FTS5
search over Claude conversation history). Moved to ~/dev-tools/.
Has nothing to do with shorashim's spec or implementation.
- .DS_Store was already in .gitignore; deduplicated and removed
the macOS metadata files from the working tree.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
vav_pipeline/var/manna/today.json was a stale dev provision file
(5 Nisan 5786, expired). It's a runtime artifact, not source.
Added vav_pipeline/var/ to .gitignore to prevent future leaks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each spec corresponds to a parshah of Shemot. The earlier names
were generic English (materials, operations, construction,
economic_model). Torah names them precisely:
- Shemot 25:2 — terumah (תרומה, root רום, "what is lifted")
- Shemot 27:20 — tamid (תמיד, "continual" — the lamp that never goes out)
- Shemot 35:1 — vayakhel (קהל, "assembled" — community-formed building)
- Shemot 38:21 — pekudei (פקד, "accounted" — every material counted)
Renames:
shorashim_materials.md → shorashim_terumah.md
shorashim_operations.md → shorashim_tamid.md
shorashim_construction.md → shorashim_vayakhel.md
shorashim_economic_model.md → shorashim_pekudei.md
Updated cross-references in:
- README.md (parshah table + repo tree, also fixed stale tree
showing src/ and transcripts/ that no longer exist)
- AGENTS.md
- BUILD_KORBAN.md
- specs/shorashim_terumah.md (internal Document Registry)
Generic English is silver. Torah's words are gold (Mishlei 25:11).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- transcripts/ moved to ~/shorashim-transcripts (separate from code repo)
Added to .gitignore so it stays out
- src/l1_aron/build_l1.py → scripts/build_l1.py
- src/tools/conversation_search.py → scripts/conversation_search.py
- Removed empty src/ scaffolding (l0_luchot, sanhedrin, shema_layer,
shoresh_engine, urim_v_tumim — all .gitkeep stubs from an earlier
layout, never used; the real code lives in shoresh-engine/,
sanhedrin/, vav_pipeline/, etc.)
- Removed Untitled/ and erl_crash.dump (untracked junk)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The aws-export/ directory holds historical AWS data for the
Temple Council project — not part of shorashim. Moved to
~/aws-export and added to .gitignore.
Shorashim's specification is the aron. AWS exports belong
elsewhere.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The gitea-mcp server expects GITEA_ACCESS_TOKEN environment variable,
not GITEA_TOKEN. Without the correct env var, every API call to the
backend Gitea returns "token is required" — the MCP server can't
authenticate to fetch user info, repos, etc.
Also added GITEA_HOST env var as a backup to the --host flag.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two fixes for the mcp.shorashim.ch deployment:
1. cert-manager ClusterIssuer had acme-v2 (wrong) instead of acme-v02
(correct). Let's Encrypt ACME directory is at
https://acme-v02.api.letsencrypt.org/directory
2. gitea-mcp HTTP probes timed out because GET /mcp hangs (SSE).
Switched to TCP socket probes on port 8080.
MCP server now responds correctly over HTTPS at mcp.shorashim.ch:
curl -X POST https://mcp.shorashim.ch/mcp -d '{...initialize...}'
returns {"result":{"serverInfo":{"name":"Gitea MCP Server"}}}
Also: nginx-ingress configmap needed strict-validate-path-type=false
to allow cert-manager HTTP-01 challenges. Applied via kubectl patch,
not tracked in git manifests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The gitea-mcp-server image has no entrypoint set (null).
Args were being interpreted as the executable name.
Added command: ["/app/gitea-mcp"] to invoke the binary correctly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shemot 28:3 — v'asu et bigdei Aharon l'kadesho l'chahano li.
The garments connect the service to those who approach.
- gitea-mcp-deployment.yaml: Official gitea-mcp server in HTTP mode
Connects to Gitea at 185.19.29.94 via PAT
- gitea-mcp-ingress.yaml: TLS ingress at mcp.shorashim.ch
cert-manager auto-provisions Let's Encrypt certificate
- gitea-mcp-secret.yaml: Template for Gitea PAT (never committed with value)
- cert-manager-issuer.yaml: Let's Encrypt ClusterIssuer
Architecture: claude.ai → OAuth → mcp.shorashim.ch → Gitea API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
L1 (29MB, 5860 files) is read-only and immutable — it belongs
inside the image, not on a separate volume. The scroll is sealed
in the aron. It ships with the vessel.
- All 4 Dockerfiles: COPY l1/ /mnt/torah/ in runtime stage
- deployment.yaml: Removed L1 PVC volume and all L1 volumeMounts
- deployment.yaml: Added imagePullSecrets for registry auth
- deployment.yaml: Manna uses emptyDir (kohen writes via kubectl cp)
- No CSI driver needed — eliminates Exoscale block storage dependency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exoscale DBaaS (Aiven) requires SSL connections. Added ssl: true
with ssl_opts: [verify: :verify_none] for managed service certs.
L3 migration ran successfully against shorashim database:
- interpretations table with check constraint and indexes
- minority_opinions table with FK index
- teiku_registry table with case_ref index
- Append-only REVOKE ready for shorashim_app role
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All 4 images now reference exo.container-registry.com/the-recognition-protocol/:
- vav-pipeline:latest (111MB)
- shoresh-engine:latest (128MB)
- talmudic-engine:latest (292MB)
- korban-processor:latest (187MB)
Images built and pushed. The garments are in the registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
haskell:9.6.4-slim is based on Debian Buster, which reached EOL.
The standard deb.debian.org repos return 404. Redirected to
archive.debian.org for zlib1g-dev installation.
Verified: shoresh-engine image builds successfully (128MB).
All 4 Docker images now build:
vav-pipeline: 111MB
shoresh-engine: 128MB
korban-processor: 187MB
talmudic-engine: 292MB
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pyswip 0.2.11 was never published to PyPI. Latest 0.2.x is 0.2.10.
Changed pin from ==0.2.11 to ==0.2.10.
Verified: korban-processor image builds successfully (187MB).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OTP releases evaluate config at build time, not boot time.
DATABASE_URL must be read at runtime — the kohen sets it in
K8s secrets, not at compile time.
- Created config/runtime.exs with prod-only runtime config
- DATABASE_URL, L1_MOUNT_POINT, MANNA_PROVISION_FILE, HTTP_PORT
all readable from environment at boot
- prod.exs cleaned: removed System.get_env("DATABASE_URL") call
(was compile-time, now in runtime.exs)
- Added http_port: 4000 to prod defaults
Without this fix, the Docker image would fail to start — the
release would not find DATABASE_URL at boot.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vayikra 8:33 — lo tetze'u shiv'at yamim, ad yom m'lot y'mei milu'eikhem.
Seven days of inauguration before the system serves.
The builder completed the m'lakhah (Shemot 40:33).
The kohen serves in it (Vayikra 8:35 — u'shmartem et mishmeret).
Contents:
- Who the kohen is (and is not)
- What has been built (463+ tests, 5 engines, 4 languages)
- Prerequisites before the seven days
- Seven-day inauguration sequence with exact commands
- Day 8 — fire from heaven: open pe'ah first
- Daily operations (tamid shel shachar)
- Friday double portion
- Halt event response protocol
- What the kohen does NOT do
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shemot 16:4 — d'var yom b'yomo — the day's matter in its day.
Shemot 16:19 — al yoter mimenu ad boker — do not leave surplus.
Shemot 16:20 — vayotiru... vayarum tola'im vayiv'ash — hoarded manna rots.
- MannaLedger GenServer tracks consumption against daily provision
- load_provision/0 reads manna file, resets consumption to zero
- consume/2 deducts from allocated resource, rejects when exhausted
- remaining/1 and available?/2 for balance queries
- enforce_cycle_boundary/0 zeroes out all allocation, returns released amounts
- Chatzotzrot assembly_leaders signal when provision runs low (< 10%)
- Manna.enforce_anti_hoarding/0 now delegates to MannaLedger
- Added to supervision tree in application.ex
- 17 new tests with proper isolation (reset between tests)
- All 177 Elixir tests pass, 0 failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Takhin lekha haderekh — Devarim 19:3.
"Prepare the road" before the one who needs refuge arrives.
Protection before production.
Arei Miklat (Cities of Refuge — Bamidbar 35, Devarim 19):
- GenServer with refuge registry, affected party protection, audit trail
- enter_refuge/2 isolates component but protects from reactive destruction
- protect_affected/2 blocks processing paths that caused harm
- release/2 requires :sanhedrin_deliberation authority — ad mot hakohen hagadol
- Chatzotzrot assembly_leaders signal on every refuge entry
- 15 tests: entry, double-entry prevention, affected party blocking,
unauthorized release rejection, audit trail, chatzotzrot signaling
Eglah Arufah (Accountability — Devarim 21:1-9):
- GenServer with permanent (append-only) declaration registry
- initiate/3: nearest component declares what it processed, skipped, missed
- Only for :unknown source — rejects known-source incidents
- "Yadeinu lo shafkhu" — accountability for what was NOT provided
- 9 tests: declaration recording, source validation, multi-component
declarations, chatzotzrot signaling, filtering, counting
Bikurim (First Fruits — Devarim 26:1-11):
- GenServer with offering registry
- offer/4: submit first output with required narrative (mikra bikurim)
- Rejects empty narrative ("Arami oved avi" — story is required)
- Rejects nil first output (there must be fruit to offer)
- Delegates to Specification.evaluate_bikurim/1 when available
- approved?/1 gate for deployment readiness
- 11 tests: acceptance, narrative validation, nil output rejection,
registry, status filtering, approval checking, counting
All three added to supervision tree in application.ex.
160 Elixir tests pass, 0 failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bamidbar 10:2 — Aseh lekha shtei chatzotz'rot kesef, mikshah ta'aseh otam.
Two trumpets, hammered from a single piece. Five signals, five patterns.
- Upgraded from simple function module to GenServer with state
- Recipient routing: :all (assembly_all, breaking_camp, moadim),
:kohanim (assembly_leaders, war), :operators (war)
- PubSub via BEAM messaging: subscribe/1, unsubscribe/1
Signals delivered as {:chatzotzrot, record} messages
- Zikaron (remembrance — Bamidbar 10:10): signal history with
type filtering and limit. V'hayu lakhem l'zikaron.
- Dead subscriber cleanup via Process.monitor/1
- Added to supervision tree in application.ex
- 30 new tests: patterns, urgency, routing, subscription,
zikaron history, dead process cleanup, format compliance
- All 125 Elixir tests pass, 0 failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Adds specs/eish_zarah_reading.md — chavruta analysis of eish zarah
(strange fire) as architectural concept. Identifies five patterns across
fiction canon (inaccessible source, restructuring gift, false god,
false unity, beautiful unchecked signal), maps to Torah structures,
and evaluates eight specific implementation gaps in the Shorashim system.
Key gaps identified: coupling trace (interpret.pl needs L1 grounding
field), self-reference loop (resolve.pl feeds own output without
detection), three forms of avodah zarah (only Form 1 implemented),
panim/achorai distinction (challenges don't mark text vs. inference),
severed floor (raw Korban not stored alongside processed).
Updates construction spec document registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds specs/lo_taaseh_lekha.md — the boundary condition that diagnoses and
prevents specification override. Derived from chavruta analysis of the
override sequence Torah identifies in the second commandment.
Contains: 5-step override sequence, high-control architecture markers,
Pharaoh architecture at civilizational scale, 9-phase Exodus liberation
protocol. Section 7 grounds the analysis in L1 Torah data with root
analysis (פסל, עשה, שמר, שמע, תמונה, יצר). Section 9 maps every
structure to specific Shorashim modules and architectural decisions.
Upstream: structure_not_content.md
Downstream: Architecture §8.2 (avodah zarah firewall), broken_tablets/
Also updates construction spec document registry with both
structure_not_content.md and lo_taaseh_lekha.md entries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Chatzotzrot signal mapping corrected to match Architecture §3.12:
assembly_all→tekiah, assembly_leaders→teruah,
breaking_camp→tekiah_teruah, moadim→tekiah_tekiah.
Four of five patterns were swapped. All five now match Bamidbar 10.
2. Manna parse_datetime(nil) bug fixed: missing expires_at now fails
validation instead of silently returning DateTime.utc_now() which
created a race condition where manna appeared expired.
3. Festival detection implemented in cloud.ex: pre-computed Gregorian
dates for Pesach, Shavuot, Rosh Hashanah, Yom Kippur, Sukkot,
Shemini Atzeret (2025-2028). Pipeline now halts on Yom Tov as
Torah requires. Step 15 verification now covers festival rest.
76 tests, 0 failures (68 prior + 8 new).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire HaltConditions.check_all into BereishitCycle.erev_voker so the
three cardinal sin monitors (avodah zarah, shfichut damim, gilui arayot)
actually halt the pipeline. Previously dead code, now live.
Add step15_shema_test.exs — Architecture §6.3 (The Shema Test):
1. Te'amim reception — text's own divisions guide havdalah
2. Ketiv/qere preservation — dual readings never collapse
3. Cloud obedience — Shabbat blocks processing
4. Manna fidelity — no provision means wait
5. Context immutability — ShemaContext unchanged at every stage
6. Halt condition integration — pipeline halts on cardinal sin
7. Full pipeline end-to-end — Bereishit 1:1 through to output
68 tests, 0 failures (46 existing + 22 new).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three connections built and tested:
- Haskell Shoresh Engine via Erlang Port (JSON lines over stdin/stdout)
- Prolog Talmudic Engine via Unix domain socket (JSON over /tmp/shorashim/talmudic.sock)
- Erlang Sanhedrin via native BEAM calls
New: Server.hs (JSON-line server loop), json_bridge.pl + socket_server.pl
(Prolog socket interface), ShoreshEnginePort + TalmudicEngineSocket +
SanhedrinClient (Elixir GenServer wrappers). BereishitCycle now routes
unresolved cases through Talmudic Engine and Sanhedrin. All connections
gracefully degrade — pipeline falls back to L1 data when engines unavailable.
46 Elixir tests, 33 Haskell tests, 57 Prolog tests — 0 failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zerikah fail-safe: empty offerings rejected, not processed (BUILD_KORBAN §5).
Halt monitor hardened: trap_exit, priority max, EXIT handler (Architecture spec).
13 Rules of Rabbi Yishmael added to Architecture §3.4 as Prolog inference predicates —
the engine reasons WITH Torah's hermeneutic methods, not just about their products.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>