80aa2b216d
The tenant_id rule was wrong in a way that would have shipped: the plan said reject when strip() is empty, but the design says reject leading and trailing whitespace outright. " t1" survives the weaker rule and then compares unequal to "t1" inside an RLS policy, so a caller who pads the value silently loses rows. Adds the test that guards a promise nothing else was guarding -- same messages and namespace with different meta must still hit the cache. Without it, folding meta into the key passes every other assertion and costs a full cache cold start plus a permanently lower hit rate, which degrades quietly instead of failing. Also pins _record's new parameter positions, splits the backfill-failure setup per backend (ownership check on PG, read-only file on SQLite, and says what SQLite cannot assert), puts the red-green gate on the integration task, and names the two wiki pages.
18 lines
2.1 KiB
Markdown
18 lines
2.1 KiB
Markdown
---
|
|
type: plan
|
|
node_id: plan:issue11-caller-dimensions
|
|
title: "调用方自定义维度实现计划(issue #11)"
|
|
date: 2026-08-17
|
|
---
|
|
|
|
# 调用方自定义维度实现计划(issue #11)
|
|
|
|
正文: `2026-08-17-issue11-caller-dimensions.md`(249 行,8 个任务)。实现 `design:issue11-caller-dimensions`。
|
|
|
|
- **任务顺序**: 端口与两个遥测后端(Task 2)先于三条调用链(Task 4/5/6)落地——后者写入的字段必须已有列可落。Task 1(校验函数 + `ChatRequest` 字段)是全部任务的前置。
|
|
- **计划阶段的新发现**: 设计只覆盖 `chat()`/`embed()`,核实代码发现**第三条遥测链路**——`OcrClient` 经同一 `TelemetryEmitter.emit_attempt` 写遥测(`ocr.py:426`),`_emit` 在 `ocr.py:398` 现场构造 `ChatRequest`,与 embedding 同构。OCR 行与 chat 行落**同一张表**,漏掉则多租户审计链缺一块且同样不可逆。列为 Task 6 并标注**超出已批准设计的字面范围**(与 issue #10 先例一致: 那次 issue 只报告 chat 的 400,OCR 被认定为同一缺陷的其余分支而一并修);可以不做,但必须在 CHANGELOG 声明"OCR 行不带调用方维度",**不得静默跳过**。
|
|
- **把 issue 的核心论点钉成测试**: Task 7 要求手工建 22 列旧表 → 用当前 recorder 打开 → 断言老行 `tenant_id` 读回**空串而非 NULL**。这直接验收 issue「先启用后加列则归属无法还原」的论点,且断言方向选空串是因为 NULL 在 RLS policy 下是对所有人永久不可见的黑洞,而非"未归属"。
|
|
- **几处易实现反的地方已写进验收**: `emit_cache_hit` 必须读**本次请求**的维度而非缓存中历史响应的(构造"请求属租户 A、缓存历史属租户 B"的用例断言落 A);`embed()` 多批时**每一批**的行都要带同一份维度(只断言首行会漏掉"只有第一批带维度"的实现);非法输入必须 `ValueError` 且 recorder **零调用**(证明校验早于遥测)。
|
|
- **不做的事**: 不把 embedding/OCR 链上已有的四个同类参数收成值对象(任务外重构);不建索引、不启用 RLS(库只交付模板,执行是下游 DBA 职责)。
|
|
|