{% extends "base.html" %} {% block title %}Health ยท {{ app_name }}{% endblock %} {% import "_chart.html" as ch %} {# ๐Ÿ”ด GAPS ARE DRAWN AS BREAKS, NOT JOINED โ€” in core/chart.py, which is where that rule now lives for the whole app. history() returns a null for a day with no reading, and the natural single polyline would draw a straight line across a fortnight nobody measured: a picture of steady progress invented out of missing data. Same contract as the tiles above โ€” unknown must not look like a value. #} {% block body %}

๐Ÿ’š Health what your body did, and what the game did about it

{% if s.unavailable %}

Not on this instance

Health readings reach Latch through its JSON API, and the API is off when Latch is hosted for several people at once. Nothing is broken and nothing is missing from your log โ€” this module simply has nothing to read here. Everything else in the game plays exactly the same.

{% elif s.stale %}

The sync has stopped

Nothing has arrived {% if s.last_sync %}since {{ s.last_sync|local }} ({{ s.last_sync|rel(now) }}){% else %}ever{% endif %}. Rules are not firing, and the numbers below โ€” if there are any โ€” are old.

Check sync-health-to-latch.py on the apps pod.

{% endif %} {% if s.recovery.on %}

๐Ÿ›Ÿ Recovery day

{% for r in s.recovery.reasons %}

โ€œ{{ r.line }}โ€

{% endfor %}

Penalties are held back today. Rewards still count โ€” moving at all on a day like this is worth more, not less.

{% endif %}

{{ 'Today' if s.is_today else 'Latest readings' }} {{ s.day }}{% if not s.is_today %} ยท {{ s.lag }} day{{ 's' if s.lag != 1 }} behind โ€” Apple exports overnight, so today fills in tomorrow{% endif %}

{% for t in s.tiles %}
{{ t.label }} {%- if not t.known -%}โ€” {%- elif t.metric == 'mood_valence' -%}{{ '%+.2f'|format(t.value) }} {%- elif t.value == t.value|round(0) -%}{{ t.value|int }} {%- else -%}{{ '%.1f'|format(t.value) }}{%- endif -%} {% if t.known and t.unit %}{{ t.unit }}{% endif %} {{ t.source if t.known else 'no reading' }}
{% endfor %}
{% if not s.any %}

Nothing measured for today yet. That is not the same as a zero โ€” no rule can fire on a day nobody measured, in either direction.

{% endif %}
{% for q in s.quiet %}

โš  {{ q.label }} stopped

{% if q.last %}Nothing logged for {{ q.days }} days โ€” last was {{ q.last }}. {% else %}Never logged.{% endif %}

Shown rather than hidden on purpose: a blank space reads as "fine", and the point of tracking this is to notice when it stops.

{% endfor %}

Rules

{% for r in s.rules %} {% endfor %}
ruletodayreadingeffect
{{ r.rule.title }} {%- if r.state is none -%}unknown {%- elif r.withheld and r.state -%}held back {%- elif r.fired -%}fired {%- elif r.state -%}ready {%- else -%}no{%- endif -%} {%- if r.value is none -%}no reading {%- else -%}{{ '%g'|format(r.value) }} vs {{ '%g'|format(r.threshold) }}{%- endif -%} {%- if r.rule.xp %}+{{ r.rule.xp }} xp{% endif -%} {%- if r.rule.seconds %}{{ ' ยท ' if r.rule.xp }}{{ (r.rule.seconds // 60)|abs }} min {{ 'off' if r.rule.seconds < 0 else 'on' }}{% endif -%} {%- if r.rule.recovery %} eases the day{% endif -%}

Last 30 days to {{ trend_end or 'โ€”' }}

{# Ends at the last day the export covered, not today: Apple delivers overnight, so a chart drawn to today falls off a cliff at the right-hand edge every single day. #}
{% for c in trends %}

{{ c.title }}

{{ ch.line(c) }}
{% endfor %}

A day with no reading is a break in the line, never a zero โ€” about a quarter of days carry none. ๐Ÿ“– how these are drawn

{% endblock %}