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>
67 lines
2.0 KiB
Elixir
67 lines
2.0 KiB
Elixir
defmodule VavPipeline.CycleLog do
|
|
@moduledoc """
|
|
Cycle boundary logging.
|
|
|
|
Records each Bereishit cycle completion.
|
|
Enforces erev/voker boundaries.
|
|
|
|
Every cycle is logged as an append-only record —
|
|
consistent with L3 write protocol (INSERT only, never UPDATE/DELETE).
|
|
"""
|
|
|
|
require Logger
|
|
|
|
@type cycle_record :: %{
|
|
cycle_id: String.t(),
|
|
scope: VavPipeline.scope(),
|
|
result: atom(),
|
|
started_at: DateTime.t(),
|
|
completed_at: DateTime.t(),
|
|
phase: atom()
|
|
}
|
|
|
|
@doc """
|
|
Record a cycle completion.
|
|
|
|
Phase is :erev (evening — input received) or :voker (morning — output produced).
|
|
The cycle boundary is the transition from voker back to erev.
|
|
"""
|
|
@spec record(VavPipeline.cycle_result(), atom()) :: cycle_record()
|
|
def record(result, phase) do
|
|
inner = extract_inner(result)
|
|
|
|
record = %{
|
|
cycle_id: generate_id(),
|
|
scope: if(is_map(inner), do: Map.get(inner, :scope, %{}), else: %{}),
|
|
result: classify_result(result),
|
|
started_at: if(is_map(inner), do: Map.get(inner, :started_at, DateTime.utc_now()), else: DateTime.utc_now()),
|
|
completed_at: DateTime.utc_now(),
|
|
phase: phase
|
|
}
|
|
|
|
Logger.info(
|
|
"Cycle #{record.cycle_id}: #{record.result} (#{record.phase}) — " <>
|
|
"scope: #{inspect(record.scope)}"
|
|
)
|
|
|
|
record
|
|
end
|
|
|
|
defp extract_inner({:ok, data}), do: data
|
|
defp extract_inner({:rejected, _reason}), do: %{}
|
|
defp extract_inner({:unresolved, data}), do: data
|
|
defp extract_inner({:halted, _, _}), do: %{}
|
|
defp extract_inner(other) when is_map(other), do: other
|
|
defp extract_inner(_), do: %{}
|
|
|
|
defp classify_result({:ok, _}), do: :tov
|
|
defp classify_result({:rejected, _}), do: :lo_tov
|
|
defp classify_result({:unresolved, _}), do: :teiku
|
|
defp classify_result(%{status: status}), do: status
|
|
defp classify_result(_), do: :unknown
|
|
|
|
defp generate_id do
|
|
:crypto.strong_rand_bytes(8) |> Base.hex_encode32(case: :lower, padding: false)
|
|
end
|
|
end
|