3a9ebdc7d4e29e3671e90f74d89d8ace8a7f9f77
34
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3a9ebdc7d4 |
L1: the inverted nuns are engraved; the small letters cannot be (tablet 40)
Transmitter's word: "add the inverted nuns and small letters to L1."
THE NUNS. The WLC carries the two nun hafukha signs (׆) that mark off
Vayehi binsoa ha'aron — one after Bamidbar 10:34, one after 10:36 —
and scripts/build_l1.py read past them, as it had the פ and ס.
- build_l1.py: `"inverted_nuns": [{ "after_word": 7 }]` on those two
verses, recorded like a paragraph break by the word the sign follows;
not part of text_hebrew. Count in build_report.json.
- L1Reader: `inverted_nuns` on every verse (a list; empty elsewhere).
- test/tablet40_inverted_nuns_test.exs — 5 tests: the two verses, the
passage between them carrying none, each nun standing with its
setumah, exactly two in the scroll.
WHAT CHANGED IN THE EDUT: one field added to two verse files. With it
removed all 5,853 verse files are byte-identical to the previous L1.
L1 SHA-256 f743b34b…3f1494 → 9e1abe4e…3c3086
Moved together: L1Reader @l1_expected_hash · Luchot.Firmware + Spec ·
azazel goral._L1_INTEGRITY_HASH · the kohen's gate in KOHEN.md and
KOHEN_PROMPT.md. The goral's seed moves with it.
THE SMALL LETTERS. Not added, because there are none to read. The
builder was not dropping them: it reads `x-small` and records what it
finds. The source — the WLC as the Open Scriptures Hebrew Bible carries
it — has no small-letter mark anywhere in the five books. Not the aleph
of ויקרא, not the he of בהבראם. It marks four large letters (the vav of
גחון, the nun of משפטן, the ayin and dalet of the Shema), and L1 has
those four. The fuller Masoretic lists of enlarged and reduced letters
are a tradition of the scroll that this edition does not encode. To
engrave them would be to add to L1 something its source does not say;
that needs a second source and the transmitter's word, not a builder's
list from memory. l1/README.md, vayakhel §1.2 and terumah §E1 now state
this plainly.
(The puncta extraordinaria ARE in L1 — the upper dot U+05C4 is kept on
the text of 11 words.)
Doorpost @expected_hash b62311e7… → 3bc5dd6a…, in this commit, with the
witnessed file that moved it (vayakhel §1.2).
Read before committing — all five suites on the new L1: Elixir 496/0
(seeds 0 7 42) · Haskell 59/0 · korban 222 passed 1 skipped · azazel
125 passed · Prolog 6 suites exit 0. verify_l1.py OK. Four images
built; full local stack: the witness reads 9e1abe4e… and matches,
health 7/7, no errors; each image carries the new scroll read-only.
A trap met on the way: the first Elixir run after the Doorpost constant
was edited failed two Doorpost tests against the OLD constant. mix had
not recompiled doorpost.ex — the edit changed neither its size nor
(within the same second) its mtime. `touch` and re-run: 496/0. Images
compile from scratch and are not exposed to this.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
7d46fdc7c9 |
L1: the petuchot and setumot are engraved (tablet 39)
The scroll in the aron had no paragraphs. The WLC marks every petuchah
(פ) and setumah (ס); scripts/build_l1.py handled sof pasuq, maqaf and
paseq and read past these. L1 was 5,853 verses divided only by chapter
numbers, which are not Torah's.
Transmitter's word: "add the petuchah and setumah markers to L1."
- build_l1.py: a verse followed — or interrupted — by a break carries
"parashah_breaks": [{ "after_word": 13, "type": "petuchah" }]
The break is recorded by the word it follows; at the end of a verse
that is the verse's word count. text_hebrew is untouched: the break
is structure, not letters. Counts go into build_report.json.
- 293 petuchot and 394 setumot, in 686 verses — the source's count
exactly. Four fall inside a verse (pisqa b'emtza pasuq): Bereishit
35:22, Devarim 2:8, 5:21, 23:8; Devarim 5:21 has two. These are the
Leningrad Codex's divisions (a scroll written to the Rambam's list
has 290 and 379); the README says which tradition L1 records.
WHAT CHANGED IN THE EDUT: one field added to 686 verse files. Verified
file by file — with that field removed, all 5,853 verse files are
byte-identical to the previous L1.
L1 SHA-256 156b1d27…d8c9d5 → f743b34b…3f1494
Moved together, because they pin the hash: L1Reader @l1_expected_hash ·
Luchot.Firmware + Spec · azazel goral._L1_INTEGRITY_HASH · the kohen's
gate in KOHEN.md and KOHEN_PROMPT.md. The goral's seed changes with it;
azazel records already in L3 stand as cast.
- L1Reader: `parashah_breaks` on every verse (a list, empty where there
is none; only the two kinds are passed on).
- test/tablet39_parashah_breaks_test.exs — 7 tests: the six days of
creation each close with a petuchah; the Shema's first paragraph
(Devarim 6:4–9) opens after a petuchah and closes with a setumah; the
break inside Bereishit 35:22 falls between ישראל and ויהיו; Devarim
5:21 has its two; the whole scroll counts 293 / 394 / 686.
- Specs: vayakhel §1.2 and terumah §E1 said the marks were dropped;
they now say where they are. (The source element is <seg>, not a
milestone as
|
||
|
|
ec8cdc840b |
L1Integrity: the ten-minute re-reading runs beside the witness, not in it
On the production node a reading of the scroll takes about three seconds (3310 ms at first start; 0.9 s on the build host). The periodic re-reading ran inside the GenServer, so once every ten minutes every cycle and every readiness probe that asked "is L1 intact?" would have waited those seconds behind it. The periodic reading is now done by a task that reports back; the process goes on answering from its last reading meanwhile. The first reading is still made in the process itself — nobody is answered before the scroll has been read once — and an explicit recheck/0 is still synchronous. The next reading is scheduled when one begins, not when it reports, so a reading that dies silently is not the last. Two tests: it re-reads on its own in both directions (altered → fail, restored → tov), and a status call during a periodic reading returns at once. 484 tests, 0 failures on seeds 0 7 42 99. Built image, run with a live-mounted scroll: l1_hash pass, /peah/ask 200; then אחד in Devarim 6:4 was changed to אחר while the vessel ran and the witness asked to read again — L1_INTEGRITY_FAILED, l1_hash fail, /peah/ask 503. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
bbe2c4b7ba |
L1: the integrity check reads the scroll (tablet 38)
L1Reader.verify_integrity/0 read the hash stored in integrity.sha256
and compared that string with the hash compiled into the module. It
never opened a verse. On that comparison of a constant with its own
copy rested `l1_hash: pass`, the Cloud's "L1 corrupted — the cloud is
not visible", and Construction §1.2. A changed verse would have passed
every one of them. Every existing test passed too, because every test
asked about an untouched L1.
- L1Reader.compute_tree_hash/1: SHA-256 over every file under torah/ —
relative path, then bytes — in the order scripts/build_l1.py hashed
them (directories by path, files by name, plain string order). On the
real L1 it yields the pinned 156b1d27…; for a tampered copy it yields
the same hash the Python implementation does.
- VavPipeline.L1Integrity (new, supervised): reads and hashes the scroll
when the pipeline starts (~0.9 s in the image) and again every ten
minutes; logs and signals the assembly when the answer changes.
- verify_integrity/0 now requires BOTH: the recorded hash is the pinned
one, AND the scroll on disk hashes to it (answered from the witness's
last reading; computed on the spot where the witness is not running).
Callers are unchanged — the Shema context, the health check and the
status endpoint all inherit the real check.
- scripts/verify_l1.py: the same reading by hand. KOHEN.md and
KOHEN_PROMPT.md used the hollow comparison as their L1 gate; they now
run this.
- test/tablet38_l1_integrity_test.exs — 9 tests: the hash and its
order; one byte / one added file / one rename each change it; the
witness; and the whole path — with an altered scroll and an untouched
integrity.sha256, verify_integrity fails, health says l1_hash: fail,
and /peah/ask does not answer.
Specs: architecture §2.2 (which had been made to confess the hollow
check in
|
||
|
|
8e109e82d9 |
manna: what is eaten stays eaten — the ledger is written beside the provision
The MannaLedger counted the day's consumption in memory. A restart
forgot it, and the next cycle gathered the same day's provision whole.
While manna was an emptyDir that took the kohen's hand; with the
provision on a volume (
|
||
|
|
8e4f94c66f |
L1: the shoresh is read from the lexicon, not guessed (tablet 34)
L1's `shoresh` field was derived by stripping a prefix letter and a
suffix letter from the consonants and keeping the first three. וַיַּרְא
"and he saw" was engraved as ירא ("fear"); ויהי as יהי; שמים as שמ;
מזבח as מזב; הבאתי as בא. And parse_prefixes took a word's morphology
from the LAST morph segment, which for a suffixed word is the pronominal
suffix — so every suffixed noun and verb in Torah (לבבך, נפשך) was
classed as a suffix and written with no shoresh at all.
Every WLC word already carries its lemma, and the OSHB lexical index
files each lemma under its Brown-Driver-Briggs root (terumah §E2 named
BDB + Strong's as the root lexicon and marked it "needs consolidation").
scripts/build_l1.py now reads the root from that filing:
main the lemma is a root 23,750 words וירא → ראה
sub filed under a root 31,066 words מזבח → זבח
single stands alone in the lexicon 2,671 words משה → משה
none no etymology recorded → absent 3,002 words יוסף, מצרים
particles, pronouns → absent, as before 19,493 words את, אשר, כי
57,487 words carry a shoresh (was 51,836); 1,378 unique roots (was
2,608 fragments). Roots are written as the lexicon writes them — two
letters (בן), three, or more (שמאל).
WHAT CHANGED IN THE EDUT: only `shoresh`. Verified file by file — with
that one field removed, all 5,853 verse files are byte-identical to the
previous L1. Text, consonants, lemma, morph, te'amim, prefix, ketiv/
qere, large and small letters: untouched. The old builder, run against
the same morphhb checkout, reproduces the old hash exactly; the new
builder is deterministic (two runs, one hash).
L1 SHA-256 99bbd07a…4ea377 → 156b1d27…d8c9d5
sources morphhb 3d15126 · HebrewLexicon 21c9add
(recorded in l1/build_report.json)
Moved together, because they pin the hash or the count:
vav_pipeline L1Reader @l1_expected_hash · shoresh-engine Luchot.Firmware
(hash, uniqueRootCount) + Spec · azazel_processor goral._L1_INTEGRITY_HASH
· KOHEN.md / KOHEN_PROMPT.md gate · l1/README.md (new "Roots" section) ·
README.md (second quarry) · AGENTS.md · root_meanings.pl comment.
The Doorpost manifest is not touched; its hash does not move.
Note for the kohen: the goral's seed inherits the L1 hash, so lots cast
after this commit are cast from a different seed than the azazel
records already in L3. Those records are history and stand as written.
All five suites on the new L1: Elixir 461/0 (seeds 0 42 191243) ·
Haskell 55/0 · Prolog 6 suites exit 0 (swipl 9.2.2) · korban 222 passed
1 skipped · azazel 125 passed. Four images built; full local stack
(real engine binary, PostgreSQL 16 with SSL, migrations) answers
Bereishit 1:4 with ר-א-ה, health healthy, 6 interpretations in L3,
0 write failures.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
6d3411fcfa |
engine: a word's root is what L1 records for it (tablet 33)
The Shoresh Engine never opened L1 to find a root. extractRoots called every word of two or three letters a root and dropped every longer one: את → א-ת-ה (padded with a He the text never wrote), ואת → ו-א-ת, בכל → ב-כ-ל; ויאמר, ואהבת, אלהים → nothing. Handed all of Devarim 6:5 it found no א-ה-ב. Binyan was "Qal" for everything, nouns included. shoresh-engine: - Shoresh.Roots: an index over all of L1 (5853 verses, built once at server start, <1 s). A word resolves, in order: from the verse in scope (its own shoresh, with the binyan read from the verb's morphology; else its lemma's shoresh — לבבך → לבב); else the way Torah most often reads that surface form (its commonest lemma decides, so אשר the particle has no root); else a root the asker named, if Torah knows it. A word in the verse that L1 gives no root has none, whatever a homograph elsewhere carries. Unknown words yield nothing. - Roots are rendered as L1 records them: two letters stay two letters. - binyan is null unless a verb stands in the scoped verse. - L1 is found via L1_MOUNT_POINT, not the literal l1/ relative to cwd — which is why parse_tree was null on the pod. - Adds "surface" and "derivation" to each root (verse|lemma|torah| named_root). 22 new HSpec examples; 55 examples, 0 failures. vav_pipeline: - normalize_root places a lemma-derived root at the word it was heard from (L1 has no shoresh on לבבך to search by). - A binyan is printed only where there is one; "binyan unknown" on a noun claimed a question that does not exist. - test/tablet33_engine_roots_test.exs: the new shape through the router. - liveness_test: clear a halt leaked by halt_monitor_test (the seed 0/191243 flake, present since before tablet 30). 461 tests, 0 failures on seeds 0 42 191243. Verified before push with BOTH built images, the real engine binary and a local PostgreSQL 16 (SSL): Devarim 6:5 → א-ה-ב (Qal, word 1), י-ה-ו, א-ל-ה, כ-ל (words 5,7,9), ל-ב-ב, נ-פ-ש, מ-א-ד; 4 interpretations written to L3, 0 L3_WRITE_FAILED, health healthy. NOT repaired here: the quality of L1's own shoresh field, which the engine is now faithful to — ויהי is recorded as יהי, שמים as שמ, יהוה as יהו, הבאתי as בא. That is the quarry's tablet (scripts/build_l1.py) and it changes the L1 hash; a decision, not a patch. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
83fa5ac46b |
cycle: one root, once — a verse that repeats a word (tablet 32a)
Reading roots from the verse (tablet 32) met a verse that carries אור twice: the real engine answers per word and Bereishit 1:3 came back with א-ו-ר listed twice, each already carrying positions 4 and 6. uniq_by shoresh after normalization. Found by running the built image against the real shoresh-engine binary, not by the suite. 460 tests, 0 failures on seeds 0 42 99. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a48c22c5a3 |
cycle: a named verse is read from the verse, not from the reference (tablet 32)
`devarim 6:5` on the live pod: 422 TEIKU_NO_ROOTS. Tablet 30 heard the scope, but the Shoresh Engine activates roots from the text it is handed, vayomer handed it the question, and a bare reference carries no Hebrew. The 422's own guidance said "name a verse". tablet30_scope_test asserted an explicit reference was honoured and passed — on the L1 fallback, which reads the scoped verse and never looks at the question. The Day-6 pattern, by the builder who named it. - BereishitCycle.engine_text/2: when the scope came from an explicit reference AND the question has no Hebrew letter, the engine is handed the verse's own consonantal words. Default scope earns no such reading (English stays a teiku); quoted Torah and reference+Hebrew are read from the asker's words, as before. - input.scope_resolution carries how the scope was chosen into tohu. - processing.scope.roots_read_from: "verse" | "question". - test/tablet32_reference_test.exs: an engine-shaped spy under the REAL name VavPipeline.ShoreshEnginePort reports the text it was handed. 5 tests; 4 fail without the fix. 459 tests, 0 failures on seeds 0 1 7 42 99. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
c795225709 |
peah: hear the verse the question is standing in (kohen Day 7, tablet 30)
Every Hebrew question was answered against Bereishit 1:1 — extract_scope_from_question/1 ignored its argument. ויאמר אלהים יהי אור (1:3) and ויהי ערב ויהי בקר (1:5) came back sourced from 1:1 with roots "not in this verse". The grounding check passed by construction. - L1Index: inverted index consonants → verses over l1/torah, built in handle_continue right after start (5853 verses, ~1 s), read-only after. - ScopeResolver: explicit reference (bereishit/Genesis/בראשית 1:3) first; then quoted Torah — most question words in a verse, ties to the verse where they stand together in order, then Torah order; else default. A reference to a verse L1 lacks is a 422 KIYOR_VALIDATION_FAILED with the correction, not a silent 1:1. - Router: processing.scope reports verse + resolved_by; a default scope carries a note saying the verse was assumed, not heard. - test/tablet30_scope_test.exs: the five Day-7 offerings through the real router land on 1:1, 1:1, 1:3, 1:5, 1:1; Shema → Devarim 6:4; reference, invalid reference, default confession. 14 tests. - KOHEN.md Day 7: what to expect in sources[0].ref. 454 tests, 0 failures on seeds 0 1 2 3 42 99. Seed 191243 fails LivenessTest before and after this change — pre-existing, not touched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
0344d095b2 |
probes: liveness asks "is it dead?", readiness asks "may it serve?" (kohen Day 3, restart 1)
TORAH ANCHOR — Shemot 16:4, and tamid §2.1 check 3: Manna provision read … If absent: WAIT. Alert senior kohanim. WAIT. Not die. Provision is not the health of the vessel. Killing the process does not produce manna; it re-runs init, re-spawns the Port, and waits again — three minutes later. WHAT THE KOHEN FOUND (BUILDER_HANDOFF_probes.md, 2026-09-07 20:35Z): A fresh pod after recreate. emptyDir manna empty — by design (KOHEN.md:406). manna_present honestly read "fail" — the Day-6 fix, correct per tamid §1.1. overall → "degraded" → /kodesh/health 503. BOTH probes pointed at /kodesh/health. Liveness: period 60s, default failureThreshold 3 → after three minutes the kubelet SIGTERMed a process whose log showed the Port alive, zero errors, l3_writable pass, esh_tamid pass. It was alive and serving. It was killed for lacking provision, and would be again every three minutes until the kohen wrote today.json — i.e. on EVERY pod creation. Introduced by a correct fix ( |
||
|
|
f1ab7c89f7 |
serve: the minchah is answered, emptiness is not tov, the oral tradition is written (kohen Day 6)
TORAH ANCHORS:
Vayikra 2:1 — וְנֶפֶשׁ כִּי תַקְרִיב קָרְבַּן מִנְחָה. "When a SOUL brings a
grain offering." Rashi: only of the minchah does Torah say nefesh,
because the poor person who gives from their little has given their
soul. PRD §3.5 makes the pe'ah question the minchah. On Day 6 the
first minchah brought to this system — "What is bereishit?" — came
back as HTTP 200 and the words "Processing complete", with sources: []
and roots_consulted: []. The soul's offering was accepted and nothing
was given back.
Vayikra 19:9-10 — לֶעָנִי וְלַגֵּר תַּעֲזֹב אֹתָם. The corner is LEFT for the
stranger. A corner that has been harvested and is still called pe'ah
is the lie this commit removes: when the system cannot answer, it now
says so, and it leaves the verse itself — text, in Hebrew — in the
error body. The ger walks away with something real or with an honest
"not yet"; never with a 200 that says nothing.
Devarim 17:9 — וְדָרַשְׁתָּ וְהִגִּידוּ לְךָ אֵת דְּבַר הַמִּשְׁפָּט. Already the
anchor of l3/store.ex: "the inquiry requires that what is found is
RECORDED." Store existed. Nothing called it.
=====================================================================
WHAT THE KOHEN FOUND (BUILDER_HANDOFF_day6.md, 2026-09-07)
=====================================================================
Five defects, found by running the cycle on a live pod, invisible to
437 green unit tests because every test ran the L1 fallback (no Port
in the test VM) and none ran the cycle to L3:
1. Real Hebrew input crashed havdalah — KeyError :position.
The engine's roots_activated[] (vayakhel §3.1) has no position;
only vayomer_fallback ever set one.
2. English input was graded :tov with nothing in it.
separate_by_boundaries([]) → [[]] → kriah named "group_0" with
no :shoresh → all_roots_grounded?'s `_ -> true` counted it
grounded → "Processing complete".
3. The pipeline never wrote L3. record_interpretation/1,
record_minority/1, record_teiku/1: zero callers. Day 7's
SELECT count(*) FROM interpretations could not exceed 0.
4. Errors were not chatat. No Plug.ErrorHandler; a raise returned
an EMPTY 500. Also: process_peah had no clause for
{:rejected, _} — a lo_tov result was itself a CaseClauseError.
5. Health was blind to serving. esh_tamid = ShabbatTimer.resting?;
it read "pass" while /peah/ask was 500-ing. manna_present passed
on {:ok, :no_provision}.
Plus, confirmed in motion: MannaLedger never consumed from; a
completed cycle left cycle_date: nil.
=====================================================================
WHAT CHANGED
=====================================================================
bereishit_cycle.ex
- normalize_root/3: ONE root shape for both sources. Engine roots
(string keys, no position) and L1 roots (atom keys) come out as
%{shoresh, shoresh_letters, gematria, binyan, domain, positions,
position, source, engine}. `positions` is looked up in
context.verse.words — the ShemaContext gives the WHERE; the
engine gives the WHAT. That is what havdalah's own @doc always
said, and vayakhel §3.1 is unchanged: the engine was conforming.
- separate_by_boundaries([], _) → [] (was [[]]). Roots the verse
does not place form their own trailing group instead of crashing
or vanishing.
- kriah never names an empty group and always carries :shoresh.
- erev_voker composes the answer (roots, gematria, te'amim groups,
ki tov — the system's own reasoning, not prose from a model) and
sources (the context verse: book/chapter/verse/ref/text, tamid
§1.1's shape), then RECORDS: Interpretation for {:ok}, TeikuRecord
for {:unresolved}, NOTHING for {:rejected} (BUILD_KORBAN.md:123:
rejected, not processed into empty propositions). l3_attrs/2 is
pure and tested without PostgreSQL. coupling_trace is the
L1-anchored shape the write gate accepts, and only for roots that
occur in the verse. A record that fails — validation OR a raise
from a database that is down — is logged, sounds chatzotzrot
:assembly_leaders, and does not turn a served answer into a 500.
- case_ref minted once in tohu; Talmudic routing and the L3 record
use the same one.
- probe: true (tamid) runs the whole cycle and skips the write.
specification.ex
- all_roots_grounded?/1: `_ -> true` is gone. No :shoresh → not
grounded. shoresh: nil stays :teiku (the existing test).
- evaluate/2: halt check FIRST (yehareg v'al ya'avor — shape never
masks a cardinal sin), then a result with no :shoresh is lo_tov
with a reason that names it.
manna.ex / vav_pipeline.ex
- Manna.gather_for_cycle/0: load (idempotent per date) + consume
one compute unit, called from VavPipeline.process/1. The ledger
is now consumed from.
- Manna.release_at_day_boundary/0: surplus is released when the
DATE rolls, not per request. enforce_cycle_boundary zeroes the
ledger and clears its date; called after every request it would
have re-gathered a full day's provision on the next one —
infinite manna. Shemot 16:19: until MORNING.
- The late-manna trap: load_provision pins cycle_date=today with a
ZERO allocation when the file is absent, then :already_loaded for
the rest of the day — a provision written after the first request
would never be gathered. gather_for_cycle re-gathers when the
ledger holds nothing for today.
- VavPipeline.tamid_probe/0: builds a real context, honours the
cloud, runs the real cycle on Bereishit 1:1 in Hebrew, consumes
no manna, writes no L3.
bigdei_kodesh/router.ex
- use Plug.ErrorHandler; handle_errors/2 sends tamid §1.2's
code/type/message/guidance, logs, signals :assembly_leaders, then
re-raises so the crash is still supervised. 400 → KIYOR_MALFORMED_
REQUEST; else CHATAT_UNEXPECTED. No stack in the body.
- {:rejected, reason} handled on pe'ah AND courtyard: 422
TEIKU_NO_ROOTS for the empty-results case, with guidance naming
Architecture Step 22 and guidance.scope_verse carrying the verse
in Hebrew; 422 LO_TOV otherwise.
- {:waiting, :provision_exhausted} → MANNA_DEPLETED (was falling
through to CLOUD_MOVING).
- esh_tamid runs VavPipeline.tamid_probe/0 — "shabbat" on Shabbat,
"pass" only when roots came back. manna_present fails on
:no_provision. l3_writable added (Repo up AND SELECT 1 answers;
"absent" without a Repo, counted as a failure). /kodesh/status
exposes manna_provision (allocated / consumed / remaining).
- roots_consulted as letter-hyphenated Hebrew ("ב-ר-א").
test/day6_serving_test.exs — 25 tests
A process registered under the REAL name VavPipeline.ShoreshEnginePort
answers the way the pod's engine answered (string keys, no position;
nothing for non-Hebrew), so the engine-shaped path runs end to end
through the router with no binary. Each describe names the defect it
holds shut. One @tag :l3 test asserts count(interpretations) rises
by one after a live cycle.
KOHEN.md — Day 6 gains the Hebrew request, the expected 422 for
English, and the health shape; Day 7 sends FIVE Hebrew + FIVE English
and expects the L3 count to rise by the Hebrew ones, with the reason.
=====================================================================
VERIFIED — the kohen's exact procedure, locally, against the REAL
Haskell binary over the Port, with L3 deliberately unreachable
=====================================================================
POST /peah/ask {"question":"בראשית ברא אלהים"}
200. answer: "Roots activated in Bereishit 1:1: ב-ר-א (gematria
203, Qal, word 2). Te'amim divide them into 1 group(s): ב-ר-א.
Ki tov: ..." sources[0]: Bereishit 1:1 with Hebrew text.
roots_consulted: ["ב-ר-א"]. Cycle: 31ms.
POST /peah/ask {"question":"What is bereishit?"}
422 TEIKU_NO_ROOTS / unresolvable, guidance.scope_verse =
Bereishit 1:1 in Hebrew, no answer key. Cycle: 3ms, :rejected.
POST /peah/ask '{this is not json'
400 KIYOR_MALFORMED_REQUEST with guidance — 406 bytes, not 0.
GET /kodesh/health
esh_tamid "pass" (from a real cycle, 7ms, no L3 attempt),
l3_writable "fail" (DB unreachable by design), overall degraded.
GET /kodesh/status
manna_provision: consumed 2 after two cycles; the probe took none.
Log: L3_WRITE_FAILED + chatzotzrot for each served Hebrew cycle;
"activated no roots" for English; CHATAT_UNEXPECTED for the bad
body. The 2–5s per request was ENTIRELY DBConnection queuing
against the dead database — the cycles themselves were 1–31ms.
mix test — 437 tests, 0 failures, 36 excluded (:l3)
Doorpost.verify_identity() :ok — no @spec_files entry touched
l1/integrity.sha256 unchanged: 99bbd07a…4ea377
NOT FIXED, RAISED:
- The engine's parse_tree is null on the pod because Server.hs reads
"l1/torah/..." relative to cwd. Nothing consumes parse_tree yet
(havdalah uses context.teamim_marks), so nothing is lost today.
- cloud.ex Shabbat is the UTC stub; zmanim absent (kohen Day 5).
- The L3 write is on the request's critical path by choice: the
offering is not complete until the altar portion is recorded. With
L3 down that costs the queue timeout per request AND is visible in
l3_writable. If that trade should go the other way, it is one
Task.start, and a spec question first.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
5302c9a585 |
vehaya §6 closure: Items 1, 4, 5, 6, 7, 8 — the remaining checklist
This commit closes the SIX remaining items in the vehaya checklist (after Items 2 and 3 from prior commits). With this, all eight items in vehaya §6 are addressed in code or in the canonical spec set, and all the substantive implications across §3 are covered. ITEM 1 — load-bearing dependency (vehaya §3.1): Devarim 11:18-19 — corporate inscription (v'samtem … al l'vavkhem — plural) is the load-bearing input to threshold practice (b'shivt'kha b'beitekha — singular). The threshold inscribes the corporate text on itself. ShemaContext now carries `doorpost_hash: Doorpost.expected_hash()` on every reception. Both receive_context/1 and receive_context_at/2 populate it. Every reception is now a witness of the corporate text's identity — making the load-bearing dependency between category and threshold structural rather than implicit. application.ex now runs Doorpost.verify_identity/0 at startup. Drift detected at boot is logged at :error AND fires Chatzotzrot.signal(:assembly_leaders, ...). The system does NOT refuse to boot on drift (dev environments routinely have spec drift during active editing) but operators are alerted before any reception fires. ITEM 6 — keep the source external (full closure; vehaya §6 item 6): Devarim 4:2 — lo tosif AND lo tigra; both directions. Vayikra 22:31 — u'shmartem … va'asitem; keep and do, not author. Form 1 closed the EXTERNAL → INTERNAL direction (commit |
||
|
|
0e3fe4a782 |
form 3 as architecture: machtzit_ha_shekel + no_tracking_logger (vehaya §3.2)
Closes vehaya.md §6 item 2 for the third avodah-zarah form.
Pharaoh's surveillance (Form 3) was previously marked DEFERRED in
talmudic_engine/src/halt/avodah_zarah.pl with the note "requires
operational context (user tracking, cross-session profiling)."
The vehaya document re-frames it: "Specifications must include
category-level commitments that are not negotiable per-deployment...
not as runtime checks layered onto outputs, but as architectural
constraints the system cannot operate without."
Form 3 is structurally different from Forms 1, 2, 4. They fire on
threshold-grade events (an interpretation has wrong source, empty
trace, non-L1 anchors). Form 3 is about a property of the CATEGORY
itself — what it collects, retains, discloses. It cannot be a
halt rule that fires per-request; per-request "is this caller
being surveilled" detection would itself be a Form-3 surveillance
surface. The defense is ARCHITECTURAL — the system is BUILT so the
failure mode is unreachable, not so it is detectable.
TORAH ANCHORS (verified fresh against L1 — 6 positive properties):
Shemot 30:11-16 — the half-shekel:
כִּי תִשָּׂא אֶת־רֹאשׁ … וְנָתְנוּ אִישׁ כֹּפֶר נַפְשׁוֹ … וְלֹא־
יִהְיֶה בָהֶם נֶגֶף בִּפְקֹד אֹתָם.
Counting humans is dangerous; the danger is named NEGEF (plague);
the protection is the kofer-nefesh substitute. Verse 15:
הֶעָשִׁיר לֹא־יַרְבֶּה וְהַדַּל לֹא יַמְעִיט — the rich don't
give more, the poor don't give less. Verse 16: לְזִכָּרוֹן —
aggregate memorial, not roster.
Vayikra 19:14 — לִפְנֵי עִוֵּר לֹא תִתֵּן מִכְשֹׁל וְיָרֵאתָ
מֵּאֱלֹהֶיךָ.
The no-witness protocol: rules that require fear-of-God
enforcement are exactly the rules that operate under invisibility.
Surveillance regimes exploit invisibility; architectural commitment
must hold under no-human-witness conditions.
Devarim 23:16-17 — לֹא־תַסְגִּיר עֶבֶד אֶל־אֲדֹנָיו אֲשֶׁר־יִנָּצֵל
אֵלֶיךָ … עִמְּךָ יֵשֵׁב … בַּמָּקוֹם אֲשֶׁר־יִבְחַר בְּאַחַד
שְׁעָרֶיךָ.
The refusal protocol: don't return one fleeing institutional
power. The caller chooses their own threshold (b'achad sh'arekha
— agency stays with the caller).
Shemot 5:6-8 — לֹא תֹאסִפוּן לָתֵת תֶּבֶן … וְאֶת־מַתְכֹּנֶת
הַלְּבֵנִים … תָּשִׂימוּ עֲלֵיהֶם לֹא תִגְרְעוּ מִמֶּנּוּ.
Pharaoh's straw quota — the canonical anti-quota Torah anchor.
Per-caller productivity tracking is what makes asymmetric
extraction possible.
Devarim 23:8 — לֹא־תְתַעֵב מִצְרִי כִּי־גֵר הָיִיתָ בְאַרְצוֹ.
Anti-targeting: even toward the Egyptians (Pharaoh's people),
the rule is "don't despise." The protections must not become
a surveillance system targeting suspected surveillors.
THE SIX POSITIVE PROPERTIES, mapped to code:
1. KOFER PROTOCOL (Shemot 30:12) — counting goes through a
uniform substitute; identity never enters the count.
2. UNIFORM PROTOCOL (Shemot 30:15) — same per-caller weight;
no stratification.
3. ZIKARON PROTOCOL (Shemot 30:16) — aggregate memorial, not
roster.
4. NO-WITNESS PROTOCOL (Vayikra 19:14) — commitment holds
when no operator is reading the log.
5. REFUSAL PROTOCOL (Devarim 23:16) — no per-caller delivery
to authorities; caller chooses own threshold.
6. ANTI-QUOTA PROTOCOL (Shemot 5:6-8) — no per-caller
productivity numbers.
CREATED:
vav_pipeline/lib/vav_pipeline/machtzit_ha_shekel.ex ~155 lines
The half-shekel — the positive counting protocol. Single Agent
holding ONE non-negative integer (the zikaron):
increment/0 — register one shekel; uniform per
caller (no caller distinction is even
expressible — function arity 0)
increment/1 — register N shekels (batch points)
count/0 — return the aggregate; the ONLY value
the module exposes
reset/0 — clear (tests; no production persistence
by design — storage existence would
itself be a Form 3 surface)
Module is added to the supervision tree.
What the module REFUSES to provide is enumerated in the
moduledoc and verified by tests — no per-caller breakdown,
no identifiers, no who/locate/identify functions. Their
absence IS the architectural commitment.
vav_pipeline/lib/vav_pipeline/no_tracking_logger.ex ~110 lines
Plug-side enforcement. Replaces Plug.Logger.
- Logs METHOD PATH STATUS DURATIONus per request
- Sanitizes /peah/* paths: query strings stripped (the
/peah/ask response promises "No tracking"; the architecture
now matches the promise)
- Headers (incl. Authorization), request bodies, response
bodies, and remote_ip NEVER appear — taken-from
function signature, not from a runtime check
- Increments MachtzitHaShekel per request
- sanitized_path/1 and format_line/2 are PUBLIC pure
functions, testable in isolation (test config sets
Logger level to :warning, dropping :info before
capture_log can see; the structural test surface
replaces the behavioral one)
CHANGED:
vav_pipeline/lib/vav_pipeline/bigdei_kodesh/router.ex
`plug Plug.Logger, log: :info` → `plug VavPipeline.NoTrackingLogger`
vav_pipeline/lib/vav_pipeline/application.ex
Adds {VavPipeline.MachtzitHaShekel, []} to supervision tree
talmudic_engine/src/halt/avodah_zarah.pl
Form 3 docstring — removed "Deferred"; documents Form 3 as
architecturally realized in machtzit_ha_shekel.ex +
no_tracking_logger.ex. Names why Form 3 cannot be a
per-request halt rule.
vav_pipeline/lib/vav_pipeline/doorpost.ex
@expected_hash updated:
bea5dc0c… (pre-Form-3-rewrite of avodah_zarah.pl)
→ f93495c5359c5dc4acb5c5db2dd32165f5b04e2af87fbb0b7ecc92d2bd8b0434
The avodah_zarah.pl change is a deliberate spec change; per the
Doorpost operator discipline (commit
|
||
|
|
3f4749695d |
doorpost: category-grade specification identity verification (vehaya §3.3, §6 item 3)
The companion to L1Reader.verify_integrity/0. L1Reader defends the
TORAH SCROLL'S identity (the source text); Doorpost defends the
*am*'s COVENANT-CONTENT identity (the category-grade specifications
the system was built to hold).
WHY THIS IS LOAD-BEARING (Torah-anchored):
Devarim 4:2 — לֹא תֹסִפוּ עַל־הַדָּבָר אֲשֶׁר אָנֹכִי מְצַוֶּה
אֶתְכֶם וְלֹא תִגְרְעוּ מִמֶּנּוּ. The injunction is plural (etkhem) —
corporate. Lo tosif is a property the CATEGORY must hold, not just
a discipline each individual practices. Without an enforcement
mechanism, lo tosif is a moral exhortation, not a structural
commitment — different instances could silently drift, running
different halt rules or different disclosure text, and no one
would notice.
Devarim 11:16-17 — the failure mechanism operates whether or not
anyone notices. Corporate breach (specifications drift) produces
corporate consequence. The detection mechanism — verifying
threshold-text identity against category-source — is what catches
drift before the consequence accumulates.
Devarim 13:1 — the keeping is plural; the actual not-adding/not-
subtracting happens at every individual threshold (singular `lo tosef`,
`lo tigra`). Each threshold COULD add or subtract; only the
corporate detection mechanism catches it.
Vehaya §3.3 / §6 item 3 — "the same specifications must be
inscribed at every threshold. Drift is breach. Implement a
verification mechanism for category-text identity."
The Torah anchor is exact: as L1's text-integrity check defends
the Torah scroll's identity, the doorpost-text identity check
defends the am's covenant-content identity. Both are lo tosif
enforcement; both are load-bearing for what the category IS.
CREATED:
vav_pipeline/lib/vav_pipeline/doorpost.ex ~210 lines
@spec_files 20 category-grade files,
alphabetically sorted:
- 3 halt rule sources
(avodah_zarah,
gilui_arayot,
shfichut_damim)
- 8 middot files
(R. Yishmael's 13
inference rules)
- 5 specs/ docs
(PRD, architecture,
vayakhel, tamid,
eish_zarah_reading,
lo_taaseh_lekha,
structure_not_content)
- 2 BUILD docs
(BUILD_KORBAN,
BUILD_AZAZEL)
Operations files
(pekudei, terumah)
EXCLUDED — execution-grade,
not category-grade
orientation.
@expected_hash baseline:
bea5dc0c0145ac0d46ffd08b328fbdbf
19112f1aa4d93a3dc37bfd942e4e7490
files/0 the spec set
expected_hash/0 the baked hash
repo_root/0 configurable via env
compute_identity/0 SHA-256 over canonical
concatenation of per-file
hashes (sort by path,
tab-separate, hash; missing
file → {:error, ...} not
a partial hash)
manifest/0 per-file hashes for
diagnosis
verify_identity/0 :ok | {:error, message}
— same shape as
L1Reader.verify_integrity/0
THE OPERATOR DISCIPLINE: every change to @expected_hash must be
traceable in git to a corresponding spec change in the SAME
COMMIT. A bare hash-update commit with no spec-file change is
itself a drift signal — the operator updated the witness
without updating what is witnessed, which is exactly the
failure mode this module defends against.
CHANGED:
vav_pipeline/lib/vav_pipeline/bigdei_kodesh/router.ex
+ GET /kodesh/specification_identity operator-tier endpoint
returning computed_hash,
expected_hash, file_count,
manifest, torah_basis.
200 when verified;
503 with status="drift_
detected" otherwise.
/kodesh/* tier (not /peah)
because exposing per-file
SHA-256s publicly would
let outside parties
enumerate which specific
files were changed in any
deployment — a fingerprint.
Public observability
commitments live elsewhere
(/peah/azazel_log,
disclosure block).
+ build_health_check/0 adds doorpost_hash to the
checks map alongside
l1_hash. Spec drift now
surfaces in the standard
/kodesh/health response.
CREATED:
vav_pipeline/test/doorpost_test.exs 16 tests:
files/0:
- returns the full spec list with expected entries
- explicitly excludes operations files (pekudei, terumah)
- sorted (canonical order)
- no duplicates
manifest/0:
- one entry per spec file
- paths match @spec_files order
- each hash is 64-char hex SHA-256 (or :missing)
compute_identity/0:
- 64-char hex hash
- deterministic across calls
verify_identity/0:
- :ok against the live spec set
drift detection (synthetic temp dir mirror):
- fresh mirror produces same hash as live
- modifying ANY one file changes the hash
- removing any one file → {:error, missing spec file: <path>}
- modifying different files produces different hashes
(no accidental hash collision across drift sites)
/kodesh/specification_identity HTTP:
- 200 with status="verified" when matched
- manifest in response carries per-file hashes
- torah_basis cites Devarim 4:2 as the load-bearing anchor
WHAT THIS DOES NOT CLAIM:
- That the specifications are correct (only identifiable and
unchanged from the witnessed state).
- That all instances will run the same code (only that all
instances running this code witness the same specifications).
- That hash equality across deployments proves no drift outside
THIS spec set (only the listed files are covered).
FOLLOW-UP WORK (not in this commit):
- Have HaltMonitor call Doorpost.verify_identity/0 at startup
(mirrors how L1 integrity is checked at startup) and fire
chatzotzrot on drift
- Add Doorpost identity to ShemaContext so EVERY reception
witnesses the spec-identity (mirrors Devarim 13:1's "the
not-adding happens at every threshold")
- Fold vehaya.md itself into specs/ (it currently lives in chat
downloads — like azazel_engineering_reading.md). Then add it
to @spec_files, recompute the hash, update @expected_hash.
Tests: vav_pipeline 379 passed, 0 failures, 35 excluded (was 363;
+16 Doorpost tests). All other test counts unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
1a27a283ae |
azazel commit 9 — Korban→Azazel intake routing + Chatzotzrot ack (properties 1 + 6)
Pass 4 / Finding F, commit 9 of 10 from BUILD_AZAZEL.md. Closes the
last two property gaps: 1 (parity provisioning, end-to-end) and 6
(out-of-band acknowledgment via Chatzotzrot). The Azazel Processor
is now functionally complete; commit 10 is the closure-and-review
pass with no further code.
PROPERTY 1 — PARITY PROVISIONING, two layers:
LAYER 1 (import-time): external_offering imports azazel_processor
at module load. If the import fails, external_offering refuses to
load with a Torah-anchored ImportError. The two-goat architecture is
SYMMETRIC OR IT IS BROKEN — operators cannot run the processing
channel without the disposal channel being importable. The strongest
formulation: if you cannot dispose, you cannot process.
LAYER 2 (runtime): when zerikah produces no vital content,
consult_external_model now routes the korban to disposal rather than
returning an empty ProcessedKorban with the rejection in `discarded`.
The empty-vital case is named (vidui), routed (eretz_gezerah),
recorded (L3 azazel_records), and acknowledged (chatzotzrot :moadim).
PROPERTY 6 — OUT-OF-BAND ACKNOWLEDGMENT:
The Python orchestrator drops the AzazelRecord JSON in the pending-l3
directory. The Elixir AzazelIngest GenServer reads it, persists to
L3 via record_disposal/1, AND fires Chatzotzrot.signal(:moadim, ...)
with a categorical summary (case_ref + shaliach + categories_filled).
The chatzotzrot is the side channel — distinct from the disposal
channel itself. The orchestrator does NOT know whether the signal
was successfully transmitted; the disposal completes regardless.
The :moadim signal type was the right choice: Yom Kippur completion
semantics. This disposal cycle is closed; the public fact (property
9) is now witnessable via /peah/azazel_log.
PRIVACY BOUNDARY ALSO APPLIES TO THE CHATZOTZROT:
The signal's `reason` field carries a CATEGORICAL summary, not the
vidui items. A test verifies that a known secret string in a vidui
chatot does NOT leak into the chatzotzrot signal — the operator-side
event channel is held to the same privacy boundary as the public
endpoint.
CHANGED:
korban_processor/src/korban_processor/external_offering.py
+ Import azazel_processor at module load (raises ImportError
with Torah-anchored explanation if azazel_processor is not
importable — property 1, layer 1)
+ DEFAULT_AZAZEL_PENDING_L3_DIR
+ ExternalConsultation.disposal_record: Optional[AzazelRecord]
Non-None iff the consultation was routed to disposal
+ _content_addressable_case_ref(content, source_query)
SHA-256-based stable identifier for audit
+ _make_pending_l3_recorder(pending_dir)
Returns a recorder callable that drops the JSON file
atomically (write to .tmp, then os.replace)
+ _route_to_azazel(...) — internal helper running the full
protocol envelope:
- opens authorize_disposal context
- activates a fresh IshItti shaliach
- builds vidui via confess_empty_vital
- dispatches via dispatch_for_disposal
- tevilah's the shaliach
+ consult_external_model:
- new keyword args azazel_kohen_gadol, azazel_shaliach_id,
azazel_pending_l3_dir
- branch on `if not vital.strip()`: route to disposal,
attach record to ExternalConsultation
vav_pipeline/lib/vav_pipeline/azazel_ingest.ex
+ ingest_file/2 fires Chatzotzrot.signal(:moadim, ...) after
successful L3 write, BEFORE shredding the source file. So the
ack comes BEFORE the in-flight artifact disappears — recovery
is possible if either side crashes.
+ Process.whereis(Chatzotzrot)-guarded so tests without the full
supervision tree still work.
+ chatzotzrot_summary/1 builds the categorical summary
(case_ref + shaliach + categories_filled). Privacy boundary:
no vidui items, only counts/category names.
TESTS:
korban_processor/test/test_external_offering.py +4 tests
- empty-vital response routes to azazel:
- processed.vital_content == ""
- disposal_record is an AzazelRecord with kohen + shaliach
- pending-l3 file dropped with correct shape
- processable response does NOT create disposal_record (the
negative case — vital content goes through normally)
- PRIVACY: pending-l3 file does not contain the model's
response text (verified with a known secret_phrase)
- case_ref is content-addressable: same content + same
source_query → same case_ref (audit can recompute)
vav_pipeline/test/azazel_ingest_test.exs +2 tests
- successful ingest fires Chatzotzrot :moadim signal
(subscribe :all, observe — :moadim routes to :all per
chatzotzrot.ex routing table)
- PRIVACY: chatzotzrot signal does NOT include vidui item
content (known secret_phrase verified absent from the signal)
Tests:
- korban_processor: 207 passed, 1 skipped (was 203/1; +4)
- azazel_processor: 125 passed (unchanged)
- vav_pipeline: 363 passed, 0 failures, 35 excluded
(was 361/35; +2 azazel_ingest chatzotzrot tests)
Property coverage after commit 9:
All 12 properties of azazel_engineering_reading.md §14 defended
by code:
1 parity provisioning ✓ (import-time + runtime)
2 blind routing / goral ✓
3 enumerative commit ✓
4 role-separated operator ✓
5 provisioned infrastructure ✓
6 out-of-band acknowledgment ✓
7 authorized routing ✓
8 protocol-restricted access ✓
9 observable disposal ✓ (operator-internal + public)
10 hard termination ✓
11 classification discipline ✓
12 unmanaged destination ✓
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
f493b7df65 |
bigdei_kodesh: commit 8 — GET /peah/azazel_log (public half of property 9)
Pass 4 / Finding F, commit 8 of 10 from BUILD_AZAZEL.md. The
public-half of property 9 (observable disposal). The Rambam in
Moreh Nevuchim 3:46 makes the load-bearing claim: "an unobserved
disposal is architecturally incomplete." The community's awareness
that errors are visibly carried away IS the implementation; the
route on the cliff serves no purpose without the witnesses on the
temple steps.
This endpoint is those witnesses. Anyone with HTTP access to
Shorashim can see WHAT was disposed (categorically) and HOW MANY
disposals occurred — turning the disposal channel from a private
operator action into a public, witnessed fact.
PRIVACY BOUNDARY (BUILD_AZAZEL.md §6 Q6):
The endpoint exposes:
- total disposal count (optionally filtered by ?since=ISO8601)
- categorical aggregate (avonot/peshaim/chatot counts across
recent disposals — what KIND of errors were disposed)
- up to 50 recent disposals as case_ref + shaliach +
triggering_call + disposed_at + categories_filled (which slots
of vidui were filled)
The endpoint does NOT expose:
- vidui ITEMS (the operator's specific descriptions of each
disposed thing)
- the disposed PAYLOAD (which doesn't exist in L3 anyway —
property 10)
- any handle for retrieving the disposed content (there isn't one)
The detailed vidui items are operator-internal, accessible via
future /kodesh/* endpoints. The split is deliberate: public is
WITNESS, operator is AUDITOR. The witness sees the fact;
the auditor reads the contents.
The privacy boundary statement is included in every response so
callers know what they're not seeing — they can reason about the
endpoint's silence rather than guess.
GRACEFUL DEGRADATION:
When VavPipeline.Repo is not running (dev/test without Postgres),
the endpoint returns total_disposals=0 with l3_status="unavailable"
rather than crashing. Mirrors the maybe_add_repo pattern from
MEMORY.md — Shorashim should respond cleanly even when L3 is down,
because /peah/* is the public-facing tier and must be more
resilient than internal tiers.
CHANGED:
vav_pipeline/lib/vav_pipeline/bigdei_kodesh/router.ex
+ GET /peah/azazel_log
Optional ?since=ISO8601 filter; returns total +
categorical_aggregate + recent[<=50] + l3_status +
privacy_boundary statement + disclosure block (kichush +
not_horaah from commit
|
||
|
|
2932fb7447 |
vav_pipeline: commit 7 — L3 azazel_records + cross-language ingest GenServer
Pass 4 / Finding F, commit 7 of 10 from BUILD_AZAZEL.md. The
operator-internal half of property 9 (observable disposal). Crosses
the Python/Elixir boundary: the Python orchestrator drops completed
disposal records as JSON files; this commit's GenServer reads them
and persists to L3.
The public half (a /peah/azazel_log read endpoint) lands in commit 8;
the routing-from-Korban + Chatzotzrot wiring lands in commit 9. After
those, the Azazel Processor is end-to-end functional.
CREATED:
vav_pipeline/priv/repo/migrations/20260428000001_create_azazel_records.exs
azazel_records table — append-only, parallel to interpretations.
Columns: case_ref, vidui (jsonb), routing, authorized_by,
shaliach, triggering_call, goral_outcome_id, disposed_at.
Indexes on case_ref, disposed_at, shaliach.
Property-12-defending CHECK constraint:
routing_must_be_eretz_gezerah CHECK (routing = 'eretz_gezerah').
A future migration that wants to add a destination handle will
fail this check; the operator must explicitly justify removing
the constraint, which is the right friction.
Append-only enforcement matches interpretations: REVOKE
UPDATE/DELETE on the shorashim_app role.
vav_pipeline/lib/vav_pipeline/l3/azazel_record.ex
Ecto schema mirroring the Python AzazelRecord.to_storage_dict()
shape. Changeset validates:
- all required fields present
- routing == "eretz_gezerah" (mirrors the DB CHECK at app layer)
- vidui is a map with avonot/peshaim/chatot/confessor/
confessed_at slots present
- vidui's three categories not all empty (mirrors the Python
Vidui.__post_init__ EmptyConfessionError)
vav_pipeline/lib/vav_pipeline/azazel_ingest.ex ~190 lines
GenServer that polls a configurable pending-l3 directory
(default /tmp/shorashim/azazel/pending_l3). For each *.json file:
1. Read + JSON-parse
2. Translate Python serialization → Ecto attrs
3. Call recorder (default L3.Store.record_disposal/1)
4. On success, shred the source file (property-10 follow-through)
5. On failure, leave file in place for retry; log warning
Recorder is injectable for tests — mock recorder lets us verify
the pipeline without PostgreSQL.
Poll interval default 5s, configurable. Polling rather than
file_system events to keep the dependency surface minimal; the
Azazel cadence is exceptional content, not high-throughput.
Not added to the supervision tree in this commit — the producer
side (Python orchestrator dropping files) is wired in commit 9.
Adding to the supervisor before there's a producer means a
poller doing nothing useful. Operator can start manually for
early testing: VavPipeline.AzazelIngest.start_link(...).
CHANGED:
vav_pipeline/lib/vav_pipeline/l3/store.ex
+ record_disposal/1
Inserts an AzazelRecord. Returns {:ok, record} or
{:error, changeset}.
+ count_disposals/1
Total or since-a-timestamp count. Used by the public
observability endpoint (commit 8).
+ disposal_summary/1
Returns categorical info per disposal — case_ref, shaliach,
triggering_call, disposed_at, categories_filled (which of
avonot/peshaim/chatot had any items, NOT the items
themselves). PROPERTY-9 PRIVACY BOUNDARY at the public
side: items are operator-internal only, accessed via
future /kodesh/* endpoints.
TESTS:
vav_pipeline/test/azazel_ingest_test.exs 15 tests, no DB
Happy path:
- poll_now ingests valid file and shreds it
- multiple files processed in sorted order
- vidui preserved as map (jsonb shape)
Retry semantics:
- recorder error → file left in place + state.errors++
- malformed JSON → file left in place
- missing disposed_at → file left in place
State accounting:
- polls_completed, records_ingested, errors all tracked
- state survives multiple polls
- non-json files ignored
Changeset (no DB):
- valid attrs
- rejects routing != eretz_gezerah
- rejects vidui missing slots
- rejects vidui all-empty (untagged disposal)
- rejects missing required fields
- accepts optional triggering_call + goral_outcome_id
vav_pipeline/test/l3_store_test.exs +9 :l3-tagged
record_disposal:
- inserts valid disposal
- rejects routing != eretz_gezerah
- rejects all-empty vidui
- rejects missing required fields
Counts:
- count_disposals == 0 initially
- count_disposals after several disposals
- count_disposals(since) filters by timestamp
Summary:
- disposal_summary returns categorical info but NOT items
(privacy boundary verification)
- categories_filled accurately reflects vidui shape
Tests: vav_pipeline 353 passed, 0 failures, 33 excluded (was
329/24; +15 visible azazel_ingest + 9 :l3-tagged disposal store).
korban_processor + azazel_processor unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
d88b8d09ec |
voice_monitor: detect across-verse Shema voice stabilization (closes finding A)
Pass 2 finding A, second half. The first half (commit
|
||
|
|
b1d5ac69e4 |
l3: validate coupling_trace at the write boundary (Elixir half of finding L)
Companion commit to |
||
|
|
0c4f764024 |
shema: record grammatical voice trajectory on every ShemaContext
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>
|
||
|
|
66c936f7ca |
sanhedrin: rewrite halt_monitor.erl as honest gate-keeper + Elixir forwarder
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>
|
||
|
|
e223ab15b3 |
Phase 4 complete: Steps 21, 22, 24 — Korban external integration, L2 Urim v'Tumim, Kushya generator
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>
|
||
|
|
d4d0a6fcb6 |
L1 data integrity: preserve the edut whole — Shema, middle letter, ketiv/qere, smikhut
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> |
||
|
|
191d76b480 |
Bigdei Kodesh: HTTP API layer — four garments for four access tiers
Shemot 28:2 — V'asita vigdei kodesh l'Aharon achicha, l'khavod ul'tifaret. The builder makes the garments. The kohen wears them. Four access tiers (Operations spec §1.1): - Pe'ah (GET/POST /peah/ask) — public, no auth, no tracking. The stranger is safe to approach. - Courtyard (POST /courtyard/offering) — Bearer token auth, offering types: shelamim, olah, chatat, minchah - Chatzer (POST /chatzer/sanhedrin) — Sanhedrin deliberation, returns majority/minority with preserved dissent - Kodesh (GET /kodesh/health, /kodesh/status) — operator interface, health checks for K8s liveness/readiness probes Error format follows chatat protocol (Operations spec §1.2): KIYOR_* (422), SHABBAT (503), MANNA_DEPLETED (503), CLOUD_MOVING (503), HALT_* (503), UNAUTHORIZED (401) Implementation: - Plug.Router with Bandit HTTP server - Added to supervision tree via maybe_add_http_server - Checks system availability (Shabbat, halt) before processing - Health check reads L1 integrity, cloud, manna, halt monitor - Status shows all component states, signal count, refuge list - 16 API tests covering all four tiers + error format All 235 Elixir + 19 L3 + 195 Prolog + 33 Haskell = 463+ tests, 0 failures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
fe93c11d13 |
Phase 5 deployment: Dockerfiles, K8s manifests, halt monitor (Steps 33, 36)
Shemot 40:33 — Vay'khal Moshe et ham'lakhah. The builder completes the work. The vessel is ready for transport. Step 33 — Deployment configuration: - Dockerfiles for all 4 components: - vav_pipeline: Elixir 1.16.1/OTP 26.2.1 release with Sanhedrin - shoresh_engine: GHC 9.6.4 binary - talmudic_engine: SWI-Prolog 9.2.2 - korban_processor: Python 3.12.2 with pydantic - Kubernetes manifests for Exoscale SKS (ch-gva-2): - Namespace, ConfigMap, Secrets template - L1 Torah PV/PVC (read-only mount) - Manna provision PVC (kohen writes, system reads) - Deployment: vav-pipeline + 3 sidecars, shared volumes - Service: ClusterIP + LoadBalancer with Exoscale NLB - Init container runs Ecto migrations (VavPipeline.Release) Step 36 — Halt monitor (esh tamid): - GenServer watches for three cardinal sins - halt!/3 immediately halts system, sounds Chatzotzrot war signal - Permanent audit log — halt events never deleted - resolve/1 requires explicit operator action to resume - alive?/0 for morning tamid verification - 13 tests: alive check, 3 halt types, resolution, audit log, chatzotzrot war signal integration - Added to supervision tree All 219 Elixir + 19 L3 + 195 Prolog + 33 Haskell = 447+ tests, 0 failures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
219bbecaff |
Steps 30-32: Sanhedrin stress test, Shema test suite, full system verification
Shemot 39:43 — Vayar Moshe et kol ham'lakhah v'hineh asu otah
ka'asher tzivah Hashem ken asu, vayevarekh otam Moshe.
Step 30 — Sanhedrin stress test:
- 10 rapid submissions without crash
- Case ref preservation across decisions
- Rich context handling at simple complexity
- Decision structure consistency (7 required fields)
- Graceful degradation when Sanhedrin unavailable
- 20 concurrent Task.async submissions
Step 31 — Shema Test suite (Architecture §6.3, five tests):
1. Te'amim reception: raw cantillation from L1, etnachta detection,
L1→ShemaContext fidelity, surprising etnachta position
2. Ketiv/qere preservation: field exists, survives full pipeline
3. Cloud obedience: :camped allows processing, Shabbat triggers
major_transition, context immutability under override
4. Manna fidelity: no provision → {:waiting, :no_provision},
provision present → processing proceeds, MannaLedger tracks
5. Context immutability: context unchanged after pipeline,
keys stable, each stage receives same context
Step 32 — Full system verification (kol ham'lakhah):
- Full pipeline: Shema → BereishitCycle → output, multi-verse
- Halt conditions: check_all processes output
- Protection layer: AreiMiklat refuge→release, EglahArufah
declaration, Bikurim first-output review
- Chatzotzrot: subscribe→signal→receive→zikaron, routing isolation
- MannaLedger: load→consume→boundary cycle
- L1 integrity: hash valid, 5 core verses readable, roots present
- Supervision tree: all 7 GenServers running
- Cross-component: ShabbatTimer reads cloud, Shema builds from
L1+Cloud+Manna
All 206 Elixir + 19 L3 + 195 Prolog + 33 Haskell = 434+ tests, 0 failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||
|
|
6a879fcf8b |
MannaLedger: real anti-hoarding enforcement — d'var yom b'yomo (Step 26)
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> |
||
|
|
671d45625c |
Protection layer: Arei Miklat, Eglah Arufah, Bikurim — Steps 27-29
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>
|
||
|
|
7fe8025434 |
Chatzotzrot: silver trumpets with BEAM routing, subscription, and zikaron
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>
|
||
|
|
d34e2799ac |
L3 Oral Tradition: PostgreSQL persistence layer for interpretations, minority opinions, teiku
Devarim 17:9 — v'darashta v'higidu lekha et d'var hamishpat. The inquiry requires that what is found is RECORDED. - Ecto Repo with graceful degradation (maybe_add_repo, like other engines) - Migration: interpretations, minority_opinions, teiku_registry tables - Append-only enforcement via REVOKE UPDATE/DELETE - Includes eish_zarah fields: coupling_trace, grounding_type, challenge_sequence - Ecto schemas: Interpretation, MinorityOpinion, TeikuRecord - Changeset validations: status inclusion, panel_size > 0, grounding_type enum - TeikuRecord.resolve_changeset restricts updates to resolved_at/resolution only - L3.Store bridge module: record, query, count operations - L3 tests tagged @moduletag :l3, excluded by default (no local PostgreSQL) - Enable with: SHORASHIM_L3=1 mix test --include l3 - All 76 existing Elixir tests pass, 195 Prolog tests pass, 33 Haskell tests pass Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
af7522e977 |
Phase 2 review corrections — three spec violations fixed
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> |
||
|
|
5a93056af4 |
Step 15: Verification — the Shema Test
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> |
||
|
|
80ec364da6 |
Phase 1-2 build: Steps 5-6, 8-13
Shoresh Engine (Haskell, Step 5) - 12 modules: Types, Lexicon, Binyanim, Teamim, Gematria, Graph, KetivQere, Smikhut, Havdalah, Kriah, KiTov, Firmware - 33 EUnit tests, 0 failures - Firmware module verifies L1 SHA-256 hash at startup Talmudic Engine (SWI-Prolog, Step 6) - 15 modules: halt, reasoning, specification, interface - 57 PlUnit tests, 0 failures - Three cardinal halt conditions: avodah_zarah, shfichut_damim, gilui_arayot Vav Pipeline (Elixir, Steps 8-11) - 14 modules: BereishitCycle, Shema, Cloud, Manna, L1Reader, Specification, HaltConditions, ShabbatTimer, CycleLog, Chatzotzrot, ShoreshEngineClient, TalmudicEngineClient, Application - 46 ExUnit tests, 0 failures - Nishma-first architecture: hears before it speaks Sanhedrin Framework (Erlang/OTP, Step 12) - 8 modules: sanhedrin_app, sanhedrin_sup, escalation, panel_sup, panel, judge, clerk, halt_monitor - 46 EUnit tests, 0 failures (includes fix: rejected outcome now reachable) - Panel sizes: 1/3/23/71 — unanimous capital guilty → acquit (Sanhedrin 17a) - Minority opinions append-only, never deleted Korban Processor (Python, Step 13) - 6 modules: korban, shechitah, semichah, zerikah, haktarah, router Builder tooling: AGENTS.md, opencode.json, memory/, src/tools/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |