<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Health Dashboard on Alexey Panfilov — Product, AI, Systems</title><link>https://dzarlax.dev/series/health-dashboard/</link><description>Recent content in Health Dashboard on Alexey Panfilov — Product, AI, Systems</description><generator>Hugo</generator><language>en</language><atom:link href="https://dzarlax.dev/series/health-dashboard/index.xml" rel="self" type="application/rss+xml"/><item><title>Health Dashboard, Part 1: A Score I Could Trust</title><link>https://dzarlax.dev/articles/health-dashboard-part-1-a-score-i-could-trust/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://dzarlax.dev/articles/health-dashboard-part-1-a-score-i-could-trust/</guid><description>&lt;p&gt;This is Part 1 of a series about building my self-hosted Health Dashboard. The first version was not a methodology project. It was a pipe: take data from Apple Health, POST it to my server, show a score in the morning.&lt;/p&gt;
&lt;p&gt;That sounds clean until the first bad night of data lands in Postgres. A health score is only as trustworthy as the ingestion path underneath it, and the early version of this system was mostly teaching me that lesson the hard way.&lt;/p&gt;</description></item><item><title>Health Dashboard, Part 2: Outgrowing Health Auto Export</title><link>https://dzarlax.dev/articles/health-dashboard-part-2-outgrowing-health-auto-export/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://dzarlax.dev/articles/health-dashboard-part-2-outgrowing-health-auto-export/</guid><description>&lt;p&gt;In Part 1 the server learned to accept observations without losing them and to rebuild every derived table from raw data. That was enough to make a dashboard useful. It was not enough to make the data honest.&lt;/p&gt;
&lt;p&gt;This part is about the moment a third-party exporter stopped being a sufficient ingestion path on its own, and about the two regressions that followed when I added my own iOS client alongside it. Health Auto Export still runs against the server today. The &lt;code&gt;/health&lt;/code&gt; endpoint accepts both producers, and the code path that parses HAE payloads is maintained. The &amp;ldquo;outgrowing&amp;rdquo; in the title is about its limits, not its retirement.&lt;/p&gt;</description></item><item><title>Health Dashboard, Part 3: My Wearables Kept Lying by Omission</title><link>https://dzarlax.dev/articles/health-dashboard-part-3-my-wearables-kept-lying-by-omission/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://dzarlax.dev/articles/health-dashboard-part-3-my-wearables-kept-lying-by-omission/</guid><description>&lt;p&gt;After Part 2 the ingestion layer feels clean. The server accepts payloads, a native iOS client cooperates with Health Auto Export, the schema knows about per-segment sleep, the dashboard renders five sleep phases. It looks finished. It is not.&lt;/p&gt;
&lt;p&gt;The next class of problem only became visible once the data was technically correct. On any given night I have &lt;strong&gt;three devices&lt;/strong&gt; capable of saying something about my sleep: Apple Watch on my wrist, RingConn&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; on my finger, and the iPhone next to my bed running Apple&amp;rsquo;s own Sleep Schedule estimate. Each one knows something the others do not. None of them agree about what they measured.&lt;/p&gt;</description></item><item><title>Health Dashboard, Part 4: When Readiness Stopped Being One Number</title><link>https://dzarlax.dev/articles/health-dashboard-part-4-when-readiness-stopped-being-one-number/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://dzarlax.dev/articles/health-dashboard-part-4-when-readiness-stopped-being-one-number/</guid><description>&lt;p&gt;In Part 1 I described the original readiness score:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;readiness = HRV_score * 0.40 + RHR_score * 0.30 + Sleep_score * 0.30
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It was a useful number. It told me, every morning, whether something in last night&amp;rsquo;s data looked unusual against my personal baseline. It also turned out to be measuring the wrong thing.&lt;/p&gt;
&lt;p&gt;This part is the audit that surfaced that, the redesign that came out of it, and the moment Phase 1 closed without producing a single model that beat its naive baseline by the criterion we had set in advance.&lt;/p&gt;</description></item><item><title>Health Dashboard, Part 5: The Energy Bank Problem</title><link>https://dzarlax.dev/articles/health-dashboard-part-5-the-energy-bank-problem/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://dzarlax.dev/articles/health-dashboard-part-5-the-energy-bank-problem/</guid><description>&lt;p&gt;In Part 4 the audit invalidated the readiness formula and surfaced a parallel finding: EnergyBank v1 was wrong-signed against next-day HRV&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; (r=−0.149) and next-day RHR&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; (r=+0.212) over 387 paired days.&lt;/p&gt;
&lt;p&gt;Wrong-signed is a strong claim. It means the concept is intact but the target is mis-specified: what v1 was measuring was probably &lt;em&gt;productive strain&lt;/em&gt;, not &lt;em&gt;recovery deficit&lt;/em&gt;. The two correlate on many days and diverge precisely on the days that matter, like a quiet but anxious day, an illness, a watch off the wrist.&lt;/p&gt;</description></item><item><title>Health Dashboard, Part 6: Measuring Stress Without Lying to Myself</title><link>https://dzarlax.dev/articles/health-dashboard-part-6-measuring-stress-without-lying-to-myself/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://dzarlax.dev/articles/health-dashboard-part-6-measuring-stress-without-lying-to-myself/</guid><description>&lt;p&gt;In Part 5 the EnergyBank redesign left a placeholder: &lt;code&gt;drain = α · active_kcal + β · sustained_hr_load&lt;/code&gt;, with &lt;code&gt;β = 0&lt;/code&gt; until a validation rubric per-user returns &lt;code&gt;validated&lt;/code&gt;. That term, the autonomic-load drain, is the v2.2 piece. It is also the one I most wanted to be careful with, because &amp;ldquo;stress&amp;rdquo; is the single most over-claimed metric in consumer health products.&lt;/p&gt;
&lt;p&gt;This part is about what stress actually means physiologically, what my data can and cannot say about it, why the obvious formula was wrong, and what the rubric is for.&lt;/p&gt;</description></item><item><title>Health Dashboard, Part 7: The App That Stopped Doing the Math</title><link>https://dzarlax.dev/articles/health-dashboard-part-7-the-app-that-stopped-doing-the-math/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://dzarlax.dev/articles/health-dashboard-part-7-the-app-that-stopped-doing-the-math/</guid><description>&lt;p&gt;The first six parts of this series were about the server learning to have opinions. Ingestion gates, source identity, sub-score eligibility, formula-version boundaries, validation rubrics: every piece earned its right to a number. Once that work was done, a new question opened on the other side of the wire. What is the iOS client allowed to do with those numbers?&lt;/p&gt;
&lt;p&gt;The answer turned out to be narrower than I expected when I started. The interesting part of building the mobile app was not what got added to it. It was what got &lt;em&gt;removed&lt;/em&gt; from it, repeatedly, as the server learned to do each thing better.&lt;/p&gt;</description></item><item><title>Health Dashboard, Part 8: Asking Before Telling</title><link>https://dzarlax.dev/articles/health-dashboard-part-8-asking-before-telling/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://dzarlax.dev/articles/health-dashboard-part-8-asking-before-telling/</guid><description>&lt;p&gt;Part 6 said: subjective input cannot validate the stress formula. That rule stands. A formula that auto-tunes itself against a user&amp;rsquo;s self-report becomes a closed loop with no external referent. The user rationalises post-hoc, the formula updates toward the rationalisation, and the next round of self-report is biased by the formula&amp;rsquo;s previous output. The cure for that is to keep the rubric external: next-morning HRV, RHR shift, sleep architecture. Numbers the user is not consciously writing down.&lt;/p&gt;</description></item></channel></rss>