Files
lixi 222990e587
CI / docs-build (push) Successful in 1m19s
docs: M2 第二波收口——报告 13~21 与契约草案入档挂导航
- 13~18 后端纵切六单报告(T2-03~08,测试 95→182)
- 14 + openapi-pets-draft.yaml 契约起草档案
- 19 契约冻结报告(v1.2.0,22 项草案修正对照)
- 20 契约一致性测试(快照机制 + 1 漂移修复)
- 21 第二波收口总表(定型语义汇总,第三波接入依据)
- mkdocs build --strict 通过

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-08 10:40:27 +08:00

118 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 19 · T2-09 契约冻结报告:pets 域 12 路径合入正典(v1.2.0
- **日期**2026-09-08
- **工单**:T2-09(M2 第二波,契约冻结)
- **仓库**patbond-docmain 分支
- **角色**API 契约工程师
- **结论先行**`docs/api/openapi.yaml` 由 1.1.06 路径)升至 **1.2.018 路径 / 24 操作 / 45 schema**pets 域 12 路径按 13/16/17/18 号定型表修正草案后合入;新增错误码 8 个(40300/40401/40402/40902/40903/40904/42201/42202,其中 40903/40904/42201/42202 为 M2 新引入,42200 不引入);校验通过(YAML 解析、$ref 全解析、`mkdocs build --strict`)。**自本报告起 pets 域契约冻结。**
---
## 1. 冻结端点总表(12 路径 / 18 操作)
| # | 端点 | 操作 | 权限档 | 成功 | 分页/排序 | 幂等 | 定型依据 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | `/api/v1/pets` | GET | 隐式(按 pet_owners 过滤) | 200 数组 | 不分页,created_at DESC | — | 13 §2.1 |
| 2 | `/api/v1/pets` | POST | 任何登录用户 | **201** | — | 无键(唯一约束兜底) | 13 §2.1/§2.4 |
| 3 | `/api/v1/pets/{petId}` | GET | READ | 200(含 myRole | — | — | 13 §2.1 |
| 4 | `/api/v1/pets/{petId}` | PATCH | MANAGE(仅 owner | 200 | — | 乐观锁 version | 13 §2.1/§2.3 |
| 5 | `/api/v1/breeds` | GET | 仅 Bearer(字典) | 200 数组 | 不分页,sort_order | — | 13 §2.1 |
| 6 | `/api/v1/pets/{petId}/weights` | GET | READ | 200 分页信封 | cursormeasured_at DESC, id DESC | — | 16 §1 |
| 7 | `/api/v1/pets/{petId}/weights` | POST | WRITE | **201** | — | 可选 Idempotency-Key | 16 §1/§3 |
| 8 | `/api/v1/vaccine-catalog` | GET | 仅 Bearer(字典) | 200 数组 | 不分页,species, name | — | 16 §1 |
| 9 | `/api/v1/pets/{petId}/vaccinations` | GET | READ | 200 数组 | **不分页**series_key, dose_no, created_at, id | — | 16 §1(偏差 #6 |
| 10 | `/api/v1/pets/{petId}/vaccinations` | POST | WRITE | **201** | — | 可选 Idempotency-Key | 16 §1/§3 |
| 11 | `/api/v1/vaccinations/{vaccinationId}` | PATCH | WRITE | 200 | 顶层短路径 | 乐观锁 version | 16 §114 号裁量 #1 照采) |
| 12 | `/api/v1/pets/{petId}/health-events` | GET | READ | 200 分页信封 | cursoroccurred_at DESC, id DESC | — | 17 §1 |
| 13 | `/api/v1/pets/{petId}/health-events` | POST | WRITE | **201** | — | 可选 Idempotency-Key | 17 §1 |
| 14 | `/api/v1/health-events/{eventId}` | PATCH | WRITE | 200 | 顶层短路径 | 乐观锁 version | 17 §1 |
| 15 | `/api/v1/pets/{petId}/care-reminders` | GET | READ | 200 数组 | **不分页**due_at ASC, id`?status=` 过滤 | — | 17 §1(偏差 #4 |
| 16 | `/api/v1/pets/{petId}/care-reminders` | POST | WRITE | **201** | — | 可选 Idempotency-Key | 17 §1(偏差 #5,拍板 B |
| 17 | `/api/v1/care-reminders/{reminderId}` | PATCH | WRITE | 200 | 顶层短路径 | 状态守卫(无 version 列) | 17 §1/§2.2(偏差 #6 |
| 18 | `/api/v1/pets/{petId}/summary` | GET | READ | 200 | `?tz=` IANA,缺省 UTC | — | 18 §1/§2/§3 |
**软删除端点 `DELETE /api/v1/pets/{petId}` 不进 M2 契约**(拍板 B;D2-7 首版仅归档,13 §1 明确不在单)。
### 汇总数
| 维度 | 1.1.0 | 1.2.0 |
| --- | --- | --- |
| 路径 | 6 | **18**+12 |
| 操作 | 6 | **24**+18 |
| schema | 15 | **45**+30 |
| 错误码(业务码,不含 0) | 10 | **18**+840300/40401/40402/40902/40903/40904/42201/42202 |
| 复用组件 | — | 新增 responses 4PetNotFound/RecordNotFound/PetWriteDenied/VersionConflict)、parameters 4PetIdParam/PageLimitParam/PageCursorParam/IdempotencyKeyHeader |
## 2. 草案 → 冻结的全部修正项对照(22 项)
草案 = `openapi-pets-draft.yaml` + 14 号起草报告;修正一律以实现定型表为准(实现定型表 > 草案)。
### 2.1 错误码(拍板 A1
| # | 草案 | 冻结定案 | 依据 |
| --- | --- | --- | --- |
| 1 | 剂次重复用 40903 | **40904 VACCINATION_DOSE_EXISTS**40903 已被 T2-03 的 MICROCHIP_EXISTS 占用,按「不复用不改号」顺延) | 16 §4、偏差 #1 |
| 2 | 42200 BREED_CONSTRAINT_VIOLATION(品种互斥 422 | **不引入**;品种双填/双空/物种错配/品种不存在或停用一律 400/40000 | 13 §2.4、16 偏差 #2 |
| 3 | 42201 疫苗状态机(草案提议) | **照采**,语义定为疫苗专属 VACCINATION_RULE_VIOLATION | 16 §4 |
| 4 | 提醒 422 复用 42201 | **42202 REMINDER_RULE_VIOLATION(新增)**,跨资源不复用错误码 | 17 §4、偏差 #1 |
| 5 | 草案无 40903 芯片号语义 | **40903 MICROCHIP_EXISTS 新增**POST/PATCH pets 的 409 分支) | 13 §2.4 |
### 2.2 响应形态与命名(拍板 A2)
| # | 草案 | 冻结定案 | 依据 |
| --- | --- | --- | --- |
| 6 | 资源主键用类型化名(petId/weightId/vaccinationId/eventId/reminderId14 号裁量 #7 | **裸 `id`**,关联字段保留类型名(petId/vaccineId 等);路径参数名不变 | 16 偏差 #3、17 偏差 #2 |
| 7 | Vaccination 无疫苗名称 | 响应**增加 `vaccineName`**(同 breedDisplayName 先例) | 16 偏差 #4 |
| 8 | Pet 无 breedDisplayName;列表 Pet 不带 myRole14 号裁量 #8 | **增加 `breedDisplayName`****myRole 进全部宠物响应**(列表/详情/创建/更新统一 Pet schemaPetDetail 撤销) | 13 §2.2 |
| 9 | Pet 含 avatarAssetId(只读回显)、status 枚举含 deleted | **avatarAssetId 移除**(ADR-010 整体不出现);响应 status 枚举去 deleted(软删宠物一律 404/40401,永不返回) | 13 §2.2/§2.4 |
| 10 | 创建 201、分页信封 `{items, nextCursor, hasMore}`(草案形态) | **照采并升格为全 API 分页正典**,写入 info 通用约定 | 拍板 A2、16 §1.1 |
### 2.3 分页与列表(拍板 A3)
| # | 草案 | 冻结定案 | 依据 |
| --- | --- | --- | --- |
| 11 | 疫苗列表分页待定(TODO-FREEZE #5 | **不分页**`series_key, dose_no, created_at, id` 排序定死;列表不过滤 status | 16 偏差 #6 |
| 12 | 提醒列表分页/待办过滤待定(TODO-FREEZE #8 | **不分页** + `?status=` 白名单过滤,`due_at ASC, id` 排序 | 17 偏差 #4 |
| 13 | GET /pets 是否分页待定(TODO-FREEZE #2 | **不分页**created_at DESC | 13 §2.1 |
| 14 | 列表 GET 无 400 分支 | 补 400/40000limit 越界、cursor 无效、status/species 非法参数) | 13 §2.4、16 §4、17 §4 |
### 2.4 PATCH 语义与请求体(拍板 A4/B)
| # | 草案 | 冻结定案 | 依据 |
| --- | --- | --- | --- |
| 15 | Update 请求字段标 nullable(暗示可清空) | **缺席=不变,不支持清空回 null**,三个 Update schema 全部去 nullable;宠物品种对为唯一例外(整体替换) | 13 §2.3、16 偏差 #7、17 偏差 #3 |
| 16 | UpdatePetRequest 权限待定(TODO-FREEZE #4 | MANAGE 仅 ownerspecies 不可改;status=deleted 经 PATCH 一律 400/40000 | 13 §2.1/§2.3 |
| 17 | CreateVaccinationRequest.status 含 cancelled | 创建仅 **scheduled/completed**(创建即取消 400/40000 | 16 偏差 #5 |
| 18 | UpdateVaccinationRequest 可改 vaccineId/seriesKey/doseNo?(草案未禁) | **不可改**(不在请求体),修正路径 cancel 后重建;completed/cancelled 均为终态 | 16 §1.2/§2 |
| 19 | care-reminders PATCH 无 409 | **补 409/40902**(无 version 列,当前状态条件更新守卫落空) | 17 偏差 #6、§2.2 |
| 20 | 顶层短路径待拍板(TODO-FREEZE #11 | **照采**;40402 定型为记录级防枚举(记录不存在与所属宠物不可见响应完全一致);40401 定型为宠物级防枚举(不存在/软删/无关系一致) | 拍板 A4、13 §2.4、16 §4 |
### 2.5 PetSummary 与其它(拍板 A5/B
| # | 草案 | 冻结定案 | 依据 |
| --- | --- | --- | --- |
| 21 | PetSummary 全 schema 占位(TODO-FREEZE #9/#10 | 按 18 §2 全量替换:`nextVaccination``dueOn`+`source(planned|nextDue)` 替代单一 plannedOn,增加 vaccinationId/vaccineId/doseNo/doseLabel`monthlyExpense` 恒非 null、增 timezone 回显、month 定 ISO year-month;进度分母 = 已登记剂次;无记录 null 语义(progress null ≠ 0/0);四项聚合口径**逐字**进 schema 描述;新增 `tz` 查询参数(IANA,缺省 UTC,非法 40000 | 18 §2/§3 |
| 22 | 实现侧收紧补进契约描述 | 疫苗须存在/enabled/物种匹配(40000);doseNo ≤32767health-event notes ≤2000amountCents 拒绝小数(40000,不静默截断);title btrim 空白 40000;创建提醒不收 statuscreatedByUserId 取自 token 不收请求体;Idempotency-Key 语义细则(≤255、调用者×宠物×资源隔离、不比对请求体、无 TTL) | 16 §5 末段、17 §4/§6 末段 |
## 3. 定型表间矛盾核查
逐项交叉核对 13/16/17/18 号定型表:**未发现互相矛盾处**(40902 在提醒流转守卫上的复用为 17 号显式定型,非撞号;42201/42202 分立与「不复用不改号」原则自洽;防枚举语义 13→16→17 单点继承一致;18 号聚合口径与 16 号「聚合侧自行排除 cancelled」的移交一致)。
**一处拍板措辞与定型表的出入(已按定型表执行,非仲裁)**:拍板 B 组表述为「Idempotency-Key 为可选头(weights/health-events/care-reminders 三个 POST)」,未列 vaccinations POST;而 16 号定型表明确 `POST .../vaccinations` 支持可选 Idempotency-Key 且有测试锁定(同键两次 201 同 id、落库 1 行),草案亦本已声明该头(14 号裁量 #6,三个 POST 含 vaccinations)。判断拍板枚举的是「本次需拍板的三处」(care-reminders 为 17 号新增偏差 #5weights/health-events 为可选性确认),vaccinations 属草案既有、无争议项。冻结契约按实现收录**四个** POST 的可选 Idempotency-Key。若此判断与拍板本意不符,请显著上报——收窄为三个属于从契约中移除已实现并已测试的行为,需两端同步。
## 4. 冻结纪律声明
自 v1.2.0 起,pets 域 12 路径与全部 schema/错误码**冻结**
1. **任何字段变更(增、删、改名、改类型、改必填性、改枚举、改口径)须显著上报**,经评审后走契约变更流程,**两端(后端 patbond-api、客户端 patbond-flutter)同步**,禁止任一侧单方面偏离。
2. 纯增量扩展(新增可选响应字段、新增端点、新增错误码)允许在次版本内追加,但同样先改契约再改实现(契约先行,docs/api/index.md 约定)。
3. 错误码永不复用、永不改号、永不改义(40903=MICROCHIP_EXISTS、40904=VACCINATION_DOSE_EXISTS、42201=疫苗专属、42202=提醒专属,已在错误码表定死)。
4. 已知的未来破坏性调整须走上报流程的存量项:① totalDoses 分母若引入「系列应打总针数」(18 §6);② 幂等键无 TTL 若改为 idempotency 表 + TTL16 §7);③ ADR-010 裁剪字段(avatar/certificate/provider/bookingM5 按纯增量补入(非破坏性,但须契约先行)。
5. 提醒的 title/dueAt 编辑与删除端点、宠物软删除端点均**不在** M2 契约;M2 内改期路径为 dismiss 后重建(17 §7),归档经 `PATCH status=archived`
## 5. 校验与提交
- `python3 yaml.safe_load` 解析通过;158 个 `$ref` 全部可解析;18 路径 / 24 操作 / 45 schema / 错误码表 19 行计数核对一致。
- `mkdocs build --strict` 通过。
- 提交:`docs/api/openapi.yaml` + `docs/api/index.md` 独立提交并推送 main(提交 `511617b`);本报告与草案文件(14 号、openapi-pets-draft.yaml)按波末统一入档,暂不提交;mkdocs.yml 未动。