Output:
Chunk ID: 2d0811
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 5277
Output:
"""Render the v5 app shell around a validated, non-executable JSON bundle."""
from __future__ import annotations

import html
from typing import Any

from dashboard_v5.contracts import safe_json

VIEW_LABELS = (
    ("today", "Heute", "Heute"), ("cockpit", "Cockpit", "Trend"), ("explorer", "Explorer", "Daten"),
    ("nutrition", "Ernährung", "Essen"), ("doctor", "Arzt", "Arzt"),
)

def render(
    bundle: dict[str, Any], *, echarts_prototype: bool = False,
    explorer_6c: bool = False, calendar_day_6d: bool = False,
    health_record_6e: bool = False,
) -> str:
    payload = safe_json(bundle)
    explorer_6c = explorer_6c or calendar_day_6d
    base_labels = tuple((key, "Akte" if key == "doctor" and health_record_6e else label, "Akte" if key == "doctor" and health_record_6e else short) for key, label, short in VIEW_LABELS)
    view_labels = base_labels + (("calendar", "Kalender", "Kalender"),) if calendar_day_6d else base_labels
    nav = "".join(
        f"<button type='button' class='nav-item' data-dashboard-view='{key}' role='tab' aria-label='{html.escape(label)}' aria-controls='view-{key}' aria-selected='{'true' if key == 'today' else 'false'}'>{html.escape(label)}{html.escape(short_label)}</button>"
        for key, label, short_label in view_labels
    )
    periods = "".join(
        f"<button type='button' data-dashboard-period='{value}' aria-pressed='{'true' if value == '30' else 'false'}'>{label}</button>"
        for value, label in (("7", "7 T"), ("30", "30 T"), ("90", "90 T"), ("180", "180 T"), ("all", "Alle"))
    )
    symptom_fields = "".join(
        f"{label}<select name='{key}' required><option value=''>–</option>"
        + "".join(f"<option value='{score}'>{score}</option>" for score in range(4))
        + "</select>"
        for key, label in (
            ("aphthen", "Aphthen"), ("gi", "GI/Darm"), ("fatigue", "Fatigue"),
            ("skin", "Haut"), ("eyes", "Augen"), ("joints", "Gelenke"), ("vascular", "Vaskulär"),
        )
    )
    prototype_controls = "".join(
        f"
<button type='button' data-prototype-series-toggle data-series='Synthetische Reihe {index}' aria-pressed='true'>Reihe {index}</button><button type='button' data-prototype-series-solo data-series='Synthetische Reihe {index}' aria-label='Nur synthetische Reihe {index} anzeigen'>solo</button>
"
        for index in range(1, 9)
    )
    prototype_markup = f"""

Sprint 6A · nur synthetisch
Apache-ECharts-Interaktionsprototyp

365 Tage, acht deterministische Reihen; keine produktiven Gesundheitsdaten.

<button type='button' data-prototype-action='zoom-90'>Letzte 90 Tage</button><button type='button' data-prototype-action='zoom-all'>Gesamtzeitraum</button><button type='button' data-prototype-action='pan'>Drag/Pan</button><button type='button' data-prototype-action='brush'>Bereich auswählen</button><button type='button' data-prototype-action='clear-brush'>Auswahl löschen</button><button type='button' data-prototype-action='all'>Reihen zurücksetzen</button>

{prototype_controls}

Synthetisches Referenzband: 40–60. ◆E1, E2 und E3 markieren synthetische Ereignisse. Muster, Text und Form ergänzen Farbe.

Ausgewählter Tag: <time data-prototype-selected-day datetime='2025-07-14'>noch keiner</time>

  Zugängliche synthetische Datentabelle

365 synthetische Tage und acht synthetische Reihen; Datumsschaltflächen lösen denselben dokumentierten ISO-Callback wie Chartpunkte aus.

Datum	{''.join(f'Reihe {index}	' for index in range(1, 9))}

""" if echarts_prototype else ""
    prototype_scripts = (
        ""
        ""
        if echarts_prototype else ""
    )
    explorer_scripts = (
        ""
        ""
        if explorer_6c else ""
    )
    calendar_header = (
        "Datum <input type='date' data-day-header-date>"
        "<button type='button' data-day-header-open>Tag öffnen</button>"
        "<button type='button' data-day-today>Heute</button>"
        if calendar_day_6d else ""
    )
    calendar_markup = """

Dokumentierte Tage
Kalender

Kalenderkategorien zeigen vorhandene Dokumentation, keine medizinische Bewertung.

<button type='button' data-calendar-previous>Vorheriger Monat</button><button type='button' data-calendar-today>Heute</button><button type='button' data-calendar-next>Nächster Monat</button>Monat <input type='month' data-calendar-month>

● Messwerte● Symptome● Ernährung● Medikamente● Labor● Dokumente● Termine/Ereignisse

Von <input type='date' data-calendar-range-from>Bis <input type='date' data-calendar-range-to>
<button type='button' data-calendar-range-compare disabled>Zeitraum im Explorer vergleichen</button>
Bereich im Kalender ziehen oder Von/Bis eingeben.

Tagesübersicht
Tag

<button type='button' data-day-previous>Vorheriger Tag</button><button type='button' data-day-next>Nächster Tag</button><button type='button' data-day-calendar>Kalender öffnen</button><button type='button' data-day-compare>Im Explorer vergleichen</button><button type='button' data-day-symptom>Symptome erfassen</button>

7-Tage-Kontext
Dokumentierte Messwerte

Persönlicher Verlauf; fehlende Werte bleiben unbekannt.

Symptome

Ernährung

Medikamente

Labor

Termine und Ereignisse

Dokumente

Nicht erfasst

  Details und Datenherkunft

""" if calendar_day_6d else ""
    calendar_scripts = (
        ""
        ""
        if calendar_day_6d else ""
    )
    record_markup = """

Persönliche Gesundheitsakte
Gesundheitsakte

Dokumentierte Fakten; keine Diagnose, Kausalitäts- oder Therapieaussage.

<button type='button' data-record-back>Zur Übersicht</button>

  <button type='button' data-record-tab='overview'>Übersicht</button><button type='button' data-record-tab='labs'>Labore</button><button type='button' data-record-tab='medications'>Medikamente</button><button type='button' data-record-tab='appointments'>Termine</button><button type='button' data-record-tab='documents'>Dokumente</button><button type='button' data-record-tab='report'>Arztbericht</button>

Akte / Übersicht

""" if health_record_6e else """

Arzt

Nur gegen das Original verifizierte, kanonisch freigegebene Laborwerte. Fehlende oder unvollständige Daten bleiben unbekannt. Keine Diagnose, Kausalitätsaussage oder Therapieempfehlung.

Verifizierte Labore

<button type='button' id='print-view'>Drucken</button>
"""
    record_scripts = "" if health_record_6e else ""
    range_scripts = "" if explorer_6c else ""
    global_search_markup = """<button type='button' class='global-search-open' data-global-search-open aria-haspopup='dialog' aria-controls='global-search-dialog'>Suchen ⌘K</button><dialog id='global-search-dialog' class='global-search-dialog' data-global-search-dialog aria-labelledby='global-search-title'>

Globale Suche
<button type='button' data-global-search-close aria-label='Suche schließen'>×</button>
Gesundheitsdaten durchsuchen
<input id='global-search-input' type='search' data-global-search-input autocomplete='off'><button type='button' data-global-search-submit>Suchen</button>

</dialog>""" if health_record_6e else ""
    global_search_scripts = "" if health_record_6e else ""
    return f"""<!doctype html>
<meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'>
<title>JARVIS Health Dashboard v5</title>
<meta name='health-browser-session-csrf' content='__BROWSER_SESSION_CSRF__'>
<link rel='icon' href='data:,'>
<link rel='stylesheet' href='/health-assets/dashboard-v5.css'>

Zum Inhalt

JARVIS HealthManager
Gesundheit

{calendar_header}{global_search_markup}Letzte 30 TageDatenstand wird geprüft<button type='button' id='privacy-toggle' aria-pressed='false'>Privacy</button><button type='button' id='more-toggle' aria-controls='view-more' aria-expanded='false'>Mehr</button>

{periods}Von/Bis
Von <input type='date' data-range-from>Bis <input type='date' data-range-to><button type='button' data-range-apply>Anwenden</button>

{nav}

Tagesübersicht
Heute

Das Wichtigste aus den zuletzt dokumentierten Daten. Fehlende Werte bleiben unbekannt.

Momentaufnahme

Aufgaben

Medikation

<button type='button' class='primary-action mobile-capture-action' id='open-checkin' aria-describedby='capture-helper'>＋ Beschwerden erfassen</button>

Alle sieben Werte sind für einen vollständigen Tag erforderlich. Fehlende Angaben werden nicht als 0 gespeichert.

<dialog id='checkin-dialog' aria-labelledby='checkin-title'><form method='post' action='/health-actions/symptom-checkin'><input type='hidden' name='csrf_token' value='__CSRF_TOKEN__'><input type='hidden' name='return_to' value='v5'><input type='hidden' name='date' value='__CAPTURE_DATE__'>
Beschwerden erfassen

Erfassung für <time id='capture-date' datetime='__CAPTURE_DATE__'>__CAPTURE_DATE_LABEL__</time>

{symptom_fields}
Notiz, optional<textarea name='notes' maxlength='300'></textarea>
<button type='button' id='close-checkin'>Abbrechen</button><button type='submit'>Sicher vormerken</button>
</form></dialog>

Persönliche Trends
Cockpit

Dokumentierte Werte im persönlichen Verlauf; keine generische medizinische Bewertung.

Verlauf
Gesundheitsverlauf

<canvas id='cockpit-chart' role='img' aria-label='Gesundheitsverlauf'></canvas>
Keine dokumentierten Beobachtungen im gewählten Zeitraum.

Explorer
Gesundheitsverläufe

Einheitliche ECharts-Verlaufsansicht. Dokumentierte Werte ohne Diagnose-, Kausalitäts- oder Therapieaussage.

<button type='button' data-api-explorer-mode='raw' aria-pressed='true'>Rohwerte</button><button type='button' data-api-explorer-mode='baseline' aria-pressed='false'>Baseline · Index 100</button>

<button type='button' data-api-explorer-resolution='day' aria-pressed='true'>Täglich</button><button type='button' data-api-explorer-resolution='week' aria-pressed='false'>Wöchentlich</button>

      <button type='button' data-api-explorer-clear>Auswahl leeren</button>

Abkürzungen<button type='button' data-api-explorer-shortcut='Herz'>Herz/Kreislauf</button><button type='button' data-api-explorer-shortcut='Schlaf'>Schlaf/Erholung</button><button type='button' data-api-explorer-shortcut='Schritte'>Aktivität</button><button type='button' data-api-explorer-shortcut='Symptome'>Symptome</button>

Gesundheitswert hinzufügen
<input id='explorer-metric-search' type='search' data-api-explorer-search autocomplete='off'><button type='button' data-api-explorer-search-button>Suchen</button>

<button type='button' data-api-explorer-retry>Erneut versuchen</button>

    Zugängliche Datentabelle

  {prototype_markup}

{calendar_markup}

Ernährung

SIGHi-Zuordnungen dokumentieren Quellen und Unsicherheit; sie sind keine allgemeine Lebensmittelsicherheitsbewertung.

<canvas id='nutrition-chart' role='img' aria-label='Dokumentierter Histamin-Score'></canvas>
Keine vollständig klassifizierten Ernährungstage im gewählten Zeitraum.

Offene Lebensmittel-Zuordnungen

Nur Anzeige – Bearbeitung folgt im Ernährungs-Sprint 6G.

{record_markup}

Daten & System

Technische Datenqualität und sekundäre Arbeitsansichten sind bewusst von den primären Gesundheitsansichten getrennt.

{range_scripts}{explorer_scripts}{calendar_scripts}{record_scripts}{global_search_scripts}{prototype_scripts}
Dashboard v5 benötigt lokales JavaScript. Dashboard v4 bleibt als Fallback verfügbar.

"""


Output:
Chunk ID: d41183
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 3634
Output:
"""Read-only, allowlisted data provider for Dashboard v5."""
from __future__ import annotations

import json
import re
import sqlite3
from collections import defaultdict
from datetime import date, datetime, timedelta, timezone
from pathlib import Path
from statistics import median
from typing import Any

from apple_health_analytics import daily_series as apple_daily
from dashboard_v5.contracts import SCHEMA_VERSION
from dashboard_v5.lab_registry import EXACT_LAB_NUMBER, LAB_ALLOWLIST
from dashboard_v5.metric_registry import BY_ID, public_explorer, public_registry

TZ = "Europe/Zurich"
SYMPTOM_LABELS = {
    "Aphthen/Mundulzera", "GI/Darm", "Müdigkeit/Fatigue", "Haut", "Augen",
    "Gelenke", "Vaskulär/Thrombose-Warnzeichen",
}
APPLE_SPECS = {
    "apple.sleep": ("sleep_analysis", "sum"),
    "apple.resting_heart_rate": ("resting_heart_rate", "avg"),
    "apple.hrv": ("heart_rate_variability", "avg"),
    "apple.steps": ("step_count", "sum"),
}
ADMINISTERED = {
    "administered", "verabreicht",
    "erste injektion / therapiebeginn", "planmäßige injektion", "planmässige injektion", "planmaessige injektion",
}
EXPLICIT_PLANS = {"planned", "scheduled", "geplant"}
EXCLUDED_PLANS = {"cancelled", "canceled", "abgesagt", "missed", "verpasst"}
PUBLIC_TEXT = re.compile(r"^[^\x00-\x1f\x7f]{1,160}$")
IDENTIFIER = re.compile(r"^[a-z0-9_:.-]+$")

def public_text(value: Any, maximum: int = 120, *, allow_empty: bool = False) -> str | None:
    text = " ".join(str(value or "").split())
    if (not text and not allow_empty) or len(text) > maximum or not PUBLIC_TEXT.fullmatch(text or " "):
        return None
    if re.search(r"^(?:/|~/|[A-Za-z]:[\\/]|file:|https?://)|(?:^|/)\.hermes(?:/|$)", text, re.I):
        return None
    return text

def connect(path: Path) -> sqlite3.Connection:
    connection = sqlite3.connect(f"file:{path}?mode=ro", uri=True)
    connection.row_factory = sqlite3.Row
    return connection

def table_exists(connection: sqlite3.Connection, name: str) -> bool:
    return connection.execute(
        "SELECT 1 FROM sqlite_master WHERE type='table' AND name=?", (name,)
    ).fetchone() is not None

def slug(value: Any) -> str:
    normalized = str(value or "").casefold().translate(
        str.maketrans({"ä": "ae", "ö": "oe", "ü": "ue", "ß": "ss"})
    )
    return re.sub(r"[^a-z0-9]+", "_", normalized).strip("_")

def unit_slug(value: Any) -> str:
    return slug(str(value or "").replace("µ", "u").replace("μ", "u").replace("%", " percent "))

def parse_day(value: Any) -> str | None:
    text = str(value or "").strip()
    if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", text):
        return None
    try:
        return date.fromisoformat(text).isoformat()
    except ValueError:
        return None

def parse_score(value: Any) -> int | None:
    match = re.search(r"(?:^|\()([0-3])\)?\s*$", str(value or "").strip())
    return int(match.group(1)) if match else None

def rolling_baseline(points: list[dict[str, Any]], days: int, minimum: int = 7) -> list[dict[str, Any]]:
    observed = {date.fromisoformat(p["date"]): float(p["value"]) for p in points if p["value"] is not None}
    result: list[dict[str, Any]] = []
    for point in points:
        current = date.fromisoformat(point["date"])
        start = current - timedelta(days=days)
        values = [value for day, value in observed.items() if start <= day < current]
        result.append({"date": point["date"], "value": round(median(values), 3) if len(values) >= minimum else None})
    return result

def symptom_series(connection: sqlite3.Connection) -> tuple[list[dict[str, Any]], set[str]]:
    if not table_exists(connection, "symptom_log"):
        return [], set()
    grouped: dict[str, dict[str, list[int | None]]] = defaultdict(lambda: defaultdict(list))
    for row in connection.execute(
        "SELECT datum,symptom,schwergrad FROM symptom_log WHERE kontext='daily_quick_score' ORDER BY datum,id"
    ):
        day = parse_day(row["datum"])
        score = parse_score(row["schwergrad"])
        label = str(row["symptom"] or "")
        if day and label in SYMPTOM_LABELS:
            grouped[day][label].append(score)
    complete = {
        day
        for day, values in grouped.items()
        if set(values) == SYMPTOM_LABELS
        and all(len(scores) == 1 and scores[0] is not None for scores in values.values())
    }
    return [
        {"date": day, "value": sum(score for scores in grouped[day].values() for score in scores if score is not None), "quality": "complete"}
        for day in sorted(complete)
    ], complete

def apple_series(connection: sqlite3.Connection, metric: str, mode: str) -> list[dict[str, Any]]:
    if not table_exists(connection, "apple_health_records"):
        return []
    rows = list(connection.execute(
        """SELECT id,metric,value,unit,start_date,end_date,source_name,file_name,file_hash
           FROM apple_health_records WHERE metric=? AND value IS NOT NULL AND start_date IS NOT NULL
           ORDER BY start_date,end_date,source_name,id""", (metric,)
    ))
    values = apple_daily(metric, mode, _rows=rows)
    return [{"date": day, "value": value, "quality": "observed"} for day, value in sorted(values.items())]

def medication_data(connection: sqlite3.Connection, today: str) -> tuple[dict[str, Any], list[dict[str, Any]]]:
    if not table_exists(connection, "medication_administrations"):
        return {"last_administered": None, "next_planned": None}, []
    rows = list(connection.execute(
        "SELECT datum,medication_name,dose,event_type,scheduled_next_date FROM medication_administrations ORDER BY datum"
    ))
    actual = [
        row for row in rows
        if str(row["event_type"] or "").strip().casefold() in ADMINISTERED
        and (administered_day := parse_day(row["datum"])) is not None
        and administered_day <= today
    ]
    last = actual[-1] if actual else None
    cancelled_plans = {
        (str(row["medication_name"] or "").strip().casefold(), day)
        for row in rows
        if str(row["event_type"] or "").strip().casefold() in EXCLUDED_PLANS
        for day in (parse_day(row["datum"]), parse_day(row["scheduled_next_date"]))
        if day
    }
    candidates = []
    for row in rows:
        event_type = str(row["event_type"] or "").strip().casefold()
        medication_key = str(row["medication_name"] or "").strip().casefold()
        scheduled = parse_day(row["scheduled_next_date"])
        explicit_day = parse_day(row["datum"])
        planned = None
        if (
            scheduled
            and event_type in ADMINISTERED
            and explicit_day is not None
            and explicit_day <= today
        ):
            planned = scheduled
        elif event_type in EXPLICIT_PLANS:
            planned = explicit_day
        if planned and planned > today and (medication_key, planned) not in cancelled_plans:
            candidates.append((planned, row))
    next_item = min(candidates, key=lambda item: item[0]) if candidates else None
    def public_medication(row: sqlite3.Row | None, day: str | None, *, planned: bool) -> dict[str, Any] | None:
        if row is None or day is None:
            return None
        name = public_text(row["medication_name"], 120)
        dose = public_text(row["dose"], 40, allow_empty=True)
        if name is None or dose is None:
            return None
        item: dict[str, Any] = {"date": day, "name": name, "dose": dose}
        if planned:
            item["status"] = "planned"
        return item

    medication = {
        "last_administered": public_medication(last, parse_day(last["datum"]) if last else None, planned=False),
        "next_planned": public_medication(next_item[1], next_item[0], planned=True) if next_item else None,
    }
    events = []
    for row in actual:
        label = public_text(row["medication_name"], 120)
        day = parse_day(row["datum"])
        if label and day:
            events.append({"date": day, "type": "medication_administered", "label": label})
    return medication, events

def verified_labs(
    connection: sqlite3.Connection,
    limit: int = 12,
    *,
    through_day: str | None = None,
) -> list[dict[str, Any]]:
    if not table_exists(connection, "laborwerte"):
        return []
    rows = list(connection.execute(
        """SELECT parameter_name,wert,einheit,reference_min,reference_max,abnahme_datum,befund_datum,
                  reference_range_source,source_type
           FROM laborwerte
           WHERE lower(trim(COALESCE(validierungsstatus,'')))='validiert'
             AND verified_against_original=1
             AND reference_range_source='scanned_original'
             AND trim(COALESCE(einheit,''))<>''
           ORDER BY id"""
    ))
    candidates: dict[tuple[str, str, str], list[sqlite3.Row]] = defaultdict(list)
    for row in rows:
        raw_key = (slug(row["parameter_name"]), unit_slug(row["einheit"]))
        canonical = LAB_ALLOWLIST.get(raw_key)
        day = parse_day(row["abnahme_datum"]) or parse_day(row["befund_datum"])
        if canonical and day and (through_day is None or day <= through_day):
            canonical_parameter, canonical_unit = canonical
            candidates[(canonical_parameter, canonical_unit, day)].append(row)
    result = []
    for (canonical_parameter, canonical_unit, day), same_day in candidates.items():
        if len(same_day) != 1:
            continue
        row = same_day[0]
        if not EXACT_LAB_NUMBER.fullmatch(str(row["wert"] or "").strip()):
            continue
        result.append({
            "parameter": canonical_parameter, "value": str(row["wert"]).strip(),
            "unit": canonical_unit, "date": day,
            "reference_min": row["reference_min"], "reference_max": row["reference_max"],
            "quality": "verified_original", "source_type": "scanned_original",
        })
    result.sort(key=lambda item: item["date"], reverse=True)
    return result[:limit]

def nutrition_data(connection: sqlite3.Connection) -> dict[str, Any]:
    daily: list[dict[str, Any]] = []
    if table_exists(connection, "nutrition_daily_summary_v2"):
        for row in connection.execute("SELECT * FROM nutrition_daily_summary_v2 ORDER BY datum DESC LIMIT 180"):
            day = parse_day(row["datum"])
            complete = (
                day is not None and row["item_count"] is not None and int(row["item_count"]) > 0
                and row["histamine_unknown_count"] is not None and int(row["histamine_unknown_count"]) == 0
                and row["histamine_score"] is not None
                and row["histamine_label"] in {"green", "yellow", "orange", "red"}
            )
            if day:
                daily.append({
                    "date": day, "kcal": row["kcal"], "item_count": row["item_count"],
                    "histamine_score": row["histamine_score"] if complete else None,
                    "histamine_status": str(row["histamine_label"]) if complete else "unknown",
                    "unknown_items": row["histamine_unknown_count"], "quality": "complete" if complete else "incomplete",
                })
    review = []
    if table_exists(connection, "nutrition_review_queue"):
        for row in connection.execute("SELECT example_name,occurrence_count FROM nutrition_review_queue WHERE status='open' ORDER BY occurrence_count DESC,last_seen DESC LIMIT 25"):
            name = public_text(row["example_name"], 160)
            if name:
                review.append({"name": name, "occurrences": int(row["occurrence_count"] or 0), "reason": "Zuordnung fehlt"})
    return {"daily": list(reversed(daily)), "mapping_review": review, "mapping_open_count": len(review)}

def correlations(connection: sqlite3.Connection) -> dict[str, Any]:
    dimensions = {
        "lag_days": [0, 1, 2, 3],
        "medication_phases": ["baseline_pre_treatment", "early_treatment", "stable_treatment", "unknown"],
        "lag_direction": "predictor_d_to_target_d_plus_lag",
    }
    if not table_exists(connection, "multimodal_correlation_results"):
        return {"dimensions": dimensions, "results": []}

    import multimodal_correlations as engine

    results = []
    rows = connection.execute(
        """SELECT predictor,target,lag_days,medication_phase,n,eligible_target_days,
                  expected_target_days,target_coverage,missing_pairs,rho,p_value,q_value,
                  status,method,quality_flags,interpretation
           FROM multimodal_correlation_results
           ORDER BY predictor,target,lag_days,medication_phase LIMIT 1000"""
    )
    for row in rows:
        try:
            flags_raw = json.loads(str(row["quality_flags"]))
            if not isinstance(flags_raw, list) or not all(isinstance(flag, str) for flag in flags_raw):
                continue
            result = engine.CorrelationResult(
                predictor=str(row["predictor"]), target=str(row["target"]),
                lag_days=int(row["lag_days"]), medication_phase=str(row["medication_phase"]),
                n=int(row["n"]), eligible_target_days=int(row["eligible_target_days"]),
                expected_target_days=int(row["expected_target_days"]),
                target_coverage=float(row["target_coverage"]), missing_pairs=int(row["missing_pairs"]),
                rho=row["rho"], p_value=row["p_value"], q_value=row["q_value"],
                status=str(row["status"]), method=str(row["method"]),
                quality_flags=tuple(flags_raw), interpretation=str(row["interpretation"]),
            )
            engine._validate_result_for_storage(result)
        except (TypeError, ValueError, json.JSONDecodeError):
            continue
        results.append({
            "id": {"predictor": result.predictor, "target": result.target},
            "dimensions": {"lag_days": result.lag_days, "medication_phase": result.medication_phase},
            "sample": {
                "eligible_target_days": result.eligible_target_days,
                "expected_target_days": result.expected_target_days,
                "observed_pairs": result.n,
                "missing_pairs": result.missing_pairs,
                "target_coverage": result.target_coverage,
            },
            "statistics": {"rho": result.rho, "p_value": result.p_value, "q_value": result.q_value},
            "status": result.status,
            "method": result.method,
            "quality_flags": list(result.quality_flags),
        })
    return {"dimensions": dimensions, "results": results}


Output:
Chunk ID: a5669c
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2257
Output:
"""Bounded read-only data API provider for Dashboard v5 Sprint 6B."""

from __future__ import annotations

import base64
import hashlib
import hmac
import json
import math
import re
import secrets
import sqlite3
import time
from statistics import median
from collections import defaultdict
from dataclasses import dataclass
from datetime import date, datetime, timedelta
from pathlib import Path
from typing import Any
from urllib.parse import parse_qs
from zoneinfo import ZoneInfo

from apple_health_analytics import daily_points
from dashboard_v5.data_provider import (
    ADMINISTERED,
    SYMPTOM_LABELS,
    parse_day,
    parse_score,
    public_text,
)
from dashboard_v5.document_chunks import (
    decode_chunk_cursor,
    document_chunks,
    encode_chunk_cursor,
)
from dashboard_v5.document_originals import probe_original
from dashboard_v5.lab_registry import EXACT_LAB_NUMBER, LAB_ALLOWLIST
from dashboard_v5.metric_catalog_v2 import (
    APPLE_ANALYTICS_UNITS,
    APPLE_SOURCE_SPECS,
    BY_ID_V2,
    LAB_CATALOG_SPECS,
    MetricV2,
    SourceInventoryLimitError,
    catalog_search,
    inventory_sources,
    public_catalog,
)

TZ_NAME = "Europe/Zurich"
LOCAL_TZ = ZoneInfo(TZ_NAME)
MAX_RANGE_DAYS = 3660
MAX_SERIES_ROWS = 3660
MAX_RAW_APPLE_ROWS = 100000
MAX_RAW_LAB_ROWS = 10000
MAX_EVENT_SOURCE_ROWS = 10000
MAX_DAILY_SOURCE_ROWS = 30000
MAX_EVENT_ROWS = 1000
MAX_LAB_ROWS = 100
MAX_SEARCH_ROWS_PER_GROUP = 20
MAX_CALENDAR_DAYS = 62
MAX_FUTURE_DAYS = 366
MAX_QUERY_BYTES = 512
QUERY_TIMEOUT_SECONDS = 1.0
ALLOWED_RESOLUTIONS = frozenset({"day", "week"})
ALLOWED_EVENT_TYPES = frozenset(
    {"medication_administered", "symptom_day", "health_event", "health_period"}
)
FORBIDDEN_METADATA_TEXT = re.compile(
    r"(?:/home/|/tmp/|/Users/|/(?:var|etc|usr|opt|srv|root|run|mnt|media|private)/|"
    r"~/|file:|https?://|[A-Za-z]:[\\/]|"
    r"(?:^|[\s:|])/(?:[^/\s]+/)+[^/\s]+|\.\.[\\/]|\\\\[^\\/\s]+[\\/]|"
    r"\.hermes(?:/|$))",
    re.IGNORECASE,
)
DRIVE_ID_TOKEN = re.compile(r"(?<![A-Za-z0-9_-])[A-Za-z0-9_-]{25,}(?![A-Za-z0-9_-])")
API_PATHS = frozenset(
    {
        "/api/v1/metric-catalog",
        "/api/v1/series",
        "/api/v1/events",
        "/api/v1/labs",
        "/api/v1/calendar",
        "/api/v1/search",
    }
)
EXPECTED_ANALYTICS_UNITS = APPLE_ANALYTICS_UNITS

@dataclass
class APIError(Exception):
    status: int
    code: str

    def __str__(self) -> str:
        return self.code

def safe_metadata_text(
    value: Any, maximum: int, *, allow_empty: bool = False
) -> str | None:
    text = public_text(value, maximum, allow_empty=allow_empty)
    drive_id_like = bool(
        text
        and any(
            any(char.isalpha() for char in token)
            and any(char.isdigit() for char in token)
            for token in DRIVE_ID_TOKEN.findall(text)
        )
    )
    if text is None or FORBIDDEN_METADATA_TEXT.search(text) or drive_id_like:
        return None
    return text

def api_document_id(
    raw_id: Any, document_day: str | None, category: str, institution: str
) -> str:
    material = json.dumps(
        [int(raw_id), document_day, category, institution],
        ensure_ascii=False,
        separators=(",", ":"),
    ).encode("utf-8")
    return f"api-document-{hashlib.sha256(b'health-api-document-v1:' + material).hexdigest()[:24]}"

def connect_read_only(database: Path) -> sqlite3.Connection:
    connection = sqlite3.connect(f"{database.resolve().as_uri()}?mode=ro", uri=True)
    connection.row_factory = sqlite3.Row
    connection.execute("PRAGMA query_only=ON")
    connection.execute("PRAGMA trusted_schema=OFF")
    deadline = time.monotonic() + QUERY_TIMEOUT_SECONDS
    connection.set_progress_handler(lambda: int(time.monotonic() > deadline), 1000)
    return connection

def table_exists(connection: sqlite3.Connection, table: str) -> bool:
    return (
        connection.execute(
            "SELECT 1 FROM sqlite_master WHERE type='table' AND name=?", (table,)
        ).fetchone()
        is not None
    )

def parse_query(query: str, allowed: set[str]) -> dict[str, str]:
    if len(query.encode("utf-8")) > MAX_QUERY_BYTES:
        raise APIError(414, "query_too_large")
    try:
        parsed = (
            parse_qs(
                query,
                keep_blank_values=True,
                strict_parsing=True,
                max_num_fields=max(1, len(allowed) + 1),
            )
            if query
            else {}
        )
    except ValueError as error:
        raise APIError(400, "invalid_query") from error
    if not set(parsed) <= allowed:
        raise APIError(400, "unknown_parameter")
    if any(len(values) != 1 for values in parsed.values()):
        raise APIError(400, "duplicate_parameter")
    return {key: values[0] for key, values in parsed.items()}

def parse_iso_day(raw: str, *, code: str = "invalid_date") -> date:
    if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", raw):
        raise APIError(400, code)
    try:
        return date.fromisoformat(raw)
    except ValueError as error:
        raise APIError(400, code) from error

def local_today() -> date:
    return datetime.now(LOCAL_TZ).date()

def parse_range(
    params: dict[str, str], *, required: bool = False
) -> tuple[date | None, date | None]:
    raw_start = params.get("from")
    raw_end = params.get("to")
    if bool(raw_start) != bool(raw_end):
        raise APIError(400, "incomplete_range")
    if required and not raw_start:
        raise APIError(400, "range_required")
    if not raw_start:
        return None, None
    start = parse_iso_day(raw_start)
    end = parse_iso_day(raw_end or "")
    if end < start:
        raise APIError(400, "range_reversed")
    if start > local_today() or end > local_today():
        raise APIError(422, "future_range_not_allowed")
    if (end - start).days + 1 > MAX_RANGE_DAYS:
        raise APIError(422, "range_too_large")
    return start, end

def _apple_rows(
    connection: sqlite3.Connection,
    identifier: str,
    start: date | None,
    end: date | None,
    *,
    include_raw_json: bool = False,
) -> list[sqlite3.Row]:
    if include_raw_json:
        sql = """SELECT id,metric,value,unit,start_date,end_date,source_name,
                        file_name,file_hash,raw_json
                 FROM apple_health_records WHERE metric=? AND start_date IS NOT NULL"""
    else:
        sql = """SELECT id,metric,value,unit,start_date,end_date,source_name,file_name,file_hash
                 FROM apple_health_records WHERE metric=? AND start_date IS NOT NULL"""
    parameters: list[Any] = [identifier]
    # Keep the (metric,start_date) index usable with a deliberately coarse raw
    # candidate interval.  It includes one whole calendar day on either side;
    # the upper edge is exclusive so all lexical ISO values on end + 1 are kept.
    # daily_points remains the sole authority for Europe/Zurich assignment and
    # exact start/end filtering—this SQL clause never assigns a health day.
    if start is not None and start > date.min:
        sql += " AND start_date>=?"
        parameters.append((start - timedelta(days=1)).isoformat())
    # date.max cannot represent the exclusive edge after end + 1.  Omitting
    # that impossible upper bound preserves the exact canonical filter while
    # avoiding an arithmetic overflow at the ISO boundary.
    if end is not None and end < date.max - timedelta(days=1):
        sql += " AND start_date<?"
        parameters.append((end + timedelta(days=2)).isoformat())
    sql += " ORDER BY start_date,end_date,source_name,id LIMIT ?"
    parameters.append(MAX_RAW_APPLE_ROWS + 1)
    rows = list(connection.execute(sql, parameters))
    if len(rows) > MAX_RAW_APPLE_ROWS:
        raise APIError(422, "source_row_limit_exceeded")
    return rows

def _numeric(value: float, precision: int, value_type: str) -> int | float:
    rounded = round(float(value), precision)
    if value_type == "integer" or (precision == 0 and rounded.is_integer()):
        return int(rounded)
    return rounded

def _apple_points(
    connection: sqlite3.Connection,
    metric: MetricV2,
    start: date | None,
    end: date | None,
) -> list[dict[str, Any]]:
    rows = _apple_rows(connection, metric.source_identifier, start, end)
    points = daily_points(
        metric.source_identifier,
        mode=metric.aggregation,
        stable_only=False,
        start_date=start.isoformat() if start else None,
        end_date=end.isoformat() if end else None,
        _rows=rows,
    )
    result = []
    for day, point in sorted(points.items()):
        if point.unit != EXPECTED_ANALYTICS_UNITS.get(metric.source_identifier):
            continue
        result.append(
            {
                "date": day,
                "value": _numeric(point.value, metric.precision, metric.value_type),
                "quality": point.quality,
                "source_class": point.source_class,
            }
        )
    return result

def _blood_pressure_points(
    connection: sqlite3.Connection,


The renderer still injects Chart.js globally for V5 and uses canvas elements for cockpit/nutrition. I’m going to replace those V5 surfaces with shared ECharts-backed containers while keeping V4 and the older prototype path intact.


sed -n '280,760p' scripts/health/dashboard_v5/read_api.py


sed -n '1,360p' scripts/health/assets/health-assets/dashboard-v5.js


sed -n '1,360p' scripts/health/assets/health-assets/dashboard-v5-api-explorer.js


sed -n '1,360p' scripts/health/health_dashboard_action_worker.py


Output:
Chunk ID: f1facf
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 4614
Output:
    connection: sqlite3.Connection,
    metric: MetricV2,
    start: date | None,
    end: date | None,
) -> list[dict[str, Any]]:
    component = "systolic" if metric.id.endswith(".systolic") else "diastolic"
    by_day: dict[str, tuple[datetime, float]] = {}
    for row in _apple_rows(
        connection, "blood_pressure", start, end, include_raw_json=True
    ):
        try:
            timestamp = datetime.fromisoformat(
                str(row["start_date"]).replace("Z", "+00:00")
            )
            if timestamp.tzinfo is None:
                timestamp = timestamp.replace(tzinfo=LOCAL_TZ)
            day = timestamp.astimezone(LOCAL_TZ).date()
            payload = json.loads(str(row["raw_json"] or ""))
            unit = re.sub(r"[^a-z]", "", str(row["unit"] or "").casefold())
            systolic = float(payload["systolic"])
            diastolic = float(payload["diastolic"])
            if unit != "mmhg" or not all(
                math.isfinite(item) for item in (systolic, diastolic)
            ):
                continue
            value = systolic if component == "systolic" else diastolic
        except (ValueError, TypeError, KeyError, json.JSONDecodeError):
            continue
        if not math.isfinite(value):
            continue
        if start is not None and day < start:
            continue
        if end is not None and day > end:
            continue
        existing = by_day.get(day.isoformat())
        if existing is None or timestamp > existing[0]:
            by_day[day.isoformat()] = (timestamp, value)
    return [
        {
            "date": day,
            "value": _numeric(item[1], metric.precision, metric.value_type),
            "quality": "paired_observation",
            "source_class": "apple_health",
        }
        for day, item in sorted(by_day.items())
    ]

def _symptom_dimension_points(
    connection: sqlite3.Connection,
    metric: MetricV2,
    start: date | None,
    end: date | None,
) -> list[dict[str, Any]]:
    sql = "SELECT datum,schwergrad FROM symptom_log WHERE kontext='daily_quick_score' AND symptom=?"
    parameters: list[Any] = [metric.source_identifier]
    if start:
        sql += " AND datum>=?"
        parameters.append(start.isoformat())
    if end:
        sql += " AND datum<=?"
        parameters.append(end.isoformat())
    sql += " ORDER BY datum,id LIMIT ?"
    parameters.append(MAX_DAILY_SOURCE_ROWS + 1)
    rows = list(connection.execute(sql, parameters))
    if len(rows) > MAX_DAILY_SOURCE_ROWS:
        raise APIError(422, "source_row_limit_exceeded")
    grouped: dict[str, list[int | None]] = defaultdict(list)
    for row in rows:
        day = parse_day(row["datum"])
        if day:
            grouped[day].append(parse_score(row["schwergrad"]))
    return [
        {"date": day, "value": scores[0], "quality": "observed"}
        for day, scores in sorted(grouped.items())
        if len(scores) == 1 and scores[0] is not None
    ]

def _symptom_total_points(
    connection: sqlite3.Connection,
    start: date | None,
    end: date | None,
) -> list[dict[str, Any]]:
    sql = "SELECT datum,symptom,schwergrad FROM symptom_log WHERE kontext='daily_quick_score'"
    parameters: list[Any] = []
    if start:
        sql += " AND datum>=?"
        parameters.append(start.isoformat())
    if end:
        sql += " AND datum<=?"
        parameters.append(end.isoformat())
    sql += " ORDER BY datum,id LIMIT ?"
    parameters.append(MAX_DAILY_SOURCE_ROWS + 1)
    rows = list(connection.execute(sql, parameters))
    if len(rows) > MAX_DAILY_SOURCE_ROWS:
        raise APIError(422, "source_row_limit_exceeded")
    grouped: dict[str, dict[str, list[int | None]]] = defaultdict(
        lambda: defaultdict(list)
    )
    for row in rows:
        day = parse_day(row["datum"])
        label = str(row["symptom"] or "")
        if day and label in SYMPTOM_LABELS:
            grouped[day][label].append(parse_score(row["schwergrad"]))
    result = []
    for day, dimensions in sorted(grouped.items()):
        if set(dimensions) != SYMPTOM_LABELS:
            continue
        if not all(
            len(scores) == 1 and scores[0] is not None for scores in dimensions.values()
        ):
            continue
        result.append(
            {
                "date": day,
                "value": sum(int(scores[0]) for scores in dimensions.values()),
                "quality": "complete",
            }
        )
    return result

def _nutrition_points(
    connection: sqlite3.Connection,
    start: date | None,
    end: date | None,
) -> list[dict[str, Any]]:
    sql = """SELECT datum,histamine_score,item_count,histamine_unknown_count,histamine_label
             FROM nutrition_daily_summary_v2 WHERE item_count>0
               AND histamine_unknown_count=0 AND histamine_score IS NOT NULL
               AND histamine_label IN ('green','yellow','orange','red')"""
    parameters: list[Any] = []
    if start:
        sql += " AND datum>=?"
        parameters.append(start.isoformat())
    if end:
        sql += " AND datum<=?"
        parameters.append(end.isoformat())
    sql += " ORDER BY datum LIMIT ?"
    parameters.append(MAX_DAILY_SOURCE_ROWS + 1)
    rows = list(connection.execute(sql, parameters))
    if len(rows) > MAX_DAILY_SOURCE_ROWS:
        raise APIError(422, "source_row_limit_exceeded")
    result = []
    for row in rows:
        day = parse_day(row["datum"])
        try:
            value = float(row["histamine_score"])
        except (TypeError, ValueError):
            continue
        if day and math.isfinite(value):
            result.append({"date": day, "value": value, "quality": "complete"})
    return result

def _lab_key(parameter: Any, unit: Any) -> tuple[str, str]:
    def slug(value: Any) -> str:
        normalized = (
            str(value or "")
            .casefold()
            .replace("µ", "u")
            .replace("μ", "u")
            .replace("%", " percent ")
        )
        return re.sub(r"[^a-z0-9]+", "_", normalized).strip("_")

    return slug(parameter), slug(unit)

def _verified_lab_rows(
    connection: sqlite3.Connection,
    *,
    include_missing_reference: bool = False,
    start: date | None = None,
    end: date | None = None,
) -> list[dict[str, Any]]:
    if not table_exists(connection, "laborwerte"):
        return []
    date_expression = "COALESCE(NULLIF(l.abnahme_datum,''),l.befund_datum)"
    filters = [
        "lower(trim(COALESCE(l.validierungsstatus,'')))='validiert'",
        "l.verified_against_original=1",
        "l.reference_range_source='scanned_original'",
        "trim(COALESCE(l.einheit,''))<>''",
    ]
    values: list[Any] = []
    if start:
        filters.append(f"{date_expression}>=?")
        values.append(start.isoformat())
    if end:
        filters.append(f"{date_expression}<=?")
        values.append(end.isoformat())
    rows = list(
        connection.execute(
            """SELECT l.id,l.parameter_name,l.wert,l.einheit,l.reference_min,l.reference_max,
                  l.abnahme_datum,l.befund_datum,l.reference_range_source,l.source_type,
                  l.canonical_document_id,d.document_date,d.kategorie,d.institution,d.review_status
               FROM laborwerte l LEFT JOIN dokumente d ON d.id=l.canonical_document_id
               WHERE """
            + " AND ".join(filters)
            + f" ORDER BY {date_expression},l.id LIMIT ?",
            (*values, MAX_RAW_LAB_ROWS + 1),
        )
    )
    if len(rows) > MAX_RAW_LAB_ROWS:
        raise APIError(422, "source_row_limit_exceeded")
    grouped: dict[tuple[str, str, str], list[sqlite3.Row]] = defaultdict(list)
    for row in rows:
        canonical = LAB_ALLOWLIST.get(_lab_key(row["parameter_name"], row["einheit"]))
        day = parse_day(row["abnahme_datum"]) or parse_day(row["befund_datum"])
        if canonical and day and date.fromisoformat(day) <= local_today():
            grouped[(canonical[0], canonical[1], day)].append(row)
    result: list[dict[str, Any]] = []
    for (parameter, unit, day), same_day in sorted(grouped.items()):
        if len(same_day) != 1:
            continue
        row = same_day[0]
        raw_value = ("" if row["wert"] is None else str(row["wert"])).strip()
        if not EXACT_LAB_NUMBER.fullmatch(raw_value):
            continue
        numeric = float(raw_value.replace(",", "."))
        if not math.isfinite(numeric):
            continue
        value: int | float = int(numeric) if numeric.is_integer() else numeric
        reference_min = str(row["reference_min"] or "").strip()
        reference_max = str(row["reference_max"] or "").strip()
        reference_min = (
            reference_min
            if EXACT_LAB_NUMBER.fullmatch(reference_min)
            and math.isfinite(float(reference_min.replace(",", ".")))
            else None
        )
        reference_max = (
            reference_max
            if EXACT_LAB_NUMBER.fullmatch(reference_max)
            and math.isfinite(float(reference_max.replace(",", ".")))
            else None
        )
        item: dict[str, Any] = {
            "id": f"lab-observation-{int(row['id'])}",
            "metric_id": LAB_CATALOG_SPECS[parameter].metric_id,
            "parameter": parameter,
            "value": value,
            "unit": unit,
            "date": day,
            "quality": "verified_original",
        }
        if reference_min is None and reference_max is None:
            if not include_missing_reference:
                continue
            item["reference_status"] = "missing_reference"
        else:
            item["reference"] = {
                "min": reference_min,
                "max": reference_max,
                "source": "scanned_original",
            }
            item["reference_status"] = "verified_observation_specific"
        if (
            row["canonical_document_id"] is not None
            and row["review_status"] == "geprueft"
        ):
            category = safe_metadata_text(row["kategorie"], 80, allow_empty=True)
            institution = safe_metadata_text(row["institution"], 120, allow_empty=True)
            document_day = parse_day(row["document_date"])
            if category is not None and institution is not None:
                item["document"] = {
                    "id": api_document_id(
                        row["canonical_document_id"],
                        document_day,
                        category,
                        institution,
                    ),
                    "date": document_day,
                    "category": category,
                    "institution": institution,
                }
        result.append(item)
    return result

def _metric_points(
    connection: sqlite3.Connection,
    metric: MetricV2,
    start: date | None,
    end: date | None,
) -> list[dict[str, Any]]:
    if metric.value_type == "panel":
        raise APIError(400, "metric_not_series")
    if metric.source == "apple_health":
        if metric.source_identifier == "blood_pressure":
            return _blood_pressure_points(connection, metric, start, end)
        return _apple_points(connection, metric, start, end)
    if metric.id == "symptom.total":
        return _symptom_total_points(connection, start, end)
    if metric.id == "symptom.aphthae":
        return _symptom_dimension_points(connection, metric, start, end)
    if metric.id == "nutrition.histamine":
        return _nutrition_points(connection, start, end)
    if metric.source == "laborwerte":
        return [
            {
                key: row[key]
                for key in ("date", "value", "quality", "reference", "reference_status")
                if key in row
            }
            for row in _verified_lab_rows(connection, include_missing_reference=True)
            if row["metric_id"] == metric.id
            and (start is None or row["date"] >= start.isoformat())
            and (end is None or row["date"] <= end.isoformat())
        ]
    return []

def _weekly_rule(metric: MetricV2) -> dict[str, Any]:
    if metric.aggregation == "observation" or metric.value_type == "panel":
        return {
            "id": "unsupported_for_metric",
            "minimum_observations": None,
            "requires_complete_calendar_week": False,
        }
    if metric.expected_frequency == "daily":
        return {
            "id": "complete_calendar_week_daily_metric",
            "minimum_observations": 7,
            "requires_complete_calendar_week": True,
        }
    if metric.expected_frequency == "intermittent":
        return {
            "id": "observed_measurements_within_iso_week",
            "minimum_observations": 1,
            "requires_complete_calendar_week": False,
        }
    return {
        "id": "unsupported_for_metric",
        "minimum_observations": None,
        "requires_complete_calendar_week": False,
    }

def _add_past_only_baselines(points: list[dict[str, Any]], metric: MetricV2) -> None:
    rule = metric.baseline_rule
    if not rule:
        return
    window = int(rule["window_days"])
    minimum = int(rule["minimum_observations"])
    for point in points:
        day = date.fromisoformat(point["date"])
        prior = [
            float(candidate["value"])
            for candidate in points
            if date.fromisoformat(candidate["date"]) < day
            and (day - date.fromisoformat(candidate["date"])).days <= window
        ]
        point["baseline"] = (
            _numeric(float(median(prior)), metric.precision, metric.value_type)
            if len(prior) >= minimum
            else None
        )

def _weekly(
    points: list[dict[str, Any]], metric: MetricV2, rule: dict[str, Any]
) -> list[dict[str, Any]]:
    if rule["id"] == "unsupported_for_metric":
        return []
    grouped: dict[tuple[int, int], list[dict[str, Any]]] = defaultdict(list)
    for point in points:
        day = date.fromisoformat(point["date"])
        iso = day.isocalendar()
        grouped[(iso.year, iso.week)].append(point)
    result = []
    for (year, week), rows in sorted(grouped.items()):
        distinct = {row["date"] for row in rows}
        if rule["requires_complete_calendar_week"] and len(distinct) != 7:
            continue
        values = [float(row["value"]) for row in rows]
        if metric.aggregation == "sum":
            value = sum(values)
        elif metric.aggregation == "last":
            value = float(max(rows, key=lambda row: row["date"])["value"])
        else:
            value = sum(values) / len(values)
        week_start = date.fromisocalendar(year, week, 1)
        week_end = week_start + timedelta(days=6)
        item = {
            "week": f"{year}-W{week:02d}",
            "date": min(distinct),
            "week_start": week_start.isoformat(),
            "week_end": week_end.isoformat(),
            "drilldown_date": week_start.isoformat(),
            "value": _numeric(value, metric.precision, metric.value_type),
            "observation_count": len(rows),
            "observed_days": len(distinct),
            "quality": (
                "complete_calendar_week"
                if rule["requires_complete_calendar_week"]
                else "observed_measurements"
            ),
        }
        result.append(item)
    return result

def _coverage(
    points: list[dict[str, Any]], start: date | None, end: date | None
) -> dict[str, Any]:
    observed = sorted({date.fromisoformat(point["date"]) for point in points})
    effective_start = start or (observed[0] if observed else None)
    effective_end = end or (observed[-1] if observed else None)
    if effective_start is not None and effective_end is not None:
        span = (effective_end - effective_start).days + 1
        if span > MAX_RANGE_DAYS:
            raise APIError(422, "range_too_large")
    else:
        span = 0
    return {
        "from": effective_start.isoformat() if effective_start else None,
        "to": effective_end.isoformat() if effective_end else None,
        "expected_days": span,
        "observed_days": len(observed),
        "observation_count": len(points),
        "missing_days": max(0, span - len(observed)),
        "gaps": "omitted_not_interpolated",
    }

def _series(connection: sqlite3.Connection, params: dict[str, str]) -> dict[str, Any]:
    metric_id = params.get("metric", "")
    metric = BY_ID_V2.get(metric_id)
    if metric is None:
        raise APIError(404, "metric_not_allowed")
    resolution = params.get("resolution", "day")
    if resolution not in ALLOWED_RESOLUTIONS:
        raise APIError(400, "resolution_not_allowed")
    start, end = parse_range(params)
    points = _metric_points(connection, metric, start, end)
    today = local_today().isoformat()
    points = [point for point in points if point["date"] <= today]
    _add_past_only_baselines(points, metric)
    if start is None and points:
        observed_start = date.fromisoformat(points[0]["date"])
        observed_end = date.fromisoformat(points[-1]["date"])
        if (observed_end - observed_start).days + 1 > MAX_RANGE_DAYS:
            raise APIError(422, "range_too_large")
    coverage = _coverage(points, start, end)
    if end is None:
        coverage["to"] = today
        if coverage["from"] is not None:
            coverage["expected_days"] = (
                date.fromisoformat(today) - date.fromisoformat(coverage["from"])
            ).days + 1
            coverage["missing_days"] = max(
                0, coverage["expected_days"] - coverage["observed_days"]
            )
    aggregation_rule = {
        "id": "daily_metric_points",
        "minimum_observations": 1,
        "requires_complete_calendar_week": False,
    }
    if resolution == "week":
        aggregation_rule = _weekly_rule(metric)
        points = _weekly(points, metric, aggregation_rule)
    if len(points) > MAX_SERIES_ROWS:
        raise APIError(422, "row_limit_exceeded")
    return {
        "metric": metric.id,
        "label": metric.label,
        "unit": metric.unit,
        "aggregation": metric.aggregation,
        "aggregation_rule": aggregation_rule,
        "resolution": resolution,
        "source": {
            "type": metric.source,
            "identifier": metric.source_identifier,
            "parser": metric.parser_contract,
        },
        "coverage": coverage,
        "timezone": TZ_NAME,
        "today": today,


Output:
Chunk ID: a19308
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 3963
Output:
(() => {
  "use strict";

  const VIEW_IDS = ["today", "cockpit", "explorer", "nutrition", "doctor", "more"];
  if (document.querySelector("[data-dashboard-panel='calendar']")) VIEW_IDS.push("calendar");
  if (document.querySelector("[data-dashboard-panel='day']")) VIEW_IDS.push("day");
  const PERIODS = ["7", "30", "90", "180", "all"];
  const charts = new Map();
  let bundle = {};
  let activeView = "today";
  let activePeriod = "30";
  let explorerMode = "raw";
  let explorerCadence = "daily";

  const q = (selector, root = document) => root.querySelector(selector);
  const qa = (selector, root = document) => Array.from(root.querySelectorAll(selector));

  function readBundle() {
    const node = document.getElementById("health-dashboard-bundle");
    if (!node) return {};
    try {
      const value = JSON.parse(node.textContent || "{}");
      return value && typeof value === "object" && !Array.isArray(value) ? value : {};
    } catch (_error) {
      const status = q("[data-dashboard-status]");
      if (status) status.textContent = "Die Dashboard-Daten konnten nicht gelesen werden.";
      return {};
    }
  }

  function getDate(item) {
    if (!item || typeof item !== "object") return null;
    const raw = item.date || item.datetime || item.timestamp || item.measured_at || item.recorded_at;
    if (!raw) return null;
    const value = new Date(raw);
    return Number.isNaN(value.getTime()) ? null : value;
  }

  function periodData(value) {
    if (!Array.isArray(value)) return value;
    const range = window.healthRange?.get?.();
    if (range?.from && range?.to) {
      return value.filter((item) => {
        const date = getDate(item);
        if (!date) return true;
        const day = date.toISOString().slice(0, 10);
        return day >= range.from && day <= range.to;
      });
    }
    if (activePeriod === "all") return value;
    const cutoff = new Date(`${bundle.today || new Date().toISOString().slice(0, 10)}T00:00:00`);
    cutoff.setDate(cutoff.getDate() - Number(activePeriod) + 1);
    return value.filter((item) => {
      const date = getDate(item);
      return !date || date >= cutoff;
    });
  }

  function lookup(path) {
    if (!path) return null;
    const value = path.split(".").reduce((current, key) => {
      return current && Object.prototype.hasOwnProperty.call(current, key) ? current[key] : undefined;
    }, bundle);
    return periodData(value);
  }

  function formatValue(value, format) {
    if (value === null || value === undefined || value === "") return "–";
    if (format === "date") {
      const date = new Date(value);
      return Number.isNaN(date.getTime()) ? "–" : new Intl.DateTimeFormat("de-CH").format(date);
    }
    if (typeof value === "number") return new Intl.NumberFormat("de-CH", { maximumFractionDigits: 1 }).format(value);
    return String(value);
  }

  function updateBindings(panel) {
    qa("[data-bundle-value]", panel).forEach((node) => {
      const value = lookup(node.dataset.bundleValue);
      node.textContent = formatValue(value, node.dataset.format);
    });
    qa("[data-bundle-count]", panel).forEach((node) => {
      const value = lookup(node.dataset.bundleCount);
      node.textContent = Array.isArray(value) ? String(value.length) : "0";
    });
    qa("[data-empty-for]", panel).forEach((node) => {
      const value = lookup(node.dataset.emptyFor);
      node.hidden = Array.isArray(value) ? value.length > 0 : Boolean(value);
    });
  }

  function chartConfig(canvas) {
    const rows = lookup(canvas.dataset.chartSource);
    if (!Array.isArray(rows) || !rows.length) return null;
    const xKey = canvas.dataset.chartX || "date";
    const yKeys = (canvas.dataset.chartY || "value").split(",").map((key) => key.trim()).filter(Boolean);
    const labels = rows.map((row) => formatValue(row[xKey], xKey.includes("date") ? "date" : ""));
    const palette = ["#315b70", "#826a3d", "#66567a", "#536b58"];
    return {
      type: canvas.dataset.chartType || "line",
      data: {
        labels,
        datasets: yKeys.map((key, index) => ({
          label: canvas.dataset[`label${index + 1}`] || key,
          data: rows.map((row) => Number.isFinite(Number(row[key])) ? Number(row[key]) : null),
          borderColor: palette[index % palette.length],
          backgroundColor: `${palette[index % palette.length]}26`,
          pointRadius: rows.length > 45 ? 0 : 2,
          borderWidth: 2,
          tension: 0.2,
          spanGaps: false
        }))
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        animation: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? false : undefined,
        interaction: { intersect: false, mode: "index" },
        plugins: { legend: { position: "bottom", labels: { usePointStyle: true } } },
        scales: {
          x: { grid: { display: false }, ticks: { maxTicksLimit: 7 } },
          y: { beginAtZero: canvas.dataset.beginZero === "true", ticks: { maxTicksLimit: 6 } }
        }
      }
    };
  }

  function initializeCharts(panel) {
    if (!window.Chart) return;
    qa("canvas[data-chart-source]", panel).forEach((canvas) => {
      const previous = charts.get(canvas);
      const config = chartConfig(canvas);
      if (!config) {
        if (previous) previous.destroy();
        charts.delete(canvas);
        const empty = canvas.closest("[data-chart-frame]")?.querySelector("[data-chart-empty]");
        if (empty) empty.hidden = false;
        canvas.hidden = true;
        return;
      }
      canvas.hidden = false;
      const empty = canvas.closest("[data-chart-frame]")?.querySelector("[data-chart-empty]");
      if (empty) empty.hidden = true;
      if (previous) {
        previous.data = config.data;
        previous.options = config.options;
        previous.update();
        previous.resize();
      } else {
        charts.set(canvas, new window.Chart(canvas.getContext("2d"), config));
      }
    });
  }

  function metricSeries(metricId) {
    return periodData(bundle.series && Array.isArray(bundle.series[metricId]) ? bundle.series[metricId] : []);
  }

  function isoWeekMonday(day) {
    const value = new Date(`${day}T00:00:00Z`);
    if (Number.isNaN(value.getTime())) return null;
    const offset = (value.getUTCDay() + 6) % 7;
    value.setUTCDate(value.getUTCDate() - offset);
    return value.toISOString().slice(0, 10);
  }

  function completeWeeklySeries(rows, valueFor, aggregation = "avg") {
    const buckets = new Map();
    rows.forEach((row) => {
      const monday = isoWeekMonday(row.date);
      if (!monday) return;
      if (!buckets.has(monday)) buckets.set(monday, new Map());
      buckets.get(monday).set(row.date, valueFor(row));
    });
    return [...buckets].sort(([left], [right]) => left.localeCompare(right)).map(([date, byDay]) => {
      const values = [...byDay.values()];
      const numericDays = values.filter((value) => typeof value === "number" && Number.isFinite(value)).length;
      const complete = byDay.size === 7 && numericDays === 7;
      const value = !complete ? null : aggregation === "sum"
        ? values.reduce((total, item) => total + item, 0)
        : values.reduce((total, item) => total + item, 0) / values.length;
      return { date, value: value === null ? null : Number(value.toFixed(3)), complete_days: numericDays };
    });
  }

  function explorerSeries(metricId, metric, mode = explorerMode) {
    const rows = metricSeries(metricId);
    if (explorerCadence === "daily") {
      return rows.map((point) => ({ date: point.date, value: explorerPointValue(point, metric, mode) }));
    }
    const aggregation = mode === "baseline" ? "avg" : metric?.aggregation || "avg";
    return completeWeeklySeries(rows, (point) => explorerPointValue(point, metric, mode), aggregation);
  }

  function weeklyAxisDays(observedDays) {
    if (!observedDays.length) return [];
    const days = [];
    const cursor = new Date(`${observedDays[0]}T00:00:00Z`);
    const end = new Date(`${observedDays[observedDays.length - 1]}T00:00:00Z`);
    while (cursor <= end) {
      days.push(cursor.toISOString().slice(0, 10));
      cursor.setUTCDate(cursor.getUTCDate() + 7);
    }
    return days;
  }

  function node(tag, className, text) {
    const element = document.createElement(tag);
    if (className) element.className = className;
    if (text !== undefined) element.textContent = text;
    return element;
  }

  function latestPoint(metricId) {
    const rows = metricSeries(metricId).filter((row) => row.value !== null && row.value !== undefined);
    return rows.length ? rows[rows.length - 1] : null;
  }

  function daysBetween(start, end) {
    const left = new Date(`${start}T00:00:00Z`);
    const right = new Date(`${end}T00:00:00Z`);
    if (Number.isNaN(left.getTime()) || Number.isNaN(right.getTime())) return null;
    return Math.round((right.getTime() - left.getTime()) / 86400000);
  }

  function measurementAge(day) {
    const age = daysBetween(day, bundle.today);
    if (age === null || age < 0) return "Messalter unbekannt";
    if (age === 0) return "heute dokumentiert";
    if (age === 1) return "vor 1 Tag dokumentiert";
    return `vor ${age} Tagen dokumentiert`;
  }

  function documentationCoverage(metricId) {
    const rows = metricSeries(metricId).filter((row) => row.value !== null && row.value !== undefined);
    let expected = activePeriod === "all" ? 0 : Number(activePeriod);
    if (activePeriod === "all" && rows.length) expected = Math.max(1, (daysBetween(rows[0].date, bundle.today) || 0) + 1);
    return { observed: new Set(rows.map((row) => row.date)).size, expected };
  }

  function sparkline(metricId, label) {
    const rows = metricSeries(metricId).filter((row) => row.value !== null && row.value !== undefined).slice(-45);
    if (!rows.length) return node("div", "v5-empty", "Keine Trendpunkte im Zeitraum");
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("class", "metric-sparkline");
    svg.setAttribute("viewBox", "0 0 100 32");
    svg.setAttribute("role", "img");
    svg.setAttribute("aria-label", `${label}: ${rows.length} dokumentierte Trendpunkte; Lücken werden nicht verbunden.`);
    const values = rows.map((row) => Number(row.value));
    const minimum = Math.min(...values);
    const maximum = Math.max(...values);
    const range = maximum - minimum || 1;
    const segments = [];
    let current = [];
    rows.forEach((row, index) => {
      if (index && daysBetween(rows[index - 1].date, row.date) !== 1) {
        if (current.length) segments.push(current);
        current = [];
      }
      const x = rows.length === 1 ? 50 : (index / (rows.length - 1)) * 96 + 2;
      const y = 29 - ((Number(row.value) - minimum) / range) * 26;
      current.push(`${x.toFixed(2)},${y.toFixed(2)}`);
    });
    if (current.length) segments.push(current);
    segments.forEach((points) => {
      const line = document.createElementNS("http://www.w3.org/2000/svg", "polyline");
      line.setAttribute("class", "sparkline-segment");
      line.setAttribute("points", points.join(" "));
      svg.append(line);
    });
    const dot = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    const finalPoint = segments[segments.length - 1].at(-1).split(",");
    dot.setAttribute("class", "sparkline-dot");
    dot.setAttribute("cx", finalPoint[0]);
    dot.setAttribute("cy", finalPoint[1]);
    dot.setAttribute("r", "2.2");
    svg.append(dot);
    return svg;
  }

  function renderMetricCards() {
    const target = q("#metric-cards");
    if (!target || target.dataset.renderedPeriod === activePeriod) return;
    target.replaceChildren();
    (bundle.metrics || []).forEach((metric) => {
      const point = latestPoint(metric.id);
      const coverage = documentationCoverage(metric.id);
      const card = node("article", "v5-card metric-card");
      const displayedValue = point
        ? metric.id === "symptom.total" ? `${formatValue(point.value)} / 21` : `${formatValue(point.value)} ${metric.unit}`
        : "unbekannt";
      const deltaUnit = metric.id === "symptom.total" ? "Punkte" : metric.unit;
      card.dataset.private = "true";
      card.append(node("h3", "v5-label", metric.label));
      card.append(node("div", "v5-kpi", displayedValue));
      card.append(node("div", "v5-meta", point ? `${formatValue(point.date, "date")} · ${measurementAge(point.date)}` : "Keine dokumentierte Beobachtung im Zeitraum"));
      const comparison = point && point.baseline !== null && point.baseline !== undefined
        ? `Abweichung zur persönlichen ${metric.baseline_days}-Tage-Basis: ${formatValue(point.value - point.baseline)} ${deltaUnit}`
        : "Persönliche Vergleichsbasis noch nicht ausreichend";
      card.append(node("div", "v5-meta", comparison));
      card.append(sparkline(metric.id, metric.label));
      const footer = node("div", "metric-card-footer");
      footer.append(node("span", "v5-badge", point?.quality === "complete" ? "vollständig" : point ? "dokumentiert" : "unbekannt"));
      footer.append(node("span", "v5-meta", coverage.expected ? `${coverage.observed}/${coverage.expected} Tage im Zeitraum` : `${coverage.observed} dokumentierte Tage`));
      card.append(footer);
      target.append(card);
    });
    target.dataset.renderedPeriod = activePeriod;
  }

  function renderDataRecency() {
    const target = q("#header-data-status");
    if (!target) return;
    const days = Object.values(bundle.series || {}).flat()
      .filter((point) => point.value !== null && point.value !== undefined)
      .map((point) => point.date)
      .concat((bundle.labs || []).map((item) => item.date))
      .concat(bundle.medication?.last_administered?.date || [])
      .filter((day) => typeof day === "string" && day <= bundle.today)
      .sort();
    if (!days.length) {
      target.textContent = "Keine aktuellen Daten dokumentiert";
      return;
    }
    const latest = days[days.length - 1];
    target.textContent = `Neuester Datenpunkt: ${measurementAge(latest)}`;
    target.dataset.private = "true";
  }

  function renderToday() {
    const snapshot = q("#today-snapshot");
    if (snapshot) {
      const symptom = latestPoint("symptom.total");
      snapshot.replaceChildren();
      snapshot.append(node("p", "v5-kpi", symptom ? `${formatValue(symptom.value)} / 21` : "Beschwerden unbekannt"));
      snapshot.append(node("p", "v5-meta", symptom ? `Letzter vollständiger Symptomtag: ${formatValue(symptom.date, "date")} · ${measurementAge(symptom.date)}` : "Kein vollständiger Symptomtag im Zeitraum"));
      const metrics = new Map((bundle.metrics || []).map((metric) => [metric.id, metric]));
      const quick = node("div", "today-vitals");
      ["apple.sleep", "apple.hrv", "apple.resting_heart_rate"].forEach((metricId) => {
        const point = latestPoint(metricId);
        const metric = metrics.get(metricId);
        if (!point || !metric) return;
        const item = node("div", "today-vital");
        item.append(node("span", "v5-label", metric.label));
        item.append(node("strong", "", `${formatValue(point.value)} ${metric.unit}`));
        item.append(node("span", "v5-meta", measurementAge(point.date)));
        quick.append(item);
      });
      if (quick.childElementCount) snapshot.append(quick);
      snapshot.dataset.private = "true";
    }
    const tasks = q("#today-tasks");
    if (tasks) {
      tasks.replaceChildren();
      const rows = (bundle.tasks || []).slice(0, 3);
      if (!rows.length) tasks.append(node("p", "v5-empty", "Keine offenen Dashboard-Aufgaben"));
      rows.forEach((item) => tasks.append(node("div", "v5-card v5-card--quiet", `${item.label}${item.count ? ` (${item.count})` : ""}`)));
    }
    renderMedication(q("#today-medication"));
  }


Output:
Chunk ID: 315719
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 4321
Output:
(() => {
  'use strict';

  const shell = document.querySelector('[data-api-explorer]');
  if (!shell || shell.dataset.apiExplorerEnabled !== '1') return;

  const q = selector => shell.querySelector(selector);
  const qa = selector => [...shell.querySelectorAll(selector)];
  const statusNode = q('[data-api-explorer-status]');
  const selectedNode = q('[data-api-explorer-selected]');
  const resultsNode = q('[data-api-explorer-results]');
  const eventsNode = q('[data-api-explorer-events]');
  const tableNode = q('[data-api-explorer-table]');
  const chartNode = q('[data-api-explorer-chart]');
  const searchField = q('[data-api-explorer-search]');
  const selected = [];
  let mode = 'raw';
  let resolution = 'day';
  let chart = null;
  let refreshVersion = 0;
  let catalogVersion = 0;
  let latestCatalog = [];
  let lastPayloads = [];

  const GROUP_LABELS = {
    cardiovascular: 'Herz/Kreislauf', vital_signs: 'Herz/Kreislauf', respiratory: 'Herz/Kreislauf',
    sleep: 'Schlaf/Erholung', activity: 'Aktivität', body_measurement: 'Körpermesswerte',
    laboratory: 'Labor', symptoms: 'Symptome', nutrition: 'Ernährung',
  };

  function setStatus(message, code = '') {
    statusNode.textContent = message;
    if (code) statusNode.dataset.errorCode = code; else delete statusNode.dataset.errorCode;
  }

  async function request(path) {
    await window.healthApiSessionReady;
    const response = await fetch(path, { credentials: 'same-origin' });
    let data = null;
    try { data = await response.json(); } catch (_error) { data = null; }
    if (!response.ok) {
      const error = new Error(data?.error || `api_${response.status}`);
      error.code = data?.error || `api_${response.status}`;
      throw error;
    }
    return data;
  }

  async function requestSession() {
    const meta = document.querySelector("meta[name='health-browser-session-csrf']");
    if (!meta?.content) throw new Error('missing_csrf');
    const response = await fetch('/api/v1/browser-session', {
      method: 'POST', credentials: 'same-origin', headers: { 'X-Health-Browser-CSRF': meta.content },
    });
    if (!response.ok) throw new Error(`session_${response.status}`);
  }

  const metricKey = metric => String(metric.id || '');
  const visible = () => selected.filter(metric => metric.visible !== false);
  const distinctUnits = metrics => new Set(metrics.map(metric => metric.unit || 'Ohne Einheit'));
  const safeModeLimit = () => mode === 'baseline' ? 6 : 4;

  function updateModeButtons() {
    qa('[data-api-explorer-mode]').forEach(button => button.setAttribute('aria-pressed', String(button.dataset.apiExplorerMode === mode)));
    qa('[data-api-explorer-resolution]').forEach(button => button.setAttribute('aria-pressed', String(button.dataset.apiExplorerResolution === resolution)));
  }

  function renderSelected() {
    selectedNode.replaceChildren();
    const heading = document.createElement('p');
    heading.className = 'api-explorer-selected-heading';
    heading.textContent = selected.length ? `Ausgewählte Werte (${selected.length}/${safeModeLimit()}):` : 'Noch kein Gesundheitswert ausgewählt.';
    selectedNode.append(heading);
    const list = document.createElement('div');
    list.className = 'metric-chip-list';
    selected.forEach(metric => {
      const chip = document.createElement('div');
      chip.className = 'metric-chip';
      chip.dataset.metricId = metric.id;
      const toggle = document.createElement('button');
      toggle.type = 'button';
      toggle.textContent = metric.label;
      toggle.setAttribute('aria-pressed', String(metric.visible !== false));
      toggle.setAttribute('aria-label', `${metric.label} ${metric.visible === false ? 'einblenden' : 'ausblenden'}`);
      toggle.addEventListener('click', () => { metric.visible = metric.visible === false; renderSelected(); refresh(); });
      const solo = document.createElement('button');
      solo.type = 'button'; solo.textContent = 'solo'; solo.setAttribute('aria-label', `${metric.label} solo anzeigen`);
      solo.addEventListener('click', () => { selected.forEach(item => { item.visible = item === metric; }); renderSelected(); refresh(); });
      const remove = document.createElement('button');
      remove.type = 'button'; remove.textContent = '×'; remove.setAttribute('aria-label', `${metric.label} entfernen`);
      remove.addEventListener('click', () => { selected.splice(selected.indexOf(metric), 1); renderSelected(); refresh(); });
      chip.append(toggle, solo, remove); list.append(chip);
    });
    selectedNode.append(list);
  }

  function addMetrics(metrics) {
    const additions = metrics.filter(metric => metric?.id && metric.value_type !== 'panel' && !selected.some(item => item.id === metric.id));
    if (!additions.length) return;
    const candidate = [...selected, ...additions];
    if (candidate.length > safeModeLimit()) {
      setStatus(`${mode === 'baseline' ? 'Baseline' : 'Rohwerte'} erlaubt höchstens ${safeModeLimit()} Metriken.`, 'metric_limit');
      return;
    }
    if (mode === 'raw' && distinctUnits(candidate).size > 2) {
      setStatus('Eine dritte Einheit ist im Rohwertmodus nicht zulässig. Bitte persönliche Baseline verwenden.', 'third_unit_rejected');
      q('[data-api-explorer-mode="baseline"]')?.focus();
      return;
    }
    additions.forEach(metric => selected.push({ ...metric, visible: true }));
    renderSelected();
    setStatus(additions.length === 2 ? 'Blutdruck mit zwei getrennt steuerbaren Reihen hinzugefügt.' : 'Gesundheitswert hinzugefügt.');
    refresh();
  }

  function addResult(metric, metrics) {
    if (metric.value_type === 'panel') {
      const members = metrics.filter(candidate => candidate.panel_id === metric.id);
      if (members.length !== 2) return setStatus('Blutdruckpanel ist unvollständig.', 'panel_incomplete');
      addMetrics(members);
    } else {
      addMetrics([metric]);
    }
  }

  function renderResults(metrics) {
    resultsNode.replaceChildren();
    if (!metrics.length) {
      const empty = document.createElement('p'); empty.className = 'v5-empty'; empty.textContent = 'Keine passenden freigegebenen Gesundheitswerte.'; resultsNode.append(empty); return;
    }
    const grouped = new Map();
    metrics.forEach(metric => {
      if (metric.panel_id && metrics.some(parent => parent.id === metric.panel_id)) return;
      const label = GROUP_LABELS[metric.category] || 'Weitere Werte';
      if (!grouped.has(label)) grouped.set(label, []);
      grouped.get(label).push(metric);
    });
    grouped.forEach((items, label) => {
      const section = document.createElement('section'); section.className = 'metric-search-group'; section.append(Object.assign(document.createElement('h4'), { textContent: label }));
      const choices = document.createElement('div'); choices.className = 'metric-search-results';
      items.forEach(metric => {
        const button = document.createElement('button'); button.type = 'button'; button.textContent = metric.label;
        button.dataset.apiExplorerResult = metric.id;
        button.disabled = selected.some(item => item.id === metric.id) || (metric.value_type === 'panel' && selected.some(item => item.panel_id === metric.id));
        button.setAttribute('aria-label', `${metric.label} hinzufügen`);
        button.addEventListener('click', () => addResult(metric, metrics)); choices.append(button);
      });
      section.append(choices); resultsNode.append(section);
    });
  }

  async function searchCatalog(query = searchField.value.trim()) {
    if (query.length < 2) return setStatus('Mindestens zwei Zeichen eingeben.', 'query_too_short');
    const version = ++catalogVersion;
    setStatus('Gesundheitswerte werden gesucht …');
    try {
      const data = await request(`/api/v1/metric-catalog?q=${encodeURIComponent(query)}`);
      if (version !== catalogVersion) return;
      latestCatalog = Array.isArray(data?.groups?.metrics) ? data.groups.metrics : [];
      renderResults(latestCatalog);
      setStatus(latestCatalog.length ? 'Gesundheitswert auswählen.' : 'Keine passenden Werte gefunden.');
    } catch (error) {
      if (version === catalogVersion) setStatus(`Suche fehlgeschlagen (${error.code || 'catalog_error'}).`, error.code || 'catalog_error');
    }
  }

  function baselineValue(point) {
    const value = Number(point?.value); const baseline = Number(point?.baseline);
    return Number.isFinite(value) && Number.isFinite(baseline) && baseline > 0 ? Number((100 * value / baseline).toFixed(2)) : null;
  }

  function buildSeries(payloads) {
    const shown = visible();
    const units = [...distinctUnits(shown)];
    return payloads.filter(payload => shown.some(metric => metric.id === payload.metric)).map(payload => {
      const metric = shown.find(item => item.id === payload.metric);
      const unit = mode === 'baseline' ? 'Index 100' : (payload.unit || metric?.unit || '');
      return {
        id: payload.metric,
        name: payload.label || metric?.label || payload.metric,
        type: 'line', connectNulls: false, symbolSize: 6,
        yAxisIndex: mode === 'baseline' ? 0 : Math.max(0, units.indexOf(metric?.unit || payload.unit || 'Ohne Einheit')),
        data: (payload.points || []).map(point => [point.date, mode === 'baseline' ? baselineValue(point) : point.value]),
        emphasis: { focus: 'series' },
        unit,
      };
    });
  }

  function renderTable(payloads) {
    tableNode.replaceChildren();
    const shown = visible();
    const days = [...new Set(payloads.flatMap(payload => (payload.points || []).map(point => point.date)))].sort();
    const head = document.createElement('thead'); const header = document.createElement('tr');
    ['Datum', ...shown.map(metric => metric.label)].forEach(label => { const th = document.createElement('th'); th.textContent = label; header.append(th); });
    head.append(header); const body = document.createElement('tbody');
    days.forEach(day => {
      const row = document.createElement('tr'); const th = document.createElement('th'); const dayButton = document.createElement('button');
      dayButton.type = 'button'; dayButton.textContent = day; dayButton.dataset.apiExplorerDay = day; dayButton.addEventListener('click', () => window.healthDayRouter?.open?.({ date: day, source: 'explorer_table' })); th.append(dayButton); row.append(th);
      shown.forEach(metric => { const payload = payloads.find(item => item.metric === metric.id); const point = payload?.points?.find(item => item.date === day); const td = document.createElement('td'); const value = mode === 'baseline' ? baselineValue(point) : point?.value; td.textContent = value === null || value === undefined ? '–' : String(value); row.append(td); });
      body.append(row);
    });
    tableNode.append(head, body);
  }

  function renderEvents(events) {
    eventsNode.replaceChildren();
    if (!events.length) return;
    const list = document.createElement('ul');
    events.forEach(item => { const row = document.createElement('li'); const button = document.createElement('button'); button.type = 'button'; button.dataset.apiExplorerEvent = 'true'; button.textContent = `${item.date}: ${item.label || 'Dokumentiertes Ereignis'}`; button.addEventListener('click', () => window.healthDayRouter?.open?.({ date: item.date, source: 'explorer_event' })); row.append(button); list.append(row); });
    eventsNode.append(list);
  }

  function renderChart(payloads, events) {
    if (!window.echarts) return setStatus('ECharts nicht verfügbar; Tabellenansicht bleibt nutzbar.', 'echarts_unavailable');
    const series = buildSeries(payloads);
    const range = window.healthRange.get();
    if (chart) chart.dispose();
    chart = window.echarts.init(chartNode, null, { renderer: 'canvas' });
    const units = mode === 'baseline' ? ['Index 100'] : [...new Set(series.map(item => item.unit))];
    chart.setOption({
      animation: false,
      aria: { enabled: true, description: 'Dokumentierte Gesundheitsverläufe im gewählten Zeitraum; fehlende Werte bleiben Lücken.' },
      tooltip: { trigger: 'axis', confine: true },
      legend: { type: 'scroll', selectedMode: true },
      grid: { left: 58, right: units.length > 1 ? 58 : 24, top: 52, bottom: 62, containLabel: true },
      dataZoom: [{ type: 'slider', start: 0, end: 100, bottom: 18 }],
      xAxis: { type: 'time', min: `${range.from}T00:00:00`, max: `${range.to}T23:59:59`, name: 'Datum' },
      yAxis: units.map((unit, index) => ({ type: 'value', name: unit, scale: true, position: index ? 'right' : 'left' })),
      series,
    }, { replaceMerge: ['series', 'yAxis'] });
    chart.on('legendselectchanged', event => {
      selected.forEach(metric => { if (Object.hasOwn(event.selected, metric.label)) metric.visible = event.selected[metric.label]; });
      renderSelected();
    });
    chart.on('click', event => { const day = Array.isArray(event?.value) ? String(event.value[0]).slice(0, 10) : ''; if (day) window.healthDayRouter?.open?.({ date: day, source: 'explorer_chart' }); });
    window.__apiExplorerChart = chart;
    window.__apiExplorerChartContract = { series, range: { ...range }, units };
    window.__apiExplorerRange = { ...range };
    window.__apiExplorerSeriesCount = series.length;
  }

  async function refresh() {
    const version = ++refreshVersion;
    const shown = visible();
    if (!shown.length) {
      tableNode.replaceChildren(); eventsNode.replaceChildren(); chart?.dispose(); chart = null; setStatus('Mindestens einen Gesundheitswert einblenden.'); return;
    }
    const range = window.healthRange.get();
    setStatus('Explorer-Daten werden geladen …');
    try {
      const suffix = `&from=${encodeURIComponent(range.from)}&to=${encodeURIComponent(range.to)}`;
      const payloads = await Promise.all(shown.map(metric => request(`/api/v1/series?metric=${encodeURIComponent(metric.id)}&resolution=${resolution}${suffix}`)));
      const eventsData = await request(`/api/v1/events?from=${encodeURIComponent(range.from)}&to=${encodeURIComponent(range.to)}&types=medication_administered,health_event,health_period`);
      if (version !== refreshVersion) return;
      lastPayloads = payloads;
      const events = Array.isArray(eventsData?.events) ? eventsData.events : [];
      renderChart(payloads, events); renderTable(payloads); renderEvents(events);
      const expected = payloads.reduce((sum, item) => sum + Number(item.coverage?.expected_days || 0), 0);
      const missing = payloads.reduce((sum, item) => sum + Number(item.coverage?.missing_days || 0), 0);
      setStatus(`${payloads.length} Reihe(n) · ${mode === 'baseline' ? 'Index 100 zur früheren persönlichen Baseline' : `${distinctUnits(shown).size} Einheit(en)`} · Lücken ${missing}/${expected}.`);
    } catch (error) {
      if (version === refreshVersion) setStatus(`Explorer-Daten fehlgeschlagen (${error.code || 'explorer_error'}). Erneut versuchen.`, error.code || 'explorer_error');
    }
  }

  function selectMode(nextMode) {
    if (!['raw', 'baseline'].includes(nextMode)) return;
    mode = nextMode;
    if (mode === 'raw') {
      while (selected.length > 4) selected.pop();
      while (distinctUnits(selected).size > 2) selected.pop();
    }
    updateModeButtons(); renderSelected(); refresh();
  }

  function clearSelection() { selected.splice(0); renderSelected(); refresh(); }

  q('[data-api-explorer-search-button]').addEventListener('click', () => searchCatalog());
  searchField.addEventListener('keydown', event => { if (event.key === 'Enter') { event.preventDefault(); searchCatalog(); } });
  qa('[data-api-explorer-mode]').forEach(button => button.addEventListener('click', () => selectMode(button.dataset.apiExplorerMode)));
  qa('[data-api-explorer-resolution]').forEach(button => button.addEventListener('click', () => { resolution = button.dataset.apiExplorerResolution; updateModeButtons(); refresh(); }));
  q('[data-api-explorer-clear]').addEventListener('click', clearSelection);
  qa('[data-api-explorer-shortcut]').forEach(button => button.addEventListener('click', () => { searchField.value = button.dataset.apiExplorerShortcut; searchCatalog(button.dataset.apiExplorerShortcut); }));
  q('[data-api-explorer-retry]').addEventListener('click', refresh);
  window.addEventListener('health-range-change', refresh);
  window.addEventListener('resize', () => chart?.resize());

  window.healthExplorerAddMetric = async metricId => {
    if (!metricId) return false;
    const query = metricId.startsWith('lab.') ? metricId.slice(4).replaceAll('_', ' ') : metricId.split('.').at(-1).replaceAll('_', ' ');
    const data = await request(`/api/v1/metric-catalog?q=${encodeURIComponent(query)}`);
    const metrics = data?.groups?.metrics || [];
    const metric = metrics.find(item => item.id === metricId);
    if (!metric) return false;
    addResult(metric, metrics); return true;
  };

  window.healthApiSessionReady = requestSession();
  window.healthApiSessionReady.then(() => {
    shell.hidden = false; updateModeButtons(); renderSelected(); setStatus('Explorer bereit. Gesundheitswert hinzufügen.');
  }).catch(error => setStatus(`Sitzung fehlgeschlagen (${error.message || 'session_error'}).`, error.message || 'session_error'));
})();


Output:
Chunk ID: 993bf8
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1668
Output:
#!/usr/bin/env python3
"""Consume locally queued Dashboard actions outside the network-facing service."""

from __future__ import annotations

import json
import os
import re
import stat
import subprocess
import sys
from datetime import date, datetime
from pathlib import Path
from typing import Any
from zoneinfo import ZoneInfo

BASE = Path.home() / ".hermes" / "assets" / "Gesundheit"
DEFAULT_DASHBOARD_DB = (BASE / "health_data.db").resolve()
DASHBOARD_DB = (
    Path(os.environ["HEALTH_DASHBOARD_DB"]).resolve()
    if os.environ.get("HEALTH_DASHBOARD_DB")
    else None
)
ACTION_INBOX = Path(
    os.environ.get(
        "HEALTH_DASHBOARD_ACTION_INBOX",
        str(BASE / "runtime" / "dashboard-actions"),
    )
).resolve()
DASHBOARD_FILE = Path(
    os.environ.get(
        "HEALTH_DASHBOARD_FILE",
        str(BASE / "reports" / "health_dashboard_v4.html"),
    )
).resolve()
DASHBOARD_V5_FILE = (
    Path(os.environ["HEALTH_DASHBOARD_V5_FILE"]).resolve()
    if os.environ.get("HEALTH_DASHBOARD_V5_FILE")
    else None
)
SCRIPT_DIR = Path(__file__).resolve().parent
QUICK_ADD = SCRIPT_DIR / "health_symptom_quick_add.py"
DASHBOARD_V4 = SCRIPT_DIR / "health_dashboard_v4.py"
DASHBOARD_V5 = SCRIPT_DIR / "health_dashboard_v5.py"
FIELDS = ("aphthen", "gi", "fatigue", "skin", "eyes", "joints", "vascular")
NAME_RE = re.compile(r"[0-9a-f]{32}\.json")
LOCAL_TIMEZONE = ZoneInfo("Europe/Zurich")
V5_PROFILE_DEFAULT = "default"
V5_PROFILE_HEALTH_RECORD_6E = "health-record-6e"
ALLOWED_V5_PROFILES = frozenset({V5_PROFILE_DEFAULT, V5_PROFILE_HEALTH_RECORD_6E})

def parse_v5_profile(raw: str | None) -> str:
    """Return the one allowed regeneration profile or fail before any mutation."""
    value = V5_PROFILE_DEFAULT if raw is None or raw == "" else raw
    if value not in ALLOWED_V5_PROFILES:
        raise RuntimeError("invalid HEALTH_DASHBOARD_V5_PROFILE")
    return value

DASHBOARD_V5_PROFILE = parse_v5_profile(os.environ.get("HEALTH_DASHBOARD_V5_PROFILE"))

def local_today() -> date:
    return datetime.now(LOCAL_TIMEZONE).date()

def validate_payload(payload: Any) -> tuple[str, dict[str, int], str]:
    if not isinstance(payload, dict) or set(payload) != {
        "version",
        "action",
        "date",
        "scores",
        "notes",
    }:
        raise ValueError("invalid payload shape")
    if payload["version"] != 1 or payload["action"] != "symptom_checkin":
        raise ValueError("unsupported action")
    try:
        day = date.fromisoformat(payload["date"])
    except (TypeError, ValueError) as exc:
        raise ValueError("invalid date") from exc
    if day.year < 2000 or day > local_today():
        raise ValueError("date outside allowed range")
    scores = payload["scores"]
    if not isinstance(scores, dict) or set(scores) != set(FIELDS):
        raise ValueError("incomplete scores")
    if any(
        type(scores[field]) is not int or scores[field] not in range(4)
        for field in FIELDS
    ):
        raise ValueError("invalid score")
    notes = payload["notes"]
    if not isinstance(notes, str) or len(notes) > 300:
        raise ValueError("invalid notes")
    return day.isoformat(), {field: scores[field] for field in FIELDS}, notes.strip()

def reject_duplicate_object_pairs(pairs: list[tuple[str, object]]) -> dict[str, object]:
    result: dict[str, object] = {}
    for key, value in pairs:
        if key in result:
            raise ValueError("duplicate JSON key")
        result[key] = value
    return result

def ensure_private_inbox() -> None:
    ACTION_INBOX.mkdir(mode=0o700, parents=True, exist_ok=True)
    metadata = ACTION_INBOX.lstat()
    if not stat.S_ISDIR(metadata.st_mode) or metadata.st_uid != os.getuid():
        raise OSError("action inbox is not a private owned directory")
    os.chmod(ACTION_INBOX, 0o700)

def load_action(path: Path) -> tuple[str, dict[str, int], str]:
    if not NAME_RE.fullmatch(path.name):
        raise ValueError("invalid filename")
    descriptor = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
    try:
        metadata = os.fstat(descriptor)
        if (
            not stat.S_ISREG(metadata.st_mode)
            or metadata.st_uid != os.getuid()
            or stat.S_IMODE(metadata.st_mode) != 0o600
        ):
            raise ValueError("invalid action file permissions")
        if metadata.st_size > 4096:
            raise ValueError("invalid action file")
        raw = os.read(descriptor, 4097)
    finally:
        os.close(descriptor)
    if len(raw) > 4096:
        raise ValueError("action too large")
    return validate_payload(
        json.loads(raw.decode("utf-8"), object_pairs_hook=reject_duplicate_object_pairs)
    )

def apply_action(day: str, scores: dict[str, int], notes: str) -> None:
    if DASHBOARD_DB is None:
        raise RuntimeError("HEALTH_DASHBOARD_DB is required")
    command = [
        sys.executable,
        str(QUICK_ADD),
        "--db",
        str(DASHBOARD_DB),
        "--date",
        day,
        "--notes",
        notes,
    ]
    for field in FIELDS:
        command.extend((f"--{field}", str(scores[field])))
    subprocess.run(command, check=True, timeout=120, capture_output=True, text=True)
    if DASHBOARD_DB == DEFAULT_DASHBOARD_DB:
        subprocess.run(
            [sys.executable, str(DASHBOARD_V4), "--output", str(DASHBOARD_FILE)],
            check=True,
            timeout=120,
            capture_output=True,
            text=True,
        )
    if DASHBOARD_V5_FILE is not None:
        v5_command = [
            sys.executable,
            str(DASHBOARD_V5),
            "--db",
            str(DASHBOARD_DB),
            "--output",
            str(DASHBOARD_V5_FILE),
            "--today",
            local_today().isoformat(),
        ]
        if DASHBOARD_V5_PROFILE == V5_PROFILE_HEALTH_RECORD_6E:
            v5_command.append("--health-record-6e")
        subprocess.run(
            v5_command,
            check=True,
            timeout=120,
            capture_output=True,
            text=True,
        )

def main() -> int:
    if DASHBOARD_DB is None:
        print("HEALTH_DASHBOARD_DB is required", file=sys.stderr)
        return 2
    ensure_private_inbox()
    failures = 0
    for path in sorted(ACTION_INBOX.glob("*.json")):
        try:
            day, scores, notes = load_action(path)
            apply_action(day, scores, notes)
            path.unlink()
        except Exception:
            failures += 1
            try:
                path.replace(path.with_suffix(".failed"))
            except OSError:
                pass
    return 1 if failures else 0

if __name__ == "__main__":
    raise SystemExit(main())


The action worker currently only accepts symptom check-ins. I’m adding a second validated action type for nutrition mappings and keeping all reads bounded and public-safe.


sed -n '760,1280p' scripts/health/dashboard_v5/read_api.py


sed -n '360,880p' scripts/health/assets/health-assets/dashboard-v5.js


sed -n '1,320p' scripts/health/health_dashboard_server.py


rg -n "CREATE TABLE.*nutrition|nutrition_|review_queue|action_inbox|browser-session|health-actions|csrf|ASSET_ROUTES|read_api" database scripts tests -S