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>
This commit is contained in:
Scott KarpandClaude Sonnet 4.6 committed 2026-02-26 14:02:34 -05:00
1 parent 622e814c9e
commit 80ec364da6
86 files changed
+9646

No files matched your search

@@ -0,0 +1,252 @@
defmodule VavPipeline.BereishitCycle do
@moduledoc """
The Bereishit processing cycle — the six days of creation as computation.
Architecture §3.3:
Each step chains to the next via |> (vav-consecutive).
The cycle operates WITHIN the ShemaContext, never modifying it.
The context was received by Shema (nishma). Now we do (na'aseh).
Steps:
1. tohu — decompose input into undifferentiated state
2. vayomer — produce structured symbolic output (Shoresh Engine)
3. havdalah — separate into distinguished categories
4. kriah — assign stable names
5. ki_tov — evaluate against specification
6. erev_voker — log cycle completion, enforce boundary
Latency budget (Construction spec §2.5): 5000ms total
"""
alias VavPipeline.{Specification, CycleLog, Manna}
require Logger
@type cycle_result ::
{:ok, map()}
| {:rejected, String.t()}
| {:unresolved, map()}
| {:halted, atom(), String.t()}
@doc """
Execute the Bereishit cycle on input within received context.
"""
@spec execute(VavPipeline.input(), VavPipeline.Shema.shema_context()) :: cycle_result()
def execute(input, context) do
started_at = System.monotonic_time(:millisecond)
result =
input
|> tohu(context)
|> vayomer(context)
|> havdalah(context)
|> kriah(context)
|> ki_tov(context)
completed_at = System.monotonic_time(:millisecond)
elapsed = completed_at - started_at
Logger.info("BereishitCycle: completed in #{elapsed}ms — #{inspect(elem(result, 0))}")
# erev_voker — cycle boundary
erev_voker(result, context)
end
@doc """
Tohu — decompose input into undifferentiated state.
Strip structure, extract raw content. This is the formless void
before vayomer brings order.
"""
@spec tohu(VavPipeline.input(), VavPipeline.Shema.shema_context()) :: map()
def tohu(input, _context) do
%{
raw: extract_content(input),
provenance: Map.get(input, :source, "unknown"),
scope: Map.get(input, :verse_scope, %{}),
started_at: DateTime.utc_now()
}
end
@doc """
Vayomer — produce structured symbolic output.
The Shoresh Engine receives the ShemaContext — it reads te'amim,
ketiv/qere, gematria as part of its analysis.
In Phase 2, this calls the Shoresh Engine via port/NIF.
Until the port is built (Step 14), this uses the L1 data
directly from the ShemaContext.
"""
@spec vayomer(map(), VavPipeline.Shema.shema_context()) :: map()
def vayomer(state, context) do
# In Phase 2: use L1 data from ShemaContext directly
# In Phase 3: call ShoreshEngineClient.process(state.raw, context)
roots =
context.verse.words
|> Enum.filter(fn w -> w.shoresh != nil end)
|> Enum.map(fn w ->
%{
shoresh: w.shoresh,
word: w.consonants,
position: w.position,
morph: w.morph,
gematria: Map.get(context.root_gematria, w.shoresh, 0)
}
end)
Map.merge(state, %{
roots_activated: roots,
teamim_parse: context.teamim_marks,
ketiv_qere: context.ketiv_qere,
stage: :vayomer
})
end
@doc """
Havdalah — separate into distinguished categories.
Te'amim inform the separation — the text's own divisions guide havdalah.
Uses the te'amim marks from the ShemaContext to determine boundaries.
"""
@spec havdalah(map(), VavPipeline.Shema.shema_context()) :: map()
def havdalah(utterance, context) do
# Group roots by domain based on te'amim divisions
# Te'amim melekh marks (disjunctors) create boundaries
melekh_positions =
context.teamim_marks
|> Enum.filter(fn m -> m.role == "melekh" end)
|> Enum.map(fn m -> m.word_index end)
|> Enum.sort()
# Separate roots into groups divided by melekh marks
roots = Map.get(utterance, :roots_activated, [])
groups = separate_by_boundaries(roots, melekh_positions)
Map.merge(utterance, %{
separated_groups: groups,
separation_boundaries: melekh_positions,
stage: :havdalah
})
end
@doc """
Kriah — assign stable names to each distinction.
Each separated group receives a name based on its primary root.
"""
@spec kriah(map(), VavPipeline.Shema.shema_context()) :: map()
def kriah(distinctions, _context) do
named =
distinctions
|> Map.get(:separated_groups, [])
|> Enum.with_index()
|> Enum.map(fn {group, idx} ->
primary_root = List.first(group)
name =
if primary_root do
primary_root.shoresh
else
"group_#{idx}"
end
%{
name: name,
roots: group,
index: idx
}
end)
Map.merge(distinctions, %{
named_results: named,
stage: :kriah
})
end
@doc """
Ki Tov — evaluate against specification.
Ketiv/qere positions are checked — both readings inform evaluation.
Returns {:ok, results}, {:rejected, reason}, or {:unresolved, results}.
"""
@spec ki_tov(map(), VavPipeline.Shema.shema_context()) :: VavPipeline.cycle_result()
def ki_tov(named, context) do
results = Map.get(named, :named_results, [])
case Specification.evaluate(results, context.ketiv_qere) do
:tov ->
{:ok,
Map.merge(named, %{
evaluation: :tov,
stage: :ki_tov
})}
{:lo_tov, reason} ->
{:rejected, reason}
:teiku ->
{:unresolved,
Map.merge(named, %{
evaluation: :teiku,
stage: :ki_tov
})}
end
end
@doc """
Erev Voker — log cycle completion, enforce boundary.
Release any manna surplus — do not hoard into next cycle.
"""
@spec erev_voker(VavPipeline.cycle_result(), VavPipeline.Shema.shema_context()) ::
VavPipeline.cycle_result()
def erev_voker(result, _context) do
# Log the cycle
phase =
case result do
{:ok, _} -> :voker
{:rejected, _} -> :erev
{:unresolved, _} -> :erev
_ -> :erev
end
CycleLog.record(result, phase)
# Enforce anti-hoarding
Manna.enforce_anti_hoarding()
result
end
# --- Private helpers ---
defp extract_content(input) do
Map.get(input, :content, "") |> String.trim()
end
# Separate roots into groups based on melekh boundary positions
defp separate_by_boundaries([], _boundaries), do: [[]]
defp separate_by_boundaries(roots, []), do: [roots]
defp separate_by_boundaries(roots, boundaries) do
# Sort boundaries and use them to split the root list
sorted_boundaries = Enum.sort(boundaries)
{groups, current} =
Enum.reduce(roots, {[], []}, fn root, {groups, current} ->
pos = root.position - 1
if pos in sorted_boundaries and current != [] do
# Boundary hit — close current group, start new one with this root
{groups ++ [current], [root]}
else
{groups, current ++ [root]}
end
end)
# Don't forget the last group
groups ++ [current]
end
end