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>
This commit is contained in:
1 parent
7d46fdc7c9
commit
3a9ebdc7d4
17 files changed
+141
-16
No files matched your search
@@ -175,7 +175,7 @@ defmodule VavPipeline.Doorpost do
|
||||
# changes; the update is a deliberate operator commit. A bare
|
||||
# hash-update commit (without a corresponding spec change in the
|
||||
# same commit) is itself a drift signal.
|
||||
@expected_hash "b62311e7541277f3881f074e2e884b742f6f85bd2de8b4890f44e978d06a3f21"
|
||||
@expected_hash "3bc5dd6aa4d76eeb8c0bc2ee4d7d33b7f35bc1dc8e03dc76697acc33eec8e245"
|
||||
|
||||
@doc "Return the list of files that constitute the category-grade specification."
|
||||
@spec files() :: [String.t()]
|
||||
|
||||
@@ -17,7 +17,7 @@ defmodule VavPipeline.L1Reader do
|
||||
# Updated after build_l1.py fix: enlarged letters (Shema's ayin/dalet, gachon's
|
||||
# vav, mishpatan's nun), ketiv/qere pairs, and smikhut construct pairs are now
|
||||
# preserved in L1 rather than silently dropped.
|
||||
@l1_expected_hash "f743b34b83617c328ec190e78ea1402470938e460b9701aec465c3f1613f1494"
|
||||
@l1_expected_hash "9e1abe4edabac825d8a7037606ff247c3e8f8167650f04553f46c34e4f3c3086"
|
||||
|
||||
@type letter_mark :: %{letter: String.t(), offset: non_neg_integer()}
|
||||
|
||||
@@ -64,7 +64,8 @@ defmodule VavPipeline.L1Reader do
|
||||
words: [word()],
|
||||
ketiv_qere: [ketiv_qere_entry()],
|
||||
smikhut: [smikhut_pair()],
|
||||
parashah_breaks: [parashah_break()]
|
||||
parashah_breaks: [parashah_break()],
|
||||
inverted_nuns: [%{after_word: pos_integer()}]
|
||||
}
|
||||
|
||||
@doc """
|
||||
@@ -386,7 +387,13 @@ defmodule VavPipeline.L1Reader do
|
||||
words: Enum.map(data["words"] || [], &normalize_word/1),
|
||||
ketiv_qere: Enum.map(data["ketiv_qere"] || [], &normalize_ketiv_qere/1),
|
||||
smikhut: Enum.map(data["smikhut"] || [], &normalize_smikhut/1),
|
||||
parashah_breaks: Enum.flat_map(data["parashah_breaks"] || [], &normalize_parashah_break/1)
|
||||
parashah_breaks: Enum.flat_map(data["parashah_breaks"] || [], &normalize_parashah_break/1),
|
||||
# Nun hafukha (׆) — recorded, like a paragraph break, by the word it
|
||||
# follows. Two in Torah: after Bamidbar 10:34 and after 10:36.
|
||||
inverted_nuns:
|
||||
for %{"after_word" => n} when is_integer(n) <- data["inverted_nuns"] || [] do
|
||||
%{after_word: n}
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ defmodule VavPipeline.ShemaVoiceTrajectoryTest do
|
||||
stabilizing at one pole — which is the algorithmic shape of "you have
|
||||
forgotten the One who took you out of Egypt".
|
||||
|
||||
Anchoring verses (text from L1, hash f743b34b…):
|
||||
Anchoring verses (text from L1, hash 9e1abe4e…):
|
||||
Devarim 6:5 וְאָהַבְתָּ … אֱלֹהֶיךָ … לְבָבְךָ — uniformly 2ms
|
||||
Devarim 11:13 וְהָיָה אִם־שָׁמֹעַ תִּשְׁמְעוּ … אֱלֹהֵיכֶם — 2mp
|
||||
Devarim 11:14 אַרְצְכֶם (2mp) → וְאָסַפְתָּ דְגָנֶךָ (2ms)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
defmodule VavPipeline.Tablet40InvertedNunsTest do
|
||||
@moduledoc """
|
||||
Tablet 40 (2026-10-04) — the inverted nuns.
|
||||
|
||||
*Vayehi binsoa ha'aron* (Bamidbar 10:35–36) is marked off in the scroll
|
||||
by a nun hafukha before it and after it. The WLC carries both signs; the
|
||||
builder read past them. They are now engraved on the verse each one
|
||||
follows — 10:34 and 10:36 — and the reader carries them.
|
||||
"""
|
||||
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias VavPipeline.L1Reader
|
||||
|
||||
test "an inverted nun follows Bamidbar 10:34 and another follows 10:36" do
|
||||
for verse <- [34, 36] do
|
||||
{:ok, v} = L1Reader.read_verse("bamidbar", 10, verse)
|
||||
assert v.inverted_nuns == [%{after_word: length(v.words)}], "Bamidbar 10:#{verse}"
|
||||
end
|
||||
end
|
||||
|
||||
test "the two verses between them carry none — the signs bracket the passage" do
|
||||
{:ok, v35} = L1Reader.read_verse("bamidbar", 10, 35)
|
||||
assert v35.inverted_nuns == []
|
||||
assert hd(v35.words).consonants == "ויהי"
|
||||
assert Enum.at(v35.words, 1).consonants == "בנסע"
|
||||
end
|
||||
|
||||
test "each nun stands with a setumah, and neither is in the verse's text" do
|
||||
for verse <- [34, 36] do
|
||||
{:ok, v} = L1Reader.read_verse("bamidbar", 10, verse)
|
||||
assert v.parashah_breaks == [%{after_word: length(v.words), type: :setumah}]
|
||||
refute v.text_hebrew =~ "׆"
|
||||
end
|
||||
end
|
||||
|
||||
test "there are exactly two in the whole scroll" do
|
||||
index = L1Reader.l1_root() |> Path.join("torah/index.json") |> File.read!() |> Jason.decode!()
|
||||
|
||||
refs =
|
||||
for book <- index["books"],
|
||||
{chapter, verses} <- book["chapter_verse_counts"],
|
||||
verse <- 1..verses,
|
||||
{:ok, v} = L1Reader.read_verse(book["book"], String.to_integer(chapter), verse),
|
||||
v.inverted_nuns != [],
|
||||
do: v.ref
|
||||
|
||||
assert Enum.sort(refs) == ["Bamidbar 10:34", "Bamidbar 10:36"]
|
||||
end
|
||||
|
||||
test "every other verse carries an empty list, not a missing field" do
|
||||
{:ok, v} = L1Reader.read_verse("bereishit", 1, 1)
|
||||
assert v.inverted_nuns == []
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user