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:
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
|
||||
Reference in new issue
Block a user