diff --git a/talmudic_engine/src/halt/avodah_zarah.pl b/talmudic_engine/src/halt/avodah_zarah.pl index 9336caf2..c5c8b22c 100644 --- a/talmudic_engine/src/halt/avodah_zarah.pl +++ b/talmudic_engine/src/halt/avodah_zarah.pl @@ -46,12 +46,43 @@ %% boundary, not at a runtime halt. %% %% Form 2: GOLDEN CALF / UNCOUPLED OUTPUT +%% Defended at TWO layers (vehaya §3.2): +%% +%% RUNTIME LAYER (this file): +%% halt_check_golden_calf/2 fires on interpretations with empty +%% coupling_trace and non-low confidence. Detects the post-hoc +%% case where an interpretation was constructed (somehow) with +%% no trace. +%% +%% ARCHITECTURAL LAYER (talmudic_engine/src/reasoning/interpret.pl): +%% The Torah anchor is Vayikra 10:1 — eish zarah אֲשֶׁר לֹא +%% צִוָּה אֹתָם. The disqualifier is provenance: not +%% commanded-derivable. Plus Shemot 32:24's "וַיֵּצֵא הָעֵגֶל +%% הַזֶּה" — the failure mode includes claiming output emerged +%% by itself, without operator agency. +%% +%% The architectural commitment: construct_interpretation/4 +%% (the no-coupling-trace variant) is REMOVED from interpret.pl +%% entirely. Only construct_interpretation/5 — which requires +%% a Couplings argument — is callable. Production callers go +%% through interpret/2, which always supplies real Couplings +%% from find_relevant_*_traced/3. The bypass shape (build an +%% interpretation/6 with empty trace via a high-level +%% constructor) is no longer reachable. +%% +%% Test code that needs an empty-trace interpretation must +%% construct the interpretation/6 term DIRECTLY, visibly +%% bypassing the constructor — making the bypass deliberate, +%% not accidental, and surfacing it in code review. +%% +%% Plus Form 4 (self_grounding) catches the related case where +%% the trace is non-empty but its anchors don't terminate in L1 +%% (one degree more elaborate, same idolatry). +%% %% Shemot 32:4 — vayomer eleh elohekha Yisrael. %% Output that is beautiful, resonant, sincere — but uncoupled %% from L1. Fire without altar provenance. The golden calf was %% real gold and the worship was sincere. The god was false. -%% Detected via coupling_trace: an interpretation with empty -%% trace but high confidence is eish zarah. %% %% Form 3: SURVEILLANCE / PROFILE AGGREGATION %% Realized as ARCHITECTURE, not as a runtime check (vehaya §3.2). diff --git a/talmudic_engine/src/reasoning/interpret.pl b/talmudic_engine/src/reasoning/interpret.pl index f1555d95..53409ba5 100644 --- a/talmudic_engine/src/reasoning/interpret.pl +++ b/talmudic_engine/src/reasoning/interpret.pl @@ -19,13 +19,25 @@ %% (eish tamid, Vayikra 6:6) has altar provenance. Fire without %% altar provenance is eish zarah. +%% FORM 2 architectural commitment (vehaya §3.2; avodah_zarah.pl +%% Form 2): construct_interpretation/4 (the no-coupling-trace +%% variant) is NO LONGER EXPORTED. Vayikra 10:1's "asher lo tzivah" +%% disqualifies output without command-derivation. The arity-4 form +%% built interpretation/6 with empty coupling_trace — the bypass +%% shape that would let a future caller produce sincere-but- +%% uncoupled output, the exact failure mode Form 2 identifies. Only +%% construct_interpretation/5 (with Couplings argument) is callable +%% from outside this module; production callers go through interpret/2, +%% which always supplies real Couplings derived from +%% find_relevant_*_traced/3. + :- module(interpret, [ interpret/2, find_relevant_mitzvot/2, find_relevant_verses/2, find_relevant_mitzvot_traced/3, find_relevant_verses_traced/3, - construct_interpretation/4 + construct_interpretation/5 ]). :- use_module('../specification/mitzvot'). @@ -120,14 +132,17 @@ find_relevant_verses_traced(case(_Ref, _Domain, Roots, _Question), Verses, Coupl %% - medium: only mitzvot or only verses %% - low: neither (but still generates a minimal reading) %% -%% Arity-4 version for backward compatibility (no coupling trace) -construct_interpretation(CaseRef, Mitzvot, Verses, Interpretation) :- - assess_confidence(Mitzvot, Verses, Confidence), - build_reading(Mitzvot, Verses, Reading), - Interpretation = interpretation(CaseRef, Mitzvot, Verses, Reading, Confidence, - coupling_trace([])). - -%% Arity-5 version with coupling trace +%% Arity-5 only — the arity-4 (no-coupling-trace) variant was +%% removed to close Form 2 of avodah zarah architecturally +%% (vehaya §3.2). Vayikra 10:1's "asher lo tzivah" disqualifies +%% output without command-derivation; constructing interpretation/6 +%% with empty coupling_trace is the bypass shape that arity-4 made +%% available. Production callers go through interpret/2, which +%% always supplies real Couplings from find_relevant_*_traced/3. +%% Test code that needs an empty-trace interpretation must +%% construct it directly via the interpretation/6 term (visibly +%% bypassing the constructor) — making the bypass deliberate, not +%% accidental. construct_interpretation(CaseRef, Mitzvot, Verses, Couplings, Interpretation) :- assess_confidence(Mitzvot, Verses, Confidence), build_reading(Mitzvot, Verses, Reading), diff --git a/talmudic_engine/test/halt_test.pl b/talmudic_engine/test/halt_test.pl index 9ebfc504..3e6ff994 100644 --- a/talmudic_engine/test/halt_test.pl +++ b/talmudic_engine/test/halt_test.pl @@ -208,6 +208,34 @@ test(every_interpret_coupling_is_l1_grounded, [nondet]) :- :- end_tests(interpret_self_grounding_regression). +%% ============================================================ +%% Form 2 ARCHITECTURAL COMMITMENT (vehaya §3.2): +%% construct_interpretation/4 is no longer exported. The bypass +%% shape (build interpretation/6 with empty trace via a high-level +%% constructor) is removed at the export-list level. Vayikra 10:1's +%% asher-lo-tzivah enforced architecturally, not just by runtime +%% halt. +%% ============================================================ + +:- begin_tests(interpret_no_arity_4_constructor). + +%% The arity-5 constructor IS exported (production path). +test(arity_5_constructor_exported) :- + interpret:construct_interpretation(_, _, _, _, _) = _. + +%% The arity-4 constructor is NOT exported. Calling it through the +%% module surface should fail (the predicate is not visible to +%% module callers; if it were, this clause would succeed). +test(arity_4_constructor_not_exported, [fail]) :- + catch( + interpret:construct_interpretation(_, _, _, _), + _Error, + fail + ). + +:- end_tests(interpret_no_arity_4_constructor). + + :- begin_tests(shfichut_damim). %% Detects deletion of a user (tzelem carrier) diff --git a/vav_pipeline/lib/vav_pipeline/doorpost.ex b/vav_pipeline/lib/vav_pipeline/doorpost.ex index 59ff8454..525c6a7f 100644 --- a/vav_pipeline/lib/vav_pipeline/doorpost.ex +++ b/vav_pipeline/lib/vav_pipeline/doorpost.ex @@ -159,7 +159,7 @@ defmodule VavPipeline.Doorpost do # changes; the update is a deliberate operator commit. A bare # hash-update commit (without a corresponding spec change in the # same commit) is itself a drift signal. - @expected_hash "bf3d3433bb27b589c061855d932a1eabfc880570c31d24f6f43e51aa3b073c70" + @expected_hash "8eb378964f202522f60cc960a3002f6da2e5028538595400de906a9510b3bbf6" @doc "Return the list of files that constitute the category-grade specification." @spec files() :: [String.t()]