Skip to content

Machloket Handling

Halachic literature is replete with disputes (machloket) between authorities. Mistaber's multi-world architecture is specifically designed to represent these disputes accurately. This document explains how to identify, encode, and test machloket across the seven Kripke worlds.

Types of Disputes

Mechaber vs Rema (Primary Dispute Pattern)

The most common machloket pattern: Mechaber (Sefardi) vs Rema (Ashkenazi) on foundational issues.

graph TD
    A[Shulchan Aruch Seif] --> B{Rema glosses?}

    B -->|Yes - Explicit disagreement| C[Mechaber + Rema worlds<br/>with override]
    B -->|Yes - Addition only| D[Mechaber world<br/>Rema inherits + adds]
    B -->|No gloss| E[Mechaber world only<br/>All inherit]

When to encode as machloket: - Rema explicitly says "yesh omrim" (some say) differently - Rema adds "v'yeish l'hachmir" (and one should be stringent) - Rema's gloss contradicts Mechaber's ruling - Later poskim document this as a machloket

When NOT to encode as machloket: - Rema adds a case not covered by Mechaber - Rema provides additional detail without disagreement - Rema's silence (implies agreement)

Rishonim Disputes (Pre-SA)

Disputes between Rishonim that the Shulchan Aruch resolved:

% SA follows Rambam over Rosh on this point
rule(r_following_rambam).
makor(r_following_rambam, sa("yd:XX:Y")).
makor(r_following_rambam, rambam("hilchot:X:Y")).

% Document the Rishonim machloket in comments
% RISHONIM MACHLOKET:
% Rambam: [Position A]
% Rosh: [Position B]
% SA follows: Rambam
% Reason: Per Beit Yosef...

scope(r_following_rambam, mechaber).

Rishonim Disputes

When encoding SA, follow the SA's resolution. Document alternative Rishonim views in comments for context, but do not create separate worlds for Rishonim.

Acharonim Disputes (Post-SA)

Disputes between later authorities about interpreting SA/Rema:

% Taz and Shach disagree on interpretation
% === Following Shach's interpretation (more widely accepted) ===
rule(r_shach_interpretation).
makor(r_shach_interpretation, sa("yd:XX:Y")).
makor(r_shach_interpretation, shach("yd:XX:Z")).
scope(r_shach_interpretation, mechaber).

% === Alternative: Taz interpretation ===
% If Taz's view is followed in specific child worlds, encode there
% See: ashk_ah may follow Taz in some cases

Later Poskim (Child World) Disputes

When Mishnah Berurah and Aruch HaShulchan disagree:

% === Mishnah Berurah position ===
rule(r_mb_stricter_view).
makor(r_mb_stricter_view, mishnah_berurah("yd:XX:Y")).
scope(r_mb_stricter_view, ashk_mb).

asserts(ashk_mb, stricter_ruling(X)).

% === Aruch HaShulchan position ===
rule(r_ah_lenient_view).
makor(r_ah_lenient_view, aruch_hashulchan("yd:XX:Y")).
scope(r_ah_lenient_view, ashk_ah).

override(ashk_ah, stricter_ruling(X), lenient_ruling).
asserts(ashk_ah, lenient_ruling(X)).

Override Semantics

The override/3 Predicate

Syntax: override(World, OverriddenProp, DescriptiveValue)

The third argument is a descriptive value indicating the overriding position, NOT 'invalid' or 'false':

% CORRECT - descriptive values
override(rema, sakana(M), no_sakana) :-
    is_dag_chalav_mixture(M).

override(rema, issur(achiila, M, sakana), permitted_eating) :-
    is_dag_chalav_mixture(M).

override(ashk_ah, safek_policy(d_rabanan, l_chumra), l_kula) :-
    context(normal).

Never Use 'invalid' in Override

% WRONG - never use 'invalid'
override(rema, sakana(M), invalid).

% WRONG - never use 'false'
override(rema, sakana(M), false).

% WRONG - never use 'null'
override(rema, sakana(M), null).

How Override Works with Kripke Inheritance

graph TD
    subgraph "Without Override"
        A1[base asserts X] --> B1[mechaber inherits X]
        B1 --> C1[sefardi_yo inherits X]
    end

    subgraph "With Override"
        A2[mechaber asserts sakana M] --> B2[sefardi_yo inherits sakana M]
        A2 -.->|override| C2[rema: no_sakana M]
        C2 --> D2[ashk_mb inherits no_sakana M]
        C2 --> E2[ashk_ah inherits no_sakana M]
    end

Override Propagation Rules

Scenario Result
Parent asserts X, no override Child inherits X
Parent asserts X, child overrides Child has override value
Grandchild of overriding world Inherits the override
Override in one branch Other branches unaffected
% mechaber asserts sakana
asserts(mechaber, sakana(M)) :- is_dag_chalav_mixture(M).

% rema overrides
override(rema, sakana(M), no_sakana) :- is_dag_chalav_mixture(M).

% Inheritance result:
% - sefardi_yo: inherits sakana(M) from mechaber
% - ashk_mb: inherits no_sakana(M) from rema (via override)
% - ashk_ah: inherits no_sakana(M) from rema (via override)

Multi-World Encoding Strategy

Step 1: Identify the Dispute

Analyze the source to determine:

  1. Who are the disputants?
  2. Mechaber vs Rema?
  3. Shach vs Taz?
  4. MB vs AH?

  5. What is the nature of disagreement?

  6. Complete opposition?
  7. Scope limitation?
  8. Stringency level?

  9. Which worlds are affected?

  10. Does it affect all descendants?
  11. Is it limited to specific traditions?

Step 2: Encode the Base Position

Start with the position in the primary world:

% ============================================================
% MACHLOKET: Fish + Dairy
% Mechaber: Forbidden due to sakana
% Rema: Permitted
% ============================================================

% === Mechaber's Position (Primary) ===
rule(r_bb_dag_sakana).
makor(r_bb_dag_sakana, sa("yd:87:3")).
makor(r_bb_dag_sakana, beit_yosef("yd:87")).
scope(r_bb_dag_sakana, mechaber).

asserts(mechaber, sakana(M)) :-
    is_dag_chalav_mixture(M).

asserts(mechaber, issur(achiila, M, sakana)) :-
    is_dag_chalav_mixture(M).

Step 3: Encode the Override Position

Add the overriding position in the appropriate world:

% === Rema's Override Position ===
rule(r_rema_dag_chalav_mutar).
makor(r_rema_dag_chalav_mutar, rema("yd:87:3")).
makor(r_rema_dag_chalav_mutar, taz("yd:87:3")).
makor(r_rema_dag_chalav_mutar, shach("yd:87:5")).
scope(r_rema_dag_chalav_mutar, rema).

% Override the sakana assertion
override(rema, sakana(M), no_sakana) :-
    is_dag_chalav_mixture(M).

override(rema, issur(achiila, M, sakana), permitted) :-
    is_dag_chalav_mixture(M).

% Explicitly assert the permissive position
asserts(rema, heter(achiila, M)) :-
    is_dag_chalav_mixture(M).

asserts(rema, no_sakana(M)) :-
    is_dag_chalav_mixture(M).

Step 4: Mark the Machloket

Use the machloket/4 predicate to document the dispute:

% Document the machloket
machloket(dag_chalav_sakana, mechaber, rema, M) :-
    is_dag_chalav_mixture(M).

Step 5: Verify Child World Inheritance

Confirm child worlds inherit correctly:

% === Verification: sefardi_yo ===
% Should inherit sakana from mechaber
% No override in sefardi_yo, so mechaber's position propagates

% === Verification: ashk_mb ===
% Should inherit no_sakana from rema
% No override in ashk_mb, so rema's override propagates

% === Verification: ashk_ah ===
% Should inherit no_sakana from rema
% Also accessible from gra (who also permits)
% No override in ashk_ah, so rema's position propagates

Testing Both Positions

Required Tests for Machloket

Every machloket encoding requires tests for both positions:

import pytest
from mistaber import query

class TestFishDairyMachloket:
    """Tests for fish+dairy machloket between Mechaber and Rema."""

    @pytest.fixture
    def fish_dairy_mixture(self):
        return """
            mixture(m1).
            food(salmon). food_type(salmon, dag).
            food(cream). food_type(cream, chalav).
            contains(m1, salmon). contains(m1, cream).
        """

    # === Mechaber Position Tests ===

    def test_mechaber_asserts_sakana(self, fish_dairy_mixture):
        """Mechaber holds fish+dairy is sakana."""
        result = query(fish_dairy_mixture, world="mechaber")
        assert result.holds("sakana(m1)")

    def test_mechaber_forbids_eating(self, fish_dairy_mixture):
        """Mechaber forbids eating fish+dairy due to sakana."""
        result = query(fish_dairy_mixture, world="mechaber")
        assert result.holds("issur(achiila, m1, sakana)")

    def test_sefardi_yo_inherits_sakana(self, fish_dairy_mixture):
        """Yalkut Yosef inherits sakana from Mechaber."""
        result = query(fish_dairy_mixture, world="sefardi_yo")
        assert result.holds("sakana(m1)")
        assert result.holds("issur(achiila, m1, sakana)")

    # === Rema Position Tests ===

    def test_rema_permits_eating(self, fish_dairy_mixture):
        """Rema permits eating fish+dairy."""
        result = query(fish_dairy_mixture, world="rema")
        assert result.holds("heter(achiila, m1)")
        assert not result.holds("sakana(m1)")

    def test_rema_asserts_no_sakana(self, fish_dairy_mixture):
        """Rema explicitly holds no sakana."""
        result = query(fish_dairy_mixture, world="rema")
        assert result.holds("no_sakana(m1)")

    def test_ashk_mb_inherits_permission(self, fish_dairy_mixture):
        """Mishnah Berurah inherits permission from Rema."""
        result = query(fish_dairy_mixture, world="ashk_mb")
        assert result.holds("heter(achiila, m1)")
        assert result.holds("no_sakana(m1)")

    def test_ashk_ah_inherits_permission(self, fish_dairy_mixture):
        """Aruch HaShulchan inherits permission from Rema."""
        result = query(fish_dairy_mixture, world="ashk_ah")
        assert result.holds("heter(achiila, m1)")

    # === Machloket Detection Test ===

    def test_machloket_detected(self, fish_dairy_mixture):
        """The machloket between Mechaber and Rema is detected."""
        result = query(fish_dairy_mixture, world="base")
        assert result.holds("machloket(dag_chalav_sakana, mechaber, rema, m1)")

Cross-World Comparison Tests

def test_cross_world_divergence(fish_dairy_mixture):
    """Verify that worlds diverge correctly on this machloket."""
    mechaber_result = query(fish_dairy_mixture, world="mechaber")
    rema_result = query(fish_dairy_mixture, world="rema")

    # Mechaber and Rema should disagree
    assert mechaber_result.holds("sakana(m1)")
    assert not rema_result.holds("sakana(m1)")

    # Verify they have opposite rulings
    assert mechaber_result.holds("issur(achiila, m1, sakana)")
    assert rema_result.holds("heter(achiila, m1)")

Edge Cases in Disputes

Partial Agreement

When authorities agree on principle but differ on application:

% Both agree poultry+dairy is d_rabanan
% But disagree on specific application

% === Shared Agreement ===
% Encode in both worlds explicitly
rule(r_bb_of_drabbanan_mechaber).
scope(r_bb_of_drabbanan_mechaber, mechaber).
asserts(mechaber, issur(achiila, M, d_rabanan)) :-
    is_of_chalav_mixture(M).

rule(r_bb_of_drabbanan_rema).
scope(r_bb_of_drabbanan_rema, rema).
asserts(rema, issur(achiila, M, d_rabanan)) :-
    is_of_chalav_mixture(M).

% === Disagreement on Application ===
% Mechaber: Specific leniency applies
% Rema: Does not apply
% Encode the disagreement in specific rule

Three-Way Disputes

When GRA differs from both Mechaber and Rema:

% === Mechaber's Position ===
rule(r_mechaber_pos).
scope(r_mechaber_pos, mechaber).
asserts(mechaber, position_a(X)).

% === Rema's Position (differs from Mechaber) ===
rule(r_rema_pos).
scope(r_rema_pos, rema).
override(rema, position_a(X), position_b).
asserts(rema, position_b(X)).

% === GRA's Position (differs from both) ===
rule(r_gra_pos).
scope(r_gra_pos, gra).
override(gra, position_a(X), position_c).  % Overrides if inherited from base
asserts(gra, position_c(X)).

% === Aruch HaShulchan ===
% AH inherits from both rema AND gra
% Need to resolve which position AH follows
% If AH follows GRA on this:
override(ashk_ah, position_b(X), position_c) :-
    follows_gra(ashk_ah, this_topic).

Conditional Machloket

When dispute only applies under certain conditions:

% Machloket only applies when hefsed is present
% In normal circumstances, all agree

% === Agreement in Normal Circumstances ===
asserts(mechaber, issur(achiila, M, d_rabanan)) :-
    some_mixture(M),
    context(ctx_normal).

% Rema inherits (no override needed for normal context)

% === Machloket in Hefsed ===
% Mechaber: Still forbidden
asserts(mechaber, issur(achiila, M, d_rabanan)) :-
    some_mixture(M),
    context(ctx_hefsed).

% Rema: Permitted due to hefsed
rule(r_rema_hefsed_leniency).
scope(r_rema_hefsed_leniency, rema).

asserts(rema, heter(achiila, M)) :-
    some_mixture(M),
    context(ctx_hefsed),
    has_supporting_opinion(M).

machloket(hefsed_leniency, mechaber, rema, M) :-
    some_mixture(M),
    context(ctx_hefsed).

Temporal Machloket

When practice changed over time:

% Historical: Earlier practice
% Current: Contemporary practice

% === Original Ruling ===
rule(r_original_ruling).
makor(r_original_ruling, sa("yd:XX:Y")).
scope(r_original_ruling, mechaber).
asserts(mechaber, original_practice(X)).

% === Contemporary Override (in child world) ===
rule(r_contemporary_practice).
makor(r_contemporary_practice, yalkut_yosef("yd:XX:Y")).
scope(r_contemporary_practice, sefardi_yo).

% Yalkut Yosef updates the practice
override(sefardi_yo, original_practice(X), contemporary_practice).
asserts(sefardi_yo, contemporary_practice(X)).

% Document this is a temporal change, not disagreement
temporal_change(original_ruling, contemporary_practice, sefardi_yo).

Machloket Documentation Template

Use this template for documenting machloket:

% ============================================================
% MACHLOKET: [Topic Name]
% ============================================================
%
% DISPUTANTS:
%   - [Authority 1]: [Their position]
%   - [Authority 2]: [Their position]
%
% SOURCES:
%   - [Authority 1]: [Citation]
%   - [Authority 2]: [Citation]
%
% AFFECTED WORLDS:
%   - [World 1]: Follows [Authority X]
%   - [World 2]: Follows [Authority Y]
%
% NATURE OF DISPUTE:
%   [Complete opposition / Scope limitation / Stringency level]
%
% PRACTICAL DIFFERENCE:
%   [What changes between the positions]
%
% ============================================================

% [Encoding follows...]

Common Machloket Mistakes

Mistake 1: Missing Override for One Branch

% WRONG - only encoded mechaber, rema has no override
asserts(mechaber, position_a(X)).
% No rema encoding -> rema incorrectly inherits position_a

% CORRECT - both positions encoded
asserts(mechaber, position_a(X)).
override(rema, position_a(X), position_b).
asserts(rema, position_b(X)).

Mistake 2: Override Without Positive Assertion

% WRONG - override without alternative assertion
override(rema, issur(achiila, M, sakana), no_issur).
% What IS permitted? Unclear.

% CORRECT - override with positive assertion
override(rema, issur(achiila, M, sakana), permitted).
asserts(rema, heter(achiila, M)).  % Explicit permission

Mistake 3: Encoding Agreement as Machloket

% WRONG - no actual disagreement
asserts(mechaber, issur(achiila, M, d_oraita)).
asserts(rema, issur(achiila, M, d_oraita)).  % Same thing!
machloket(topic, mechaber, rema, M).  % Not a machloket!

% CORRECT - only mechaber needed, rema inherits
asserts(mechaber, issur(achiila, M, d_oraita)).
% No machloket declaration - they agree

Mistake 4: Missing machloket/4 Declaration

% WRONG - machloket exists but not declared
asserts(mechaber, sakana(M)).
override(rema, sakana(M), no_sakana).
% No machloket/4 - dispute not discoverable

% CORRECT - machloket declared
asserts(mechaber, sakana(M)).
override(rema, sakana(M), no_sakana).
machloket(dag_chalav_sakana, mechaber, rema, M).  % Documented