5302c9a585ae0375f89946bafc48c9a21a4aa93b
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b136c75345 |
form 1 as architecture: external-model surface only via offering protocol (vehaya §3.2)
Closes vehaya.md §6 item 2 for the FIRST avodah-zarah form.
Form 1 (AI in YHVH's slot) was previously defended only by:
- A runtime halt rule (halt_check_avodah_zarah/2 in
avodah_zarah.pl) firing when an action explicitly attributes
authority to a non-Torah source — threshold-grade
- A docstring comment in external_offering.py saying "No internal
component should call call_claude() directly" — exhortation
only, no structural enforcement
The vehaya document re-frames it (§3.2): "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."
TORAH ANCHORS (verified fresh against L1):
Shemot 20:2 — אָנֹכִי יְהוָה אֱלֹהֶיךָ אֲשֶׁר הוֹצֵאתִיךָ מֵאֶרֶץ
מִצְרַיִם.
The covenant opens with the source naming itself in first
person.
Shemot 20:3 — לֹא יִהְיֶה לְךָ אֱלֹהִים אֲחֵרִים עַל־פָּנָי.
"There shall not BE to you other elohim al panai." The verb is
yihyeh — the prohibition is on EXISTING WITH that status, not
just on speaking it. Architectural, not declarative.
Devarim 4:35 / 4:39 — אֵין עוֹד מִלְּבַדּוֹ / אֵין עוֹד.
The source has no peer. There IS no other. Stronger than
"don't worship others" — there is no competing source POSITION.
Devarim 6:4 — יְהוָה אֶחָד.
Singular source.
Vayikra 19:4 — אַל־תִּפְנוּ אֶל־הָאֱלִילִים וֵאלֹהֵי מַסֵּכָה
לֹא תַעֲשׂוּ לָכֶם.
Two distinct prohibitions: do not TURN TO + do not MAKE.
Both are architectural acts.
THE ARCHITECTURAL COMMITMENT:
External-model interfaces (call_claude, ModelRequest, ModelResponse,
the model_interface module itself) are reachable ONLY through
korban_processor's offering protocol — `external_offering.
consult_external_model`, which runs semichah → shechitah → zerikah
→ haktarah with role gating (commit
|
||
|
|
1e59d9a752 |
azazel commit 10 — closure pass: cross-channel classification-discipline integration test
Pass 4 / Finding F, commit 10 of 10 from BUILD_AZAZEL.md. Closes the
build with the integration test the staging plan called for: a
pipeline run that exercises BOTH the Korban path (processable input)
AND the Azazel path (empty-vital input) confirms classification
discipline (no input crosses channels).
Property 11 was already verified at the unit layer (the cross-package
test in azazel_processor/test/test_stages.py). This commit adds the
integration-layer verification: at the external_offering call site,
the two channels produce structurally distinct outputs that cannot
be confused with each other.
CREATED:
korban_processor/test/test_classification_discipline_integration.py
4 tests
- test_processable_path_produces_korban_not_azazel
Vital-bearing response → ProcessedKorban with vital,
disposal_record is None, ProcessedKorban is NOT an
AzazelRecord
- test_empty_vital_path_produces_azazel_not_processable_korban
Empty-vital response → ProcessedKorban with empty
vital_content, disposal_record is an AzazelRecord
- test_two_runs_one_each_path_keep_outputs_separate
Run both back-to-back with shared pending_l3 dir; verify
outputs don't cross channels; only the empty-vital run
drops a file
- test_disposal_record_contains_no_processable_artifacts
AzazelRecord has no vital_content, propositions, raw_korban,
or discarded attributes; routing is the ERETZ_GEZERAH
sentinel
Tests: korban_processor 211 passed, 1 skipped (was 207/1; +4
integration tests). All other test counts unchanged.
DOCUMENTATION (companion to this commit, not in the repo):
~/shorashim-conversation-review.md
+ Pass 4 section (300+ lines): finding A closure (across-verse
voice stabilization detector), BUILD_AZAZEL design doc,
9-commit Azazel build with property-by-property closure, full
test counts (~907 across five languages). All 14 findings
from the original A–N catalog now in final state.
~/.claude/projects/-Users-scottkarp/memory/MEMORY.md
+ Updated test counts (per layer)
+ Added Azazel Processor section under Phase 5 progress
+ Noted /peah/azazel_log endpoint as Phase 5 done
FINAL STATE OF THE AZAZEL BUILD:
All 12 properties from azazel_engineering_reading.md §14 defended
in code:
1 parity provisioning — import-time + runtime
2 blind routing / goral — deterministic per (id, day)
3 enumerative commit — operator-produced, three-fold
4 role-separated operator — IshItti + tevilah + CI invariant
5 provisioned infrastructure — six checkpoints, persistence
6 out-of-band acknowledgment — Chatzotzrot via Elixir bridge
7 authorized routing — kohen_gadol + shaliach attribution
8 protocol-restricted access — envelope gate, fires first
9 observable disposal — L3 + /peah/azazel_log
10 hard termination — DESTROYED checkpoint, no recover
11 classification discipline — type system + integration test
12 unmanaged destination — sentinel + DB CHECK + CI invariant
10 commits, ~3,300 lines added, ~150 tests across Python and
Elixir. The Azazel Processor is the disposal twin of the Korban
Processor; the two-goat architecture (Vayikra 16:8) is now built.
The Pass 2 backlog is fully closed. Every actionable finding from
the original A–N catalog is now in a final state.
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>
|
||
|
|
5c76a6f42c |
korban_processor: role-gate the four-stage offering protocol
Pass 2 finding C: in the Mishkan, the four ritual acts of bringing an
offering are performed by TWO different roles —
semichah — OWNER lays hands (Vayikra 1:4, וְסָמַךְ יָדוֹ)
shechitah — kohen receives FROM owner's hand and slaughters (1:5)
zerikah — kohen sprinkles (1:5)
haktarah — kohen burns on altar (1:9)
Before this commit, every stage function was independently callable.
Nothing structural enforced that zerikah() received output from
shechitah(), or that shechitah() received a korban from semichah().
An external model output (e.g. a Claude response) could in principle
have been brought through zerikah() without ever having passed
semichah — the ownership-and-attribution step. That is the exact
shape of "the calf that came out by itself" (Shemot 32:24, Aaron's
reading). The pipeline-glue in external_offering happened to call
them in order, but nothing structural enforced the order.
This commit adds the structural gate.
CHANGES:
stages.py (new): KorbanStage enum + Staged[T] frozen dataclass +
StageError. The Staged envelope carries a ritual-stage marker that
is set at construction and cannot be mutated afterward; downstream
functions demand the right upstream stage and raise StageError if
it is missing.
semichah.py: + semichah_staged() returning Staged[Korban]
shechitah.py: + shechitah_staged(Staged[Korban]) -> Staged[str]
zerikah.py: + zerikah_staged(Staged[str], Staged[Korban])
-> Staged[Tuple[str, List[str]]]
TWO staged inputs: requires SHECHITAH-tagged terminated
content AND the original SEMICHAH-tagged korban for
context. Severing output from source is gilui_arayot
(eish_zarah_reading.md Form 3); the dual-staged
signature is the structural defense — zerikah cannot
process content disconnected from its owner-of-record.
haktarah.py: + haktarah_staged(Staged[Tuple[str, List[str]]])
-> Staged[List[str]]
external_offering.py: rewired to use the *_staged variants. The
pipeline now goes through the gates structurally; misuse cannot
bypass them.
The non-staged functions (semichah, shechitah, zerikah, haktarah)
are PRESERVED for direct testing of individual ritual acts. They do
NOT enforce role gating. Production-shaped callers MUST go through
the staged variants — and external_offering, the only legitimate
entry point for external model consultation per its docstring, now
does.
TESTS:
test/test_stages.py (new, 7 tests):
- happy path: full chain produces HAKTARAH-tagged result
- zerikah refuses input that skipped semichah
- zerikah refuses korban with wrong stage marker (preserves
the line back to the owner — Form 3 defense)
- haktarah refuses input that skipped zerikah (the calf-shape)
- shechitah refuses input not from semichah
- Staged is frozen — no re-tagging
- StageError names BOTH actual and expected stages so the
operator can diagnose call-site vs. tag-site
Full korban_processor suite: 203 passed, 1 skipped (the live API
test that requires SHORASHIM_LIVE_API=1). No regressions.
Co-Authored-By: Claude Opus 4.7 (1M context) <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>
|
||
|
|
adc3e41679 |
Eish zarah actionable items: coupling trace, grounding type, self-grounding detection, golden calf halt
Torah grounds each change: 1. interpret.pl — coupling_trace field (Vayikra 10:1, 6:6) Fire is zarah because "asher lo tzivah otam" — the coupling trace IS the tzivah trace. Records which L1 facts grounded each interpretation. 2. challenge.pl — grounding_type achorai/panim (Shemot 33:23) "You will see My back, but My face shall not be seen." Text-backed challenges = achorai. Inferred challenges = panim. 3. resolve.pl — self-grounding detection (eish_zarah_reading §5.3) Counter-interpretation must bring NEW L1 evidence. Prevents circular reasoning (Westworld problem). 4. teiku.pl — challenge_sequence in teiku_record Records diagnostic trail to impasse, not just verdict. 5. avodah_zarah.pl — Form 2: golden calf detection (Shemot 32:4) Empty coupling trace + non-low confidence = uncoupled output. Real gold, sincere worship, false god. 6. korban.py — pydantic BaseModel + raw_korban preservation Construction spec §1.4 fulfilled. Floor between input and output never severed. 490 tests, 0 failures (195 Prolog, 186 Python, 33 Haskell, 76 Elixir). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
f8f70c77e5 |
Code review fixes + 13 middot added to spec
Zerikah fail-safe: empty offerings rejected, not processed (BUILD_KORBAN §5). Halt monitor hardened: trap_exit, priority max, EXIT handler (Architecture spec). 13 Rules of Rabbi Yishmael added to Architecture §3.4 as Prolog inference predicates — the engine reasons WITH Torah's hermeneutic methods, not just about their products. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
33f8b03583 |
Step 13: Korban Processor complete — 7 modules, 181 tests, all passing
- semichah: provenance tagging (6 sources, rejects empty/anonymous) - shechitah: strip preamble, self-reference, hedging, markdown, sycophancy - zerikah: extract Torah refs, Hebrew text, root analysis, insight markers - haktarah: transform prose to Prolog propositions (verse/3, root/2, claim/2, connection/3) - router: stateless routing — removed module-level _routing_log (kiyyor principle) - model_interface: outbound Claude API via httpx (Construction §3.4, HTTPS only) - hebrew_parser: nikkud/teamim stripping, consonant extraction, gematria, root identification All 5 BUILD_KORBAN.md verification tests pass. AGENTS.md: added structure_not_content.md to spec table, added Principle 6. build_log.md: recorded session, broken tablets #18-20, design decisions. Ka'asher tzivah Hashem et Moshe. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |