# 生理データを自分の手に取り戻す：AIと協働でつくった生理情報データ基盤の共有、あなたも自分でできる

> 個人の生理データ日誌をGoogle Health、Python、SQLite、Cloudflareでどうつなぐか。5分ごとの歩行データ確認、毎日の生理データ同期、3つの公開データ契約、AIとの協働の実際の範囲を解説する。

- Author: Paul Kuo（郭曜郎）
- Date: 2026-10-21
- Pillar: 知性と秩序 / Intelligence & Order
- Tags: AIとの協働, Google Health, Fitbit, Python, SQLite, Cloudflare
- Canonical: https://paulkuo.tw/ja/articles/physiology-data-ai-collaboration/
- Language: Japanese (日本語)
- Translation: AI-translated from the zh-Hant (Traditional Chinese) original
- Original (zh-Hant): https://paulkuo.tw/articles/physiology-data-ai-collaboration.md
- Site index for LLMs: https://paulkuo.tw/llms.txt

---

> このプロジェクトでは、私自身が利用を許可したFitbit／Google Healthのデータをローカルに取得し、日付の整理、欠損値の処理、許可リストの確認を経て、指定した日次要約データを公開する。AIは設計、実装、レビューを支援し、日々のデータ整理とページの要約文は固定のプログラムルールで処理する。

## なぜ自分の生理データをウェブサイトにするのか

何年も前に、『身體調校聖經』（The 4-Hour Body）を読んだ。その頃から、自分の身体のデータを把握することに情熱を持つようになった。私にとって「データがなければ管理できない」という考え方は、健康の維持にも当てはまる。

<figure style="max-width: 420px; margin: 2rem auto;">
  <img src="/images/articles/physiology-data-ai-collaboration/the-4-hour-body.jpg" alt="『身體調校聖經』（The 4-Hour Body）繁体字中国語版の表紙" width="1108" height="1477" loading="lazy" decoding="async" />
  <figcaption>『身體調校聖經』（The 4-Hour Body）繁体字中国語版。写真提供：Paul。</figcaption>
</figure>

### 『The 4-Hour Body』から考えるデータ管理

Tim Ferrissは本書で、食事、トレーニング、睡眠などを自己実験によって探究している。このサイトにつながるのは、測定と追跡に関するいくつかの考え方である。

- **出発点を記録する。** 体重だけでなく、身体の周囲径や体脂肪などで基準を残す。[原書の測定に関する章](https://tim.blog/wp-content/uploads/2014/10/4-hour-body.pdf)
- **測定方法をそろえる。** 測定器、計算式、条件の違いを、身体の変化と取り違えることがある。[原書の測定に関する章](https://tim.blog/wp-content/uploads/2014/10/4-hour-body.pdf)
- **継続して比較できる記録を残す。** 巻末の関連資料は、習慣や身体の記録を追跡するQuantified Selfや自己実験の方法につながっている。[著者の関連資料](https://tim.blog/gear/)
- **「最小有効量」で考える。** MEDは、目標とする結果に必要な最小の介入量を指し、何が作用するかに着目する。[出版社の抜粋](https://penguinrandomhouselibrary.com/book/?isbn=9780307463630)

私はこれらの考え方を、出典と日付を残し、定義をそろえ、長期的に振り返れる記録にするという設計へとつなげている。データ基盤の設計上の参考であり、本書の事例をこのサイトの健康上の効果の証明にするものではない。

今はAIがあり、当時の期待を形にできる可能性が広がった。この思いを、継続して記録し、整理し、振り返ることのできるデータ基盤へと少しずつつなげていきたい。

自分の活動、睡眠、一部の生理記録をウェブサイトに掲載している。本稿で紹介したいのは、そのシステムがどう動くかである。

サイトに表示される一つの数値にも、答えるべき問いがある。どこから取得したデータか。どの日の記録か。まだ集計の途中なのか。記録がなければどう表示するか。どこまで公開できるか。

これらの問いへの対応が、グラフを正しく読めるかどうかを左右する。自動処理でエラーが発生したとき、不確かな結果をそのままサイトに送り続けるかどうかも、ここで決まる。

本稿が記録するのは2026年10月時点の構成である。Google Health API、ローカルのPythonとSQLite、Cloudflare KV／Worker、ウェブサイトの画面を通じて、継続的に更新する日次の生理データ日誌を構築した。[初期にFitbit MCP、Apple Healthのエクスポート、デプロイスクリプトを使った試み](/ja/articles/personal-health-data-infrastructure/)とは、異なる段階の構成である。今回はデータの出典、公開範囲、失敗時の処理に焦点を当てる。

<link rel="stylesheet" href="/styles/physiology-article-visuals-v1.css" />
<figure class="physio-visual" id="physio-data-atlas">
  <p class="physio-visual__notice">説明用データ · Paulの実測値ではありません</p>
  <div class="physio-atlas">
    <img src="/images/articles/physiology-data-ai-collaboration/physiology-data-atlas-unlabeled-v2.webp" alt="睡眠の棒グラフ、心拍変動と安静時心拍数の推移、データのグリッドで日別記録を表した概念図" width="1536" height="1024" loading="lazy" decoding="async" />
    <span class="physio-atlas__label physio-atlas__label--sleep" aria-hidden="true">睡眠</span>
    <span class="physio-atlas__label physio-atlas__label--hrv" aria-hidden="true">HRV</span>
    <span class="physio-atlas__label physio-atlas__label--rhr" aria-hidden="true">RHR</span>
  </div>
  <ul class="physio-visual__legend physio-visual__legend--atlas" aria-label="凡例">
    <li><span class="physio-visual__swatch physio-visual__swatch--sleep" aria-hidden="true"></span>睡眠</li>
    <li><span class="physio-visual__swatch physio-visual__swatch--hrv" aria-hidden="true"></span>心拍変動（HRV）</li>
    <li><span class="physio-visual__swatch physio-visual__swatch--rhr" aria-hidden="true"></span>安静時心拍数（RHR）</li>
  </ul>
  <figcaption>AI生成のデータ図。睡眠、心拍変動（HRV）、安静時心拍数（RHR）の日別記録と推移を模式的に描いた。図形はすべて説明用で、Paulの実測記録ではない。帯状の陰影も医学的な正常範囲を示すものではない。</figcaption>
</figure>

## Google Health、Python、ウェブサイトをどうつなぐか

全体の処理を、収集、整理、公開、表示の4層に分けている。

```mermaid
flowchart TD
    A["Fitbitデバイスと提供元サービスの同期"] --> B["Google Health API"]
    B -->|"本人が許可した読み取り専用のデータアクセス権限"| C["ローカルPythonで収集"]
    C --> D["非公開のSQLiteとアクセスを制限した生レスポンス"]
    D --> E["日付の整理、日次集計、欠損値と競合の処理"]
    T["ローカルのTakeoutによる一般指標の履歴"] --> E
    E --> F["公開を承認した許可リストとNodeによる検証"]
    F --> G["Cloudflare KV"]
    G --> H["Workerの読み取り専用エンドポイント"]
    H --> I["Astro／JavaScriptによる4言語サイト"]
    J["AIとの協働：設計、コード、文面、レビュー"] -.-> C
    J -.-> I
```

実線はデータの流れ、破線は構築と保守における協働を示す。更新のたびに生理データをモデルへ送るという意味ではない。Takeoutは一般指標の履歴にのみ使い、HRVと安静時心拍数の個人参照帯の計算には使わない。

ウェアラブルデバイスがまず提供元のサービスにデータを同期し、その後ローカルのプログラムが、許可済みのGoogle Healthの読み取り専用権限で記録を取得する。プログラムはアカウントとHealth identityを照合し、クエリ結果の全ページを読み取ったうえで、取得データをローカルのデータベースに書き込む。APIの生レスポンスはアクセスを制限したディレクトリに保存する。

ここでいう「読み取り専用」は、Google Healthに書き戻さないことを指す。ローカルでのデータ整理と、公開を許可した要約データの配信には、それぞれ別の書き込み処理がある。

データの定義も先に確認する必要がある。Google Healthは日次、区間、単一時点などのデータ型を区別し、型ごとに必要な権限を示している。似た指標に見えても、そのまま同じデータとして扱うことはできない。[Google Healthのデータ型](https://developers.google.com/health/data-types)

公開用の要約データは別のプログラムで作成し、承認済みの項目だけを受け付ける。Nodeによる許可リストの検証に通った後、既存のCloudflare KVに書き込み、Workerを介して読み出し、サイト上のグラフと説明文に表示する。通常のデータ更新はKVを通すため、そのたびにサイトを再デプロイする必要はない。

## 5分ごとの確認で、実際には何が更新されるのか

現在のスケジュールには、2種類の頻度がある。

<p class="physio-table-hint" id="physio-table-1-hint">画面が狭い場合は、表を左右にスクロールできます。</p>
<div class="physio-table-scroll" role="region" aria-label="更新頻度と対象範囲" aria-describedby="physio-table-1-hint" tabindex="0">
  <table>
    <caption>更新頻度と対象範囲</caption>
    <thead><tr><th scope="col">処理</th><th scope="col">確認の目標時刻・間隔</th><th scope="col">更新範囲</th></tr></thead>
    <tbody>
      <tr><td>歩行データの更新</td><td>5分ごと</td><td>今日と昨日の歩数・距離の日次累積値</td></tr>
      <tr><td>日次の完全同期</td><td>毎日09:00、台北時間</td><td>直近7日間を再取得し、成功後に残りの承認済み要約データと独立した生理データ欄を更新</td></tr>
    </tbody>
  </table>
</div>

睡眠、HRV、安静時心拍数は、5分ごとの歩行データ処理では再計算しない。

2つの処理はロックを共有し、同時に収集や上書きが走るのを防ぐ。現在はCodexのスケジュールからローカルの固定Pythonプログラムを起動し、データ整理と要約計算はプログラムのルールに従って実行する。MacとCodexが稼働している必要があり、ネットワークや上流の同期状況も実際の実行時刻に影響する。したがって5分は確認の目標間隔である。デバイスがまだ同期していなければ、クエリの回数を増やしても新しい記録は得られない。

公開データは3つの契約に分け、`api.paulkuo.tw`上のエンドポイントから提供する。

<p class="physio-table-hint" id="physio-table-2-hint">画面が狭い場合は、表を左右にスクロールできます。</p>
<div class="physio-table-scroll" role="region" aria-label="公開エンドポイントと内容" aria-describedby="physio-table-2-hint" tabindex="0">
  <table>
    <caption>公開エンドポイントと内容</caption>
    <thead><tr><th scope="col">エンドポイント</th><th scope="col">内容</th></tr></thead>
    <tbody>
      <tr><td><code>/health-journal</code></td><td>一般指標の日次要約データと、その日に固定した今日の平均心拍数1件</td></tr>
      <tr><td><code>/health-journal/history</code></td><td>平均心拍数を含まない、7つの一般指標の日次履歴</td></tr>
      <tr><td><code>/health-journal/physiology</code></td><td>直近7日間の睡眠、日次HRV、安静時心拍数、個人参照帯</td></tr>
    </tbody>
  </table>
</div>

7つの一般指標は、歩数、距離、活動消費カロリー、睡眠時間、睡眠中の平均血中酸素飽和度、主睡眠中の呼吸数、皮膚温の偏差である。

平均心拍数と安静時心拍数は異なる指標である。今日の平均心拍数はデータ更新時点までに記録されたデータから算出し、その日最初のリモート公開を試みる前に固定する。同じ日の再試行でも同じ値を使い、5分ごとの歩行データ更新でも再計算しない。24時間全体の平均を表すものではなく、検証済みの当日値を利用できなければ空欄を保つ。安静時心拍数は、別途承認した生理データの要約に7日間の記録を表示する。

## グラフにデータの制約をどう残すか

数値を見るとき、その数値が成り立つ条件も読者に見えるようにしたい。

<figure class="physio-visual" id="physio-signals">
  <img src="/images/articles/physiology-data-ai-collaboration/physiology-signals-infographic.webp" style="height: auto; max-height: none; margin: 0;" alt="人物の輪郭と4つの番号付きパネルで、睡眠、心拍変動、安静時心拍数、歩行活動のデータを表した概念図" width="1536" height="1024" loading="lazy" decoding="async" />
  <ul class="physio-visual__legend physio-visual__legend--signals" aria-label="凡例">
    <li><span class="physio-visual__number" aria-hidden="true">01</span>睡眠</li>
    <li><span class="physio-visual__number" aria-hidden="true">02</span>心拍変動（HRV）</li>
    <li><span class="physio-visual__number" aria-hidden="true">03</span>安静時心拍数（RHR）</li>
    <li><span class="physio-visual__number" aria-hidden="true">04</span>歩行活動</li>
  </ul>
  <figcaption style="margin-top: 0.75rem; font-size: 0.88rem; line-height: 1.6; color: var(--text-secondary);">AI生成の概念図。01 睡眠、02 心拍変動（HRV）、03 安静時心拍数（RHR）、04 歩行活動。波形と図形はいずれも説明用の模式表現で、Paulの実測データは使用していない。</figcaption>
</figure>

歩数と距離は台北の日付で集計し、今日の値はまだ増える途中である。睡眠は起床した日に割り当て、夜間の指標は提供元の日付を保つ。睡眠時間は保存時とAPI層では分単位を維持し、画面では時間単位に換算して読みやすくする。

欠損値は空欄または`null`のままにし、ゼロでは埋めない。出典間で値が競合する場合も空欄を保つ。過去のデータは元の日付を維持し、今日のラベルに置き換えない。過去のエクスポートと最近のAPIデータは、出典ごとのルールに従って統合し、重複集計を防ぐ。

生理データ欄はページの上部に置き、一文の要約、3つの根拠、7日間のグラフで、睡眠、日次HRV、安静時心拍数を示す。HRVには日次平均RMSSDの元の値を使い、安静時心拍数には睡眠データを含む`WITH_SLEEP`の定義を使う。[Google Healthのデータポイント定義](https://developers.google.com/health/reference/rest/v4/users.dataTypes.dataPoints)

個人参照帯には、各評価日より前の28日間に対応する、同じ定義のAPIデータを使う。最低21日分の有効な記録を必要とし、中央値と第25～75パーセンタイルを算出する。評価日当日は含めず、未検証のTakeoutデータも混ぜない。有効な記録が足りなければ「基準を作成中」と表示する。

この参照帯が表すのは、最近の記録の分布である。帯の内側にあっても健康を意味せず、外側にあっても診断には使えない。ページでは残りのエネルギーを推定せず、これをもとに運動の安全性を判断することもない。

### HRVとRHRを日々の経験とどう照らし合わせるか

**HRVが示すのは、心拍と心拍の間隔の変動である。** 自律神経による心拍の調節と関係し、1分間の心拍数とは異なる。日々の記録は、自分の推移を睡眠、ストレス、生活習慣と照らし合わせるために使える。単発の数値を他人と競うためのものではない。[Google HealthによるHRVの説明](https://support.google.com/googlehealth/answer/14237938?hl=en)

**RHRが示すのは、安静時の心拍数である。** 体温、感情、痛み、薬など、心拍数に影響する要因はさまざまだ。数値が上がっても、それだけで原因はわからない。[米国心臓協会による心拍数の説明](https://www.heart.org/en/health-topics/high-blood-pressure/the-facts-about-high-blood-pressure/all-about-heart-rate-pulse)

自分の記録では、はっきりした傾向を感じている。お酒を飲むとHRVが下がり、体調が悪いとき、よく眠れなかったとき、病気のときにはRHRが目立って上がる。これは私個人の観察であり、誰もが同じ反応をするという意味ではない。

<!-- Personal-observation animation: illustrative art and fictional example values, no measured data. -->
<figure class="physio-cartoon">
<link rel="stylesheet" href="/styles/physiology-observation-cartoon-v2.css" />
<div class="physio-cartoon__heading"><span class="physio-cartoon__kicker">個人の観察 × 生体信号</span><p>からだの小さな二場面</p></div>
<input class="physio-cartoon__toggle" id="physio-cartoon-motion" type="checkbox" checked aria-describedby="physio-cartoon-caption" />
<label class="physio-cartoon__control" for="physio-cartoon-motion"><span class="physio-cartoon__switch" aria-hidden="true"></span><span>動きを再生</span><span class="physio-cartoon__playing" aria-hidden="true">再生中</span><span class="physio-cartoon__paused" aria-hidden="true">一時停止</span><span class="physio-cartoon__reduced" aria-hidden="true">設定により静止表示</span></label>
<p class="physio-cartoon__notice" id="physio-cartoon-data-note">数値は説明用の例。Paul の実測ではない</p>
<fieldset class="physio-cartoon__modes" aria-describedby="physio-cartoon-data-note"><legend>二つの例を切り替える</legend><div><input class="physio-cartoon__mode physio-cartoon__mode--reference" id="physio-cartoon-reference" name="physio-cartoon-example" type="radio" /><label for="physio-cartoon-reference">比較用の例</label><input class="physio-cartoon__mode physio-cartoon__mode--scenario" id="physio-cartoon-scenario" name="physio-cartoon-example" type="radio" checked /><label for="physio-cartoon-scenario">変化の例</label></div></fieldset>
<div class="physio-cartoon__stage">
  <div class="physio-cartoon__scene physio-cartoon__scene--hrv">
    <p class="physio-cartoon__situation"><span class="physio-cartoon__value--reference">HRV · 比較用の例</span><span class="physio-cartoon__value--scenario">飲酒後の HRV</span></p>
    <div class="physio-cartoon__portrait" role="img" aria-label="ワインを手にしたハンサムな成人男性のカートゥーン。胸元の表示は説明用の HRV 値"><img class="physio-cartoon__sprite" src="/images/articles/physiology-data-ai-collaboration/physiology-observation-cartoon.webp" alt="" aria-hidden="true" width="1536" height="1024" loading="lazy" decoding="async" /><div class="physio-cartoon__body-data" aria-hidden="true"><span class="physio-cartoon__body-heart"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21S2 15 2 8.5C2 3 9 2 12 7c3-5 10-4 10 1.5C22 15 12 21 12 21Z" /></svg></span><span class="physio-cartoon__body-kind">HRV · 説明用の例</span><span class="physio-cartoon__body-number"><span class="physio-cartoon__value--reference">68</span><span class="physio-cartoon__value--scenario">42</span><small>ms</small></span></div></div>
    <div class="physio-cartoon__reading"><span class="physio-cartoon__value--reference">HRV</span><span class="physio-cartoon__value--scenario">HRV が下がる</span><span class="physio-cartoon__arrow physio-cartoon__value--scenario" aria-hidden="true">↓</span></div>
    <div class="physio-cartoon__data-reading"><span class="physio-cartoon__state-name physio-cartoon__value--reference">比較用の例</span><span class="physio-cartoon__state-name physio-cartoon__value--scenario">変化の例</span><strong><span class="physio-cartoon__value--reference">68</span><span class="physio-cartoon__value--scenario">42</span><small>ms</small></strong><span class="physio-cartoon__data-note">説明用の数値。Paul の実測ではない</span></div>
    <div class="physio-cartoon__signal"><div class="physio-cartoon__signal-label">心拍間隔の模式図</div><svg class="physio-cartoon__intervals" viewBox="0 0 192 50" aria-hidden="true"><path class="physio-cartoon__rail" d="M10 40H182" /><g class="physio-cartoon__value--reference"><path d="M12 15v22" /><path d="M40 15v22" /><path d="M77 15v22" /><path d="M103 15v22" /><path d="M144 15v22" /><path d="M180 15v22" /></g><g class="physio-cartoon__value--scenario"><path d="M12 15v22" /><path d="M46 15v22" /><path d="M79 15v22" /><path d="M113 15v22" /><path d="M146 15v22" /><path d="M180 15v22" /></g><circle class="physio-cartoon__scan" cx="12" cy="40" r="3" /></svg><p class="physio-cartoon__signal-explainer physio-cartoon__value--scenario">間隔のばらつきが小さくなる</p></div>
  </div>
  <div class="physio-cartoon__scene physio-cartoon__scene--rhr">
    <p class="physio-cartoon__situation"><span class="physio-cartoon__value--reference">RHR · 比較用の例</span><span class="physio-cartoon__value--scenario">寝不足・体調が悪いときの RHR</span></p>
    <div class="physio-cartoon__portrait" role="img" aria-label="同じハンサムな成人男性が毛布をまとい、胸元に説明用の RHR 値と動くハートの図があるカートゥーン"><img class="physio-cartoon__sprite" src="/images/articles/physiology-data-ai-collaboration/physiology-observation-cartoon.webp" alt="" aria-hidden="true" width="1536" height="1024" loading="lazy" decoding="async" /><div class="physio-cartoon__body-data" aria-hidden="true"><span class="physio-cartoon__body-heart"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21S2 15 2 8.5C2 3 9 2 12 7c3-5 10-4 10 1.5C22 15 12 21 12 21Z" /></svg></span><span class="physio-cartoon__body-kind">RHR · 説明用の例</span><span class="physio-cartoon__body-number"><span class="physio-cartoon__value--reference">60</span><span class="physio-cartoon__value--scenario">78</span><small>bpm</small></span></div></div>
    <div class="physio-cartoon__reading"><span class="physio-cartoon__value--reference">RHR</span><span class="physio-cartoon__value--scenario">RHR が上がる</span><span class="physio-cartoon__arrow physio-cartoon__value--scenario" aria-hidden="true">↑</span></div>
    <div class="physio-cartoon__data-reading"><span class="physio-cartoon__state-name physio-cartoon__value--reference">比較用の例</span><span class="physio-cartoon__state-name physio-cartoon__value--scenario">変化の例</span><strong><span class="physio-cartoon__value--reference">60</span><span class="physio-cartoon__value--scenario">78</span><small>bpm</small></strong><span class="physio-cartoon__data-note">説明用の数値。Paul の実測ではない</span></div>
    <div class="physio-cartoon__signal"><div class="physio-cartoon__signal-label">心拍リズムの模式図</div><div class="physio-cartoon__rhythm" aria-hidden="true"><span class="physio-cartoon__rhythm-line"></span><span class="physio-cartoon__rhythm-dot"></span><span class="physio-cartoon__rhythm-ring"></span></div><p class="physio-cartoon__signal-explainer physio-cartoon__value--scenario">リズムが速くなる</p></div>
  </div>
</div>
<figcaption id="physio-cartoon-caption">二つの例を切り替えると、キャラクターの数値表示、心拍間隔、心拍リズムが連動する。数値と信号はすべて説明用であり、Paul の実測、正常範囲、診断ではなく、誰もが同じ反応をするという意味でもない。動きは一時停止でき、システムの動きを減らす設定にも対応する。</figcaption>
</figure>
<!-- End personal-observation animation. -->

照らし合わせられる研究もある。WHOOPが資金提供した2026年のウェアラブル端末による後ろ向き研究では、飲酒と夜間HRVの低下、夜間RHRの上昇との関連が観察された。ただし、観察研究で示された関連から、私のある日の変化の原因まで確定することはできない。[原著論文](https://journals.plos.org/digitalhealth/article?id=10.1371/journal.pdig.0001284)

私にとって、この2つの指標の価値は、日々の経験に振り返れる記録が加わることにある。単日の高低を追うより、定義と測定条件をそろえ、自分の長期的な推移を見ることを大切にしたい。体の感覚や症状を、グラフの数値で置き換えることもできない。

## このプロジェクトでAIは何をしたか

私の役割は、要件を示し、公開範囲を決め、成果を確認することである。AIはデータフローの分解、プログラムの作成、4言語の文面の整備を支援し、日付、欠損値、公開項目などのルールを確認した。独立したレビューでは、当初の説明や実装で見落としやすい問題を探した。

現在、ページの一文の要約は、あらかじめ用意した文面と固定の判定ルールで生成している。更新のたびに生理データの生記録一式をモデルに渡し、解釈し直させる必要はない。

この方式なら、データの出典、計算ルール、画面の結果を一つずつ照合でき、エラーも再現しやすい。完了したかどうかは、プログラムのチェックと実際の読み戻し結果で判断する必要がある。

データの扱いの境界も明確にする必要がある。このパイプラインでは、ダウンロードしたAPIの生レスポンスとローカルの認証情報ファイルを、アクセスを制限したローカルパスに保存し、公開層には承認済みの要約データだけを渡す。上流のGoogle／Fitbitは引き続き元のデータを保有する。またCodexとの協働で使うプロンプト、コード断片、ツール出力は、AIサービスの処理に入る可能性がある。ローカルで実行することは、全工程が完全にオフラインであることを意味しない。

この取り組みを通じて、AIと協働するときは、要件そのものを十分に具体化する必要があると感じた。「データをつなぐ」だけでなく、どの値を公開できるか、失敗したらどこで止めるか、何を証拠に完了を確認するかまで定義する必要がある。これも、私が[知能と秩序](/ja/ai/)というテーマで考え続けている、人間とAIの協働の課題である。

## 成果は、失敗時の動作まで含めて見る

このシステムは、非公開のデータ収集、日次要約、サイト表示をつなぎ、公開の条件もプログラムに組み込んでいる。クエリ結果が不完全なら、新しい要約データの公開処理には進まない。

歩行データと独立した生理データ欄では、アップロードの結果が不明な場合、固定した公開候補を保持し、まず読み戻して検証してから再試行の要否を判断する。一般指標の日次要約では、当日の平均心拍数を固定し、公開後に公開内容を照合する。

現在、一般要約のcurrentとhistoryは、それぞれ別のKV keyに書き込むため、アトミックな更新とはいえない。一部のアップロードだけが成功した場合、一時的に両者の版が異なることがある。これは明示すべき技術上の制約である。

公開後の検証では公開エンドポイントを読み戻し、内容のハッシュと`no-store`レスポンスヘッダーを照合する。確認できるのは、読み戻した内容とHTTPのキャッシュポリシーであり、世界中のすべての地点で同時に新しい値を取得できるという意味ではない。Cloudflare KVは結果整合性を採用しており、地点によって反映に遅れが生じうる。[Cloudflare KVの整合性に関する説明](https://developers.cloudflare.com/kv/concepts/how-kv-works/)

現時点で確認できる成果は、データフローと表示方法が構築され、公開範囲が明確に制限され、エラー時の停止、検証、通知の仕組みがあることである。これらの技術的な成果を、健康改善、診断精度、作業時間の削減を証明するものとして扱うことはできない。

[この生理データ日誌](/ja/health/)にある一つひとつの数値が、同じ問いに答えられるようにしたい。どのように得られた値で、まだ何が分かっていないのか。
