Tutorial 5: Encoding Machloket¶
This tutorial teaches you how to encode halachic disputes (machloket) between authorities using Mistaber's multi-world system.
Learning Objectives¶
- Understand what constitutes a machloket in Mistaber
- Encode disputes using asserts and override
- Use the machloket detection system
- Compare rulings across worlds
Prerequisites¶
- Tutorial 4: Writing Rules completed
- Understanding of world inheritance
Estimated Time¶
20 minutes
Steps¶
Step 1: What is a Machloket?¶
A machloket (dispute) occurs when different halachic authorities reach different conclusions on the same question. In Mistaber:
- Different worlds hold different values for the same predicate
- The system can detect and report these differences
- Each position is traceable to its source (makor)
Common types of machloket: - Forbidden vs Permitted: One authority forbids, another permits - D'oraita vs D'rabanan: Same prohibition, different normative level - Different conditions: Same conclusion but under different circumstances
Step 2: The Fish and Dairy Machloket¶
The classic example in YD 87 is fish with dairy:
| Authority | Position | Reasoning |
|---|---|---|
| Mechaber | Forbidden (sakana) | Medical danger cited in Beit Yosef |
| Rema | Permitted | No Talmudic source for danger |
| Taz | Permitted (strongly) | The Mechaber's source is a scribal error |
| Shach | Conditional | Only forbidden if cooked together |
Let's see how this is encoded.
Step 3: Mechaber's Position (Issur)¶
In mechaber.lp:
% YD 87:3 - Mechaber forbids fish+dairy due to sakana
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).
% Fish + dairy is forbidden due to health danger
asserts(mechaber, sakana(M)) :-
is_dag_chalav_mixture(M).
asserts(mechaber, issur(achiila, M, sakana)) :-
is_dag_chalav_mixture(M).
This creates:
- holds(sakana(M), mechaber) - There is a health danger
- holds(issur(achiila, M, sakana), mechaber) - Eating is forbidden
Step 4: Rema's Position (Heter with Override)¶
In rema.lp:
% Rema overrides Mechaber's sakana ruling
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")).
scope(r_rema_dag_chalav_mutar, rema).
% Override the sakana ruling
override(rema, sakana(M), no_sakana) :-
is_dag_chalav_mixture(M).
override(rema, issur(achiila, M, sakana), permitted) :-
is_dag_chalav_mixture(M).
% Explicitly permit fish + dairy
asserts(rema, heter(achiila, M)) :-
is_dag_chalav_mixture(M).
asserts(rema, no_sakana(M)) :-
is_dag_chalav_mixture(M).
% Mark this as a machloket
machloket(dag_chalav, mechaber, rema, M) :-
is_dag_chalav_mixture(M).
Key mechanisms:
- override/3 prevents inheritance of Mechaber's issur
- asserts/2 establishes Rema's positive ruling
- machloket/4 explicitly marks this as a dispute
Step 5: Detect Machloket Programmatically¶
Use the MachloketDetector to find disputes:
from pathlib import Path
from mistaber.engine import HsrsEngine
from mistaber.engine.machloket import MachloketDetector
engine = HsrsEngine(Path("mistaber/ontology"))
# Add a fish+dairy mixture
scenario = """
food(salmon).
food(cream).
food_type(salmon, dag).
food_type(cream, chalav).
mixture(lox_cream).
contains(lox_cream, salmon).
contains(lox_cream, cream).
"""
# Create engine with scenario facts
# (Using analyze to add facts)
engine_result = engine.analyze(scenario, world="base")
# Detect machloket
detector = MachloketDetector(engine)
machloket_list = detector.find_machloket_between(
"holds(issur(achiila, M, sakana), W)",
worlds=["mechaber", "rema"]
)
print("Machloket found:")
for m in machloket_list:
print(f" Topic: {m.topic}")
print(f" Opinions:")
for authority, opinion in m.opinions.items():
print(f" {authority}: {opinion}")
Step 6: Using the CLI for Machloket¶
The CLI has a dedicated machloket command:
# Find all machloket on a pattern
python -m core.cli.main --ontology ./mistaber/ontology machloket "status(X, Y)"
# Find machloket between specific worlds
python -m core.cli.main --ontology ./mistaber/ontology machloket \
"holds(issur(achiila, M, D), W)" \
--worlds "mechaber,rema"
Step 7: Encoding a New Machloket¶
Let's encode a fictional machloket about a new issue.
Scenario: There's a dispute about whether item X requires blessing A or blessing B.
% === World 1: Authority A says blessing_aleph ===
% In authority_a.lp
world(authority_a).
accessible(authority_a, base).
rule(r_auth_a_bracha).
makor(r_auth_a_bracha, source_a("1:1")).
scope(r_auth_a_bracha, authority_a).
asserts(authority_a, bracha(item_x, blessing_aleph)) :-
food(item_x),
category(item_x, disputed_category).
% === World 2: Authority B says blessing_bet ===
% In authority_b.lp
world(authority_b).
accessible(authority_b, base).
rule(r_auth_b_bracha).
makor(r_auth_b_bracha, source_b("2:2")).
scope(r_auth_b_bracha, authority_b).
% Override authority A's ruling (if B inherits from A)
override(authority_b, bracha(item_x, blessing_aleph), different_bracha) :-
food(item_x),
category(item_x, disputed_category).
asserts(authority_b, bracha(item_x, blessing_bet)) :-
food(item_x),
category(item_x, disputed_category).
% Mark the dispute
machloket(bracha_on_item_x, authority_a, authority_b, item_x) :-
food(item_x),
category(item_x, disputed_category).
Step 8: Compare Command for Machloket Analysis¶
Use the compare command to see all positions:
from pathlib import Path
from mistaber.engine import HsrsEngine
engine = HsrsEngine(Path("mistaber/ontology"))
# Compare a ruling across all worlds
comparison = engine.compare(
"holds(issur(achiila, M, Level), W)"
)
print("Issur achiila across all worlds:")
for world, results in comparison.items():
print(f"\n{world}:")
if results:
for r in results[:3]: # First 3
print(f" M={r.get('M')}, Level={r.get('Level')}")
else:
print(" (no issur found)")
Step 9: Interpretations Layer for Nuanced Disputes¶
Some disputes are about interpreting the same rule differently. The Shach and Taz interpretations show this:
% In shach.lp - Shach's interpretation of Mechaber's fish+dairy rule
% Mechaber's sakana only applies when COOKED together
adds_condition(shach, r_bb_dag_sakana, cooked_together).
makor(interpretation(shach, r_bb_dag_sakana), shach("yd:87:5")).
% In taz.lp - Taz's interpretation
% The entire sakana ruling is a scribal error - no issur at all
removes_condition(taz, r_bb_dag_sakana, sakana).
makor(interpretation(taz, r_bb_dag_sakana), taz("yd:87:3")).
annotation(taz, r_bb_dag_sakana, scribal_error_argument).
annotation(taz, r_bb_dag_sakana, original_text_said_meat).
Step 10: Handling Safek in Machloket¶
When there's a machloket, some authorities use different safek policies:
from pathlib import Path
from mistaber.engine import HsrsEngine
engine = HsrsEngine(Path("mistaber/ontology"))
# Compare safek policies
ashk_mb_policy = engine.query("safek_policy(ashk_mb, d_rabanan, P)")
ashk_ah_policy = engine.query("safek_policy(ashk_ah, d_rabanan, P)")
print(f"Mishnah Berurah on safek d'rabanan: {ashk_mb_policy}")
print(f"Aruch Hashulchan on safek d'rabanan: {ashk_ah_policy}")
# MB: l_chumra (stringent)
# AH: l_kula (lenient)
Patterns for Encoding Machloket¶
Pattern 1: Direct Disagreement¶
Authority B explicitly disagrees with Authority A:
% A's position
asserts(authority_a, status(item, forbidden)).
% B's position (with override if B inherits from A)
override(authority_b, status(item, forbidden), disagreement).
asserts(authority_b, status(item, permitted)).
Pattern 2: Different Conditions¶
Same conclusion but under different circumstances:
% A: Forbidden in all cases
asserts(authority_a, issur(act, item)) :- relevant_item(item).
% B: Forbidden only with specific condition
asserts(authority_b, issur(act, item)) :-
relevant_item(item),
specific_condition(item).
Pattern 3: Different Normative Levels¶
Same prohibition but different madrega:
% A: Torah-level prohibition
madrega(r_rule_a, d_oraita).
asserts(authority_a, issur(act, item, d_oraita)) :- condition(item).
% B: Only rabbinic prohibition
madrega(r_rule_b, d_rabanan).
asserts(authority_b, issur(act, item, d_rabanan)) :- condition(item).
Exercises¶
Exercise 1: Detect Existing Machloket¶
Use the engine to find all existing machloket markers:
Solution
Exercise 2: Encode Waiting Time Machloket¶
Encode the dispute about waiting time between meat and dairy (6 hours vs 3 hours vs 1 hour).
Solution
% Standard Ashkenazi: 6 hours
asserts(ashk_standard, waiting_time(meat_to_dairy, 6)).
% German tradition: 3 hours
asserts(ashk_german, waiting_time(meat_to_dairy, 3)).
% Dutch tradition: 1 hour
asserts(ashk_dutch, waiting_time(meat_to_dairy, 1)).
% Mark disputes
machloket(waiting_time, ashk_standard, ashk_german, meat_to_dairy).
machloket(waiting_time, ashk_standard, ashk_dutch, meat_to_dairy).
What You've Learned¶
- Machloket occurs when different authorities derive different conclusions
- Use
asserts/2for positive rulings andoverride/3to block inheritance - The
machloket/4predicate explicitly marks disputes - MachloketDetector finds disputes automatically
- Interpretations can add/remove conditions rather than replace rules
Next Steps¶
Continue to Tutorial 6: Extending Ontology to learn how to add new foods and rules to Mistaber.
Production Encoding Workflow
For systematic encoding of machloket with human review checkpoints, see the Handling Machloket Tutorial in the Encoding Tutorials section, which uses the mistaber-skills Claude Code plugin.