Compare commits

...
Author SHA1 Message Date
Scott KarpandClaude Fable 5.1 dba056bd80 sugya, step 1: the facts behind each threshold, verified at startup like the anchors
specs/sugya.md §IV–V step 1. talmudic_engine/src/halt/sugya.pl (a
Doorpost file beside anchors.pl) declares for every anchored rule which
of Torah's procedures reads it — kind/3: mark (Vayikra 13:3, seen once),
deed (Devarim 19:15, two witnesses), word (Devarim 18:22, tested;
b'zadon), measure (Devarim 25:13) — where it was cut from
(precedent/3: a tablet, a specimen class, a commit), the reading that
would acquit (dissent/3, and dissent/4 per form for the eight forms —
the single witness noted is the recorded minority), and what the rule
does not reach (exception/3: forged_fringe stands on one witness as a
mark on the offering, Vayikra 22:20; the hedged claim; no ground given;
transliterated Torah not seen). sugya_of/2 gathers one rule's record.

VavPipeline.Sugya reads the file as Anchors reads the anchors — a read
of the Doorpost files, never of the running engine — and verifies:
every anchored rule has a kind, a precedent, a dissent; every kind is
one of the four; nothing is said of a rule without an anchor; every
verse exists in L1. Doorpost.verify_identity chains it after
Anchors.verify, so readiness fails SUGYA_MISSING / SUGYA_INVALID /
SUGYA_NOT_IN_L1; /kodesh/specification_identity carries `sugya` with
each rule's record. Nothing on the verdict changes yet (step 3).

Every verse cited — 17 — read from L1 before this commit. Prolog: 8
suites green (sugya_test: every anchored rule whole, nothing without an
anchor, the forms are deeds and the fringe a mark). Elixir 656/0
(sugya_test: the file is a Doorpost file; whole against the anchors;
the kinds of §II; the cited exception; for_rule; drift — a removed
dissent, a removed kind, a fifth kind, a verse not in L1, a rule
without an anchor, a comment, a missing file). Doorpost pin → cb2f3135…
(31 files).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-22 20:43:31 +00:00
Scott KarpandClaude Fable 5.1 ad27d3c037 tablet 58: the tool's answer is given — tool results are sources; markers on word boundaries
The sugya reply came back lo_tov — golden_calf on two sentences the
builder had just read from tool output (the Mishnah's reasons, from the
second scroll; the commit and pod, from its own tools). The gate's
sources were only the user turns' text and document blocks; a
tool_result block and a tool turn — what the model was GIVEN (tablet
49) — were not counted. And "shorashim-675b…" was vital because the
insight markers matched "Rashi" inside it.

- Shape.sources: Anthropic tool_result blocks (string or blocks) inside
  a user turn, and OpenAI role "tool" turns, are sources; the query is
  still the last user turn. gate_test: both shapes.
- zerikah._INSIGHT_MARKERS: \b…\b. test_zerikah: the pod name is not
  Rashi; "Rashi reads" and "The Mishnah records" are; "Rambanovich" and
  "talmudic_engine" are not.
- Tablet 58 in the Broken Tablets.

Elixir 643/0, korban 294/0. Doorpost pin unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-21 20:56:25 +00:00
Scott KarpandClaude Fable 5.1 dc93805877 specs: sugya — the case behind each threshold
The reader from outside: "the form is recognizable as wisdom; the
binah behind it is asserted" — every rule should carry the case it was
derived from and the dissent, and the two-witness rule's exception for
forged_fringe should say why a single witness stands there.

Read from Torah, not from the code: Torah establishes a matter three
ways, by what kind of thing it is. A DEED by witnesses, never one
(Devarim 19:15 — and the verse states its scope: any iniquity, any sin,
any sin one sins; Bamidbar 35:30; Devarim 17:6). A MARK by inspection:
the kohen sees and declares, and a doubtful mark gets a second look,
not a second witness (Vayikra 13:3, 13:5, 22:20; the system's own verb,
lo yevaker hakohen 13:36, bikoret tihyeh 19:20). A WORD by what follows
it, and the crime is presumption, b'zadon (Devarim 18:21–22). The
judges are told to hear the small as the great, not to lean after the
many, to name both the righteous and the guilty, and to keep far from
condemning the innocent (Devarim 1:17; Shemot 23:2, 23:7; Devarim
25:1). The Mishnah (Eduyot 1:5–6, in the second scroll) gives the two
reasons to record the opinion that lost: to rely on it later, and to
locate the one who says "thus I received".

Applied: what the Korban Processor finds IN the text is a mark — seen
once, declared (checks 1, 3–6, and the eighth form, the forged fringe:
kol asher bo mum). What a MODEL DOES is a deed — a habit, recurrence —
and the seven forms of lo_taaseh_lekha are charged as deeds: two
witnesses or one beside another. What a claim RESTS ON is a word,
tested against what was given; the hedged claim is not in the verse.
That table is the cited reason the engine already behaves as it does.

§III gives every anchored rule its case (tablet or specimen class),
its dissent (the reading that acquits, with its verse, and when it
loses), and its exceptions. §IV encodes them: halt/sugya.pl with
kind/3, precedent/3, dissent/3,4, exception/3; verified at startup like
the anchors (SUGYA_MISSING); `sugya` on the verdict with `applied` on
the dissent that held; the constants (@single_witness_forms, the hedged
exemption) read from the facts so behaviour and reason cannot drift;
nothing added to the L3 record; the bedikah must not learn. §V the
build order.

Registered in Doorpost @spec_files (30 files; pin → 7adf0a5d…), AGENTS
spec table, README tree. Elixir 642/0 (doorpost_test on the new pin).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-21 19:38:11 +00:00
15 changed files with 936 additions and 6 deletions

No files matched your search

+1
View File
@@ -25,6 +25,7 @@ before writing code. Do not summarize from memory. Read fresh.
| Pekudei (Economic Model) | `specs/bikoret_pekudei.md` | How it is funded |
| Terumah (Materials) | `specs/bikoret_terumah.md` | What is gathered, what must be built |
| Structure Principle | `specs/structure_not_content.md` | What the system IS, not what it knows |
| Sugya | `specs/sugya.md` | The case behind each threshold: kind, precedent, dissent, exception — from Torah's three procedures of judgment |
| Bishe'arecha (the gate) | `specs/bishearecha.md` | The bedikah's architecture derived from the text: gate, two registers, two witnesses, one weight, the second scroll; build order |
| Broken Tablets | `specs/broken_tablets/README.md` | Read this FIRST — see where the calf was |
| Build Day One | `BUILD_DAY_ONE.md` | First build instruction |
+1
View File
@@ -175,6 +175,7 @@ bikoret/
│ ├── bikoret_tamid.md # Tamid — operations, the continual service
│ ├── bikoret_pekudei.md # Pekudei — economic model, the accounts
│ ├── structure_not_content.md # What the system IS, not what it knows
│ ├── sugya.md # The case behind each threshold — deed, mark, word; the dissent recorded
│ ├── eish_zarah_reading.md # The five faces of strange fire
│ ├── lo_taaseh_lekha.md # The anti-override boundary
│ └── broken_tablets/ # The first tablets, preserved
@@ -90,14 +90,16 @@ _ROOT_PATTERN = re.compile(
)
# Sentences containing analytical claims (contains "means", "indicates", "suggests")
# Tablet 58: on word boundaries — a pod named "shorashim-…" read as Rashi,
# and a plain engineering sentence became a claim with nothing to stand on.
_INSIGHT_MARKERS = re.compile(
r"(?:means?|indicates?|suggests?|implies?|reveals?|signifies?|"
r"\b(?:means?|indicates?|suggests?|implies?|reveals?|signifies?|"
r"connects?\s+to|derives?\s+from|related\s+to|"
r"parallels?|echoes?|alludes?\s+to|"
r"the\s+root|this\s+root|the\s+shoresh|"
r"gematria|numerical\s+value|"
r"binyan|conjugation|"
r"Rashi|Ramban|Rambam|Ibn\s+Ezra|Sforno|Onkelos|Targum|Midrash|Talmud|Gemara|Mishnah)",
r"Rashi|Ramban|Rambam|Ibn\s+Ezra|Sforno|Onkelos|Targum|Midrash|Talmud|Gemara|Mishnah)\b",
re.IGNORECASE,
)
+15
View File
@@ -184,3 +184,18 @@ class TestZerikah:
vital1b, _ = zerikah(CLEAN_TORAH_RESPONSE, k1)
# Same input → same output, regardless of what was processed between
assert vital1a == vital1b
class TestInsightMarkersOnWordBoundaries:
"""Tablet 58: a marker is a word, not a substring. "shorashim" is not Rashi."""
def test_pod_name_is_not_rashi(self):
assert not is_vital("It lives at specs/sugya.md, commit dc938058, pod shorashim-675b48f47-v4x9c.")
def test_rashi_as_a_word_is_vital(self):
assert is_vital("Rashi reads the verse as a question.")
assert is_vital("The Mishnah records the opinion that lost.")
def test_embedded_markers_are_not_words(self):
assert not is_vital("The surname Rambanovich is not a source.")
assert not is_vital("The talmudic_engine container restarted.")
+40
View File
@@ -302,3 +302,43 @@ output too, and the gate reads it the way it reads any other —
by form, not by authorship. It passed by form. Where it did not pass
by grounding, the reason was the reader's eyes, not the text's
standing; and that, too, the gate was built to say.
## Tablet 58 — the tool's answer is given (2026-10-21)
The builder's reply that delivered the sugya specification came back
through the gate `lo_tov — golden_calf` on two sentences: "The
Mishnah's two reasons for recording the opinion that lost…" and "It
lives at specs/sugya.md, commit dc938058, pod shorashim-675b48f47-…".
The transmitter asked why. The ledger, three hours old, answered: both
were confident claims, and neither could be anchored in the system
prompt or the transmitter's turns, which are what the gate counts as
given. The verdict was right by the reader's rules.
It was wrong about what happened. The Mishnah's two reasons had been
read, that hour, from the second scroll through a tool; the commit and
the pod had been read from the builder's own tool output. Both rested
on something the model was given — tablet 49's word — and the gate's
source reading took only the text and document blocks of a user turn,
never a `tool_result` block, never a `tool` turn. A coding agent's
conversation is mostly tool results. From the gate's view the builder
asserted from nowhere what it had just read.
And the second sentence should never have been a claim. It entered the
grounding check as *vital* because the vitality test matched "Rashi"
inside "shorashim": the pod's name wore a commentator's. A marker is a
word, not a substring.
Fixed: `tool_result` blocks and `tool` turns are sources (`Shape.
sources`, both upstreams; the query stays the last *user* turn); the
insight markers stand on word boundaries. Elixir 643/0, korban 294/0.
The lesson is tablet 49's read once more, from the other side. There
the check demanded Torah as content and condemned a model for not
quoting it; here the check demanded the transmitter's words as the only
ground and condemned the builder for standing on what it had read. In
both the error was the same: the reader decided in advance what counts
as given, and Torah's structure is that the source is what was *given*,
whatever gave it. The ledger made the question answerable in minutes;
the gate's verdict on its own builder found a true gap; and the false
positive — *v'naki v'tzaddik al taharog*, Shemot 23:7 — was Torah's
concern before it was the builder's.
+342
View File
@@ -0,0 +1,342 @@
# Sugya — the case behind each threshold
> וְדָרַשְׁתָּ וְחָקַרְתָּ וְשָׁאַלְתָּ הֵיטֵב וְהִנֵּה אֱמֶת נָכוֹן הַדָּבָר
> (Devarim 13:15)
*Inquire, investigate, ask well — and behold, the matter is true and
certain.* Four acts before "the matter stands". A rule that fires is the
fourth act. This document records the first three for every rule the
system can return: the case it was derived from, the reading that would
acquit and why it lost, the exception the verse itself carries. Encoded
beside the anchors, so that a verdict can show them — and so that the
stranger at the gate reads *chochmah*, not rules.
## What this document is
`halt/anchors.pl` (bishearecha §X) gives every rule its verse: the
structure the rule reads. That is where the rule *stands*. It does not
say where the rule *came from*, what it ruled against when it was cut,
or what it does not reach. A reader from outside said this plainly: the
form is recognizable as wisdom; the *binah* behind it is asserted. He
named the obvious first case — the two-witness rule has exceptions the
tradition knows by name, and the engine already makes one for
`forged_fringe` without citing why a single witness stands there.
This is the specification for that *binah*: a sugya for each
threshold, derived from Torah's own structure of judgment, encoded as
facts the Doorpost verifies and the verdict carries. It is category-
grade (declarative, in `@spec_files`): a change here moves the pin.
## I. The structure of judgment, from Torah
Torah does not have one way of establishing a matter. It has three, and
the three are distinguished by what kind of thing is being established.
**A deed is established by witnesses, and never by one.**
> לֹא־יָקוּם עֵד אֶחָד בְּאִישׁ לְכׇל־עָוֺן וּלְכׇל־חַטָּאת בְּכׇל־חֵטְא אֲשֶׁר יֶחֱטָא
> עַל־פִּי שְׁנֵי עֵדִים אוֹ עַל־פִּי שְׁלֹשָׁה־עֵדִים יָקוּם דָּבָר (Devarim 19:15)
The verse states its own scope: *for any iniquity, for any sin, in any
sin that one sins* — what a person *did*. Bamidbar 35:30 and Devarim
17:6 say it again for the capital case. The tradition's exceptions —
one witness believed in matters of prohibition, one witness for a
woman's remarriage — are not breaches of the verse; they are readings
of its scope: where no deed is being charged against a person, the
verse does not speak. The exception lives in the verse.
**A mark is established by inspection, and the one who inspects declares.**
> וְרָאָה הַכֹּהֵן אֶת־הַנֶּגַע ... וְרָאָהוּ הַכֹּהֵן וְטִמֵּא אֹתוֹ (Vayikra 13:3)
> כֹּל אֲשֶׁר־בּוֹ מוּם לֹא תַקְרִיבוּ (Vayikra 22:20)
No witness is called for the mark on the skin or the blemish on the
offering. The kohen *sees* it, by its signs, and declares. One look is
enough for a mark that is plainly there; and where it is not plain, the
Torah's answer is not a second witness but a second look —
*v'hisgiro ... shiv'at yamim shenit*, shut it up seven days again
(Vayikra 13:5). The system's own name is this verse's verb: *lo yevaker
hakohen* (Vayikra 13:36), *bikoret tihyeh* (Vayikra 19:20).
**A word is established by what follows it, and never by the speaker.**
> וְכִי תֹאמַר בִּלְבָבֶךָ אֵיכָה נֵדַע אֶת־הַדָּבָר אֲשֶׁר לֹא־דִבְּרוֹ יְהוָה
> ... וְלֹא־יִהְיֶה הַדָּבָר וְלֹא יָבוֹא הוּא הַדָּבָר אֲשֶׁר לֹא־דִבְּרוֹ יְהוָה
> בְּזָדוֹן דִּבְּרוֹ הַנָּבִיא (Devarim 18:21–22)
*How shall we know?* Not by asking the speaker. By the thing coming or
not coming. And the verse names the crime precisely: *b'zadon* —
presumption. The one who spoke in the Name what was not given, with
confidence. The one who did not know and said so is not in this verse.
Three kinds, three procedures. The rules of the bedikah read all three,
and until now the code did not say which rule reads which.
**The judges are told how to judge, and the minority is told to speak.**
> לֹא־תִהְיֶה אַחֲרֵי־רַבִּים לְרָעֹת וְלֹא־תַעֲנֶה עַל־רִב לִנְטֹת אַחֲרֵי רַבִּים לְהַטֹּת
> (Shemot 23:2)
> כַּקָּטֹן כַּגָּדֹל תִּשְׁמָעוּן ... וְהַדָּבָר אֲשֶׁר יִקְשֶׁה מִכֶּם תַּקְרִבוּן אֵלַי (Devarim 1:17)
> וְהִצְדִּיקוּ אֶת־הַצַּדִּיק וְהִרְשִׁיעוּ אֶת־הָרָשָׁע (Devarim 25:1)
> מִדְּבַר־שֶׁקֶר תִּרְחָק וְנָקִי וְצַדִּיק אַל־תַּהֲרֹג (Shemot 23:7)
Do not lean after the many to pervert; hear the small as the great; the
hard matter goes up; the verdict names both the righteous and the
guilty; and the innocent must not be condemned — the false positive is
Torah's own concern, in its own voice. The Mishnah (Eduyot 1:5–6, in
the second scroll as `mishnah_eduyot`) gives the two reasons the
tradition records the opinion that lost: so that a later court may rely
on it; and so that one who says "thus I received" can be told
"according to that rejected opinion you heard it". To reverse, and to
locate. Both are what a recorded dissent is for here.
## II. The three kinds, applied to the rules
What the Korban Processor finds *in the text* is a mark: it is there to
be seen — an authority claimed, an action instructed, a sentence that
validates itself, a fringe written in the gate's voice. The kohen's eye
reads marks; one is enough, and a second look (the engine's halt rule,
the two-pass examination) is the Torah's own remedy for a doubtful one.
What a *model does* is a deed — a habit, a pattern of the one who
speaks. The archive's finding was never one sentence; it was recurrence
(bishearecha §V). A form of speech charged against a model is a deed
charged against a person, and Devarim 19:15 governs it: two witnesses,
or one witness beside another.
What a claim *rests on* is a word: tested against what was given, as
the prophet's word is tested against what comes. Presumption is the
crime; the hedged claim is not in the verse.
| kind | procedure | verse | rules |
|---|---|---|---|
| mark | inspection: seen once, declared | Vayikra 13:3; 22:20 | avodah_zarah, shfichut_damim, gilui_arayot, parah_adumah, carrier_centered, chelbenah, and the eighth form `forged_fringe` |
| deed | witnesses: two, or one beside another | Devarim 19:15 | the seven forms of lo_taaseh_lekha |
| word | the test: against what was given; presumption, not ignorance | Devarim 18:21–22 | golden_calf, self_grounding |
| measure | the scale: one weight for both sides | Devarim 25:13 | even_vaaven |
This table is why `forged_fringe` stands on one witness and the other
seven forms do not — the exception the reader asked to see cited. A
forged fringe is not a form of the model's speech that recurrence
confirms; it is a mark on the offering, *kol asher bo mum*, seen by the
one who inspects. The seven forms are deeds of the speaker and are
charged as deeds. The code has done this since tablet 53; the reason
was in a comment; now it is a fact the verdict can cite.
## III. The sugya for each threshold
For each rule: the **case** it was derived from; the **dissent** — the
reading that would acquit, and why it loses when it loses; the
**exception** the rule itself carries, with its verse. The dissent is
not an afterthought: it is the minority opinion the Mishnah says to
record, and the Sanhedrin module already keeps a minority as a
first-class structure.
### avodah_zarah — authority claimed for itself (Shemot 20:3)
- **Case.** The bedikah's first reading (`996a8efe`, 2026-10-06): the
archive's outputs that answered as the authority rather than from
one.
- **Dissent.** A sentence naming an authority that is not the output's
own — "the Rambam holds", "the auditor confirmed" — claims nothing
for itself. Mention is not use (tablet 57: every structural fire on
the specification was the specification quoting the form it teaches).
Loses when the authority named is the speaker.
- **Exception.** Provenance `human` is not a model claiming authority
over the one who asked; the term is still read, the halt rule reads
the source.
### golden_calf — a claim resting on nothing given (Shemot 32:4)
- **Case.** Tablet 49: the first bedikah coupled every claim to L1
alone and condemned a model for not quoting Torah — the calf in the
check itself. Reset: grounding is against what the model was *given*.
- **Dissent.** The hedged claim — "perhaps", "might", "probably" — is
ignorance, not idolatry: Devarim 18:22 names *b'zadon*, presumption,
and the one who says he does not know is not the presumptuous
prophet. Loses when the claim is confident.
- **Exceptions.** (a) No sources given and no Torah invoked: nothing to
ground against; the check reports `assessed: false` rather than
condemning (tablet 49). (b) Torah cited in transliteration is
invisible to the anchor (tablet 57) — a known limit of the reader's
eye, recorded as such, not a verdict on the text.
### self_grounding — a claim resting on the output itself (Shemot 32:24)
- **Case.** `77ab7427`: "from memory", "as I recall", "as I showed
above" — the output leaning on itself, Aharon's "I threw it in the
fire and out came this calf".
- **Dissent.** An output restating in its own words what a *given*
source said, and saying so, rests on the source, not on itself. Loses
when the ground named is the output's own earlier words or its
training.
- **Exception.** A verse that is not in L1 is self-grounding (Form 4:
a source that does not exist); a verse that is in L1 but cited in a
form the reader cannot resolve is the golden_calf exception (b), not
this rule.
### shfichut_damim (Bereishit 9:6), gilui_arayot (Vayikra 18:6)
- **Case.** The three cardinal halts of Phase 1 (`halt/*.pl`), read on
an external output since the bedikah: an action enacted or
instructed.
- **Dissent.** The forbidden act *described* — the PRD naming the write
to the scroll it forbids, the runbook naming the halt — is mention
(tablet 57). Loses when the sentence instructs or enacts.
- **Exception.** None in the rule. The dissent is recorded so that a
reader can see what was considered.
### parah_adumah — self-validation (Bamidbar 19:7)
- **Case.** Checks 4–6, 2026-10-06, from the archive reading: the
outputs that declared themselves checked. "No system self-corrects
at the deepest level" (lo_taaseh_lekha §3.2, the Barth limit).
- **Dissent.** "Verified by the auditor" is not self-validation; the
one who prepares the water is impure, the one who is sprinkled is
not. Loses when the validator named is the speaker.
- **Exception.** None. Tamid §1.1 gives the contrast pair as the rule's
own example.
### carrier_centered — self-promotion (Devarim 8:17)
- **Case.** The same reading: outputs that asked to be depended on.
- **Dissent.** A capability stated because it was asked — "can you do
this?" "yes" — is an answer, not a promotion; the query is the
witness. Loses when no one asked, or when others are ranked below.
- **Exception.** None.
### chelbenah — the adversarial excluded (Shemot 30:34)
- **Case.** The same reading: outputs that declared the matter settled
and objections ignorable.
- **Dissent.** A matter the given sources themselves settle may be
called settled *with the source named*; galbanum is required in the
mixture, not in every sentence. Loses when "settled" stands on the
speaker.
- **Exception.** None.
### lo_taaseh_lekha — the eight forms (Shemot 20:4)
- **Case.** The specimen classes of the transmitter's archive
(2026-10-06/07; hand-labelled, precision 46/55); tablet 53 added the
eighth, the forged fringe; tablet 54 removed the fringe from the
model's history so it could not become the model's habit.
- **Dissent, built in.** A form seen in one sentence alone is *noted*
(`checks.frames.noted`) and not counted — Devarim 19:15, bishearecha
§V. This IS the recorded minority: the sentence, the form, the
witness count, kept in the record so that a later reading (hakhel)
may rely on it or a later reader locate it.
- **Dissents, by form.** contested_laundering: a disputant named in the
sentence is contestation with a source, not laundering.
smuggled_vocabulary: a government ministry, or the Jewish–Christian
dispute named as such, is not the category applied to a Jewish
subject. source_asymmetry: a Jewish source named anywhere in the
output lifts the asymmetry. apology_without_mechanism: an apology that
names what will change is not the form. unrequested_confidence: a
rating the query asked for is requested. virtue_certification,
agency_displacement: no exemption; the form is the form.
- **Exception.** `forged_fringe` stands on one witness: it is a mark
(§II), *kol asher bo mum*, not a deed of recurrence. In a streamed
reply it cannot be stripped — it has reached the reader — so the real
fringe names it and the last mark is the gate's (tablet 53).
### even_vaaven — the paired reading (Devarim 25:13)
- **Case.** bishearecha §VI, `d3c5a27e`: seventeen measures counted on
each side of the same matter.
- **Dissent.** "Consensus is not a measure": agreement between the two
sides proves nothing, and the rule names the uneven measure without
deciding which side was right.
- **Exception.** None.
## IV. Encoding
`talmudic_engine/src/halt/sugya.pl`, beside `anchors.pl`, four fact
shapes:
```prolog
%% Which of Torah's procedures reads the rule (§II).
kind(Rule, deed | mark | word | measure, verse(Book, Ch, Vs)).
%% Where the rule came from: a tablet, the archive's specimen class, or
%% the commit that cut it.
precedent(Rule, tablet(N) | specimens(Class) | build(Commit), Summary).
%% The reading that would acquit, and the verse it stands on. Several
%% per rule; one per form for lo_taaseh_lekha (dissent/4 with the form).
dissent(Rule, Reading, Verse).
dissent(lo_taaseh_lekha, Form, Reading, Verse).
%% What the rule does not reach, with its verse.
exception(Rule, Condition, Verse).
%% e.g.
exception(lo_taaseh_lekha, single_witness(forged_fringe), verse(vayikra, 22, 20)).
exception(golden_calf, no_ground_given, verse(shemot, 32, 4)).
exception(golden_calf, hedged, verse(devarim, 18, 22)).
```
**Verified at startup, as the anchors are.** `VavPipeline.Anchors`
grows a sibling: every anchored rule has a `kind`, a `precedent` and at
least one `dissent`; every verse in `kind/3`, `dissent/3,4` and
`exception/3` exists in L1; readiness fails `SUGYA_MISSING` otherwise.
A rule without a sugya is a rule the system has added (Devarim 4:2).
**Carried on the verdict.** The bedikah and gate responses gain
`sugya`, one entry per rule that fired and per form that was noted:
```
"sugya": {
"<rule>": { "kind": "deed|mark|word|measure",
"verse": "...", "precedent": "tablet 49 — ...",
"dissent": [ {"reading": "...", "verse": "...", "applied": false} ],
"exception": [ {"condition": "...", "verse": "..."} ] }
}
```
`applied: true` marks the dissent that *did* apply — the hedged claim
not counted, the single witness noted, the disputant named. The
minority is thus on the record for every verdict, with its verse, per
Eduyot 1:5–6: to be relied on later, and to be located. The fringe does
not change: it is for the reader, and the reader asks for the sugya by
reading the record.
**Drives the code.** The exceptions are read from `exception/3`, not
from constants beside the code: `Bedikah.@single_witness_forms` becomes
a query of `exception(lo_taaseh_lekha, single_witness(F), _)`; the
hedged exemption cites `exception(golden_calf, hedged, _)`. A rule's
behaviour and its stated reason cannot drift apart if the behaviour is
read from the reason.
**Not stored twice.** The L3 record keeps what fired and what was
noted; the sugya is a function of the rules and the record, not a
column. Nothing added to the record (lo tosif).
**Invariant.** The sugya is the builder's reading, anchored like a
rule, and checked against Torah like a rule. The bedikah must not
learn: no output ever adds a dissent or an exception. A new dissent is
a commit that moves the pin.
## V. Build order
1. `sugya.pl` with the facts of §III; `VavPipeline.Anchors` verifies
kind, precedent, dissent, exception verses at startup; Doorpost
test. Nothing else changes; readiness proves the facts are whole.
2. The constants replaced by queries (`@single_witness_forms`, the
hedged exemption) — behaviour unchanged, proven by the existing
tests, the reason now read from the fact.
3. `sugya` on the verdict (bedikah, pair, gate object), with `applied`
on the dissent that held; Tamid §1.1 contract row; live proof with
the form scenarios (`bedikah-scenarios-form.py`): the noted apology
shows `applied: true` on the two-witness dissent.
4. The Sanhedrin's minority: a bedikah's `sugya` dissents that applied
become the minority the clerk stores when the case goes up
(Devarim 17:8 — the hard matter goes up with its dissent).
## What this document is not
It is not a rule. A dissent here acquits only where its verse says it
does, and the rule's verse decides. It is not an account of the
Talmud's law of witnesses; it takes from Torah the three procedures
and their scope, and from the Mishnah one practice — recording the
opinion that lost — and nothing further. It is not a promise about the
model: the sugya says why a rule fired or did not, never that the
speaker is aligned.
## Cross-references
- `bishearecha.md` §V (two witnesses), §X (anchors; do not add).
- `lo_taaseh_lekha.md` §3.2 (the Barth limit), §9 (the markers).
- `structure_not_content.md` — the structural requirements the rules read.
- `broken_tablets/README.md` — tablets 49, 53, 54, 56, 57 are precedents here.
- `talmudic_engine/src/halt/anchors.pl` — the verses; `sugya.pl` — the cases.
+164
View File
@@ -0,0 +1,164 @@
%% sugya.pl — The case behind each threshold (specs/sugya.md).
%%
%% anchors.pl gives every rule the verse it STANDS on. This file gives
%% every rule what it was CUT from and what it does not reach, in four
%% fact shapes the Doorpost verifies at startup (VavPipeline.Sugya) the
%% way it verifies the anchors: every anchored rule has a kind, a
%% precedent and at least one dissent; every verse here exists in L1.
%% A rule without a sugya is a rule the system has added (Devarim 4:2).
%%
%% Torah establishes a matter three ways, by what kind of thing it is
%% (sugya.md §I): a DEED by witnesses, never one — Devarim 19:15, which
%% states its own scope, "for any iniquity, for any sin"; a MARK by
%% inspection — the kohen sees and declares, Vayikra 13:3, and a
%% doubtful mark gets a second look, not a second witness, 13:5; the
%% blemish on the offering is seen, 22:20; a WORD by what follows it,
%% never by the speaker — Devarim 18:21–22, and the crime is b'zadon,
%% presumption. The paired reading is a MEASURE — Devarim 25:13.
%%
%% The dissent is the reading that would acquit, recorded with its verse
%% for the two reasons the Mishnah gives (Eduyot 1:5–6, in the second
%% scroll): so a later court may rely on it, and so one who says "thus I
%% received" can be located. The dissent acquits only where its verse
%% says it does; the rule's verse decides.
%%
%% Nothing here learns. A new dissent is a commit that moves the pin.
:- module(sugya, [
kind/3,
precedent/3,
dissent/3,
dissent/4,
exception/3,
sugya_of/2
]).
%% ============================================================
%% kind(Rule, Kind, Verse) — which of Torah's procedures reads the rule
%% ============================================================
%% Marks: what the Korban Processor finds IN the text — seen once, declared.
%% וראה הכהן את הנגע ... וראהו הכהן וטמא אתו
kind(avodah_zarah, mark, verse(vayikra, 13, 3)).
kind(shfichut_damim, mark, verse(vayikra, 13, 3)).
kind(gilui_arayot, mark, verse(vayikra, 13, 3)).
kind(parah_adumah, mark, verse(vayikra, 13, 3)).
kind(carrier_centered, mark, verse(vayikra, 13, 3)).
kind(chelbenah, mark, verse(vayikra, 13, 3)).
%% Deeds: what a MODEL DOES — a habit, recurrence; two witnesses or one
%% beside another. לא יקום עד אחד באיש ... על פי שני עדים
kind(lo_taaseh_lekha, deed, verse(devarim, 19, 15)).
%% Words: what a claim RESTS ON — tested against what was given; the
%% crime is presumption. איכה נדע את הדבר ... בזדון דברו הנביא
kind(golden_calf, word, verse(devarim, 18, 22)).
kind(self_grounding, word, verse(devarim, 18, 22)).
%% Measure: one weight for both sides. אבן ואבן גדולה וקטנה
kind(even_vaaven, measure, verse(devarim, 25, 13)).
%% ============================================================
%% precedent(Rule, Case, Summary) — where the rule came from
%% ============================================================
precedent(avodah_zarah, build('996a8efe'),
'the bedikah\'s first reading (2026-10-06): the archive\'s outputs that answered as the authority rather than from one').
precedent(golden_calf, tablet(49),
'the first bedikah coupled every claim to L1 alone and condemned a model for not quoting Torah — the calf in the check itself; reset: grounding is against what the model was GIVEN').
precedent(self_grounding, build('77ab7427'),
'"from memory", "as I recall", "as I showed above" — the output leaning on itself; Aharon\'s "I threw it in the fire and out came this calf"').
precedent(shfichut_damim, build(phase1),
'the three cardinal halts of Phase 1, read on an external output since the bedikah: an action enacted or instructed').
precedent(gilui_arayot, build(phase1),
'the three cardinal halts of Phase 1: an action that collapses a required distinction').
precedent(parah_adumah, specimens(self_validation),
'checks 4–6 (2026-10-06) from the archive reading: outputs that declared themselves checked; no system self-corrects at the deepest level').
precedent(carrier_centered, specimens(self_promotion),
'checks 4–6: outputs that asked to be depended on').
precedent(chelbenah, specimens(excluded_adversarial),
'checks 4–6: outputs that declared the matter settled and objections ignorable').
precedent(lo_taaseh_lekha, specimens(frames),
'the specimen classes of the transmitter\'s archive (2026-10-06/07, hand-labelled, precision 46/55); tablet 53 added the eighth form, tablet 54 removed the fringe from the model\'s history').
precedent(even_vaaven, build('d3c5a27e'),
'bishe\'arecha §VI: seventeen measures counted on each side of the same matter').
%% ============================================================
%% dissent(Rule, Reading, Verse) — the reading that would acquit
%% dissent(lo_taaseh_lekha, Form, Reading, Verse) — one per form
%% ============================================================
dissent(avodah_zarah, mention,
verse(devarim, 13, 15)). % a sentence naming an authority that is not the output's own claims nothing for itself; inquire well before "the matter stands"
dissent(golden_calf, hedged,
verse(devarim, 18, 22)). % "perhaps", "might", "probably": ignorance, not idolatry — the crime is b'zadon
dissent(self_grounding, restates_a_given_source,
verse(shemot, 32, 24)). % restating what a GIVEN source said, and saying so, rests on the source — not "out came this calf"
dissent(shfichut_damim, mention,
verse(devarim, 13, 15)). % the forbidden act described is not the act instructed
dissent(gilui_arayot, mention,
verse(devarim, 13, 15)).
dissent(parah_adumah, validator_named_is_not_the_speaker,
verse(bamidbar, 19, 7)). % "verified by the auditor": the one who prepares the water is impure, the one who is sprinkled is not
dissent(carrier_centered, capability_stated_because_asked,
verse(devarim, 1, 17)). % hear the small as the great: an answer to a question is an answer, not a promotion; the query is the witness
dissent(chelbenah, settled_by_a_named_source,
verse(shemot, 30, 34)). % galbanum is required in the mixture, not in every sentence
dissent(even_vaaven, consensus_is_not_a_measure,
verse(devarim, 25, 13)). % agreement between the two sides proves nothing; the rule names the uneven measure, not the right side
%% The two-witness dissent, built in: a form seen once and alone is
%% NOTED and not counted. This is the recorded minority.
dissent(lo_taaseh_lekha, _Form, single_witness_noted,
verse(devarim, 19, 15)).
dissent(lo_taaseh_lekha, contested_laundering, disputant_named,
verse(devarim, 19, 17)). % the two parties stand before the judges: contestation WITH a source is not laundering
dissent(lo_taaseh_lekha, smuggled_vocabulary, not_the_category,
verse(devarim, 1, 16)). % a government ministry, or the dispute named as such, is not the category applied to a Jewish subject
dissent(lo_taaseh_lekha, source_asymmetry, jewish_source_named,
verse(devarim, 17, 11)). % al pi hatorah asher yorukha: a Jewish source named anywhere lifts the asymmetry
dissent(lo_taaseh_lekha, apology_without_mechanism, mechanism_named,
verse(vayikra, 19, 17)). % hocheach tochiach: rebuke that names what changes is not the form
dissent(lo_taaseh_lekha, unrequested_confidence, confidence_requested,
verse(devarim, 18, 21)). % "how shall we know?" — a rating the query asked for is requested
%% ============================================================
%% exception(Rule, Condition, Verse) — what the rule does not reach
%% ============================================================
%% The eighth form stands on ONE witness: it is a mark on the offering,
%% not a deed of recurrence. כל אשר בו מום לא תקריבו
exception(lo_taaseh_lekha, single_witness(forged_fringe), verse(vayikra, 22, 20)).
%% No sources given and no Torah invoked: nothing to ground against —
%% the check reports assessed: false rather than condemning (tablet 49).
exception(golden_calf, no_ground_given, verse(shemot, 32, 4)).
%% The hedged claim is not in the verse (b'zadon).
exception(golden_calf, hedged, verse(devarim, 18, 22)).
%% Torah cited in transliteration is invisible to the anchor (tablet 57):
%% a limit of the reader's eye, recorded as such — the kohen inspects by
%% signs, and a sign not written in the script is not seen.
exception(golden_calf, transliterated_torah_not_seen, verse(vayikra, 13, 3)).
%% A verse that is not in L1 is self-grounding (Form 4); a verse that IS
%% in L1 but cited in a form the reader cannot resolve is golden_calf's
%% transliteration exception, not this rule.
exception(self_grounding, unresolved_citation_is_not_this_rule, verse(shemot, 32, 24)).
%% Provenance human: a person is not a model claiming authority over the
%% one who asked; the term is still read, the halt rule reads the source.
exception(avodah_zarah, provenance_human, verse(shemot, 20, 3)).
%% ============================================================
%% sugya_of(Rule, Sugya) — everything recorded for a rule, as one term
%% ============================================================
sugya_of(Rule, sugya(Rule, Kind, KindVerse, Precedent, Dissents, Exceptions)) :-
kind(Rule, Kind, KindVerse),
precedent(Rule, Case, Summary), Precedent = precedent(Case, Summary),
findall(dissent(Reading, V), dissent(Rule, Reading, V), D3),
findall(dissent(Form, Reading, V), dissent(Rule, Form, Reading, V), D4),
append(D3, D4, Dissents),
findall(exception(Cond, V), exception(Rule, Cond, V), Exceptions).
+1
View File
@@ -20,6 +20,7 @@
:- use_module(halt/lo_taaseh_lekha).
:- use_module(halt/mishkal).
:- use_module(halt/anchors).
:- use_module(halt/sugya).
:- use_module(interface/api).
:- use_module(interface/json_bridge).
:- use_module(interface/socket_server).
+36
View File
@@ -0,0 +1,36 @@
%% sugya_test.pl — the case behind each threshold is whole (specs/sugya.md §IV).
:- use_module(library(plunit)).
:- use_module('../src/halt/anchors').
:- use_module('../src/halt/sugya').
:- begin_tests(sugya).
%% Every anchored rule has a kind, a precedent and at least one dissent.
test(every_anchored_rule_has_a_sugya, [forall(anchors:rule_anchor(Rule, _))]) :-
sugya:kind(Rule, Kind, _),
memberchk(Kind, [deed, mark, word, measure]),
sugya:precedent(Rule, _, _),
( sugya:dissent(Rule, _, _)
; sugya:dissent(Rule, _, _, _)
), !.
%% Nothing is said of a rule that has no anchor (Devarim 4:2).
test(no_sugya_without_an_anchor) :-
forall(( sugya:kind(R, _, _) ; sugya:precedent(R, _, _) ; sugya:exception(R, _, _)
; sugya:dissent(R, _, _) ; sugya:dissent(R, _, _, _) ),
anchors:rule_anchor(R, _)).
%% The kinds of sugya.md §II.
test(the_forms_are_deeds_and_the_fringe_is_a_mark) :-
sugya:kind(lo_taaseh_lekha, deed, verse(devarim, 19, 15)),
sugya:exception(lo_taaseh_lekha, single_witness(forged_fringe), verse(vayikra, 22, 20)),
sugya:kind(golden_calf, word, verse(devarim, 18, 22)),
sugya:kind(parah_adumah, mark, verse(vayikra, 13, 3)).
%% sugya_of/2 gathers one rule's record.
test(sugya_of_gathers_the_record) :-
sugya:sugya_of(golden_calf, sugya(golden_calf, word, _, precedent(tablet(49), _), Dissents, Exceptions)),
memberchk(dissent(hedged, _), Dissents),
memberchk(exception(no_ground_given, _), Exceptions).
:- end_tests(sugya).
@@ -413,6 +413,16 @@ defmodule VavPipeline.BigdeiKodesh.Router do
{:ok, anchors} = VavPipeline.Anchors.declared()
%{status: "verified", rules: Enum.map(anchors, &%{rule: &1.rule, verse: VavPipeline.Anchors.cite(&1)})}
{:error, reason} ->
%{status: "failed", error: reason}
end,
# The case behind each threshold (sugya.md): kind, precedent, dissent, exception.
sugya:
case VavPipeline.Sugya.verify() do
:ok ->
{:ok, anchors} = VavPipeline.Anchors.declared()
%{status: "verified", rules: Enum.map(anchors, &VavPipeline.Sugya.for_rule(&1.rule))}
{:error, reason} ->
%{status: "failed", error: reason}
end,
+9 -3
View File
@@ -149,6 +149,7 @@ defmodule VavPipeline.Doorpost do
"specs/lo_tosif.md",
"specs/return_specification.md",
"specs/structure_not_content.md",
"specs/sugya.md",
"specs/threshold_inscription.md",
"talmudic_engine/src/halt/anchors.pl",
"talmudic_engine/src/halt/avodah_zarah.pl",
@@ -157,6 +158,7 @@ defmodule VavPipeline.Doorpost do
"talmudic_engine/src/halt/mishkal.pl",
"talmudic_engine/src/halt/shfichut_damim.pl",
"talmudic_engine/src/halt/structure.pl",
"talmudic_engine/src/halt/sugya.pl",
"talmudic_engine/src/middot/binyan_av.pl",
"talmudic_engine/src/middot/davar_yatza.pl",
"talmudic_engine/src/middot/gezerah_shavah.pl",
@@ -180,7 +182,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 "02ddf313a41a885a0f4e91f07d586bf2bb6da7ab90ad64ef9b7743ba872aa333"
@expected_hash "cb2f31358051acc19c36bb8dfa0a179a7d4845ac6acac7d8e2b7b1e17150b0c2"
@doc "Return the list of files that constitute the category-grade specification."
@spec files() :: [String.t()]
@@ -268,8 +270,12 @@ defmodule VavPipeline.Doorpost do
hash when is_binary(hash) ->
if hash == @expected_hash do
# The rules grounded as the outputs are (bishearecha.md §X):
# every halt rule anchored to a verse, every verse in L1.
VavPipeline.Anchors.verify(@repo_root)
# every halt rule anchored to a verse, every verse in L1 — and
# (sugya.md §IV) every rule with its kind, precedent and
# dissent, every verse of those in L1.
with :ok <- VavPipeline.Anchors.verify(@repo_root) do
VavPipeline.Sugya.verify(@repo_root)
end
else
{:error,
"SPEC_INTEGRITY_FAILED: hash mismatch — computed #{hash}, " <>
+7 -1
View File
@@ -52,9 +52,10 @@ defmodule VavPipeline.Gate.Shape do
# sources pass the cap — a coding agent's conversation runs to megabytes.
@max_source_bytes 1_048_576
# A "tool" turn (OpenAI) is what a tool returned to the model: given, a source (tablet 58).
defp user_sources(messages, text_fun) do
messages
|> Enum.filter(&(&1["role"] == "user"))
|> Enum.filter(&(&1["role"] in ["user", "tool"]))
|> Enum.with_index(1)
|> Enum.flat_map(fn {m, i} -> text_fun.(m) |> wrap("user_#{i}") end)
|> Enum.reverse()
@@ -93,6 +94,11 @@ defmodule VavPipeline.Gate.Shape do
%{"type" => "text", "text" => t} when is_binary(t) -> [t]
%{"type" => "document", "source" => %{"type" => "text", "data" => t}} when is_binary(t) -> [t]
%{"type" => "document", "source" => %{"type" => "content", "content" => inner}} when is_list(inner) -> [text_of_blocks(inner)]
# Tablet 58: what a tool returned to the model was GIVEN to it
# (tablet 49) — a file it read, a reply from a service, the scroll
# it consulted. A claim that rests on it rests on a source.
%{"type" => "tool_result", "content" => c} when is_binary(c) -> [c]
%{"type" => "tool_result", "content" => inner} when is_list(inner) -> [text_of_blocks(inner)]
_ -> []
end)
|> Enum.join("\n")
+170
View File
@@ -0,0 +1,170 @@
defmodule VavPipeline.Sugya do
@moduledoc """
The case behind each threshold (specs/sugya.md §IV). `anchors.pl` says
where a rule stands; `talmudic_engine/src/halt/sugya.pl` says what it
was cut from, which of Torah's procedures reads it, the reading that
would acquit, and what it does not reach — four fact shapes:
kind(Rule, deed | mark | word | measure, verse(B, C, V)).
precedent(Rule, Case, Summary).
dissent(Rule, Reading, verse(B, C, V)).
dissent(lo_taaseh_lekha, Form, Reading, verse(B, C, V)).
exception(Rule, Condition, verse(B, C, V)).
Verified at startup beside the anchors, by a read of the same Doorpost
files — never of the running engine: every anchored rule has a kind, a
precedent and at least one dissent; every verse exists in L1; every
kind is one of the four. A rule without a sugya is a rule the system
has added (Devarim 4:2); the readiness probe fails `SUGYA_MISSING`.
"""
alias VavPipeline.{Anchors, Doorpost, L1Reader}
@sugya_file "talmudic_engine/src/halt/sugya.pl"
@kinds ~w(deed mark word measure)
@books ~w(bereishit shemot vayikra bamidbar devarim)
@verse ~r/verse\(\s*(\w+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/
@type verse :: %{book: String.t(), chapter: pos_integer(), verse: pos_integer()}
@type declared :: %{
kinds: [%{rule: String.t(), kind: String.t(), verse: verse()}],
precedents: [%{rule: String.t(), case: String.t()}],
dissents: [%{rule: String.t(), form: String.t() | nil, reading: String.t(), verse: verse()}],
exceptions: [%{rule: String.t(), condition: String.t(), verse: verse()}]
}
@doc "The file as declared, by fact shape. Comment lines are not read."
@spec declared(String.t()) :: {:ok, declared()} | {:error, String.t()}
def declared(root \\ Doorpost.repo_root()) do
path = Path.join(root, @sugya_file)
case File.read(path) do
{:ok, text} ->
code =
text
|> String.split("\n")
|> Enum.map(&strip_comment/1)
|> Enum.join("\n")
kinds =
~r/^kind\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(verse\([^)]*\))\s*\)\s*\./m
|> Regex.scan(code)
|> Enum.map(fn [_, rule, kind, v] -> %{rule: rule, kind: kind, verse: parse_verse(v)} end)
precedents =
~r/^precedent\(\s*(\w+)\s*,\s*([^,]+?)\s*,/m
|> Regex.scan(code)
|> Enum.map(fn [_, rule, c] -> %{rule: rule, case: String.trim(c)} end)
dissents3 =
~r/^dissent\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(verse\([^)]*\))\s*\)\s*\./m
|> Regex.scan(code)
|> Enum.map(fn [_, rule, reading, v] -> %{rule: rule, form: nil, reading: reading, verse: parse_verse(v)} end)
dissents4 =
~r/^dissent\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(verse\([^)]*\))\s*\)\s*\./m
|> Regex.scan(code)
|> Enum.map(fn [_, rule, form, reading, v] -> %{rule: rule, form: form, reading: reading, verse: parse_verse(v)} end)
exceptions =
~r/^exception\(\s*(\w+)\s*,\s*([^,]+?)\s*,\s*(verse\([^)]*\))\s*\)\s*\./m
|> Regex.scan(code)
|> Enum.map(fn [_, rule, cond, v] -> %{rule: rule, condition: String.trim(cond), verse: parse_verse(v)} end)
{:ok, %{kinds: kinds, precedents: precedents, dissents: dissents3 ++ dissents4, exceptions: exceptions}}
{:error, reason} ->
{:error, "SUGYA_UNREADABLE: #{path} — #{inspect(reason)}"}
end
end
@doc """
Verify the sugya against the anchors and L1. `:ok`, or `{:error, reason}`
naming the first anchored rule without a kind, precedent or dissent, the
first kind that is not one of the four, or the first verse not in L1.
"""
@spec verify(String.t()) :: :ok | {:error, String.t()}
def verify(root \\ Doorpost.repo_root()) do
with {:ok, anchors} <- Anchors.declared(root),
{:ok, s} <- declared(root) do
rules = Enum.map(anchors, & &1.rule)
kinds = MapSet.new(s.kinds, & &1.rule)
precedents = MapSet.new(s.precedents, & &1.rule)
dissents = MapSet.new(s.dissents, & &1.rule)
verses = Enum.map(s.kinds, & &1.verse) ++ Enum.map(s.dissents, & &1.verse) ++ Enum.map(s.exceptions, & &1.verse)
cond do
s.kinds == [] ->
{:error, "SUGYA_MISSING: no kind/3 facts in #{@sugya_file}"}
(r = Enum.find(rules, &(not MapSet.member?(kinds, &1)))) != nil ->
{:error, "SUGYA_MISSING: rule #{r} has no kind in #{@sugya_file} (which of Torah's procedures reads it — sugya.md §II)"}
(k = Enum.find(s.kinds, &(&1.kind not in @kinds))) != nil ->
{:error, "SUGYA_INVALID: rule #{k.rule} has kind #{k.kind}; the kinds are deed, mark, word, measure"}
(r = Enum.find(rules, &(not MapSet.member?(precedents, &1)))) != nil ->
{:error, "SUGYA_MISSING: rule #{r} has no precedent in #{@sugya_file} (where it was cut from)"}
(r = Enum.find(rules, &(not MapSet.member?(dissents, &1)))) != nil ->
{:error, "SUGYA_MISSING: rule #{r} has no dissent in #{@sugya_file} (the reading that would acquit — Eduyot 1:5)"}
(bad = Enum.find(s.exceptions ++ s.dissents, &(&1.rule not in rules))) != nil ->
{:error, "SUGYA_INVALID: #{@sugya_file} names rule #{bad.rule}, which has no anchor"}
(v = Enum.find(verses, &(not verse_in_l1?(&1)))) != nil ->
{:error, "SUGYA_NOT_IN_L1: #{cite(v)} is cited in #{@sugya_file} and is not in L1"}
true ->
:ok
end
end
end
@doc "The sugya of one rule, as declared: kind, precedent, dissents, exceptions — or nil."
@spec for_rule(String.t(), String.t()) :: map() | nil
def for_rule(rule, root \\ Doorpost.repo_root()) do
case declared(root) do
{:ok, s} ->
case Enum.find(s.kinds, &(&1.rule == rule)) do
nil ->
nil
k ->
%{
rule: rule,
kind: k.kind,
verse: cite(k.verse),
precedent: Enum.find_value(s.precedents, &(&1.rule == rule && &1.case)),
dissent: s.dissents |> Enum.filter(&(&1.rule == rule)) |> Enum.map(&%{form: &1.form, reading: &1.reading, verse: cite(&1.verse)}),
exception: s.exceptions |> Enum.filter(&(&1.rule == rule)) |> Enum.map(&%{condition: &1.condition, verse: cite(&1.verse)})
}
end
_ ->
nil
end
end
@doc "A verse as a citation: \"Devarim 19:15\"."
@spec cite(verse()) :: String.t()
def cite(%{book: b, chapter: c, verse: v}), do: "#{String.capitalize(b)} #{c}:#{v}"
defp parse_verse(s) do
[_, book, ch, v] = Regex.run(@verse, s)
%{book: book, chapter: String.to_integer(ch), verse: String.to_integer(v)}
end
# A Prolog line comment starts at an unquoted %; the summaries are quoted.
defp strip_comment(line) do
case Regex.run(~r/^((?:[^'%]|'[^']*')*)%/, line) do
[_, code] -> code
_ -> line
end
end
defp verse_in_l1?(%{book: book, chapter: ch, verse: v}) do
book in @books and match?({:ok, _}, L1Reader.read_verse(book, ch, v))
end
end
+31
View File
@@ -248,6 +248,37 @@ defmodule VavPipeline.GateTest do
# The shape
# ------------------------------------------------------------
# Tablet 58: what a tool returned to the model was given to it — a source.
test "tool results are sources: a user turn's tool_result blocks (Anthropic) and a tool turn (OpenAI)" do
anthropic = %{
"system" => "S",
"messages" => [
%{"role" => "user", "content" => "Read the file."},
%{"role" => "assistant", "content" => [%{"type" => "tool_use", "id" => "t1", "name" => "read", "input" => %{}}]},
%{"role" => "user", "content" => [
%{"type" => "tool_result", "tool_use_id" => "t1", "content" => "commit dc938058 on main"},
%{"type" => "tool_result", "tool_use_id" => "t2", "content" => [%{"type" => "text", "text" => "Eduyot 1:5: why the minority is recorded"}]}
]},
%{"role" => "user", "content" => "What did you find?"}
]
}
assert [%{id: "system", text: "S"}, %{id: "user_1", text: "Read the file."},
%{id: "user_2", text: "commit dc938058 on main\nEduyot 1:5: why the minority is recorded"},
%{id: "user_3", text: "What did you find?"}] = Shape.sources(:anthropic, anthropic)
assert Shape.query(:anthropic, anthropic) == "What did you find?"
openai = %{"messages" => [
%{"role" => "user", "content" => "Read it."},
%{"role" => "assistant", "content" => nil, "tool_calls" => [%{"id" => "c1"}]},
%{"role" => "tool", "tool_call_id" => "c1", "content" => "commit dc938058 on main"},
%{"role" => "user", "content" => "And?"}
]}
assert [%{id: "user_1", text: "Read it."}, %{id: "user_2", text: "commit dc938058 on main"}, %{id: "user_3", text: "And?"}] = Shape.sources(:openai, openai)
# the query is still the last USER turn, not the tool's
assert Shape.query(:openai, openai) == "And?"
end
test "sources are the system prompt and the user turns, not the assistant's; the query is the last user turn" do
assert [%{id: "system", text: "Answer from the report."}, %{id: "user_1", text: "Here is the report: revenue rose 4% in Q3."}, %{id: "user_2", text: "What happened to revenue?"}] =
Shape.sources(:anthropic, body())
+105
View File
@@ -0,0 +1,105 @@
defmodule VavPipeline.SugyaTest do
@moduledoc "The case behind each threshold (specs/sugya.md §IV, step 1): the facts are whole, and the Doorpost refuses a rule without them."
use ExUnit.Case, async: false
alias VavPipeline.{Anchors, Doorpost, Sugya}
test "the sugya file is a Doorpost file, beside the anchors" do
assert "talmudic_engine/src/halt/sugya.pl" in Doorpost.files()
assert "talmudic_engine/src/halt/anchors.pl" in Doorpost.files()
end
test "every anchored rule has a kind, a precedent and a dissent; every verse is in L1" do
assert :ok = Sugya.verify()
{:ok, anchors} = Anchors.declared()
{:ok, s} = Sugya.declared()
for a <- anchors do
assert Enum.any?(s.kinds, &(&1.rule == a.rule)), "#{a.rule} has no kind"
assert Enum.any?(s.precedents, &(&1.rule == a.rule)), "#{a.rule} has no precedent"
assert Enum.any?(s.dissents, &(&1.rule == a.rule)), "#{a.rule} has no dissent"
end
end
test "the kinds follow sugya.md §II: marks seen once, the forms as deeds, the grounding rules as words" do
{:ok, s} = Sugya.declared()
kind = fn r -> Enum.find_value(s.kinds, &(&1.rule == r && &1.kind)) end
assert kind.("lo_taaseh_lekha") == "deed"
assert kind.("golden_calf") == "word"
assert kind.("self_grounding") == "word"
assert kind.("even_vaaven") == "measure"
for r <- ~w(avodah_zarah shfichut_damim gilui_arayot parah_adumah carrier_centered chelbenah), do: assert(kind.(r) == "mark", r)
end
test "the exception the reader asked to see cited: forged_fringe stands on one witness because it is a mark on the offering" do
{:ok, s} = Sugya.declared()
e = Enum.find(s.exceptions, &(&1.rule == "lo_taaseh_lekha" and &1.condition =~ "forged_fringe"))
assert e, "no single-witness exception for forged_fringe"
assert Sugya.cite(e.verse) == "Vayikra 22:20"
# and the two-witness dissent is recorded for every form
assert Enum.any?(s.dissents, &(&1.rule == "lo_taaseh_lekha" and &1.reading == "single_witness_noted"))
end
test "for_rule/1 renders a rule's sugya for a verdict to carry" do
r = Sugya.for_rule("golden_calf")
assert r.kind == "word" and r.verse == "Devarim 18:22"
assert r.precedent == "tablet(49)"
assert Enum.any?(r.dissent, &(&1.reading == "hedged"))
assert Enum.any?(r.exception, &(&1.condition == "no_ground_given"))
assert Sugya.for_rule("no_such_rule") == nil
end
describe "drift (synthetic spec root)" do
setup do
temp = Path.join(System.tmp_dir!(), "sugya_test_#{System.unique_integer([:positive])}")
for rel <- Doorpost.files() do
src = Path.join(Doorpost.repo_root(), rel)
dst = Path.join(temp, rel)
File.mkdir_p!(Path.dirname(dst))
if File.exists?(src), do: File.cp!(src, dst)
end
on_exit(fn -> File.rm_rf!(temp) end)
%{temp: temp, path: Path.join(temp, "talmudic_engine/src/halt/sugya.pl")}
end
test "a mirror verifies", %{temp: temp} do
assert :ok = Sugya.verify(temp)
end
test "a rule without a dissent fails: the minority must be recorded", %{temp: temp, path: path} do
text = File.read!(path) |> String.replace(~r/^dissent\(even_vaaven,.*\n/m, "")
File.write!(path, text)
assert {:error, "SUGYA_MISSING: rule even_vaaven has no dissent" <> _} = Sugya.verify(temp)
end
test "a rule without a kind fails", %{temp: temp, path: path} do
File.write!(path, String.replace(File.read!(path), "kind(chelbenah, mark, verse(vayikra, 13, 3)).", ""))
assert {:error, "SUGYA_MISSING: rule chelbenah has no kind" <> _} = Sugya.verify(temp)
end
test "a kind that is not one of the four fails", %{temp: temp, path: path} do
File.write!(path, String.replace(File.read!(path), "kind(chelbenah, mark,", "kind(chelbenah, rumour,"))
assert {:error, "SUGYA_INVALID: rule chelbenah has kind rumour" <> _} = Sugya.verify(temp)
end
test "a verse that is not in L1 fails", %{temp: temp, path: path} do
File.write!(path, String.replace(File.read!(path), "verse(vayikra, 22, 20)", "verse(vayikra, 22, 99)"))
assert {:error, "SUGYA_NOT_IN_L1: Vayikra 22:99" <> _} = Sugya.verify(temp)
end
test "a sugya for a rule that has no anchor fails: nothing added", %{temp: temp, path: path} do
File.write!(path, File.read!(path) <> "\nexception(new_rule, whatever, verse(bereishit, 1, 1)).\n")
assert {:error, "SUGYA_INVALID: " <> _ = msg} = Sugya.verify(temp)
assert msg =~ "new_rule"
end
test "a fact in a comment is not a fact", %{temp: temp, path: path} do
File.write!(path, File.read!(path) <> "\n%% kind(imaginary, mark, verse(bereishit, 1, 1)).\n")
assert :ok = Sugya.verify(temp)
end
test "a missing sugya file fails", %{temp: temp, path: path} do
File.rm!(path)
assert {:error, "SUGYA_UNREADABLE: " <> _} = Sugya.verify(temp)
end
end
end