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>
103 lines
2.4 KiB
Elixir
103 lines
2.4 KiB
Elixir
defmodule VavPipeline.ShabbatTimer do
|
|
@moduledoc """
|
|
Enforces mandatory weekly cessation.
|
|
All processing stops. System enters rest state.
|
|
|
|
Architecture §3.3:
|
|
When Shabbat begins, VavPipeline ceases all processing.
|
|
When Shabbat ends, processing resumes.
|
|
|
|
Construction spec §4.4:
|
|
cycle_boundary_check_interval_ms: 60_000 (1 minute)
|
|
|
|
In Phase 2, this is a GenServer that checks the clock.
|
|
Production will use location-aware zmanim.
|
|
"""
|
|
|
|
use GenServer
|
|
require Logger
|
|
|
|
@check_interval Application.compile_env(
|
|
:vav_pipeline,
|
|
:cycle_boundary_check_interval_ms,
|
|
60_000
|
|
)
|
|
|
|
# --- Client API ---
|
|
|
|
def start_link(opts \\ []) do
|
|
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
|
end
|
|
|
|
@doc """
|
|
Check if the system is currently resting (Shabbat/festival).
|
|
"""
|
|
@spec resting?() :: boolean()
|
|
def resting? do
|
|
GenServer.call(__MODULE__, :resting?)
|
|
end
|
|
|
|
@doc """
|
|
Get the current state.
|
|
"""
|
|
@spec state() :: map()
|
|
def state do
|
|
GenServer.call(__MODULE__, :state)
|
|
end
|
|
|
|
# --- GenServer callbacks ---
|
|
|
|
@impl true
|
|
def init(_opts) do
|
|
state = %{
|
|
resting: VavPipeline.Cloud.shabbat?(DateTime.utc_now()),
|
|
last_check: DateTime.utc_now(),
|
|
shabbat_count: 0
|
|
}
|
|
|
|
schedule_check()
|
|
|
|
Logger.info("ShabbatTimer started — resting: #{state.resting}")
|
|
{:ok, state}
|
|
end
|
|
|
|
@impl true
|
|
def handle_call(:resting?, _from, state) do
|
|
{:reply, state.resting, state}
|
|
end
|
|
|
|
@impl true
|
|
def handle_call(:state, _from, state) do
|
|
{:reply, state, state}
|
|
end
|
|
|
|
@impl true
|
|
def handle_info(:check_boundary, state) do
|
|
now = DateTime.utc_now()
|
|
is_shabbat = VavPipeline.Cloud.shabbat?(now)
|
|
|
|
new_state =
|
|
cond do
|
|
not state.resting and is_shabbat ->
|
|
# Shabbat has begun — cease all processing
|
|
Logger.info("ShabbatTimer: Shabbat begins — ceasing all processing")
|
|
%{state | resting: true, last_check: now, shabbat_count: state.shabbat_count + 1}
|
|
|
|
state.resting and not is_shabbat ->
|
|
# Shabbat has ended — resume processing
|
|
Logger.info("ShabbatTimer: Shabbat ends — resuming processing")
|
|
%{state | resting: false, last_check: now}
|
|
|
|
true ->
|
|
%{state | last_check: now}
|
|
end
|
|
|
|
schedule_check()
|
|
{:noreply, new_state}
|
|
end
|
|
|
|
defp schedule_check do
|
|
Process.send_after(self(), :check_boundary, @check_interval)
|
|
end
|
|
end
|