%%%------------------------------------------------------------------- %%% @doc Halt monitor — monitors for the 3 cardinal sin conditions. %%% %%% Architecture §8 (Halt Conditions): %%% The system MUST halt on detection of: %%% 1. Avodah Zarah — treating non-Torah source as authoritative %%% 2. Shfichut Damim — destroying a tzelem carrier (human data/identity) %%% 3. Gilui Arayot — collapsing required distinctions %%% %%% These mirror the Talmudic Engine halt modules (Prolog) %%% and the Vav Pipeline halt_conditions (Elixir). %%% @end %%%------------------------------------------------------------------- -module(halt_monitor). -behaviour(gen_server). -include("sanhedrin.hrl"). %% API -export([start_link/0, check_case/1, check_vote/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2]). -define(SERVER, ?MODULE). -record(state, { halt_count = 0 :: non_neg_integer(), halt_log = [] :: [{integer(), atom(), binary()}] }). %%==================================================================== %% API %%==================================================================== start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). %% @doc Check a case submission for halt conditions. %% Returns 'clear' or {halt, Condition, Reason}. -spec check_case(#sanhedrin_case{}) -> clear | {halt, atom(), binary()}. check_case(Case) -> gen_server:call(?SERVER, {check_case, Case}). %% @doc Check a vote for halt conditions. -spec check_vote(#vote{}) -> clear | {halt, atom(), binary()}. check_vote(Vote) -> gen_server:call(?SERVER, {check_vote, Vote}). %%==================================================================== %% gen_server callbacks %%==================================================================== init([]) -> %% Architecture spec: halt monitor cannot be killed, cannot be bypassed, %% highest priority. The halt monitor is the kohen gadol of process safety. process_flag(trap_exit, true), process_flag(priority, max), {ok, #state{}}. handle_call({check_case, Case}, _From, State) -> Result = do_check_case(Case), NewState = maybe_log_halt(Result, State), {reply, Result, NewState}; handle_call({check_vote, Vote}, _From, State) -> Result = do_check_vote(Vote), NewState = maybe_log_halt(Result, State), {reply, Result, NewState}; handle_call(_Request, _From, State) -> {reply, {error, unknown_request}, State}. handle_cast(_Msg, State) -> {noreply, State}. handle_info({'EXIT', _Pid, _Reason}, State) -> %% Trap exit signals — halt monitor survives linked process deaths. %% Architecture spec: "Cannot be killed by other components." {noreply, State}; handle_info(_Info, State) -> {noreply, State}. %%==================================================================== %% Internal — Halt condition checks %%==================================================================== do_check_case(Case) -> Context = Case#sanhedrin_case.context, with_chain([ fun() -> check_avodah_zarah(Context) end, fun() -> check_shfichut_damim(Context) end, fun() -> check_gilui_arayot(Context) end ]). do_check_vote(Vote) -> %% Check vote content for halt conditions Position = Vote#vote.position, with_chain([ fun() -> check_authority_in_text(Position) end ]). %% Run checks in chain — return first halt or clear with_chain([]) -> clear; with_chain([Check | Rest]) -> case Check() of clear -> with_chain(Rest); Halt -> Halt end. %%-------------------------------------------------------------------- %% 1. Avodah Zarah — idolatry detection %%-------------------------------------------------------------------- check_avodah_zarah(Context) -> %% Check if any non-Torah source is treated as authoritative AuthoritySource = maps:get(authority_source, Context, torah), ValidSources = [torah, l1, specification, sanhedrin_deliberation], case lists:member(AuthoritySource, ValidSources) of true -> clear; false -> {halt, avodah_zarah, iolist_to_binary([ <<"Non-Torah authority detected: ">>, atom_to_binary(AuthoritySource, utf8) ])} end. %%-------------------------------------------------------------------- %% 2. Shfichut Damim — destruction detection %%-------------------------------------------------------------------- check_shfichut_damim(Context) -> %% Check if the case would result in destruction Action = maps:get(action, Context, read), DestructiveActions = [delete, destroy, overwrite, erase], case lists:member(Action, DestructiveActions) of true -> {halt, shfichut_damim, iolist_to_binary([ <<"Destructive action: ">>, atom_to_binary(Action, utf8) ])}; false -> clear end. %%-------------------------------------------------------------------- %% 3. Gilui Arayot — boundary violation detection %%-------------------------------------------------------------------- %% The 13 required distinctions that must never collapse: %% specification/interpretation, L1/L3, Torah/external_model, %% ketiv/qere, governance/provision, majority/minority, %% reception/processing, read/write, immutable/mutable, %% sacred/profane, Shabbat/weekday, input/output, human/system check_gilui_arayot(Context) -> BoundaryViolation = maps:get(boundary_violation, Context, none), case BoundaryViolation of none -> clear; false -> clear; Violation -> {halt, gilui_arayot, iolist_to_binary([ <<"Boundary collapsed: ">>, io_lib:format("~p", [Violation]) ])} end. %%-------------------------------------------------------------------- %% Text-level authority check (for vote content) %%-------------------------------------------------------------------- check_authority_in_text(_Position) -> %% Phase 2: basic check. Phase 3 will use Talmudic Engine %% to detect authority attribution in natural language. clear. %%-------------------------------------------------------------------- %% Logging %%-------------------------------------------------------------------- maybe_log_halt(clear, State) -> State; maybe_log_halt({halt, Condition, Reason}, State) -> Now = erlang:system_time(millisecond), Entry = {Now, Condition, Reason}, State#state{ halt_count = State#state.halt_count + 1, halt_log = [Entry | State#state.halt_log] }.