From e01181959d09cb2da25253fc8ed8a0c644f6197b Mon Sep 17 00:00:00 2001 From: Scott Karp Date: Mon, 19 Oct 2026 18:25:17 +0000 Subject: [PATCH] tablet 55, fourth: the engine answers the whole dialectic over the wire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live after vav :4bffa01e the judges consulted with roots the engine could read — interpret found 4 mitzvot and 11 verses for bereishit 1:1 — and the other two seats still said teiku. The engine had no "challenge" action at all (process_json_line failed and the socket fell silent), and a resolve that SUCCEEDED came back UNEXPECTED_RESPONSE because response(ok, resolved_accepted, ...) had no JSON clause. Both pre-existing; both invisible until a judge asked. - api.pl: request(challenge, ...) — interpret, then a kushya against it → resolved_challenged with the kushya; none → no_challenge with the reading. - json_bridge.pl: interpreted | resolved_accepted | no_challenge share the "resolved" JSON; resolved_challenged now carries the interpretation's verses and mitzvot (a judge rejecting on the kushya cites its ground); resolved_synthesized and no_interpretation gain clauses. - reasoning_test.pl: dialectic_over_the_wire — all three actions answer; no roots → resolved on an empty trace (the judge abstains). Prolog: 7 suites green (bedikah 45, halt 49, middot 47, mitzvot 42, phase3 28, reasoning 18, tzaraat 34). Local probe: interpret / challenge / resolve each → resolved, 11 verses, 4 mitzvot. Live proof waits for tomorrow's manna: today's five panels were all spent on verification (503 MANNA_DEPLETED, as specified). Co-Authored-By: Claude Fable 5.1 --- talmudic_engine/src/interface/api.pl | 18 +++++++ talmudic_engine/src/interface/json_bridge.pl | 47 ++++++++++++++++--- talmudic_engine/test/reasoning_test.pl | 49 ++++++++++++++++++++ 3 files changed, 108 insertions(+), 6 deletions(-) diff --git a/talmudic_engine/src/interface/api.pl b/talmudic_engine/src/interface/api.pl index 7bb6e0ff..3fd4bf42 100644 --- a/talmudic_engine/src/interface/api.pl +++ b/talmudic_engine/src/interface/api.pl @@ -45,6 +45,24 @@ process_request(request(resolve, CaseRef, Domain, Roots, Question), Response) :- ; Response = response(error, no_resolution, CaseRef) ). +%% The challenge step of the dialectic, on its own (tablet 55: the +%% Sanhedrin's second seat asks it; until now no handler answered and +%% the socket fell silent). Interpret, then look for a kushya against +%% the interpretation: one stands → resolved_challenged, the kushya +%% named; none → no_challenge, the interpretation as read. +process_request(request(challenge, CaseRef, Domain, Roots, Question), Response) :- + Case = case(CaseRef, Domain, Roots, Question), + ( interpret(Case, Interpretation) + -> ( challenge(Interpretation, Kushya) + -> Response = response(ok, resolved_challenged, + result(interpretation(Interpretation), + challenge(Kushya))) + ; format_interpretation(Interpretation, response(ok, interpreted, Result)), + Response = response(ok, no_challenge, Result) + ) + ; Response = response(error, no_interpretation, CaseRef) + ). + process_request(request(halt_check, Action), Response) :- format_halt_check(Action, Response). diff --git a/talmudic_engine/src/interface/json_bridge.pl b/talmudic_engine/src/interface/json_bridge.pl index 69011510..bdb2a615 100644 --- a/talmudic_engine/src/interface/json_bridge.pl +++ b/talmudic_engine/src/interface/json_bridge.pl @@ -153,11 +153,15 @@ read_coupling_term(Str, Term) :- %% JSON format (Construction §3.3): %% { "status": "resolved", "interpretation": { ... } } -%% Interpreted response -response_to_json(response(ok, interpreted, result(ref(Ref), mitzvot(Mitzvot), - verses(Verses), reading(Reading), - confidence(Conf))), +%% Interpreted response — and the same shape under the names the +%% resolve and challenge steps give it when the reading stands +%% (tablet 55: resolved_accepted had no clause, so a resolve that +%% succeeded came back UNEXPECTED_RESPONSE; no_challenge is new). +response_to_json(response(ok, Kind, result(ref(Ref), mitzvot(Mitzvot), + verses(Verses), reading(Reading), + confidence(Conf))), Dict) :- + memberchk(Kind, [interpreted, resolved_accepted, no_challenge]), maplist(term_to_string, Mitzvot, MitzvotStrs), maplist(term_to_string, Verses, VerseStrs), term_to_string(Reading, ReadingStr), @@ -171,21 +175,52 @@ response_to_json(response(ok, interpreted, result(ref(Ref), mitzvot(Mitzvot), confidence: ConfStr}, challenge: null}. -%% Challenged response +%% Challenged response — the interpretation's verses and mitzvot are +%% carried, so a judge rejecting on the kushya still cites its ground. response_to_json(response(ok, resolved_challenged, result(interpretation(Interp), challenge(Kushya))), Dict) :- + Interp = interpretation(_Ref, Mitzvot, Verses, _Reading, _Conf, _Trace), + maplist(term_to_string, Mitzvot, MitzvotStrs), + maplist(term_to_string, Verses, VerseStrs), term_to_string(Interp, InterpStr), term_to_string(Kushya, KushyaStr), Dict = json{status: "challenged", interpretation: json{text: InterpStr, prolog_form: InterpStr, - grounding: [], + grounding: MitzvotStrs, + verses: VerseStrs, confidence: "medium"}, challenge: json{kushya: KushyaStr, contradicting: "", strength: "moderate"}}. +%% Synthesized resolution: both readings stand on common ground. +response_to_json(response(ok, resolved_synthesized, + result(common(Common), verses(Verses), both_sides(Both))), + Dict) :- + maplist(term_to_string, Common, CommonStrs), + maplist(term_to_string, Verses, VerseStrs), + term_to_string(Both, BothStr), + Dict = json{status: "resolved", + interpretation: json{text: BothStr, + prolog_form: BothStr, + grounding: CommonStrs, + verses: VerseStrs, + confidence: "medium"}, + challenge: null}. + +%% No interpretation possible (from resolve) +response_to_json(response(ok, no_interpretation, result(ref(Ref))), Dict) :- + atom_string(Ref, RefStr), + Dict = json{status: "teiku", + interpretation: json{text: "No interpretation found", + prolog_form: RefStr, + grounding: [], + verses: [], + confidence: "low"}, + challenge: null}. + %% Teiku response response_to_json(response(ok, teiku, result(record(Record))), Dict) :- term_to_string(Record, RecordStr), diff --git a/talmudic_engine/test/reasoning_test.pl b/talmudic_engine/test/reasoning_test.pl index 9d33564c..0f2666e6 100644 --- a/talmudic_engine/test/reasoning_test.pl +++ b/talmudic_engine/test/reasoning_test.pl @@ -112,3 +112,52 @@ test(teiku_count_works) :- 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).