%% reasoning_test.pl — Tests for the dialectical reasoning engine. :- use_module(library(plunit)). :- use_module('../src/reasoning/interpret'). :- use_module('../src/reasoning/challenge'). :- use_module('../src/reasoning/resolve'). :- use_module('../src/reasoning/teiku'). :- use_module('../src/specification/mitzvot'). :- use_module('../src/specification/torah_text'). :- begin_tests(interpret). %% Can interpret a case about creation test(interpret_creation, [nondet]) :- Case = case(test_creation, creation, [bet_resh_aleph], 'What is creation?'), interpret(Case, Interpretation), Interpretation = interpretation(test_creation, _, _, _, _, _). %% Interpretation finds relevant verses test(interpret_finds_verses, [nondet]) :- Case = case(test_verses, creation, [bet_resh_aleph], 'Find creation verses'), interpret(Case, interpretation(_, _, Verses, _, _, _)), Verses \= []. %% Interpretation finds relevant mitzvot test(interpret_finds_mitzvot, [nondet]) :- Case = case(test_mitzvot, judgment, [shin_pe_tet], 'How to judge?'), interpret(Case, interpretation(_, Mitzvot, _, _, _, _)), Mitzvot \= []. %% High confidence when both mitzvot and verses found test(interpret_high_confidence, [nondet]) :- Case = case(test_conf, holiness, [qof_dalet_shin], 'What is holiness?'), interpret(Case, interpretation(_, _, _, _, high, _)). %% Coupling trace is present (eish_zarah_reading.md §5.1) test(interpret_has_coupling_trace, [nondet]) :- Case = case(test_trace, creation, [bet_resh_aleph], 'Test coupling'), interpret(Case, interpretation(_, _, _, _, _, coupling_trace(Trace))), Trace \= []. %% Coupling trace records root→verse connections test(coupling_trace_has_verse_coupling, [nondet]) :- Case = case(test_coupling, creation, [bet_resh_aleph], 'Test verse coupling'), interpret(Case, interpretation(_, _, _, _, _, coupling_trace(Trace))), member(coupled(root(bet_resh_aleph), verse(_, _, _)), Trace). :- end_tests(interpret). :- begin_tests(challenge). %% Can challenge an interpretation about judgment (justice vs mercy tension) test(challenge_judgment, [nondet]) :- Case = case(test_judgment, judgment, [shin_pe_tet, tzade_dalet_qof], 'How to judge righteously?'), interpret(Case, Interpretation), challenge(Interpretation, Kushya), Kushya = kushya(_, _, _, _). %% Challenge has a strength test(challenge_has_strength, [nondet]) :- Case = case(test_str, judgment, [shin_pe_tet], 'Test strength'), interpret(Case, Interpretation), challenge(Interpretation, kushya(_, _, Strength, _)), member(Strength, [strong, moderate, weak]). %% Challenge has grounding type (eish_zarah_reading.md §5.2) test(challenge_has_grounding_type, [nondet]) :- Case = case(test_gtype, judgment, [shin_pe_tet, tzade_dalet_qof], 'Test grounding type'), interpret(Case, Interpretation), challenge(Interpretation, kushya(_, _, _, GType)), member(GType, [achorai, panim]). %% Grounding type for mitzvah_tension is achorai (text-backed) test(mitzvah_tension_is_achorai) :- grounding_type(contradiction(mitzvah_tension, _, _, _), achorai). %% Grounding type for domain_tension is panim (inferred) test(domain_tension_is_panim) :- grounding_type(contradiction(domain_tension, _, _, _), panim). :- end_tests(challenge). :- begin_tests(resolve). %% Can resolve a simple case (no challenge) test(resolve_simple, [nondet]) :- Case = case(test_simple, creation, [bet_resh_aleph], 'What is creation?'), resolve(Case, Resolution), ( Resolution = accepted(_) ; Resolution = challenged(_, _) ; Resolution = synthesized(_, _, _) ; Resolution = teiku(_) ). %% Resolution produces some result test(resolve_produces_result, [nondet]) :- Case = case(test_result, holiness, [qof_dalet_shin], 'What is holiness?'), resolve(Case, _Resolution). :- end_tests(resolve). :- begin_tests(teiku_module). %% Teiku count starts at zero (or is a number) test(teiku_count_works) :- teiku_count(Count), integer(Count). :- end_tests(teiku_module). %% ============================================================ %% Tablet 55 — the dialectic over the wire: interpret, challenge, %% resolve each answer JSON a judge can vote on. Before this the %% engine had no "challenge" action and a resolve that succeeded came %% back UNEXPECTED_RESPONSE (resolved_accepted had no JSON clause). %% ============================================================ :- use_module('../src/interface/api'). :- use_module('../src/interface/json_bridge'). :- use_module('../src/interface/socket_server'). :- begin_tests(dialectic_over_the_wire). roots_line(Action, Line) :- format(atom(Line), '{"action":"~w","case":{"ref":"t55-~w","question":"q","context_roots":["bet-resh-aleph","aleph-lamed-he"]}}', [Action, Action]). test(interpret_answers_resolved_with_verses, [nondet]) :- roots_line(interpret, L), socket_server:process_json_line(L, R), get_dict(status, R, "resolved"), get_dict(interpretation, R, I), get_dict(verses, I, Vs), Vs \== []. test(challenge_answers_and_carries_the_ground, [nondet]) :- roots_line(challenge, L), socket_server:process_json_line(L, R), get_dict(status, R, S), memberchk(S, ["resolved", "challenged"]), get_dict(interpretation, R, I), get_dict(verses, I, Vs), Vs \== []. test(resolve_answers_resolved_not_unexpected, [nondet]) :- roots_line(resolve, L), socket_server:process_json_line(L, R), \+ get_dict(error, R, _), get_dict(status, R, S), memberchk(S, ["resolved", "challenged", "teiku"]). test(no_roots_resolves_on_an_empty_trace, [nondet]) :- socket_server:process_json_line('{"action":"interpret","case":{"ref":"t55-empty","question":"q","context_roots":[]}}', R), get_dict(status, R, "resolved"), get_dict(interpretation, R, I), get_dict(verses, I, []), get_dict(grounding, I, []). :- end_tests(dialectic_over_the_wire).