Health Detail Insight v3 Contract

Back to API-DOCS

# 健康详情 AI 洞察接口接入规范(主服务)

**协议版本:** `health-detail-v3`
**接口:** `POST /v1/health-detail-insights/generate`
**调用方:** 主服务(完成原始数据清洗、聚合和个人基线维护)
**服务方:** AI Gateway(校验输入、执行确定性规则并生成面向用户的洞察)

> 本文是主服务唯一的健康详情接入协议。AI Gateway 是被动服务:不会补齐原始数据、重算调用方已提供的聚合值、诊断疾病或推断确定病因。

## 1. 通用请求契约

六个指标均使用 camelCase:`activity`、`rest`、`hr`、`hrv`、`rr`、`bark`;每个指标支持 `day`、`week`、`month` 三个窗口,共 18 个请求形态。

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `schemaVersion` | string | 是 | 固定为 `health-detail-v3`。旧版本请求不兼容。 |
| `userId` | string | 是 | 主服务中的用户标识。 |
| `petId` | string | 是 | 主服务中的宠物标识。 |
| `metric` | enum | 是 | `activity`、`rest`、`hr`、`hrv`、`rr`、`bark`。 |
| `viewWindow` | enum | 是 | `day`、`week`、`month`。 |
| `locale` | enum | 否 | `zh-CN` 或 `en-US`;缺失时默认 `en-US`,只返回所选语言的 `summary`。 |
| `petProfile` | object | 是 | 宠物资料,字段见下表。 |
| `period` | object | 是 | 本地自然时间窗口,字段见下表。 |
| `metrics` | object | 是 | 当前指标和当前窗口的标准化事实;具体字段见各接口。 |
| `previousPeriod` | object | 否 | 紧邻、同类型、已完成的上一完整 Week 或 Month;仅用于改善或恶化规则。 |

### 1.1 `petProfile`

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `petProfile.name` | string | 是 | 面向用户文案使用的宠物展示名。 |
| `petProfile.species` | enum | 是 | `dog` 或 `cat`。 |
| `petProfile.activityTolerance` | enum | 否 | `low`、`medium`、`high`、`unknown`;仅用于 Activity 的解释和建议。 |
| `petProfile.heatTolerance` | enum | 否 | `low`、`medium`、`high`、`unknown`;仅用于 Activity 热暴露解释。 |
| `petProfile.coldTolerance` | enum | 否 | `low`、`medium`、`high`、`unknown`;仅用于低温解释。 |
| `petProfile.humidHeatSensitivity` | enum | 否 | `low`、`medium`、`high`、`unknown`;仅用于湿热解释。 |
| `petProfile.healthRiskTags` | array<enum> | 否 | `respiratory`、`cardiovascular`、`musculoskeletal`。只能增强已有结论的建议,不能单独触发诊断或提醒。 |

### 1.2 `period`

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `period.startDate` | string(date) | 是 | 本地日期,格式 `YYYY-MM-DD`。Day 必须等于 `endDate`;Week 必须覆盖连续 7 日;Month 必须从自然月 1 日覆盖到月末。 |
| `period.endDate` | string(date) | 是 | 本地日期,格式 `YYYY-MM-DD`。 |
| `period.timezone` | string | 是 | IANA 时区,例如 `Asia/Shanghai`;用于日期、小时数组、夜间和事件的解释。 |
| `period.isCompleted` | boolean | 是 | 窗口是否结束。`false` 时只能输出截至目前的观察,不能输出完整周期的低值、趋势或最终不足结论。 |
| `period.elapsedNights` | integer | Rest、HR、HRV、RR 的 Week/Month 必须 | 已结束、理论可观察的夜晚数;Week 范围 0-7,Month 范围 0-当月天数。 |
| `period.validNights` | integer | Rest、HR、HRV、RR 的 Week/Month 必须 | 有效夜晚数,范围 0-`elapsedNights`。Rest 使用可用休息夜;HR、HRV、RR 使用至少 4 个有效样本的夜晚。 |

## 2. 通用基线契约

所有名为 `baseline` 的对象均使用以下结构。

```json
{
  "baselineLower": 40,
  "baselineUpper": 80,
  "baselineSource": "personal"
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `baselineLower` | number/null | 是 | 个体常见范围下界。`baselineSource=unavailable` 时必须为 `null`。 |
| `baselineUpper` | number/null | 是 | 个体常见范围上界,且不得小于 `baselineLower`。`unavailable` 时必须为 `null`。 |
| `baselineSource` | enum | 是 | `personal`、`blended`、`reference`、`unavailable`。只有 `personal` 可单独触发偏高或偏低结论。 |

Activity、Rest、HR 支持四种来源;HRV、RR 、Bark仅支持 `personal`、`unavailable`。`blended`、`reference` 只能帮助解释,不能单独触发个体偏离提醒。

## 3. 通用响应契约

主服务只应依赖以下字段。结构化证据、质量、展示样式和费用可以由 Gateway 内部保留,但不属于本接口响应契约。

```json
{
  "insightId": "hdi_20260723_activity_day_0001",
  "petId": "pet-1",
  "metric": "activity",
  "viewWindow": "day",
  "period": {
    "startDate": "2026-07-23",
    "endDate": "2026-07-23",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "status": "attention",
  "severity": "medium",
  "summary": "Pocky 今天的活动比平时多一些:活动了 95 分钟,比它平时多 21 分钟。接下来让它多留一点安静休息的时间。",
  "generation": {
    "ruleId": "ACTIVITY_HIGH_DAY",
    "ruleVersion": "health-detail-v3",
    "aiPolished": true,
    "generatedAt": "2026-07-23T10:00:00+08:00"
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `insightId` | string | 是 | 单条洞察唯一标识。 |
| `petId` | string | 是 | 请求中的宠物标识。 |
| `metric` | enum | 是 | 请求指标。 |
| `viewWindow` | enum | 是 | 请求时间窗口。 |
| `period` | object | 是 | 响应窗口信息。 |
| `period.startDate` | string(date) | 是 | 响应窗口开始日期。 |
| `period.endDate` | string(date) | 是 | 响应窗口结束日期。 |
| `period.isCompleted` | boolean | 是 | 请求窗口完成状态。 |
| `status` | enum | 是 | `attention`、`normal`、`improving`、`data_collecting`、`insufficient_data`。 |
| `severity` | enum | 是 | `none`、`low`、`medium`、`high`。详情页不据此直接推送。 |
| `summary` | string | 是 | 选定语言的一段自然语言,结构为“现象 + 关键依据 + 轻解释或建议”。 |
| `generation` | object | 是 | 生成元数据。 |
| `generation.ruleId` | string | 是 | 命中的确定性规则 ID。 |
| `generation.aiPolished` | boolean | 是 | 是否经 AI 润色;模板结果或 AI 失败回退为 `false`。 |
| `generation.generatedAt` | string(date-time) | 是 | ISO 8601 且带时区的生成时间。 |

优先级为:`insufficient_data` > 高严重度 `attention` > 中严重度 `attention` > 低严重度 `attention` > `improving` > `data_collecting` > `normal`。

# 4. Activity(活动)

`metric` 固定为 `activity`。天气枚举仅允许 `sunny`、`cloudy`、`overcast`、`rainy`、`snowy`、`foggy`、`windy`、`unknown`。

## Day

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "activity",
  "viewWindow": "day",
  "locale": "zh-CN",
  "petProfile": {
    "name": "Pocky",
    "species": "dog",
    "heatTolerance": "low"
  },
  "period": {
    "startDate": "2026-07-23",
    "endDate": "2026-07-23",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "wearingMinutes": 1440,
    "activityTime": {
      "activityMinutes": 95,
      "activityMinutesGoal": 60,
      "baseline": {
        "baselineLower": 56,
        "baselineUpper": 84,
        "baselineSource": "personal"
      },
      "hourlyActivityMinutes": [
        0,
        0,
        0,
        0,
        0,
        0,
        8,
        14,
        10,
        3,
        0,
        0,
        0,
        0,
        0,
        0,
        5,
        18,
        20,
        12,
        5,
        0,
        0,
        0
      ]
    },
    "steps": {
      "steps": 6800,
      "stepsGoal": 5000,
      "baseline": {
        "baselineLower": 4160,
        "baselineUpper": 6240,
        "baselineSource": "personal"
      }
    },
    "outings": {
      "count": 2,
      "totalDurationMinutes": 48,
      "items": [
        {
          "startAt": "2026-07-23T07:20:00+08:00",
          "endAt": "2026-07-23T07:35:00+08:00",
          "durationMinutes": 15
        },
        {
          "startAt": "2026-07-23T16:10:00+08:00",
          "endAt": "2026-07-23T16:43:00+08:00",
          "durationMinutes": 33
        }
      ]
    },
    "context": {
      "weather": "sunny",
      "tempMaxC": 33,
      "feelsLikeMaxC": 37,
      "humidityPct": 74
    }
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.wearingMinutes` | integer | 是 | 当日有效佩戴分钟,范围 0-1440。 |
| `metrics.activityTime.activityMinutes` | integer | 是 | 当日活动分钟,范围 0-1440。 |
| `metrics.activityTime.activityMinutesGoal` | integer/null | 否 | 当日活动目标,只用于解释和达标文案。 |
| `metrics.activityTime.baseline` | Baseline | 是 | 活动分钟基线。 |
| `metrics.activityTime.hourlyActivityMinutes` | array<integer/null> | 是 | 固定 24 项,对应本地 0-23 时;非空项范围 0-60,非空项之和必须等于 `activityMinutes`。`null` 是未采集,不是静止。 |
| `metrics.steps` | object | 否 | 设备支持步数时传入。 |
| `metrics.steps.steps` | integer | 条件必填 | 传入 `steps` 时必填的总步数。 |
| `metrics.steps.stepsGoal` | integer/null | 否 | 当日步数目标。 |
| `metrics.steps.baseline` | Baseline | 条件必填 | 步数基线。 |
| `metrics.outings` | object | 否 | 外出汇总和片段。 |
| `metrics.outings.count` | integer | 条件必填 | 必须等于 `items` 长度。 |
| `metrics.outings.totalDurationMinutes` | integer | 条件必填 | 必须等于各片段时长之和。 |
| `metrics.outings.items[].startAt` | string(date-time) | 是 | 带时区且位于请求 Day 内。 |
| `metrics.outings.items[].endAt` | string(date-time) | 是 | 带时区、晚于开始时间且位于请求 Day 内。 |
| `metrics.outings.items[].durationMinutes` | integer | 是 | 必须与起止时间间隔一致。 |
| `metrics.context.weather` | enum | 否 | 上述天气枚举。 |
| `metrics.context.tempMaxC` | number | 否 | 最高环境温度,摄氏度。 |
| `metrics.context.feelsLikeMaxC` | number | 否 | 最高体感温度,摄氏度。 |
| `metrics.context.humidityPct` | number | 否 | 相对湿度,范围 0-100。 |

Day 未完成时,允许输出已超过上限、热暴露或集中活动事实;不得输出当天活动不足或最终未达标。

## Week

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "activity",
  "viewWindow": "week",
  "locale": "en-US",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-07-13",
    "endDate": "2026-07-19",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "wearingMinutesByDay": [
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440
    ],
    "activityTime": {
      "averageDailyActivityMinutes": 72,
      "activityMinutesGoal": 60,
      "baseline": {
        "baselineLower": 56,
        "baselineUpper": 84,
        "baselineSource": "personal"
      },
      "dailyActivityMinutes": [
        70,
        55,
        80,
        68,
        90,
        75,
        66
      ]
    },
    "steps": {
      "averageDailySteps": 5314,
      "stepsGoal": 5000,
      "baseline": {
        "baselineLower": 4160,
        "baselineUpper": 6240,
        "baselineSource": "personal"
      },
      "dailySteps": [
        5000,
        4300,
        5900,
        5100,
        6700,
        5400,
        4800
      ]
    },
    "dailyOutings": [
      {
        "date": "2026-07-13",
        "count": 2,
        "totalDurationMinutes": 30
      }
    ],
    "dailyWeather": [
      {
        "date": "2026-07-13",
        "weather": "cloudy",
        "tempMaxC": 29,
        "feelsLikeMaxC": 31,
        "humidityPct": 68
      }
    ]
  },
  "previousPeriod": {
    "startDate": "2026-07-06",
    "endDate": "2026-07-12",
    "isCompleted": true,
    "averageDailyActivityMinutes": 80,
    "averageDailySteps": 5900
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.wearingMinutesByDay` | array<integer/null> | 是 | 固定 7 项,按日期排列;非空范围 0-1440。 |
| `metrics.activityTime.averageDailyActivityMinutes` | number | 是 | 非空 `dailyActivityMinutes` 的均值。 |
| `metrics.activityTime.activityMinutesGoal` | integer/null | 否 | 每日活动目标。 |
| `metrics.activityTime.baseline` | Baseline | 是 | 日均活动基线。 |
| `metrics.activityTime.dailyActivityMinutes` | array<integer/null> | 是 | 固定 7 项,非空项均值必须等于日均值。 |
| `metrics.steps.averageDailySteps` | number | 条件必填 | 提供 `steps` 时,为非空 `dailySteps` 的均值。 |
| `metrics.steps.stepsGoal` | integer/null | 否 | 每日步数目标。 |
| `metrics.steps.dailySteps` | array<integer/null> | 条件必填 | 提供 `steps` 时固定 7 项。 |
| `metrics.dailyOutings` | array<object> | 否 | 每日外出汇总;日期在窗口内且唯一。未出现日期表示未知,不代表 0。 |
| `metrics.dailyWeather` | array<object> | 否 | 每日天气上下文;日期在窗口内且唯一。 |
| `previousPeriod.averageDailyActivityMinutes` | number | 条件必填 | 提供上一周期时必填。 |
| `previousPeriod.averageDailySteps` | number | 否 | 可用时提供。 |

## Month

请求结构与 Activity Week 相同;`startDate` 必须为月初,`endDate` 必须为月末,`wearingMinutesByDay`、`dailyActivityMinutes`、`dailySteps` 的长度必须等于当月天数。`previousPeriod` 必须是紧邻上一完整自然月。

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "activity",
  "viewWindow": "month",
  "locale": "en-US",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-02-01",
    "endDate": "2026-02-28",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "wearingMinutesByDay": [
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440,
      1440
    ],
    "activityTime": {
      "averageDailyActivityMinutes": 70,
      "activityMinutesGoal": 60,
      "baseline": {
        "baselineLower": 56,
        "baselineUpper": 84,
        "baselineSource": "personal"
      },
      "dailyActivityMinutes": [
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70,
        70
      ]
    },
    "steps": {
      "averageDailySteps": 5000,
      "stepsGoal": 5000,
      "baseline": {
        "baselineLower": 4160,
        "baselineUpper": 6240,
        "baselineSource": "personal"
      },
      "dailySteps": [
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000,
        5000
      ]
    }
  },
  "previousPeriod": {
    "startDate": "2026-01-01",
    "endDate": "2026-01-31",
    "isCompleted": true,
    "averageDailyActivityMinutes": 76
  }
}
```

示例数组已按 2026-02 的完整自然月补齐 28 项。字段语义与 Week 相同。

# 5. Rest(休息)

`metric` 固定为 `rest`。Rest Day 以选中日期结束的上一夜为主,当日休息仅作为辅助证据。

## Day

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "rest",
  "viewWindow": "day",
  "locale": "zh-CN",
  "petProfile": {
    "name": "Pocky",
    "species": "dog",
    "healthRiskTags": [
      "respiratory"
    ]
  },
  "period": {
    "startDate": "2026-07-23",
    "endDate": "2026-07-23",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "night": {
      "startAt": "2026-07-22T21:30:00+08:00",
      "endAt": "2026-07-23T07:00:00+08:00",
      "isCompleted": true,
      "wearingMinutes": 550,
      "nightRest": {
        "minutes": 420,
        "baseline": {
          "baselineLower": 390,
          "baselineUpper": 510,
          "baselineSource": "personal"
        }
      },
      "interruptions": {
        "count": 4,
        "baseline": {
          "baselineLower": 0,
          "baselineUpper": 3,
          "baselineSource": "personal"
        }
      },
      "longestRestBlockMinutes": 150,
      "nightActivity": {
        "minutes": 24,
        "baseline": {
          "baselineLower": 0,
          "baselineUpper": 16,
          "baselineSource": "personal"
        }
      },
      "restSegments": []
    },
    "day": {
      "wearingMinutes": 600,
      "hourlyRestMinutes": [
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        12,
        18,
        0,
        0,
        20,
        25,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "dayRestBaseline": {
        "baselineLower": 20,
        "baselineUpper": 55,
        "baselineSource": "personal"
      }
    }
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.night.startAt` / `endAt` | string(date-time) | 是 | 带时区的上一夜窗口,允许跨自然日。 |
| `metrics.night.isCompleted` | boolean | 是 | 夜晚是否结束;`false` 时不能形成夜间主判断。 |
| `metrics.night.wearingMinutes` | integer | 是 | 夜间有效佩戴分钟。少于 300 时为数据不足。 |
| `metrics.night.nightRest.minutes` | integer | 是 | 夜间总休息分钟。 |
| `metrics.night.nightRest.baseline` | Baseline | 是 | 夜间总休息基线。 |
| `metrics.night.interruptions.count` | integer | 是 | 夜间中断次数。 |
| `metrics.night.interruptions.baseline` | Baseline | 是 | 夜间中断基线。 |
| `metrics.night.longestRestBlockMinutes` | integer | 是 | 最长连续休息分钟。 |
| `metrics.night.nightActivity.minutes` | integer | 是 | 夜间活动分钟。 |
| `metrics.night.nightActivity.baseline` | Baseline | 是 | 夜间活动基线。 |
| `metrics.night.restSegments` | array<object>/null | 是 | `null` 表示设备不提供分段能力;未覆盖时段为未知。元素含 `startAt`、`endAt`、`durationMinutes`、`type`,其中 `type` 为 `awake`、`lightMovement`、`deepRest`。 |
| `metrics.day.wearingMinutes` | integer | 是 | 选中自然日有效佩戴分钟。 |
| `metrics.day.hourlyRestMinutes` | array<integer/null> | 是 | 固定 24 项,非空范围 0-60;`null` 表示该小时不可用。 |
| `metrics.day.dayRestBaseline` | Baseline | 是 | 白天总休息分钟基线。 |

## Week

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "rest",
  "viewWindow": "week",
  "locale": "zh-CN",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-07-13",
    "endDate": "2026-07-19",
    "timezone": "Asia/Shanghai",
    "isCompleted": true,
    "elapsedNights": 7,
    "validNights": 6
  },
  "metrics": {
    "nightRest": {
      "averageMinutes": 405,
      "baseline": {
        "baselineLower": 390,
        "baselineUpper": 510,
        "baselineSource": "personal"
      }
    },
    "interruptions": {
      "averageCount": 4,
      "baseline": {
        "baselineLower": 0,
        "baselineUpper": 3,
        "baselineSource": "personal"
      }
    },
    "nightActivity": {
      "averageMinutes": 24,
      "baseline": {
        "baselineLower": 0,
        "baselineUpper": 16,
        "baselineSource": "personal"
      }
    },
    "dayRest": {
      "averageMinutes": 48,
      "baseline": {
        "baselineLower": 20,
        "baselineUpper": 55,
        "baselineSource": "personal"
      }
    },
    "anomalyNights": {
      "lowNightRestCount": 2,
      "highInterruptionCount": 3,
      "highNightActivityCount": 1
    },
    "nightlyRestDurations": [
      {
        "nightDate": "2026-07-13",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 360
      },
      {
        "nightDate": "2026-07-14",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 360
      },
      {
        "nightDate": "2026-07-15",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 360
      },
      {
        "nightDate": "2026-07-16",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 360
      },
      {
        "nightDate": "2026-07-17",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 360
      },
      {
        "nightDate": "2026-07-18",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 360
      },
      {
        "nightDate": "2026-07-19",
        "lightMovementMinutes": null,
        "deepRestMinutes": null
      }
    ]
  },
  "previousPeriod": {
    "startDate": "2026-07-06",
    "endDate": "2026-07-12",
    "isCompleted": true,
    "validNights": 6,
    "nightRestAverageMinutes": 455,
    "interruptionsAverageCount": 2,
    "nightActivityAverageMinutes": 12,
    "dayRestAverageMinutes": 30,
    "lowNightRestCount": 0,
    "highInterruptionCount": 1,
    "highNightActivityCount": 0
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.nightRest.averageMinutes` | number/null | 是 | 有效夜平均夜间总休息;`validNights=0` 时为 `null`。 |
| `metrics.interruptions.averageCount` | number/null | 是 | 有效夜平均中断次数。 |
| `metrics.nightActivity.averageMinutes` | number/null | 是 | 有效夜平均夜间活动分钟。 |
| `metrics.dayRest.averageMinutes` | number/null | 是 | 有效日平均白天休息分钟。 |
| 上述四项 `baseline` | Baseline | 是 | 对应指标的独立基线。 |
| `metrics.anomalyNights` | object | 是 | `lowNightRestCount`、`highInterruptionCount`、`highNightActivityCount`;均在 0-`validNights`。 |
| `metrics.nightlyRestDurations` | array<object> | 是 | 固定 7 项,按 `nightDate` 升序;无效夜的 `lightMovementMinutes`、`deepRestMinutes` 必须同时为 `null`。 |
| `previousPeriod` | object | 否 | 紧邻已完成上一周;必须包含日期、`validNights`、四项均值和三项异常夜计数。 |

Week 少于 3 个有效夜晚时不输出周期趋势或稳定结论。

## Month

请求结构与 Rest Week 相同,窗口必须为完整自然月;`elapsedNights`、`nightlyRestDurations` 长度等于当月天数,`previousPeriod` 必须是紧邻上一完整自然月。Month 少于 10 个有效夜晚时不输出周期趋势或稳定结论。

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "rest",
  "viewWindow": "month",
  "locale": "en-US",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-02-01",
    "endDate": "2026-02-28",
    "timezone": "Asia/Shanghai",
    "isCompleted": true,
    "elapsedNights": 28,
    "validNights": 25
  },
  "metrics": {
    "nightRest": {
      "averageMinutes": 450,
      "baseline": {
        "baselineLower": 390,
        "baselineUpper": 510,
        "baselineSource": "personal"
      }
    },
    "interruptions": {
      "averageCount": 2,
      "baseline": {
        "baselineLower": 0,
        "baselineUpper": 3,
        "baselineSource": "personal"
      }
    },
    "nightActivity": {
      "averageMinutes": 12,
      "baseline": {
        "baselineLower": 0,
        "baselineUpper": 16,
        "baselineSource": "personal"
      }
    },
    "dayRest": {
      "averageMinutes": 30,
      "baseline": {
        "baselineLower": 20,
        "baselineUpper": 55,
        "baselineSource": "personal"
      }
    },
    "anomalyNights": {
      "lowNightRestCount": 0,
      "highInterruptionCount": 1,
      "highNightActivityCount": 0
    },
    "nightlyRestDurations": [
      {
        "nightDate": "2026-02-01",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-02",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-03",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-04",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-05",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-06",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-07",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-08",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-09",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-10",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-11",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-12",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-13",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-14",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-15",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-16",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-17",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-18",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-19",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-20",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-21",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-22",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-23",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-24",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-25",
        "lightMovementMinutes": 45,
        "deepRestMinutes": 405
      },
      {
        "nightDate": "2026-02-26",
        "lightMovementMinutes": null,
        "deepRestMinutes": null
      },
      {
        "nightDate": "2026-02-27",
        "lightMovementMinutes": null,
        "deepRestMinutes": null
      },
      {
        "nightDate": "2026-02-28",
        "lightMovementMinutes": null,
        "deepRestMinutes": null
      }
    ]
  }
}
```

# 6. HR(静息心率)

`metric` 固定为 `hr`,单位为 `bpm`。仅接收静息心率,不接收运动心率。夜间静息心率为主判断,全天静息心率只可作为同方向辅助证据。

## Day

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "hr",
  "viewWindow": "day",
  "locale": "zh-CN",
  "petProfile": {
    "name": "Pocky",
    "species": "dog",
    "healthRiskTags": [
      "cardiovascular"
    ]
  },
  "period": {
    "startDate": "2026-07-23",
    "endDate": "2026-07-23",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "night": {
      "startAt": "2026-07-22T21:30:00+08:00",
      "endAt": "2026-07-23T07:00:00+08:00",
      "isCompleted": true
    },
    "nightRestHrAverage": {
      "value": 66,
      "sampleCount": 6,
      "baseline": {
        "baselineLower": 58,
        "baselineUpper": 64,
        "baselineSource": "personal"
      }
    },
    "allDayRestHrAverage": {
      "value": 70,
      "sampleCount": 13,
      "baseline": {
        "baselineLower": 62,
        "baselineUpper": 68,
        "baselineSource": "personal"
      }
    },
    "hourlyPoints": [
      [],
      [],
      [
        68
      ],
      [
        66,
        67
      ],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      []
    ],
    "context": {
      "weather": "cloudy",
      "temperatureCelsius": 28,
      "humidityPct": 72
    }
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.night` | object | 是 | 以选中日结束的上一夜,含带时区的 `startAt`、`endAt` 和 `isCompleted`。 |
| `metrics.nightRestHrAverage` | object | 是 | 夜间主指标,含 `value`、`sampleCount`、`baseline`。`sampleCount` 至少 4 才能主判断。 |
| `metrics.allDayRestHrAverage` | object | 否 | 全天静息心率,含 `value`、`sampleCount`、`baseline`;至少 8 个同方向样本才可增强已触发结论。 |
| `metrics.hourlyPoints` | array<array<number>> | 否 | 固定 24 项;每项是该小时零到多个静息样本,空数组表示无样本。只解释已触发异常时段。 |
| `metrics.context` | object | 否 | `weather`、`temperatureCelsius`、`humidityPct`;只解释已有结论。 |

`value` 样本不足时为 `null`;`sampleCount=0` 时 `value` 必须为 `null`。上述 `baseline` 支持四种通用来源。

## Week

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "hr",
  "viewWindow": "week",
  "locale": "en-US",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-07-13",
    "endDate": "2026-07-19",
    "timezone": "Asia/Shanghai",
    "isCompleted": true,
    "elapsedNights": 7,
    "validNights": 6
  },
  "metrics": {
    "nightRestHrAverage": {
      "value": 66,
      "sampleCount": 36,
      "baseline": {
        "baselineLower": 58,
        "baselineUpper": 64,
        "baselineSource": "personal"
      }
    },
    "allDayRestHrAverage": {
      "value": 68,
      "sampleCount": 78,
      "baseline": {
        "baselineLower": 62,
        "baselineUpper": 68,
        "baselineSource": "personal"
      }
    },
    "dailyNightRestHr": [
      {
        "date": "2026-07-13",
        "nightRestHrAverage": 66,
        "sampleCount": 6
      },
      {
        "date": "2026-07-14",
        "nightRestHrAverage": 66,
        "sampleCount": 6
      },
      {
        "date": "2026-07-15",
        "nightRestHrAverage": 66,
        "sampleCount": 6
      },
      {
        "date": "2026-07-16",
        "nightRestHrAverage": 66,
        "sampleCount": 6
      },
      {
        "date": "2026-07-17",
        "nightRestHrAverage": 66,
        "sampleCount": 6
      },
      {
        "date": "2026-07-18",
        "nightRestHrAverage": 66,
        "sampleCount": 6
      },
      {
        "date": "2026-07-19",
        "nightRestHrAverage": null,
        "sampleCount": 0
      }
    ]
  },
  "previousPeriod": {
    "startDate": "2026-07-06",
    "endDate": "2026-07-12",
    "isCompleted": true,
    "validNights": 6,
    "nightRestHrAverage": 61,
    "allDayRestHrAverage": 65,
    "highNightRestHrCount": 0,
    "lowNightRestHrCount": 1
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.nightRestHrAverage` | object | 是 | 当前周期夜间平均;字段同 Day,`sampleCount` 是周期样本总数。 |
| `metrics.allDayRestHrAverage` | object | 否 | 当前周期全天平均;字段同 Day。 |
| `metrics.dailyNightRestHr` | array<object> | 是 | 固定 7 项,元素为 `date`、`nightRestHrAverage`、`sampleCount`。无效夜为 `null` 和 0。 |
| `previousPeriod` | object | 否 | 紧邻完整上一周;含日期、`validNights`、夜间/全天均值、`highNightRestHrCount`、`lowNightRestHrCount`。 |

Week 少于 3 个有效夜晚时不输出趋势结论。

## Month

请求结构与 HR Week 相同;必须覆盖完整自然月,逐夜数组长度等于当月天数,`previousPeriod` 是紧邻上一完整月。Month 少于 10 个有效夜晚时不输出趋势结论。

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "hr",
  "viewWindow": "month",
  "locale": "en-US",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-02-01",
    "endDate": "2026-02-28",
    "timezone": "Asia/Shanghai",
    "isCompleted": true,
    "elapsedNights": 28,
    "validNights": 25
  },
  "metrics": {
    "nightRestHrAverage": {
      "value": 65,
      "sampleCount": 150,
      "baseline": {
        "baselineLower": 58,
        "baselineUpper": 64,
        "baselineSource": "personal"
      }
    },
    "dailyNightRestHr": [
      {
        "date": "2026-02-01",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-02",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-03",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-04",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-05",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-06",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-07",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-08",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-09",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-10",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-11",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-12",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-13",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-14",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-15",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-16",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-17",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-18",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-19",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-20",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-21",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-22",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-23",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-24",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-25",
        "nightRestHrAverage": 65,
        "sampleCount": 6
      },
      {
        "date": "2026-02-26",
        "nightRestHrAverage": null,
        "sampleCount": 0
      },
      {
        "date": "2026-02-27",
        "nightRestHrAverage": null,
        "sampleCount": 0
      },
      {
        "date": "2026-02-28",
        "nightRestHrAverage": null,
        "sampleCount": 0
      }
    ]
  }
}
```

# 7. HRV(恢复状态)

`metric` 固定为 `hrv`。用户文案称“恢复状态”,数据证据是静息 HRV 的 RMSSD,单位 `ms`。不接收原始 RR 间期,不将 HRV 表述为压力、疾病或恢复能力评分。

## Day

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "hrv",
  "viewWindow": "day",
  "locale": "zh-CN",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-07-23",
    "endDate": "2026-07-23",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "night": {
      "startAt": "2026-07-22T21:30:00+08:00",
      "endAt": "2026-07-23T07:00:00+08:00",
      "isCompleted": true
    },
    "nightRestRmssdAverage": {
      "value": 42,
      "sampleCount": 6,
      "baseline": {
        "baselineLower": 45,
        "baselineUpper": 63,
        "baselineSource": "personal"
      }
    },
    "allDayRestRmssdAverage": {
      "value": 44,
      "sampleCount": 11,
      "baseline": {
        "baselineLower": 46,
        "baselineUpper": 65,
        "baselineSource": "personal"
      }
    },
    "hourlyRmssdPoints": [
      [],
      [],
      [
        41
      ],
      [
        39,
        42
      ],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      []
    ],
    "context": {
      "weather": "cloudy",
      "temperatureCelsius": 28,
      "humidityPct": 72
    }
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.night` | object | 是 | 字段和夜间完成规则同 HR Day。 |
| `metrics.nightRestRmssdAverage` | object | 是 | 夜间主指标,含 `value`、有效 RMSSD 片段数 `sampleCount`、`baseline`;至少 4 片段才能主判断。 |
| `metrics.allDayRestRmssdAverage` | object | 否 | 全天辅助指标;至少 8 个同方向片段才可增强结论。 |
| `metrics.hourlyRmssdPoints` | array<array<number>> | 否 | 固定 24 项,每项为该小时零到多个有效 RMSSD 片段;空数组表示无片段。 |
| `metrics.context` | object | 否 | 环境上下文,只解释已触发结论。 |

HRV 的所有基线仅允许 `personal`、`unavailable`。

## Week

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "hrv",
  "viewWindow": "week",
  "locale": "en-US",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-07-13",
    "endDate": "2026-07-19",
    "timezone": "Asia/Shanghai",
    "isCompleted": true,
    "elapsedNights": 7,
    "validNights": 6
  },
  "metrics": {
    "nightRestRmssdAverage": {
      "value": 42,
      "sampleCount": 36,
      "baseline": {
        "baselineLower": 45,
        "baselineUpper": 63,
        "baselineSource": "personal"
      }
    },
    "dailyNightRestRmssd": [
      {
        "date": "2026-07-13",
        "nightRestRmssdAverage": 42,
        "sampleCount": 6
      },
      {
        "date": "2026-07-14",
        "nightRestRmssdAverage": 42,
        "sampleCount": 6
      },
      {
        "date": "2026-07-15",
        "nightRestRmssdAverage": 42,
        "sampleCount": 6
      },
      {
        "date": "2026-07-16",
        "nightRestRmssdAverage": 42,
        "sampleCount": 6
      },
      {
        "date": "2026-07-17",
        "nightRestRmssdAverage": 42,
        "sampleCount": 6
      },
      {
        "date": "2026-07-18",
        "nightRestRmssdAverage": 42,
        "sampleCount": 6
      },
      {
        "date": "2026-07-19",
        "nightRestRmssdAverage": null,
        "sampleCount": 0
      }
    ]
  },
  "previousPeriod": {
    "startDate": "2026-07-06",
    "endDate": "2026-07-12",
    "isCompleted": true,
    "validNights": 6,
    "nightRestRmssdAverage": 51,
    "allDayRestRmssdAverage": 53,
    "lowNightRestRmssdCount": 1
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.nightRestRmssdAverage` | object | 是 | 当前周期夜间平均,字段同 Day。 |
| `metrics.allDayRestRmssdAverage` | object | 否 | 当前周期全天平均,字段同 Day。 |
| `metrics.dailyNightRestRmssd` | array<object> | 是 | 固定 7 项,元素为 `date`、`nightRestRmssdAverage`、`sampleCount`。 |
| `previousPeriod` | object | 否 | 紧邻完整上一周;含日期、有效夜晚、夜间/全天均值和 `lowNightRestRmssdCount`。 |

Week 少于 3 个有效夜晚时不输出周期主判断。

## Month

请求结构与 HRV Week 相同;完整自然月、逐夜数组长度和上一周期要求同 HR Month。Month 少于 10 个有效夜晚时不输出周期主判断。

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "hrv",
  "viewWindow": "month",
  "locale": "en-US",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-02-01",
    "endDate": "2026-02-28",
    "timezone": "Asia/Shanghai",
    "isCompleted": true,
    "elapsedNights": 28,
    "validNights": 25
  },
  "metrics": {
    "nightRestRmssdAverage": {
      "value": 48,
      "sampleCount": 150,
      "baseline": {
        "baselineLower": 45,
        "baselineUpper": 63,
        "baselineSource": "personal"
      }
    },
    "dailyNightRestRmssd": [
      {
        "date": "2026-02-01",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-02",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-03",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-04",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-05",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-06",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-07",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-08",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-09",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-10",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-11",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-12",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-13",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-14",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-15",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-16",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-17",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-18",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-19",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-20",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-21",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-22",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-23",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-24",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-25",
        "nightRestRmssdAverage": 48,
        "sampleCount": 6
      },
      {
        "date": "2026-02-26",
        "nightRestRmssdAverage": null,
        "sampleCount": 0
      },
      {
        "date": "2026-02-27",
        "nightRestRmssdAverage": null,
        "sampleCount": 0
      },
      {
        "date": "2026-02-28",
        "nightRestRmssdAverage": null,
        "sampleCount": 0
      }
    ]
  }
}
```

# 8. RR(呼吸状态)

`metric` 固定为 `rr`。用户文案称“呼吸状态”,数据证据是静息呼吸频率,单位 `breaths/min`。不接收呼吸波形、绝对医学阈值、品种参考或上游预计算风险评级。

## Day

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "rr",
  "viewWindow": "day",
  "locale": "zh-CN",
  "petProfile": {
    "name": "Pocky",
    "species": "dog",
    "healthRiskTags": [
      "respiratory"
    ]
  },
  "period": {
    "startDate": "2026-07-23",
    "endDate": "2026-07-23",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "night": {
      "startAt": "2026-07-22T21:30:00+08:00",
      "endAt": "2026-07-23T07:00:00+08:00",
      "isCompleted": true
    },
    "nightRestRrAverage": {
      "value": 24,
      "sampleCount": 6,
      "baseline": {
        "baselineLower": 16,
        "baselineUpper": 21,
        "baselineSource": "personal"
      }
    },
    "allDayRestRrAverage": {
      "value": 23,
      "sampleCount": 12,
      "baseline": {
        "baselineLower": 16,
        "baselineUpper": 21,
        "baselineSource": "personal"
      }
    },
    "hourlyPoints": [
      [],
      [],
      [
        22
      ],
      [
        24,
        23
      ],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      [],
      []
    ],
    "context": {
      "weather": "cloudy",
      "temperatureCelsius": 28,
      "humidityPct": 72
    }
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.night` | object | 是 | 字段和夜间完成规则同 HR Day。 |
| `metrics.nightRestRrAverage` | object | 是 | 夜间主指标,含 `value`、`sampleCount`、`baseline`;至少 4 样本才能主判断。 |
| `metrics.allDayRestRrAverage` | object | 否 | 全天辅助指标;至少 8 个同方向样本才可增强结论。 |
| `metrics.hourlyPoints` | array<array<number>> | 否 | 固定 24 项;单小时零到多个有效静息呼吸样本。 |
| `metrics.context` | object | 否 | 环境上下文,只解释已触发结论。 |

RR 的所有基线仅允许 `personal`、`unavailable`。

## Week

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "rr",
  "viewWindow": "week",
  "locale": "en-US",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-07-13",
    "endDate": "2026-07-19",
    "timezone": "Asia/Shanghai",
    "isCompleted": true,
    "elapsedNights": 7,
    "validNights": 6
  },
  "metrics": {
    "nightRestRrAverage": {
      "value": 22,
      "sampleCount": 36,
      "baseline": {
        "baselineLower": 16,
        "baselineUpper": 21,
        "baselineSource": "personal"
      }
    },
    "dailyNightRestRr": [
      {
        "date": "2026-07-13",
        "nightRestRrAverage": 22,
        "sampleCount": 6
      },
      {
        "date": "2026-07-14",
        "nightRestRrAverage": 22,
        "sampleCount": 6
      },
      {
        "date": "2026-07-15",
        "nightRestRrAverage": 22,
        "sampleCount": 6
      },
      {
        "date": "2026-07-16",
        "nightRestRrAverage": 22,
        "sampleCount": 6
      },
      {
        "date": "2026-07-17",
        "nightRestRrAverage": 22,
        "sampleCount": 6
      },
      {
        "date": "2026-07-18",
        "nightRestRrAverage": 22,
        "sampleCount": 6
      },
      {
        "date": "2026-07-19",
        "nightRestRrAverage": null,
        "sampleCount": 0
      }
    ]
  },
  "previousPeriod": {
    "startDate": "2026-07-06",
    "endDate": "2026-07-12",
    "isCompleted": true,
    "validNights": 6,
    "nightRestRrAverage": 20,
    "allDayRestRrAverage": 20,
    "highNightRestRrCount": 0
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.nightRestRrAverage` | object | 是 | 当前周期夜间平均,字段同 Day。 |
| `metrics.allDayRestRrAverage` | object | 否 | 当前周期全天平均,字段同 Day。 |
| `metrics.dailyNightRestRr` | array<object> | 是 | 固定 7 项,元素为 `date`、`nightRestRrAverage`、`sampleCount`。 |
| `previousPeriod` | object | 否 | 紧邻完整上一周;含日期、有效夜晚、夜间/全天均值和 `highNightRestRrCount`。 |

Week 少于 3 个有效夜晚时不输出周期主判断。

## Month

请求结构与 RR Week 相同;完整自然月、逐夜数组长度和上一周期要求同 HR Month。Month 少于 10 个有效夜晚时不输出周期主判断。

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "rr",
  "viewWindow": "month",
  "locale": "en-US",
  "petProfile": {
    "name": "Pocky",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-02-01",
    "endDate": "2026-02-28",
    "timezone": "Asia/Shanghai",
    "isCompleted": true,
    "elapsedNights": 28,
    "validNights": 25
  },
  "metrics": {
    "nightRestRrAverage": {
      "value": 20,
      "sampleCount": 150,
      "baseline": {
        "baselineLower": 16,
        "baselineUpper": 21,
        "baselineSource": "personal"
      }
    },
    "dailyNightRestRr": [
      {
        "date": "2026-02-01",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-02",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-03",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-04",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-05",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-06",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-07",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-08",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-09",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-10",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-11",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-12",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-13",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-14",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-15",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-16",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-17",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-18",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-19",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-20",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-21",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-22",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-23",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-24",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-25",
        "nightRestRrAverage": 20,
        "sampleCount": 6
      },
      {
        "date": "2026-02-26",
        "nightRestRrAverage": null,
        "sampleCount": 0
      },
      {
        "date": "2026-02-27",
        "nightRestRrAverage": null,
        "sampleCount": 0
      },
      {
        "date": "2026-02-28",
        "nightRestRrAverage": null,
        "sampleCount": 0
      }
    ]
  }
}
```

# 9. Bark(吠叫状态)

`metric` 固定为 `bark`,时长单位为秒。Bark 基线仅允许 `personal`、`unavailable`。不接收原始音频、声学特征、具体地址、坐标、绝对医学阈值或疾病风险评分。

## Day

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "bark",
  "viewWindow": "day",
  "locale": "zh-CN",
  "petProfile": {
    "name": "Milo",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-07-23",
    "endDate": "2026-07-23",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "wearingMinutes": 960,
    "barkDurationSeconds": 106,
    "barkEventCount": 2,
    "longestBarkEventDurationSeconds": 84,
    "baseline": {
      "baselineLower": 80,
      "baselineUpper": 160,
      "baselineSource": "personal"
    },
    "barkEvents": [
      {
        "startAt": "2026-07-23T18:42:10+08:00",
        "endAt": "2026-07-23T18:42:32+08:00",
        "durationSeconds": 22,
        "intensity": "medium",
        "locationType": "home"
      },
      {
        "startAt": "2026-07-23T20:03:30+08:00",
        "endAt": "2026-07-23T20:04:54+08:00",
        "durationSeconds": 84,
        "intensity": "high",
        "locationType": "home"
      }
    ]
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.wearingMinutes` | integer | 是 | 唯一覆盖指标,范围 0-1440;少于 720 时只展示已识别事实。 |
| `metrics.barkDurationSeconds` | integer | 是 | 必须等于所有事件 `durationSeconds` 之和。 |
| `metrics.barkEventCount` | integer | 是 | 必须等于 `barkEvents` 长度。 |
| `metrics.longestBarkEventDurationSeconds` | integer | 是 | 必须等于事件最大时长;无事件时为 0。 |
| `metrics.baseline` | Baseline | 是 | 吠叫总时长基线,仅可使用 `personal`、`unavailable`。 |
| `metrics.barkEvents` | array<object> | 是 | 当天事件明细;无事件传空数组。 |
| `metrics.barkEvents[].startAt` / `endAt` | string(date-time) | 是 | 带时区、位于请求 Day 内,且结束晚于开始。 |
| `metrics.barkEvents[].durationSeconds` | integer | 是 | 必须与起止时间差一致。 |
| `metrics.barkEvents[].intensity` | enum | 是 | `low`、`medium`、`high`;由上游识别,Gateway 不按时长推断。 |
| `metrics.barkEvents[].locationType` | enum | 是 | `home`、`outdoor`、`unknown`;不传具体地址或坐标。 |

## Week

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "bark",
  "viewWindow": "week",
  "locale": "zh-CN",
  "petProfile": {
    "name": "Milo",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-07-13",
    "endDate": "2026-07-19",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "wearingMinutes": 5940,
    "averageDailyBarkDurationSeconds": 139.0,
    "barkEventCount": 31,
    "anomalyDayCount": 2,
    "dailyBarkDurations": [
      {
        "date": "2026-07-13",
        "wearingMinutes": 840,
        "barkDurationSeconds": 80,
        "isAnomaly": false
      },
      {
        "date": "2026-07-14",
        "wearingMinutes": 900,
        "barkDurationSeconds": 260,
        "isAnomaly": true
      },
      {
        "date": "2026-07-15",
        "wearingMinutes": 840,
        "barkDurationSeconds": 120,
        "isAnomaly": true
      },
      {
        "date": "2026-07-16",
        "wearingMinutes": 840,
        "barkDurationSeconds": 130,
        "isAnomaly": false
      },
      {
        "date": "2026-07-17",
        "wearingMinutes": 840,
        "barkDurationSeconds": 127,
        "isAnomaly": false
      },
      {
        "date": "2026-07-18",
        "wearingMinutes": 840,
        "barkDurationSeconds": 128,
        "isAnomaly": false
      },
      {
        "date": "2026-07-19",
        "wearingMinutes": 840,
        "barkDurationSeconds": 128,
        "isAnomaly": false
      }
    ]
  },
  "previousPeriod": {
    "startDate": "2026-07-06",
    "endDate": "2026-07-12",
    "isCompleted": true,
    "averageDailyBarkDurationSeconds": 90,
    "barkEventCount": 22,
    "anomalyDayCount": 1
  }
}
```

| 字段名 | 数据类型 | 必须 | 详细说明 |
|---|---|---:|---|
| `metrics.wearingMinutes` | integer | 是 | 当前周总佩戴分钟,仅用于说明;周期判断由逐日佩戴决定。 |
| `metrics.averageDailyBarkDurationSeconds` | number | 是 | 可用逐日时长的日均值。 |
| `metrics.barkEventCount` | integer | 是 | 周期内识别事件总数。 |
| `metrics.anomalyDayCount` | integer | 是 | 必须等于 `isAnomaly=true` 的日期数。 |
| `metrics.dailyBarkDurations` | array<object> | 是 | 固定 7 项,按日期连续排列。元素含 `date`、`wearingMinutes`、`barkDurationSeconds`、`isAnomaly`。 |
| `metrics.dailyBarkDurations[].isAnomaly` | boolean/null | 是 | `true` 表示上游已在佩戴达标且个人基线可用时判为高于上限;`false` 为已判断未偏高;`null` 为不可判断。 |
| `previousPeriod` | object | 否 | 紧邻完整上一周;含日均时长、事件数、异常日数。 |

Week 少于 3 个佩戴至少 720 分钟的日期时返回数据不足。

## Month

请求结构与 Bark Week 相同;必须覆盖完整自然月,`dailyBarkDurations` 长度等于当月天数,`previousPeriod` 是紧邻上一完整月。Month 少于 10 个佩戴至少 720 分钟的日期时返回数据不足。

```json
{
  "schemaVersion": "health-detail-v3",
  "userId": "user-1",
  "petId": "pet-1",
  "metric": "bark",
  "viewWindow": "month",
  "locale": "en-US",
  "petProfile": {
    "name": "Milo",
    "species": "dog"
  },
  "period": {
    "startDate": "2026-02-01",
    "endDate": "2026-02-28",
    "timezone": "Asia/Shanghai",
    "isCompleted": true
  },
  "metrics": {
    "wearingMinutes": 23520,
    "averageDailyBarkDurationSeconds": 100,
    "barkEventCount": 140,
    "anomalyDayCount": 0,
    "dailyBarkDurations": [
      {
        "date": "2026-02-01",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-02",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-03",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-04",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-05",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-06",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-07",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-08",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-09",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-10",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-11",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-12",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-13",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-14",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-15",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-16",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-17",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-18",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-19",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-20",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-21",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-22",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-23",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-24",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-25",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-26",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-27",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      },
      {
        "date": "2026-02-28",
        "wearingMinutes": 840,
        "barkDurationSeconds": 100,
        "isAnomaly": false
      }
    ]
  },
  "previousPeriod": {
    "startDate": "2026-01-01",
    "endDate": "2026-01-31",
    "isCompleted": true,
    "averageDailyBarkDurationSeconds": 96,
    "barkEventCount": 104,
    "anomalyDayCount": 1
  }
}
```

## 10. 主服务调用检查清单

1. 所有请求使用 `health-detail-v3`。
2. 主服务按 `period.timezone` 切分本地自然日、自然周和自然月。
3. 固定长度数组按日期升序补齐;文档中的请求 JSON 示例必须可直接通过本契约校验。
4. 统计值、计数和最长值必须从同一批事实聚合并满足文中相等关系。
5. 没有数据时按字段要求传 `null`,不能以 0 伪造缺失数据。
6. 基线不可用时使用 `unavailable` 和两个 `null` 边界。
7. `previousPeriod` 只能是根级、紧邻、同类型且已完成的上一周期;缺失时只跳过环比规则。
8. 收到 `422` 时按 `details[].loc` 修复调用方字段或聚合,不应对同一非法请求重试。