---
type: plan
node_id: plan:response-observability-fields
title: 响应可观测字段扩展实现计划
date: 2026-07-31
---

# 响应可观测字段扩展实现计划

全文见 `2026-07-31-response-observability-fields.md`。实现 [[response-observability-fields]] 设计(A2/B1/C1/D1)。

## 任务序列

| 任务 | 内容 | 提交 |
|---|---|---|
| T1 | `types.py` 两个类型各 +2 字段;`cache_hit` docstring 消歧 | 独立 |
| T2 | `openai_compat.py` 防御解析 + SSE sink 采集 `model` + 两处构造填值 | 独立 |
| T3 | `retry.py` 搬运;`cache.py` 零改动但用测试固化 B1 回放语义 | 独立 |
| T4 | `pricing.py` 可选缓存单价档 + 夹取防负 | 独立 |
| T5+T6 | 端口 18→20、两后端 DDL 加列与幂等补列、emitter 搬运、契约测试 | **必须合一次提交** |
| T7 | ARCHITECTURE §7.8 / CHANGELOG / `.env.example:56` / 6 处「18 字段」措辞 / 版本 1.1.0 / Gitea Wiki 站 | 独立 |

## 独立审查抓出的四个坑(已折回计划)

1. **DDL 新列必须放在 `created_at` 之后**(表末尾)。旧表走 `ALTER ADD COLUMN` 只能追加到末尾,若新建库把新列插在 `created_at` 前,两条路径列序分叉 —— 而 `test_schema_has_frozen_columns_in_order` 按 `ordinal_position` 逐位断言,且该 PG 表与真实批跑共享、严禁 DROP,分叉后无合规修法。
2. **SQLite 补列块首行必须守卫 `if self._conn is None: return`**。否则初始化失败时补列块抛 `AttributeError`/`NameError`(不被 `sqlite3.Error` 捕获)逃出 `__init__`,打破「初始化失败静默降级」契约。
3. **T5 与 T6 不得分开提交**。中间状态下 emitter 只传 18 键,后端抛 `KeyError` 被吞成 warning，该 commit 全量遥测静默丢失。
4. **天然拦截点是四处而非三处**:两个 `_record_minimal` + 两个 `_EXPECTED_COLUMNS`;`test_ports.py:96` 的全签名 fake **不会**红(Protocol 的 isinstance 不校验签名),不能当作覆盖保证。

相关: [[response-observability-fields]]、[[est-tokens-decoupling]]
