Skip to content

Contributing Encodings

This guide walks you through the complete workflow for contributing halachic encodings to Mistaber. From claiming a seif to getting your PR merged, this document covers prerequisites, workflow, quality expectations, and attribution.

Who Can Contribute

Prerequisites

Successful contributors need competency in both halachic and technical domains:

Halachic Prerequisites

Requirement Minimum Level Verification
Hebrew reading Fluent Can read SA/Rema text
Aramaic reading Basic Can follow Gemara references
SA familiarity Intermediate Has studied Yoreh Deah
Halachic methodology Basic Understands psak process

Technical Prerequisites

Requirement Minimum Level Verification
Logic programming Basic Understands Prolog/ASP syntax
Git workflow Intermediate Can branch, commit, PR
Python testing Basic Can write pytest tests
Command line Basic Can run tests locally

Ideal contributors have:

  • Yeshiva background with Yoreh Deah study
  • Programming experience (any language)
  • Attention to detail
  • Willingness to have work reviewed

First-Time Contributor Path

If you're new to Mistaber:

  1. Study existing encodings - Read mistaber/ontology/worlds/mechaber.lp
  2. Complete the tutorials - Work through the tutorial series
  3. Shadow a review - Observe PR review process
  4. Start small - Pick an uncontroversial seif for first contribution
  5. Get mentored - Pair with experienced contributor

Workflow Overview

graph TD
    A[Find Available Seif] --> B[Claim Seif]
    B --> C[Study Sources]
    C --> D[Encode Rules]
    D --> E[Write Tests]
    E --> F[Run Locally]
    F --> G{Tests Pass?}
    G -->|No| D
    G -->|Yes| H[Create PR]
    H --> I[Technical Review]
    I --> J{Approved?}
    J -->|No| K[Address Comments]
    K --> I
    J -->|Yes| L{D'oraita Content?}
    L -->|Yes| M[Halachic Review]
    L -->|No| N[Final Approval]
    M --> O{Approved?}
    O -->|No| K
    O -->|Yes| N
    N --> P[Merge]

Step 1: Claim a Seif

Finding Available Work

  1. Check the project board - Look for unclaimed seifim
  2. Review open issues - Check for requested encodings
  3. Check roadmap - See prioritized simanim
  4. Propose new work - Request to encode a specific seif

Claiming Process

  1. Comment on issue or create new issue:
## Seif Claim: YD 87:3 (Fish and Dairy)

**Contributor**: @username
**Estimated completion**: 1 week
**Experience level**: Intermediate

### Scope
- Encode Mechaber's sakana ruling
- Encode Rema's permissive override
- Test both positions

### Prerequisites checked
- [x] Read existing YD 87 encodings
- [x] Have access to SA/Rema text
- [x] Familiar with multi-world encoding
  1. Wait for assignment - Maintainer assigns you
  2. Begin work - Only after assignment confirmed

Claim Etiquette

Do Don't
Claim one seif at a time Claim multiple without completing
Provide realistic timeline Over-commit on deadline
Ask questions before claiming Claim without understanding scope
Update if delayed Go silent on claimed work

Step 2: Study Sources

Source Reading Checklist

Before writing any code:

  • [ ] Read SA seif in Hebrew
  • [ ] Read Rema's gloss (if any)
  • [ ] Read Taz and Shach on this seif
  • [ ] Check Beit Yosef for SA's reasoning
  • [ ] Note any machloket
  • [ ] Identify madrega level
  • [ ] Check related seifim

Source Notes Template

## Source Analysis: YD 87:3

### SA Text
"דגים וחגבים אין בהם איסור אפילו מדרבנן"
"Fish and locusts have no prohibition even rabbinically"

### Rema Gloss
[No explicit gloss - silence implies potential disagreement with
Beit Yosef's sakana position]

### Beit Yosef Analysis
Cites medical authorities for sakana concern with fish+dairy.
This is the basis for Sefardi practice to avoid.

### Taz 87:3
Explains Ashkenazi practice to permit, citing [source]

### Shach 87:5
Supports Ashkenazi permission, explains textual interpretation

### Madrega Analysis
- No issur from Torah (explicit in SA)
- No issur d'rabanan (explicit in SA)
- Sakana (health) concern only (Mechaber's Beit Yosef)
- Classification: sakana (not issur)

### Machloket Identified
Mechaber (via Beit Yosef): Fish+dairy = sakana
Rema (via Taz, Shach): Fish+dairy = permitted

Step 3: Encode Rules

Setting Up Development

# Clone repository
git clone https://github.com/BrainyBlaze/mistraber.git
cd mistraber

# Create feature branch
git checkout -b encode/yd-87-3-fish-dairy

# Install development dependencies
pip install -e ".[dev]"

File Structure

Create or modify files as needed:

mistaber/ontology/
  corpus/yd_87/
    base.lp           # Shared definitions (if needed)
  worlds/
    mechaber.lp       # Mechaber's position
    rema.lp           # Rema's override

tests/corpus/yd_87/
  test_fish_dairy.py  # Your tests

Encoding Process

Follow the Encoding Methodology:

  1. Add helper predicates (if needed):

    % In corpus/yd_87/base.lp
    is_dag_chalav_mixture(M) :-
        mixture_has_basar(M, dag),
        mixture_has_chalav(M).
    

  2. Encode Mechaber's position:

    % In worlds/mechaber.lp
    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).
    

  3. Encode Rema's override:

    % In worlds/rema.lp
    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(rema, sakana(M), no_sakana) :-
        is_dag_chalav_mixture(M).
    
    asserts(rema, heter(achiila, M)) :-
        is_dag_chalav_mixture(M).
    
    asserts(rema, no_sakana(M)) :-
        is_dag_chalav_mixture(M).
    
    machloket(dag_chalav_sakana, mechaber, rema, M) :-
        is_dag_chalav_mixture(M).
    

Step 4: Write Tests

Test File Template

# tests/corpus/yd_87/test_fish_dairy.py
"""
Tests for YD 87:3 fish + dairy machloket.

Mechaber: Fish with dairy is forbidden due to sakana (health danger)
Rema: Fish with dairy is permitted

This tests the encoding of both positions and inheritance.
"""

import pytest
from mistaber import query


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

    @pytest.fixture
    def fish_dairy_mixture(self):
        """Standard fish + dairy mixture for testing."""
        return """
            mixture(m1).
            food(salmon). food_type(salmon, dag).
            food(cream). food_type(cream, chalav).
            contains(m1, salmon). contains(m1, cream).
        """

    # === Positive Tests (5 minimum) ===

    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_issur_achiila_sakana(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_rema_no_sakana(self, fish_dairy_mixture):
        """Rema holds no sakana for fish+dairy."""
        result = query(fish_dairy_mixture, world="rema")
        assert result.holds("no_sakana(m1)")

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

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

    # === Negative Tests (3 minimum) ===

    def test_beheima_not_affected(self):
        """Beheima+dairy uses issur, not sakana."""
        setup = """
            mixture(m1).
            food(beef). food_type(beef, beheima).
            food(milk). food_type(milk, chalav).
            contains(m1, beef). contains(m1, milk).
        """
        result = query(setup, world="mechaber")
        assert not result.holds("sakana(m1)")
        assert result.holds("issur(achiila, m1, d_oraita)")

    def test_fish_alone_no_sakana(self):
        """Fish alone has no sakana."""
        setup = """
            food(salmon). food_type(salmon, dag).
        """
        result = query(setup, world="mechaber")
        assert not result.holds("sakana(salmon)")

    def test_dairy_alone_no_sakana(self):
        """Dairy alone has no sakana."""
        setup = """
            food(cream). food_type(cream, chalav).
        """
        result = query(setup, world="mechaber")
        assert not result.holds("sakana(cream)")

    # === Edge Cases (2 minimum) ===

    def test_fish_with_parve_no_sakana(self):
        """Fish + parve has no sakana concern."""
        setup = """
            mixture(m1).
            food(salmon). food_type(salmon, dag).
            food(rice). food_type(rice, parve).
            contains(m1, salmon). contains(m1, rice).
        """
        result = query(setup, world="mechaber")
        assert not result.holds("sakana(m1)")

    def test_multiple_fish_species(self):
        """Multiple fish with dairy still triggers sakana."""
        setup = """
            mixture(m1).
            food(salmon). food_type(salmon, dag).
            food(tuna). food_type(tuna, dag).
            food(cream). food_type(cream, chalav).
            contains(m1, salmon). contains(m1, tuna). contains(m1, cream).
        """
        result = query(setup, world="mechaber")
        assert result.holds("sakana(m1)")

    # === Multi-World Tests ===

    def test_sefardi_yo_inherits_sakana(self, fish_dairy_mixture):
        """Yalkut Yosef inherits Mechaber's sakana ruling."""
        result = query(fish_dairy_mixture, world="sefardi_yo")
        assert result.holds("sakana(m1)")

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

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

Step 5: Run Locally

Running Tests

# Run all tests
pytest tests/

# Run specific test file
pytest tests/corpus/yd_87/test_fish_dairy.py

# Run with verbose output
pytest tests/corpus/yd_87/test_fish_dairy.py -v

# Run with coverage
pytest tests/ --cov=mistaber --cov-report=html

Running Type Checker

# Check encoding syntax and types
mistaber check mistaber/ontology/worlds/mechaber.lp

# Check all files
mistaber check mistaber/ontology/

Fixing Common Issues

Issue Solution
Import error Run pip install -e .
Test failure Check encoding logic
Type error Verify predicate signatures
Warning about OWA Remove negation of OWA predicate

Step 6: Create PR

PR Title Format

encode(yd-87-3): fish and dairy machloket

PR Description Template

## Summary
Encodes YD 87:3 fish and dairy machloket:
- Mechaber: Fish+dairy forbidden due to sakana
- Rema: Fish+dairy permitted (no sakana concern)

## Changes
- Added `is_dag_chalav_mixture/1` helper in `corpus/yd_87/base.lp`
- Added Mechaber's sakana ruling in `worlds/mechaber.lp`
- Added Rema's override in `worlds/rema.lp`
- Added machloket detection

## Sources Consulted
- SA YD 87:3
- Beit Yosef YD 87
- Rema (by omission)
- Taz 87:3
- Shach 87:5

## Test Coverage
- 5 positive tests
- 3 negative tests
- 2 edge cases
- 4 multi-world tests

## Checklist
- [x] Rule IDs are semantic
- [x] All rules have makor
- [x] Override uses descriptive value
- [x] Tests pass locally
- [x] Type checker passes

Step 7: Address Review

Responding to Comments

  1. Read carefully - Understand what's being asked
  2. Ask if unclear - Request clarification
  3. Fix issues - Make requested changes
  4. Explain if disagreeing - Provide reasoning
  5. Mark resolved - After addressing

Common Review Requests

Request Action
Add more sources Add makor/2 entries
Fix override value Use descriptive value
Add edge case test Write specific test
Explain reasoning Add comment in code
Check Rema gloss Verify and document

Quality Expectations

Code Quality

  • Clean, readable code
  • Consistent with existing patterns
  • Well-commented
  • Properly organized

Halachic Quality

  • Accurate to sources
  • Complete machloket handling
  • Correct madrega assignment
  • Proper world scoping

Test Quality

  • Comprehensive coverage
  • Both positions tested
  • Edge cases covered
  • Multi-world verified

Attribution and Credit

Contributor Attribution

Your contribution is recognized:

  1. Git history - Your name in commit log
  2. PR record - Linked to your account
  3. CONTRIBUTORS.md - Added after first merge
  4. Release notes - Credited for significant additions

Source Attribution

You must cite sources accurately:

% Your encoding cites sources, not you
makor(r_example, sa("yd:87:3")).   % Source: Shulchan Aruch
makor(r_example, taz("yd:87:3")).  % Source: Taz

% NOT: makor(r_example, your_name)

Code of Conduct

All contributors must follow the Code of Conduct:

  • Be respectful in reviews
  • Welcome newcomers
  • Focus on technical merit
  • Accept feedback gracefully

Getting Help

Resources

Asking Questions

  • GitHub Discussions - General questions
  • Issue comments - Specific to claimed work
  • PR comments - During review process

Mentorship

First-time contributors can request mentorship:

## Mentorship Request

**Contributor**: @username
**Experience**: [Brief background]
**Planned contribution**: YD 87:X

Requesting mentorship for first encoding contribution.
Specific areas I'd like guidance on:
- [ ] Understanding machloket representation
- [ ] Writing effective tests
- [ ] Navigating review process