diff --git a/benchmarks/duty_rosters/README.md b/benchmarks/duty_rosters/README.md
new file mode 100644
index 000000000..f9b138bcd
--- /dev/null
+++ b/benchmarks/duty_rosters/README.md
@@ -0,0 +1,89 @@
+# Nursing Staff Duty Rosters
+
+## Overview
+
+Monthly nursing staff duty rosters from a Swiss care facility. Each image shows one row from a roster, representing a single staff member's schedule for the month. Models must identify shift icons, half-day splits, alternate unit assignments, and person metadata.
+
+Images are paired with two shared context images sent once per benchmark run:
+- **roster_header.jpg** — the roster header with unit name, month/year, and date columns
+- **icons.jpg** — the icon legend mapping visual shift indicators to their codes
+
+## Data
+
+- PEP-sheet `04-25_PEP_02-12-01.pdf` manually segmented into rows yielding 21 images, ~1200x100 pixels each
+- Language: German
+- Source: Swiss nursing care facility, April 2025
+
+## Ground Truth Format
+
+```json
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "103",
+ "profession": "WBL",
+ "employment_percent": 80,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {
+ "icon": "F-Dienst 1",
+ "length": "full",
+ "planned_on_current_unit": true,
+ "alternate_unit": "LE"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
+```
+
+Key fields:
+- **icon**: Descriptive name from the icon legend (e.g. "F-Dienst 1", "Ferien", "Freier Tag")
+- **length**: `full`, `half_left`, or `half_right` (cells can be split into two half-day shifts)
+- **planned_on_current_unit**: `true` if the icon has no red shading, `false` if the icon has red shading
+- **alternate_unit**: Unit abbreviation shown below the cell (e.g. "LE", "TS") if present, null otherwise. Multiple abbreviations for the same date are joined with a comma (e.g. "LE, TS").
+
+## Editor
+
+`editor/editor.html` is a browser-based correction tool for ground truth JSON files. Open it directly in Chrome/Edge/Opera (File System Access API required for in-place saves; other browsers fall back to downloads).
+
+Workflow:
+1. Pick the `images/` folder and the `ground_truths/` folder. Files are paired by basename.
+2. Optionally pick an output folder (defaults to the browser's download directory).
+3. Click a row in the sidebar to load the image + JSON. Edit person metadata, days, and shifts.
+4. Click "JSON Speichern" to write the file.
+
+Behavior worth knowing:
+- Same-date day entries are auto-merged into a single day with a combined `shifts` array on load and before save.
+- Edits are cached in memory per file, so switching files and back preserves unsaved changes.
+- "+ Tag anfügen" appends a day to the end; the calendar-plus button on each day inserts a day directly below.
+- Shifts can be split into `half_left` / `half_right` halves on the same date.
+
+## Scoring
+
+**F1 Micro** with field-level fuzzy matching (threshold: 0.92, rapidfuzz).
+
+All leaf fields are scored (year, month, person metadata, and per-day shift fields). TP/FP/FN are calculated per field across the full nested structure. F1 Macro (per-image F1 averaged) is also reported.
+
+## Ideas for Improvement
+
+1. **Composite header + row into a single image.** The header and roster row are currently sent as separate images, forcing models to align columns across images. Stitching the header directly above each row would make date-to-cell mapping visual and trivial — this is the single largest error source (~50% of dates are wrong).
+
+2. **Use day-of-month integers instead of ISO dates.** Converting cell position to a day number and then to an ISO date string is two steps of error. Since year and month are already captured at the Schedule level, `date: 17` would be simpler than `"2025-04-17"`.
+
+3. **Separate icon recognition from structure extraction in scoring.** Report a structure score (dates, length, planned_on_current_unit, alternate_unit, person metadata) and an icon score separately. This gives more diagnostic value than a single F1 number.
+
+4. **Crop individual cells for icon classification.** As a benchmark variant: pre-crop each day cell and pair it with the legend, asking "which icon is this?" This isolates icon recognition from layout understanding and reveals where the real bottleneck is.
+
+5. **Add a visual example of an empty cell to the legend.** Models confuse null (no icon) with "Freier Tag" or hallucinate icons like "HomeOffice" for empty cells. Showing what "no icon" looks like in the legend could help.
+
+6. **Score fields with different weights.** Currently all leaf fields count equally, so ~128 shift-level entries dominate 4 person-level fields. Consider per-day accuracy or separate person-metadata vs shift-level reporting.
+
+7. **Reduce the active icon vocabulary.** The legend has 33 icons but the ground truth only uses ~8. Noting the active subset in the prompt or evaluating icon accuracy within the active set would be informative.
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/benchmark.py b/benchmarks/duty_rosters/benchmark.py
new file mode 100644
index 000000000..d3da51979
--- /dev/null
+++ b/benchmarks/duty_rosters/benchmark.py
@@ -0,0 +1,137 @@
+"""Benchmark implementation for Nursing staff duty rosters.
+
+Parse visual nursing staff duty rosters
+"""
+
+import logging
+import os
+from typing import Dict, List
+
+from scripts.benchmark_base import Benchmark
+from scripts.scoring_helper import get_all_keys, get_nested_value, calculate_fuzzy_score
+
+
+class DutyRosters(Benchmark):
+ """Benchmark for Nursing staff duty rosters."""
+
+ # Send header + icons with every request (works across all providers)
+ cache_context_per_request = True
+
+ def get_shared_context_images(self) -> List[str]:
+ """Return header and icon legend images to prepend to every request."""
+ return [
+ os.path.join(self.benchmark_dir, 'context', 'roster_header.jpg'),
+ os.path.join(self.benchmark_dir, 'context', 'icons.jpg'),
+ ]
+
+ def score_request_answer(self, image_name: str, response: dict, ground_truth: dict) -> dict:
+ data = self.prepare_scoring_data(response)
+
+ logging.info(image_name)
+ logging.debug(f"response: {data}")
+ logging.debug(f"ground_truth: {ground_truth}")
+
+ response_keys = get_all_keys(data)
+ gt_keys = get_all_keys(ground_truth)
+
+ all_keys = set(response_keys + gt_keys)
+
+ # Filter out parent keys when child keys exist
+ filtered_keys = []
+ for key in all_keys:
+ has_children = any(
+ other_key.startswith(key + '.') or other_key.startswith(key + '[')
+ for other_key in all_keys if other_key != key
+ )
+ if not has_children:
+ filtered_keys.append(key)
+
+ tp = 0
+ fp = 0
+ fn = 0
+ field_scores = {}
+ match_threshold = 0.92
+
+ for key in filtered_keys:
+ response_value = get_nested_value(data, key)
+ gt_value = get_nested_value(ground_truth, key)
+
+ if response_value == "":
+ response_value = None
+ if gt_value == "":
+ gt_value = None
+
+ field_score = calculate_fuzzy_score(response_value, gt_value)
+ field_scores[key] = {
+ 'response': response_value,
+ 'ground_truth': gt_value,
+ 'score': field_score
+ }
+
+ if response_value is not None and gt_value is not None:
+ if field_score >= match_threshold:
+ tp += 1
+ else:
+ fp += 1
+ fn += 1
+ elif response_value is not None and gt_value is None:
+ fp += 1
+ elif response_value is None and gt_value is not None:
+ fn += 1
+
+ precision = tp / (tp + fp) if (tp + fp) > 0 else 0.0
+ recall = tp / (tp + fn) if (tp + fn) > 0 else 0.0
+ f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0.0
+
+ score = {
+ 'f1_score': round(f1, 2),
+ 'precision': precision,
+ 'recall': recall,
+ 'true_positives': tp,
+ 'false_positives': fp,
+ 'false_negatives': fn,
+ 'field_scores': field_scores,
+ 'total_fields': len(filtered_keys)
+ }
+
+ logging.info(score['f1_score'])
+ for line in score['field_scores'].values():
+ logging.debug(line)
+
+ return score
+
+ def score_benchmark(self, all_scores: list) -> dict:
+ if not all_scores:
+ return {"f1_micro": 0.0, "f1_macro": 0.0}
+
+ total_tp = 0
+ total_fp = 0
+ total_fn = 0
+ f1_scores = []
+
+ for score_data in all_scores:
+ if isinstance(score_data, dict) and 'f1_score' in score_data:
+ total_tp += score_data.get('true_positives', 0)
+ total_fp += score_data.get('false_positives', 0)
+ total_fn += score_data.get('false_negatives', 0)
+ f1_scores.append(score_data['f1_score'])
+
+ micro_precision = total_tp / (total_tp + total_fp) if (total_tp + total_fp) > 0 else 0.0
+ micro_recall = total_tp / (total_tp + total_fn) if (total_tp + total_fn) > 0 else 0.0
+ f1_micro = 2 * micro_precision * micro_recall / (micro_precision + micro_recall) if (micro_precision + micro_recall) > 0 else 0.0
+ f1_macro = sum(f1_scores) / len(f1_scores) if f1_scores else 0.0
+
+ score = {
+ "f1_micro": f1_micro,
+ "f1_macro": f1_macro,
+ "micro_precision": micro_precision,
+ "micro_recall": micro_recall,
+ "total_instances": len(f1_scores),
+ "total_tp": total_tp,
+ "total_fp": total_fp,
+ "total_fn": total_fn
+ }
+
+ logging.info(f"f1_micro: {f1_micro}, f1_macro: {f1_macro}")
+
+ return score
diff --git a/benchmarks/duty_rosters/context/icons.jpg b/benchmarks/duty_rosters/context/icons.jpg
new file mode 100644
index 000000000..eb1fb0662
Binary files /dev/null and b/benchmarks/duty_rosters/context/icons.jpg differ
diff --git a/benchmarks/duty_rosters/context/roster_header.jpg b/benchmarks/duty_rosters/context/roster_header.jpg
new file mode 100644
index 000000000..726fb285e
Binary files /dev/null and b/benchmarks/duty_rosters/context/roster_header.jpg differ
diff --git a/benchmarks/duty_rosters/context/shared_context_prompt.txt b/benchmarks/duty_rosters/context/shared_context_prompt.txt
new file mode 100644
index 000000000..beb7f87db
--- /dev/null
+++ b/benchmarks/duty_rosters/context/shared_context_prompt.txt
@@ -0,0 +1,35 @@
+This is the icon legend for a monthly nursing staff duty roster. Each icon represents a shift type or absence category. Use the descriptive name (not the number) when identifying icons in the roster rows that follow.
+
+Valid icon names:
+- F-Dienst 1 (early shift, code 300)
+- S-Dienst 1 (late shift, code 340)
+- M-Dienst 3 (code 322)
+- M-Dienst 4 (code 323)
+- N 1 (night shift, code 817)
+- SD (code 919)
+- L (code 932)
+- Bürotag (office day, code 232)
+- HomeOffice (code 200)
+- BESPRECHUNG (meeting, code 219)
+- Schülerbetreuung (code 922)
+- TV-FAL (code 905)
+- Azu-Gespräche dives (code 8897)
+- Ferien (vacation, code 202)
+- Freier Tag (free day, code 224)
+- Wunschfrei (requested free day, code 222)
+- Kranktag (sick day, code 203)
+- kIND kRANK (child sick, code 204)
+- Unfall (accident, code 206)
+- Mutterschutz (maternity protection, code 214)
+- Schwangerschaftsurlaub (maternity leave, Su)
+- Zügeltag (moving day, code 211)
+- Schultag (school day, code 216)
+- Schule (school, S)
+- Obl. Fort-Bildung (mandatory training, code 238)
+- Kurse bezahlte Weiterb. (paid courses, code 207)
+- RAI/RUG (code 228)
+- Persönliche Absenz (personal absence, PA)
+- Unbezahlter Urlaub (unpaid leave, uU)
+- Betriebsausflug (company outing)
+- Interne Einblicke (internal insights)
+- Auszubildende Lerntandem (trainee tandem)
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/dataclass.py b/benchmarks/duty_rosters/dataclass.py
new file mode 100644
index 000000000..55e53e311
--- /dev/null
+++ b/benchmarks/duty_rosters/dataclass.py
@@ -0,0 +1,88 @@
+"""Pydantic models for Nursing staff duty rosters benchmark output validation.
+
+This module defines the expected structure of model outputs.
+"""
+
+from enum import Enum
+from typing import Literal, Optional
+
+from pydantic import BaseModel
+
+ICON_MAP = {
+ "?": "Unbekannt",
+ "200": "HomeOffice",
+ "202": "Ferien",
+ "203": "Kranktag",
+ "204": "kIND kRANK",
+ "206": "Unfall",
+ "207": "Kurse bezahlte Weiterb.",
+ "211": "Zügeltag",
+ "214": "Mutterschutz",
+ "216": "Schultag",
+ "219": "BESPRECHUNG",
+ "222": "Wunschfrei",
+ "224": "Freier Tag",
+ "228": "RAI/RUG",
+ "232": "Bürotag",
+ "238": "Obl. Fort-Bildung",
+ "300": "F-Dienst 1",
+ "322": "M-Dienst 3",
+ "323": "M-Dienst 4",
+ "340": "S-Dienst 1",
+ "817": "N 1",
+ "8897": "Azu-Gespräche dives",
+ "905": "TV-FAL",
+ "919": "SD",
+ "922": "Schülerbetreuung",
+ "932": "L",
+ "Auszubildende Lerntandem": "Auszubildende Lerntandem",
+ "Betriebsausflug": "Betriebsausflug",
+ "Interne Einblicke": "Interne Einblicke",
+ "PA": "Persönliche Absenz",
+ "S": "Schule",
+ "Su": "Schwangerschaftsurlaub",
+ "uU": "Unbezahlter Urlaub",
+}
+
+IconCode = Literal[
+ "Auszubildende Lerntandem", "Azu-Gespräche dives", "BESPRECHUNG",
+ "Betriebsausflug", "Bürotag", "F-Dienst 1", "Ferien", "Freier Tag",
+ "HomeOffice", "Interne Einblicke", "kIND kRANK", "Kranktag",
+ "Kurse bezahlte Weiterb.", "L", "M-Dienst 3", "M-Dienst 4",
+ "Mutterschutz", "N 1", "Obl. Fort-Bildung", "Persönliche Absenz",
+ "RAI/RUG", "S-Dienst 1", "Schule", "Schultag", "Schülerbetreuung",
+ "Schwangerschaftsurlaub", "SD", "TV-FAL", "Unbezahlter Urlaub",
+ "Unbekannt", "Unfall", "Wunschfrei", "Zügeltag",
+]
+
+
+class ShiftLength(str, Enum):
+ FULL = "full"
+ HALF_LEFT = "half_left"
+ HALF_RIGHT = "half_right"
+
+
+class ShiftEntry(BaseModel):
+ icon: Optional[IconCode] = None
+ length: ShiftLength
+ planned_on_current_unit: bool
+ alternate_unit: Optional[str] = None
+
+
+class DayEntry(BaseModel):
+ date: str
+ shifts: list[ShiftEntry]
+
+
+class Person(BaseModel):
+ id: str
+ profession: str
+ employment_percent: int
+ is_jumper: bool
+ days: list[DayEntry]
+
+
+class Schedule(BaseModel):
+ year: int
+ month: str
+ persons: list[Person]
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/editor/groundtruth_editor.html b/benchmarks/duty_rosters/editor/groundtruth_editor.html
new file mode 100644
index 000000000..01ee1b7ec
--- /dev/null
+++ b/benchmarks/duty_rosters/editor/groundtruth_editor.html
@@ -0,0 +1,979 @@
+
+
+
+
+
+ Duty Roster Editor: Korrektur-Modus
+
+
+
+
+
+
+
+
+
+
+
Duty Roster Korrektur
+
Wählen Sie die Ordner mit den Roster-Bildern und den JSON-Dateien aus.
+
+
+
+
+
+
+
+
1. Bilder-Ordner
+
Kein Ordner gewählt
+
+
+
+
+
+
+
+
2. JSON-Ordner
+
Kein Ordner gewählt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
DR-EDITOR
+
Keine Datei ausgewählt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/benchmarks/duty_rosters/ground_truths/100.json b/benchmarks/duty_rosters/ground_truths/100.json
new file mode 100644
index 000000000..d79662eb6
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/100.json
@@ -0,0 +1,196 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "100",
+ "profession": "Tertiär",
+ "employment_percent": 50,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Bürotag","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":"LE"},
+ {"icon":"SD","length":"half_right","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"},
+ {"icon":"Unbekannt","length":"half_right","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/101.json b/benchmarks/duty_rosters/ground_truths/101.json
new file mode 100644
index 000000000..5578936e5
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/101.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "101",
+ "profession": "SRK",
+ "employment_percent": 60,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":true,"alternate_unit":"TS, 4SO"},
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":false,"alternate_unit":"TS, 4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/102.json b/benchmarks/duty_rosters/ground_truths/102.json
new file mode 100644
index 000000000..30abc81b5
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/102.json
@@ -0,0 +1,194 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "102",
+ "profession": "Prakt",
+ "employment_percent": 80,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Kranktag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Kranktag","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/103.json b/benchmarks/duty_rosters/ground_truths/103.json
new file mode 100644
index 000000000..2094979bf
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/103.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "103",
+ "profession": "WBL",
+ "employment_percent": 80,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Bürotag","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Bürotag","length":"full","planned_on_current_unit":true,"alternate_unit":"T"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Bürotag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"HomeOffice","length":"half_left","planned_on_current_unit":true,"alternate_unit":null},
+ {"icon":"Freier Tag","length":"half_right","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Bürotag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Bürotag","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Bürotag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"Bürotag","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Bürotag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/104.json b/benchmarks/duty_rosters/ground_truths/104.json
new file mode 100644
index 000000000..0203703cf
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/104.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "104",
+ "profession": "AGS",
+ "employment_percent": 80,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"S-Dienst 1","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"},
+ {"icon":null,"length":"half_right","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/105.json b/benchmarks/duty_rosters/ground_truths/105.json
new file mode 100644
index 000000000..b0acccb47
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/105.json
@@ -0,0 +1,196 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "105",
+ "profession": "SRK",
+ "employment_percent": 80,
+ "is_jumper": true,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":"4SO"},
+ {"icon":"M-Dienst 3","length":"half_right","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"half_left","planned_on_current_unit":true,"alternate_unit":"LE, TS"},
+ {"icon":null,"length":"half_right","planned_on_current_unit":true,"alternate_unit":"LE, TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/106.json b/benchmarks/duty_rosters/ground_truths/106.json
new file mode 100644
index 000000000..b5eea9b10
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/106.json
@@ -0,0 +1,194 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "106",
+ "profession": "Sek",
+ "employment_percent": 80,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":"T"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":false,"alternate_unit":"T"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Mutterschutz","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/107.json b/benchmarks/duty_rosters/ground_truths/107.json
new file mode 100644
index 000000000..d3bc86bb9
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/107.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "107",
+ "profession": "Sek",
+ "employment_percent": 100,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":"T"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":null},
+ {"icon":"SD","length":"half_right","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/108.json b/benchmarks/duty_rosters/ground_truths/108.json
new file mode 100644
index 000000000..72cc7c65f
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/108.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "108",
+ "profession": "SRK",
+ "employment_percent": 60,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"T"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"},
+ {"icon":null,"length":"half_right","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/109.json b/benchmarks/duty_rosters/ground_truths/109.json
new file mode 100644
index 000000000..602bd7bb5
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/109.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "109",
+ "profession": "SRK",
+ "employment_percent": 80,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"T"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"},
+ {"icon":null,"length":"half_right","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/110.json b/benchmarks/duty_rosters/ground_truths/110.json
new file mode 100644
index 000000000..a72c6f72e
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/110.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "110",
+ "profession": "Sek",
+ "employment_percent": 100,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Kurse bezahlte Weiterb.","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"T"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Kurse bezahlte Weiterb.","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Schülerbetreuung","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"half_left","planned_on_current_unit":true,"alternate_unit":null},
+ {"icon":"Schülerbetreuung","length":"half_right","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/111.json b/benchmarks/duty_rosters/ground_truths/111.json
new file mode 100644
index 000000000..b45b71753
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/111.json
@@ -0,0 +1,196 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "111",
+ "profession": "SRK",
+ "employment_percent": 80,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Ferien","length":"half_left","planned_on_current_unit":true,"alternate_unit":null},
+ {"icon":"Freier Tag","length":"half_right","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"},
+ {"icon":null,"length":"half_right","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/112.json b/benchmarks/duty_rosters/ground_truths/112.json
new file mode 100644
index 000000000..bd8f16117
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/112.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "112",
+ "profession": "Sek",
+ "employment_percent": 70,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"RAI/RUG","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"T, Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"RAI/RUG","length":"full","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"},
+ {"icon":null,"length":"half_right","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/113.json b/benchmarks/duty_rosters/ground_truths/113.json
new file mode 100644
index 000000000..b656bef1f
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/113.json
@@ -0,0 +1,194 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "113",
+ "profession": "Azubi",
+ "employment_percent": 100,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Schultag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Schultag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Schultag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Schultag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"L","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Schülerbetreuung","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"BESPRECHUNG","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Schülerbetreuung","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Schultag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"Schultag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Schultag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"L","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/115.json b/benchmarks/duty_rosters/ground_truths/115.json
new file mode 100644
index 000000000..82d02c6c3
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/115.json
@@ -0,0 +1,198 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "115",
+ "profession": "SRK",
+ "employment_percent": 60,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":"2SO"},
+ {"icon":"M-Dienst 3","length":"half_right","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"2SO"},
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"},
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"},
+ {"icon":null,"length":"half_right","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Kranktag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Kranktag","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/117.json b/benchmarks/duty_rosters/ground_truths/117.json
new file mode 100644
index 000000000..38e9ad868
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/117.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "117",
+ "profession": "SRK",
+ "employment_percent": 80,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"LE, T"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"},
+ {"icon":null,"length":"half_right","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/118.json b/benchmarks/duty_rosters/ground_truths/118.json
new file mode 100644
index 000000000..9f4816ca6
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/118.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "118",
+ "profession": "SRK",
+ "employment_percent": 100,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"LE, Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":true,"alternate_unit":"Wun"}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"M-Dienst 4","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"S-Dienst 1","length":"half_left","planned_on_current_unit":true,"alternate_unit":"TS"},
+ {"icon":null,"length":"half_right","planned_on_current_unit":true,"alternate_unit":"TS"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/S402.json b/benchmarks/duty_rosters/ground_truths/S402.json
new file mode 100644
index 000000000..0d0ddd375
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/S402.json
@@ -0,0 +1,194 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "402",
+ "profession": "Sek",
+ "employment_percent": 0,
+ "is_jumper": true,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"LE, 2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":"LE"}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"N 1","length":"full","planned_on_current_unit":false,"alternate_unit":"NDP"}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"TS, 2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/S414.json b/benchmarks/duty_rosters/ground_truths/S414.json
new file mode 100644
index 000000000..aee5167af
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/S414.json
@@ -0,0 +1,198 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "S414",
+ "profession": "Tertiär",
+ "employment_percent": 0,
+ "is_jumper": true,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":null},
+ {"icon":"SD","length":"half_right","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"Freier Tag","length":"half_left","planned_on_current_unit":true,"alternate_unit":null},
+ {"icon":"SD","length":"half_right","planned_on_current_unit":true,"alternate_unit":null}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"SD","length":"full","planned_on_current_unit":false,"alternate_unit":"2SO"}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":null,"length":"half_left","planned_on_current_unit":false,"alternate_unit":"ASH"},
+ {"icon":"SD","length":"half_right","planned_on_current_unit":true,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":null,"length":"half_left","planned_on_current_unit":false,"alternate_unit":"ASH"},
+ {"icon":"SD","length":"half_right","planned_on_current_unit":true,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/S420.json b/benchmarks/duty_rosters/ground_truths/S420.json
new file mode 100644
index 000000000..ece542b52
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/S420.json
@@ -0,0 +1,195 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "S420",
+ "profession": "Tertiär",
+ "employment_percent": 0,
+ "is_jumper": true,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":null,"length":"half_left","planned_on_current_unit":false,"alternate_unit":"ASH"},
+ {"icon":"M-Dienst 3","length":"half_right","planned_on_current_unit":true,"alternate_unit":"ASH"}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":null,"length":"full","planned_on_current_unit":false,"alternate_unit":"ASH"}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/ground_truths/SaA410.json b/benchmarks/duty_rosters/ground_truths/SaA410.json
new file mode 100644
index 000000000..c40acf1ce
--- /dev/null
+++ b/benchmarks/duty_rosters/ground_truths/SaA410.json
@@ -0,0 +1,194 @@
+{
+ "year": 2025,
+ "month": "April",
+ "persons": [
+ {
+ "id": "23",
+ "profession": "SRK",
+ "employment_percent": 100,
+ "is_jumper": false,
+ "days": [
+ {
+ "date": "2025-04-01",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":false,"alternate_unit":"LE, 4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-02",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"LE, 4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-03",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-04",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-05",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-06",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-07",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":false,"alternate_unit":"LE, 4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-08",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":true,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-09",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-10",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-11",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-12",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-13",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-14",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-15",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-16",
+ "shifts": [
+ {"icon":"Ferien","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-17",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-18",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-19",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-20",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-21",
+ "shifts": [
+ {"icon":"Wunschfrei","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-22",
+ "shifts": [
+ {"icon":"M-Dienst 3","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-23",
+ "shifts": [
+ {"icon":"S-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-24",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-25",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-26",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-27",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-28",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-29",
+ "shifts": [
+ {"icon":"Freier Tag","length":"full","planned_on_current_unit":false,"alternate_unit":"4SO"}
+ ]
+ },
+ {
+ "date": "2025-04-30",
+ "shifts": [
+ {"icon":"F-Dienst 1","length":"full","planned_on_current_unit":false,"alternate_unit":"FBS, 4SO"}
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/images/100.jpg b/benchmarks/duty_rosters/images/100.jpg
new file mode 100644
index 000000000..c747c95ce
Binary files /dev/null and b/benchmarks/duty_rosters/images/100.jpg differ
diff --git a/benchmarks/duty_rosters/images/101.jpg b/benchmarks/duty_rosters/images/101.jpg
new file mode 100644
index 000000000..cba6f9448
Binary files /dev/null and b/benchmarks/duty_rosters/images/101.jpg differ
diff --git a/benchmarks/duty_rosters/images/102.jpg b/benchmarks/duty_rosters/images/102.jpg
new file mode 100644
index 000000000..59ea34462
Binary files /dev/null and b/benchmarks/duty_rosters/images/102.jpg differ
diff --git a/benchmarks/duty_rosters/images/103.jpg b/benchmarks/duty_rosters/images/103.jpg
new file mode 100644
index 000000000..eddb0131e
Binary files /dev/null and b/benchmarks/duty_rosters/images/103.jpg differ
diff --git a/benchmarks/duty_rosters/images/104.jpg b/benchmarks/duty_rosters/images/104.jpg
new file mode 100644
index 000000000..741b5c5d3
Binary files /dev/null and b/benchmarks/duty_rosters/images/104.jpg differ
diff --git a/benchmarks/duty_rosters/images/105.jpg b/benchmarks/duty_rosters/images/105.jpg
new file mode 100644
index 000000000..7fbb175d7
Binary files /dev/null and b/benchmarks/duty_rosters/images/105.jpg differ
diff --git a/benchmarks/duty_rosters/images/106.jpg b/benchmarks/duty_rosters/images/106.jpg
new file mode 100644
index 000000000..2bf436735
Binary files /dev/null and b/benchmarks/duty_rosters/images/106.jpg differ
diff --git a/benchmarks/duty_rosters/images/107.jpg b/benchmarks/duty_rosters/images/107.jpg
new file mode 100644
index 000000000..e03ea9a6e
Binary files /dev/null and b/benchmarks/duty_rosters/images/107.jpg differ
diff --git a/benchmarks/duty_rosters/images/108.jpg b/benchmarks/duty_rosters/images/108.jpg
new file mode 100644
index 000000000..c0d8c5eb3
Binary files /dev/null and b/benchmarks/duty_rosters/images/108.jpg differ
diff --git a/benchmarks/duty_rosters/images/109.jpg b/benchmarks/duty_rosters/images/109.jpg
new file mode 100644
index 000000000..ebb6ba111
Binary files /dev/null and b/benchmarks/duty_rosters/images/109.jpg differ
diff --git a/benchmarks/duty_rosters/images/110.jpg b/benchmarks/duty_rosters/images/110.jpg
new file mode 100644
index 000000000..a4685aa10
Binary files /dev/null and b/benchmarks/duty_rosters/images/110.jpg differ
diff --git a/benchmarks/duty_rosters/images/111.jpg b/benchmarks/duty_rosters/images/111.jpg
new file mode 100644
index 000000000..c5eea3e03
Binary files /dev/null and b/benchmarks/duty_rosters/images/111.jpg differ
diff --git a/benchmarks/duty_rosters/images/112.jpg b/benchmarks/duty_rosters/images/112.jpg
new file mode 100644
index 000000000..6d7e10f74
Binary files /dev/null and b/benchmarks/duty_rosters/images/112.jpg differ
diff --git a/benchmarks/duty_rosters/images/113.jpg b/benchmarks/duty_rosters/images/113.jpg
new file mode 100644
index 000000000..b04e75a62
Binary files /dev/null and b/benchmarks/duty_rosters/images/113.jpg differ
diff --git a/benchmarks/duty_rosters/images/115.jpg b/benchmarks/duty_rosters/images/115.jpg
new file mode 100644
index 000000000..3d8ca20c4
Binary files /dev/null and b/benchmarks/duty_rosters/images/115.jpg differ
diff --git a/benchmarks/duty_rosters/images/117.jpg b/benchmarks/duty_rosters/images/117.jpg
new file mode 100644
index 000000000..ad1106447
Binary files /dev/null and b/benchmarks/duty_rosters/images/117.jpg differ
diff --git a/benchmarks/duty_rosters/images/118.jpg b/benchmarks/duty_rosters/images/118.jpg
new file mode 100644
index 000000000..205871f54
Binary files /dev/null and b/benchmarks/duty_rosters/images/118.jpg differ
diff --git a/benchmarks/duty_rosters/images/S402.jpg b/benchmarks/duty_rosters/images/S402.jpg
new file mode 100644
index 000000000..cbd085507
Binary files /dev/null and b/benchmarks/duty_rosters/images/S402.jpg differ
diff --git a/benchmarks/duty_rosters/images/S414.jpg b/benchmarks/duty_rosters/images/S414.jpg
new file mode 100644
index 000000000..43d6c157d
Binary files /dev/null and b/benchmarks/duty_rosters/images/S414.jpg differ
diff --git a/benchmarks/duty_rosters/images/S420.jpg b/benchmarks/duty_rosters/images/S420.jpg
new file mode 100644
index 000000000..535e88e3f
Binary files /dev/null and b/benchmarks/duty_rosters/images/S420.jpg differ
diff --git a/benchmarks/duty_rosters/images/SaA410.jpg b/benchmarks/duty_rosters/images/SaA410.jpg
new file mode 100644
index 000000000..ba35d02c2
Binary files /dev/null and b/benchmarks/duty_rosters/images/SaA410.jpg differ
diff --git a/benchmarks/duty_rosters/meta.json b/benchmarks/duty_rosters/meta.json
new file mode 100644
index 000000000..86f79d6f4
--- /dev/null
+++ b/benchmarks/duty_rosters/meta.json
@@ -0,0 +1,21 @@
+{
+ "title": "Nursing Staff Duty Rosters",
+ "title_short": "Duty Rosters",
+ "description": "Evaluates models' ability to extract structured schedule data from visual nursing staff duty rosters, including shift types, half-day splits, alternate unit assignments, and staff metadata.",
+ "example_image": "103.jpg",
+ "tags": {
+ "document-type": ["roster"],
+ "writing": ["printed", "handwritten"],
+ "century": [21],
+ "layout": ["table"],
+ "task": ["information-extraction", "document-understanding"],
+ "language": ["de"]
+ },
+ "ranking": {
+ "metric": "f1_micro",
+ "order": "desc"
+ },
+ "radar_chart": {
+ "metric": "f1_micro"
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/duty_rosters/prompts/prompt.txt b/benchmarks/duty_rosters/prompts/prompt.txt
new file mode 100644
index 000000000..8102fefaf
--- /dev/null
+++ b/benchmarks/duty_rosters/prompts/prompt.txt
@@ -0,0 +1,26 @@
+Extract the duty roster data from this image. You are given three images: (1) the roster header, (2) an icon legend, and (3) one roster row for a single person.
+
+HEADER
+------
+From the header image, extract:
+- year: the calendar year
+- month: the month name
+
+PERSON
+------
+- id: the person number (may be handwritten in the margin)
+- profession: the section label printed ABOVE the row (e.g. "WBL", "Tertiär"), not a value from the data columns
+- employment_percent: the number in the employment column (e.g. 80, 50, 0)
+- is_jumper: true if "S" is marked in the S column, false otherwise
+
+SHIFTS
+------
+For each day of the month, extract the shift(s). Use the header to map each cell to its date.
+
+- date: ISO format (YYYY-MM-DD)
+- icon: match the cell's icon against the icon legend. Use the descriptive name, not the number. Only assign an icon if you can clearly identify a matching icon from the legend. If there is no icon in the cell, use null.
+- length: "full" for a normal cell. If the cell is split into two halves, output two entries for the same date — one "half_left" and one "half_right".
+- planned_on_current_unit: false if the icon has a red dashed border or red shading, true otherwise
+- alternate_unit: the small text below the cell (e.g. "LE", "TS", "ASH"). null if absent. If multiple alternate units are listed for the same date, separate them with a comma (e.g. "LE, TS").
+
+Return the result as JSON matching the Schedule schema.
\ No newline at end of file
diff --git a/scripts/benchmark_base.py b/scripts/benchmark_base.py
index 8347dd57f..763f05e77 100644
--- a/scripts/benchmark_base.py
+++ b/scripts/benchmark_base.py
@@ -44,7 +44,7 @@ def __init__(self, config, api_key, benchmark_directory):
self.temperature = 0.5
# TODO: hotfix, to be fixed in generic-llm-api-client
- if self.model in ["gpt-5.5-2026-04-23","gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-5.1-2025-11-13", "gpt-5.2", "o3"]:
+ if self.model in ["gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-5.1-2025-11-13", "gpt-5.2", "o3", "gpt-5.5-2026-04-23", "gpt-5.3-codex"]:
self.temperature = 1
if self.model in ["claude-opus-4-7", "claude-opus-4-8", "claude-sonnet-5", "claude-fable-5"]:
self.temperature = None
diff --git a/scripts/data/pricing.json b/scripts/data/pricing.json
index c9f395de4..9a017a995 100644
--- a/scripts/data/pricing.json
+++ b/scripts/data/pricing.json
@@ -1880,6 +1880,122 @@
"added": "2026-07-03"
}
}
+ },
+ "2026-04-21": {
+ "anthropic": {
+ "claude-opus-4-7": {
+ "input_price": 5.0,
+ "output_price": 25.0,
+ "source_url": "https://web.archive.org/web/20260421095152/https://platform.claude.com/docs/en/about-claude/pricing",
+ "added": "2026-04-21"
+ }
+ },
+ "openrouter": {
+ "google/gemma-4-26b-a4b-it": {
+ "input_price": 0.08,
+ "output_price": 0.35,
+ "source_url": "https://web.archive.org/web/20260421095137/https://openrouter.ai/google/gemma-4-26b-a4b-it",
+ "added": "2026-04-21"
+ },
+ "google/gemma-4-31b-it": {
+ "input_price": 0.13,
+ "output_price": 0.38,
+ "source_url": "https://web.archive.org/web/20260421095125/https://openrouter.ai/google/gemma-4-31b-it",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.6-plus": {
+ "input_price": 0.325,
+ "output_price": 1.95,
+ "source_url": "https://web.archive.org/web/20260421083957/https://openrouter.ai/qwen/qwen3.6-plus",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.6-plus-04-02": {
+ "input_price": 0.325,
+ "output_price": 1.95,
+ "source_url": "https://web.archive.org/web/20260421083957/https://openrouter.ai/qwen/qwen3.6-plus",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.5-122b-a10b": {
+ "input_price": 0.26,
+ "output_price": 2.08,
+ "source_url": "https://web.archive.org/web/20260421084038/https://openrouter.ai/qwen/qwen3.5-122b-a10b",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.5-27b": {
+ "input_price": 0.195,
+ "output_price": 1.56,
+ "source_url": "https://web.archive.org/web/20260421084103/https://openrouter.ai/qwen/qwen3.5-27b",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.5-35b-a3b": {
+ "input_price": 0.1625,
+ "output_price": 1.3,
+ "source_url": "https://web.archive.org/web/20260421084216/https://openrouter.ai/qwen/qwen3.5-35b-a3b",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.5-397b-a17b": {
+ "input_price": 0.39,
+ "output_price": 2.34,
+ "source_url": "https://web.archive.org/web/20260421084155/https://openrouter.ai/qwen/qwen3.5-397b-a17b",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.5-plus-02-15": {
+ "input_price": 0.26,
+ "output_price": 1.56,
+ "source_url": "https://web.archive.org/web/20260421084227/https://openrouter.ai/qwen/qwen3.5-plus-02-15",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.5-plus-20260216": {
+ "input_price": 0.26,
+ "output_price": 1.56,
+ "source_url": "https://web.archive.org/web/20260421084227/https://openrouter.ai/qwen/qwen3.5-plus-02-15",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.5-flash-02-23": {
+ "input_price": 0.065,
+ "output_price": 0.26,
+ "source_url": "https://web.archive.org/web/20260421084316/https://openrouter.ai/qwen/qwen3.5-flash-02-23",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.5-flash-20260224": {
+ "input_price": 0.065,
+ "output_price": 0.26,
+ "source_url": "https://web.archive.org/web/20260421084316/https://openrouter.ai/qwen/qwen3.5-flash-02-23",
+ "added": "2026-04-21"
+ },
+ "qwen/qwen3.5-9b": {
+ "input_price": 0.1,
+ "output_price": 0.15,
+ "source_url": "https://web.archive.org/web/20260421084351/https://openrouter.ai/qwen/qwen3.5-9b",
+ "added": "2026-04-21"
+ }
+ }
+ },
+ "2026-04-24": {
+ "deepseek": {
+ "deepseek-v4-flash": {
+ "input_price": 0.028,
+ "output_price": 0.28,
+ "source_url": "https://web.archive.org/web/20260424103126/https://api-docs.deepseek.com/quick_start/pricing",
+ "added": "2026-04-24"
+ },
+ "deepseek-v4-pro": {
+ "input_price": 0.145,
+ "output_price": 3.48,
+ "source_url": "https://web.archive.org/web/20260424103126/https://api-docs.deepseek.com/quick_start/pricing",
+ "added": "2026-04-24"
+ }
+ }
+ },
+ "2026-04-27": {
+ "openai": {
+ "gpt-5.5-2026-04-23": {
+ "input_price": 5.0,
+ "output_price": 30.0,
+ "source_url": "https://web.archive.org/web/20260427071936/https://developers.openai.com/api/docs/models/gpt-5.5",
+ "added": "2026-04-27"
+ }
+ }
}
}
}
diff --git a/scripts/run_benchmarks.py b/scripts/run_benchmarks.py
index c21000634..233dc858f 100644
--- a/scripts/run_benchmarks.py
+++ b/scripts/run_benchmarks.py
@@ -90,4 +90,4 @@ def main(limit_to: list[str] = None, regenerate_existing_results: bool = False,
if __name__ == "__main__":
- main()
+ main(limit_to=["T0892"], workers=20)