> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solvice.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Rules and Constraints

> Define counters, sequences, and conditional labor rules for scheduling

Rules let you set constraints on working days, hours, and shift sequences. Use rules to enforce labor regulations, contractual limits, and scheduling policies.

## Rule Types

| Constraint | Description                                                    |
| ---------- | -------------------------------------------------------------- |
| `COUNTER`  | Count occurrences within a period (days worked, hours, shifts) |
| `SEQUENCE` | Limit consecutive occurrences (max days in a row)              |

## Counter Rules

Count and limit occurrences within a planning period.

### Working Days

Limit total working days:

```json theme={null}
{
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "DAYS_WORKED",
      "min": 2,
      "max": 4
    }
  ]
}
```

### Days Idle

Ensure minimum days off:

```json theme={null}
{
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "DAYS_IDLE",
      "min": 1,
      "max": 2
    }
  ]
}
```

### Weekends Idle

Guarantee free weekends:

```json theme={null}
{
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "WEEKENDS_IDLE",
      "min": 1,
      "max": 2
    }
  ]
}
```

<Info>
  Requires [weekend definition](/guides/fill/examples/weekend) in options to specify what constitutes a weekend.
</Info>

### Shift Type Limits

Limit specific shift types using tags:

```json theme={null}
{
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "SHIFT_TYPES_WORKED",
      "shifts": ["NIGHT"],
      "max": 3
    }
  ]
}
```

## Counter Types

| Type                       | Description                                   |
| -------------------------- | --------------------------------------------- |
| `DAYS_WORKED`              | Total days with at least one shift            |
| `DAYS_IDLE`                | Total days without any shift                  |
| `WEEKENDS_WORKED`          | Complete weekends with work                   |
| `WEEKENDS_IDLE`            | Complete weekends without work                |
| `SHIFT_TYPES_WORKED`       | Shifts matching specific tags                 |
| `SHIFT_TYPES_HOURS_WORKED` | Hours worked on shifts matching specific tags |
| `HOURS_WORKED`             | Total hours across all shifts                 |

## Period Scoping

By default, rules apply to the entire planning period. Scope rules to specific periods:

### Fixed Period

```json theme={null}
{
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "SHIFT_TYPES_WORKED",
      "shifts": ["NIGHT"],
      "max": 3,
      "period": {
        "from": "2024-03-06T08:00:00",
        "to": "2024-03-10T17:00:00"
      }
    }
  ]
}
```

### Rolling Window

Apply the rule as a sliding window:

```json theme={null}
{
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "SHIFT_TYPES_WORKED",
      "shifts": ["NIGHT"],
      "max": 3,
      "period": {
        "duration": "P3D"
      }
    }
  ]
}
```

<Tip>
  Use rolling windows for rules like "no more than 3 night shifts in any 7-day period."
</Tip>

## Sequence Rules

Limit consecutive occurrences without specifying a period window.

### Consecutive Working Days

```json theme={null}
{
  "rules": [
    {
      "constraint": "SEQUENCE",
      "type": "DAYS_WORKED",
      "min": 2,
      "max": 4
    }
  ]
}
```

<Check>
  Employees work between 2 and 4 consecutive days before a day off.
</Check>

## Conditional Rules

Trigger a rule when another rule's threshold is exceeded.

**Example:** If 20+ hours of night shifts within 72 hours, then require 2 days idle:

```json theme={null}
{
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "HOURS_WORKED",
      "period": {
        "duration": "PT72H"
      },
      "min": 20,
      "shifts": ["NIGHT"],
      "then": {
        "constraint": "SEQUENCE",
        "type": "DAYS_IDLE",
        "min": 2
      }
    }
  ]
}
```

<Warning>
  Conditional rules can create complex constraints. Test thoroughly to avoid making problems infeasible.
</Warning>

## Rule Properties

<ParamField body="constraint" type="string" required>
  Rule type: `COUNTER` or `SEQUENCE`
</ParamField>

<ParamField body="type" type="string" required>
  What to count or sequence (see tables above)
</ParamField>

<ParamField body="min" type="integer">
  Minimum count or sequence length
</ParamField>

<ParamField body="max" type="integer">
  Maximum count or sequence length
</ParamField>

<ParamField body="shifts" type="array">
  Filter rule to specific shift tags
</ParamField>

<ParamField body="period" type="object">
  Time scope with `from`/`to` dates or rolling `duration`
</ParamField>

<ParamField body="then" type="Rule">
  Conditional rule triggered when this rule is exceeded
</ParamField>

## Common Rule Patterns

<AccordionGroup>
  <Accordion title="40-hour work week">
    ```json theme={null}
    {
      "constraint": "COUNTER",
      "type": "HOURS_WORKED",
      "min": 32,
      "max": 40,
      "period": { "duration": "P7D" }
    }
    ```
  </Accordion>

  <Accordion title="Maximum 5 consecutive days">
    ```json theme={null}
    {
      "constraint": "SEQUENCE",
      "type": "DAYS_WORKED",
      "max": 5
    }
    ```
  </Accordion>

  <Accordion title="At least 2 weekends off per month">
    ```json theme={null}
    {
      "constraint": "COUNTER",
      "type": "WEEKENDS_IDLE",
      "min": 2,
      "period": {
        "from": "2024-01-01",
        "to": "2024-01-31"
      }
    }
    ```
  </Accordion>

  <Accordion title="Max 2 night shifts per week">
    ```json theme={null}
    {
      "constraint": "COUNTER",
      "type": "SHIFT_TYPES_WORKED",
      "shifts": ["NIGHT"],
      "max": 2,
      "period": { "duration": "P7D" }
    }
    ```
  </Accordion>
</AccordionGroup>
