Halakhah Yomit · Techie Talmid · On-Ramp

Shulchan Arukh, Orach Chayim 108:8-10

On-RampTechie TalmidNovember 22, 2025

Greetings, fellow data architects and algorithm aficionados! Your friendly neighborhood nerd-joy educator is back, diving headfirst into another fascinating data structure from the Talmudic-halakhic codebase. Today, we're debugging a particularly sticky problem: prayer recovery protocols.

Problem Statement

Imagine a critical system process, AmidahService.execute(), which must run within specific time windows (ShacharitTime, MinchaTime, ArvitTime). What happens when a user fails to invoke this service call? This isn't just about a missed event; it's a state integrity issue. The system needs a robust, fault-tolerant recovery mechanism, but with strict rules to prevent abuse or chaotic state transitions.

Our "bug report" from the Shulchan Arukh (Orach Chayim 108:8-10) details the Tashlumin (make-up prayer) protocol. The core challenge is to design a system that:

  1. Identifies eligibility: Under what conditions is a make-up allowed? (reasonForMissing, prayerType, timeElapsed).
  2. Determines recovery method: How many times to pray, and in what order?
  3. Handles state changes: What if the current prayer itself has special conditions (Shabbat, Rosh Chodesh)?
  4. Manages dependencies: Can multiple missed "transactions" be recovered simultaneously?

This isn't a simple retry() function. It's a complex state machine with conditional branching, parameter validation, and specific sequencing requirements. Let's trace the data flow!

Flow Model: The Tashlumin Decision Tree

Here's a high-level TashluminEligibilityEngine decision tree:

FUNCTION DetermineTashluminEligibility(missedPrayerType, reasonForMissing, currentPrayerTime)
  // Input Validation & Initial Checks
  IF missedPrayerType == 'Musaf' THEN
    RETURN { eligible: false, reason: "Musaf has no Tashlumin" } // SA 108:9
  END IF

  // Reason-based Eligibility
  IF reasonForMissing == 'On Purpose' THEN
    RETURN { eligible: false, reason: "No Tashlumin for intentional omission" } // SA 108:9
  END IF

  // Conditions for 'Ones' (Extenuating Circumstance) or 'Shogeg' (Mistake)
  // (Includes 'erred', 'forced', 'supposed time would remain', 'troubled with monetary needs', 'drunk')
  IF reasonForMissing IN ('Mistake', 'Extenuating Circumstance') THEN // SA 108:8, 108:9, 108:10
    // Time-based Eligibility: Adjacency Rule
    IF NOT IsImmediatelyAdjoining(missedPrayerType, currentPrayerTime) THEN
      RETURN { eligible: false, reason: "Tashlumin only for immediately adjoining prayer" } // SA 108:9
    END IF

    // Tashlumin Protocol Execution
    LET currentPrayer = GetCurrentPrayerDetails(currentPrayerTime)
    LET currentPrayerInstance = CreateAmidah(currentPrayer.type, currentPrayer.conditions)
    LET tashluminInstance = CreateAmidah(missedPrayerType, currentPrayer.conditions_for_tashlumin_slot)

    // Special Handling for Specific Missed Prayers
    IF missedPrayerType == 'Mincha' AND currentPrayer.type == 'Arvit' THEN
      IF currentPrayer.isErevShabbatOrRoshChodesh THEN // SA 108:10
        // Arvit for Erev Shabbat/Rosh Chodesh is special. Tashlumin takes this form.
        // Gloss on 108:10 adds nuance for Ya'aleh V'yavo.
      END IF
    END IF

    IF missedPrayerType == 'Mincha' AND currentPrayer.type == 'MotzeiShabbat' THEN // SA 108:10
      // Tashlumin for Mincha on Shabbat is performed *after* Shabbat ends.
      // Special separation rules (Ata Chonantanu) apply.
      // Gloss on 108:10 has complex logic for 'Ata Chonantanu' placement.
    END IF

    // Order of Operations: Current Prayer FIRST
    RETURN {
      eligible: true,
      action: "Pray Amidah twice",
      order: [currentPrayerInstance, tashluminInstance],
      interstitial: "Say Ashrei between Amidot" // SA 108:8
    }
  ELSE
    RETURN { eligible: false, reason: "Unknown or invalid reason for missing prayer" }
  END IF
END FUNCTION

Text Snapshot

Let's anchor our analysis to the source code:

Shulchan Arukh, Orach Chayim 108:8-10:

  • SA 108:8: "If one erred or was forced [by circumstance] and did not pray the morning prayer, one should pray the afternoon prayer twice: the first is the afternoon prayer, and the second as a make-up. If one inverted [the order], one has not fulfilled one obligation in prayer for the prayer which is a make-up, and one needs to go back and pray it [again]. And the same law applies in every case in which one must pray a make-up prayer. If one erred and did not pray the afternoon prayer, one should pray the evening prayer twice: the first is for the evening prayer, and the second is for the make-up. If one erred and did not pray the evening prayer, one should pray the morning prayer (i.e. Amidah) twice: the first for the morning prayer, and the second as a make-up. After one says "Yotzeir" [the blessings of the Recitation of the Sh'ma in the morning prayer] and the Eighteen Blessings (i.e. the Amidah), one should say Ashrei and then afterwards pray the Eighteen Blessings for the make-up evening prayer."
  • SA 108:9: "There are no make-up prayers other than the immediately adjoining [i.e. preceding] prayer alone; so that if one erred and did not pray the morning prayer and [also] the afternoon prayer, one [only] prays the evening prayer twice [with] the latter prayer as a make-up for the afternoon prayer, but for the morning prayer there is no make-up; and the same goes for all the rest of the prayers. Even though there are no make-up prayers other than for the prayer immediately adjoining that prayer, and (other) prayers that one missed [i.e. one skipped two or more as mentioned above] do not have a make-up; if one wants to pray that one [i.e. the one that cannot be make-up anymore] as a voluntary prayer and one will innovate something [new] into it, one is allowed to and it is proper to do so. If the whole day passed and one did not pray the additional prayer [on Shabbat, Festivals, and Rosh Chodesh], there is no make-up for it. [If] it was on purpose and one did not pray [an Amidah], there is no make-up for it. Even at the prayer that is immediately adjoining it."
  • SA 108:9 (continued): "One who did not pray [the Amidah] while there was still enough time to pray because one supposed that time would still remain for one after one finished whatever thing one was involved in, and between one thing and another, the time passed; and similarly, one who was troubled with monetary needs so that one would not incur a loss, and because of that one lost [one's opportunity] to pray; and similarly someone who is drunk and did not pray. All of these are considered people with extenuating circumstances and they [do] have a [an opportunity for] a make-up."
  • SA 108:10: "If one erred and did not pray the afternoon prayer on the eve of Shabbat, one should pray the evening prayer [i.e. Shabbat Amidah] twice; the first is for the evening prayer and the second is the make-up [for the afternoon prayer]... If one erred and did not pray the afternoon prayer on Shabbat, one should pray it upon the [immediately after the end of] Shabbat (two weekday prayers); one separates [Shabbat from weekday i.e. the insertion of "ata chonantanu" into the 4th blessing of the Amidah] in the first, but one does not separate in the second..."

Two Implementations: Algorithm A vs. Algorithm B in is_extenuating_circumstance()

The Shulchan Arukh (SA 108:9) defines several conditions that qualify as extenuating_circumstance (Hebrew: ones), making a missed prayer eligible for Tashlumin. This is our Algorithm A. However, later commentators (Acharonim) like the Mishnah Berurah and Biur Halacha, often building on earlier Rishonim, provide critical patches and clarifications to this definition, effectively creating Algorithm B.

Algorithm A: The Core is_extenuating_circumstance Function (SA 108:9)

The Shulchan Arukh provides a set of explicit TRUE conditions for the is_extenuating_circumstance(reason) function:

public boolean is_extenuating_circumstance(Reason reason) {
    if (reason == Reason.ERRED || reason == Reason.FORCED_BY_CIRCUMSTANCE) { // SA 108:8 initial
        return true;
    }
    if (reason == Reason.SUPPOSED_TIME_WOULD_REMAIN) { // "s'vur" case
        return true;
    }
    if (reason == Reason.TROUBLED_MONETARY_LOSS_PREVENTION) { // "terud b'tzarchei mamon"
        return true;
    }
    if (reason == Reason.DRUNK) { // "shikur"
        return true;
    }
    return false; // Default: Not an extenuating circumstance, likely "on purpose"
}

This algorithm is clear-cut: if your reason enum matches one of these predefined states, you get tashlumin eligibility. It's a direct lookup table for ones. The l'chatchila (ideally) warning in the Gloss by the Taz (Turei Zahav on SA 108:7) already hints that while these are valid post-facto excuses, they're not ideal behavior. It implies that is_extenuating_circumstance is a recovery function, not a best practice function.

Algorithm B: Refinements and Patches by the Acharonim (Magen Avraham, Mishnah Berurah, Biur Halacha)

Algorithm B acts as a series of feature enhancements and bug fixes to Algorithm A. It doesn't change the core logic but adds nuance, clarifies ambiguity, and handles complex nested conditions, especially regarding the TROUBLED_MONETARY_LOSS_PREVENTION and SUPPOSED_TIME_WOULD_REMAIN scenarios. These commentators are essentially updating the is_extenuating_circumstance API with more precise parameter handling.

Consider the SUPPOSED_TIME_WOULD_REMAIN (the s'vur case) and TROUBLED_MONETARY_LOSS_PREVENTION (terud b'tzarchei mamon) inputs.

Magen Avraham (108:11): Explicitly confirms that s'vur (supposing time would remain) is considered ones (extenuating circumstance). He acknowledges a dispute but sides with the lenient view presented in the Shulchan Arukh, effectively reinforcing Algorithm A's interpretation of this specific reason value. This is less a change and more a strong validation against alternative interpretations.

Mishnah Berurah (108:23-24): Delves deeper into the s'vur case, particularly when the 'thing one was involved in' (osek) might itself be problematic l'chatchila (initially).

  • MB 108:23: Even if the osek (activity) started improperly (b'issur) after the prayer time began (referencing SA 232), if the user intended to pray afterward and then forgot, it's still considered ones. This is a crucial clarification: the initial state of the osek doesn't automatically invalidate the ones status if the subsequent intent and forgetting were genuine. The system cares about the final failure mode (forgetting due to the activity), not just the l'chatchila compliance of the activity itself.
    // Algorithm B's refined logic for SUPPOSED_TIME_WOULD_REMAIN:
    public boolean is_extenuating_circumstance_B(Reason reason, boolean startedOsekImproperly, boolean intendedToPrayLater, boolean forgotAfterward) {
        if (reason == Reason.SUPPOSED_TIME_WOULD_REMAIN) {
            // MB 108:23: Even if startedOsekImproperly is true, if intent and forgetting are true, still ones.
            if (intendedToPrayLater && forgotAfterward) {
                return true;
            }
        }
        // ... rest of Algorithm A's logic
        return is_extenuating_circumstance(reason); // Fallback to A for other reasons
    }
    
  • MB 108:24: Expands TROUBLED_MONETARY_LOSS_PREVENTION to explicitly include being "troubled to buy and sell merchandise" (laknot v'limkor sachurato). This isn't a new concept but a specific instantiation of the general rule, making the terud parameter more concrete.

Biur Halacha (108:8:1-2): Introduces further complexity, particularly around the TROUBLED_MONETARY_LOSS_PREVENTION case, by examining the certainty and magnitude of the potential loss.

  • BH 108:8:1: If the monetary_loss is not clear (ein barur hazika), is the user poshea (negligent, no tashlumin) or shogeg (mistaken, has tashlumin)? The P'ri Megadim suggests it's a safek (doubt). In such a safek state, the recommended action is to pray twice with a conditional declaration (t'nai): "If I am obligated, this is for my obligation; if not, it's a voluntary prayer." This introduces a conditional execution path and requires a new TefillahMode.CONDITIONAL_NEDAVA.
    // Algorithm B's enhanced logic for TROUBLED_MONETARY_LOSS_PREVENTION:
    public TefillahResult handle_monetary_loss_case(boolean isLossCertain) {
        if (reason == Reason.TROUBLED_MONETARY_LOSS_PREVENTION) {
            if (isLossCertain) {
                return new TefillahResult(true, TefillahMode.OBLIGATION); // Clear ones, tashlumin
            } else { // BH 108:8:1: safek
                return new TefillahResult(true, TefillahMode.CONDITIONAL_NEDAVA); // Pray with T'nai
            }
        }
        // ...
    }
    
  • BH 108:8:2: Citing the P'ri Megadim again, suggests that perhaps ones for monetary loss only applies if the loss is more than a fifth of one's assets. This introduces a loss_threshold parameter, making the TROUBLED_MONETARY_LOSS_PREVENTION check far more granular.
    // BH 108:8:2: A potential further constraint on monetary loss
    public boolean is_extenuating_circumstance_B_final(Reason reason, double potentialLossAmount, double totalAssets) {
        if (reason == Reason.TROUBLED_MONETARY_LOSS_PREVENTION) {
            if (potentialLossAmount > (totalAssets / 5.0)) { // New threshold check
                return true; // Eligible for tashlumin if loss exceeds 1/5th
            }
            return false; // Loss below threshold might not be considered ones
        }
        // ...
    }
    

Comparison: Algorithm A is the foundational API, providing a basic, direct set of TRUE conditions. Algorithm B, driven by the Acharonim, acts as a series of if-then-else blocks, adding sub-conditions, clarifying parameter interpretations, and even introducing new return types (CONDITIONAL_NEDAVA) to the is_extenuating_circumstance function. It demonstrates the halakhic system's capacity for continuous refinement, ensuring the rules remain robust across a wider range of real-world inputs and complex user states. It’s like patching a core library function to handle more nuanced scenarios without breaking backward compatibility.

Edge Cases

Let's test our TashluminEligibilityEngine with some tricky inputs that might break a naive interpretation.

Edge Case 1: Multiple Missed Prayers (Non-Adjacent)

Input:

missedPrayerType = [SHACHRIT, MINCHA]
reasonForMissing = MISTAKE
currentPrayerTime = ARVIT_TIME

Naive Logic's Expected Output: "Pray Arvit twice; one for Arvit, one for Shacharit; and then pray a third time for Mincha." (Or some other combination attempting to make up both). This assumes a queue-like Tashlumin mechanism where all missed prayers can eventually be processed.

System-Compliant Output (SA 108:9): "Pray Arvit twice: the first for Arvit, and the second as a make-up for Mincha. Shacharit is not eligible for Tashlumin."

  • Explanation: The critical rule from SA 108:9 states: "There are no make-up prayers other than the immediately adjoining [i.e. preceding] prayer alone." In this scenario, Arvit is immediately preceded by Mincha. Shacharit is not immediately adjoining; it's a "skipped" prayer, falling outside the recovery window. The system has a strict adjacency constraint, not a full backlog processing queue.

Edge Case 2: Missed Prayer On Purpose, But Immediately Adjoining

Input:

missedPrayerType = MINCHA
reasonForMissing = ON_PURPOSE
currentPrayerTime = ARVIT_TIME

Naive Logic's Expected Output: "Pray Arvit twice: the first for Arvit, and the second as a make-up for Mincha." This prioritizes the "immediately adjoining" rule above all else.

System-Compliant Output (SA 108:9): "Pray Arvit once for Arvit. No Tashlumin for Mincha."

  • Explanation: SA 108:9 explicitly states: "[If] it was on purpose and one did not pray [an Amidah], there is no make-up for it. Even at the prayer that is immediately adjoining it." This demonstrates a hierarchical rule structure. The reasonForMissing parameter acts as a primary gatekeeper. If ON_PURPOSE is TRUE, all other Tashlumin conditions (like adjacency) become irrelevant; the Tashlumin function immediately returns FALSE. It's a hard return statement.

Refactor

The rule for multiple missed prayers in SA 108:9, "There are no make-up prayers other than the immediately adjoining [i.e. preceding] prayer alone," can be slightly ambiguous. Does "alone" mean only one make-up prayer can be done, or that only the single immediately preceding one is ever eligible? The context clarifies the latter, but a refactor can make it explicit.

Current Logic (Implicit):

IF (missed_prayer_list.count > 1 AND !is_immediately_adjoining(missed_prayer_list.last(), current_prayer_time)) THEN
    // Implies only the last one can be made up, if adjoining.
    // The others are lost.
END IF

Proposed Refactor (Minimal Change for Clarity):

Instead of implicitly deriving that only the single, immediately preceding prayer is eligible, we can make this a direct and immutable constraint in the TashluminEligibilityEngine's core logic:

// Refactored Rule for Tashlumin eligibility
public Optional<PrayerType> getEligibleTashlumin(List<PrayerType> missedPrayers, PrayerType currentPrayer) {
    // Rule: Only the single prayer immediately preceding the current one is eligible for Tashlumin.
    // All other missed prayers, regardless of reason, are not eligible for Tashlumin.

    if (missedPrayers.isEmpty()) {
        return Optional.empty();
    }

    PrayerType lastMissed = missedPrayers.getLast(); // Or however we model the "immediately preceding"
    if (isImmediatelyAdjoining(lastMissed, currentPrayer)) {
        return Optional.of(lastMissed);
    } else {
        return Optional.empty(); // No immediately adjoining eligible prayer
    }
}

This refactor clarifies that the system does not iterate through a list of missed prayers; it only ever considers one specific candidate: the one directly before the current prayer slot. This simplifies the mental model and prevents misinterpretation of "alone."

Takeaway

What a journey through the Tashlumin recovery system! This sugya beautifully illustrates several core principles of robust system design:

  1. State-Dependent Logic: Eligibility for Tashlumin isn't static; it's highly dependent on the system's current state (current prayer time, type of missed prayer) and the historical state (reason for missing, order of missed prayers).
  2. Hierarchical Rule Processing: The reasonForMissing parameter acts as a primary if-gate that can short-circuit the entire recovery process (e.g., ON_PURPOSE immediately terminates Tashlumin eligibility).
  3. Strict Adjacency Constraints: The system doesn't offer a "catch-all" backlog processing. Recovery is strictly limited to the immediately preceding failed transaction, preventing an unbounded recovery queue and ensuring system stability.
  4. Parameter Refinement and Edge Case Handling: The Acharonim's contributions are classic examples of how a robust system evolves. They don't rewrite the core API but add extensive documentation, clarify parameter definitions, and provide nuanced handling for complex inputs, ensuring the system functions reliably in diverse real-world scenarios.
  5. Fault Tolerance with Guardrails: The system provides recovery (Tashlumin) but with strict guardrails (order, timing, reason, type) to maintain integrity and prevent casual disregard for the primary process. It's a testament to a system designed for both mercy and discipline.

Understanding these Tashlumin protocols isn't just about ritual; it's about appreciating a meticulously designed, fault-tolerant system that balances user needs with core operational integrity. Keep coding, keep learning, and keep finding the elegance in every sugya!