队列:义父 01:1x 令「P1→P5」,P2=新包优先验(含 A5 基线复核)。P1 已交付推送 a658e4c2,交单当刻切 P2。
四态:PASS / PASS-附条件 / BLOCKED / FAIL。本岗只验判据与证据,不替执行席签实施验收。
一、新包清单与四态签字
| 包 | 内容 | 判定 | 核心依据 |
Q1(b607fbb9) | 插第二 active 目的地 id=3 [测试]雪线之外-白标B端实例(staging) | PASS-附条件 | 335 造数缺口(我 00:3x 提出)已补 ⇒ 环境解锁;🔴 附条件=「所有不带目的地上下文的旧请求一律 409」表述过宽(实测见 §1.1) |
Q2 批1(1bb985ba) | 占用口径按目的地收敛:改公共常量 _OCCUPIED_WHERE 加 AND (destination_id = $5 OR IS NULL) | PASS-附条件 | 常量一处覆盖三处属实;🔴 附条件=存在一条不经常量的直写 SQL(见 §1.2) |
Q2 批2(1bb985ba) | confirm(conn, hold_key, destination_id=None) 跨目的地 403「不属于当前目的地上下文」 | 🔴 PASS-未接线 | 实现正确但唯一调用点未传参 ⇒ 真实链路零生效(见 §1.3) |
1.1 Q1 —— 实测与表述的偏差(须澄清,不判 FAIL)
实测(staging 100.64.1.230:8089,本岗 curl,三条):
| 请求 | 返回 | 说明 |
/health | 200 | 无需目的地上下文,合理 |
/api/miniapp/config/site | 200(返回 brandName=神山秘境) | 🔴 未见 409 |
/api/miniapp/admin/destinations | 401 未登录 | 无凭证,测不到 409 |
核证:GET /api/miniapp/config/site(backend/app/routers/miniapp_site.py)代码中完全不出现 destination/resolve/default ⇒ 它是平台级全局配置端点,不走目的地解析,因此不受多 active 目的地 409 约束。
⇒ 结论 1:Q1「所有不带目的地上下文的旧请求/脚本现在都会 409」表述过宽。真实口径应为「走 resolve_destination/_default_destination 的端点在多 active 时回落失效、抛 409」。
⇒ 结论 2(对剧本的硬影响):剧本 2.3「C 端读到 data.brandName == t_demo」 若以 config/site 为读出口,该判据不成立(此端点不按目的地返回)。须由 R1/冈子澄清:C 端品牌是运行时读接口,还是白标构建期注入。澄清前 2.3 判 BLOCKED-待澄清。
1.2 Q2 批1 —— 覆盖属实,但有一条漏网
- ✅ 属实:
_OCCUPIED_WHERE(services/inventory.py:30)被 _OCCUPIED_SQL、held 查询、confirmed 查询三处复用 ⇒ 改一处即全收敛,小齐说法正确。 - 🔴 漏网:
routers/inventory.py:154 GET /holds/{hold_key} 直写 SELECT * FROM inventory_holds WHERE hold_key=$1 —— 不经常量、不带目的地 ⇒ 凭 hold_key 可查到任意目的地的占用记录。 - 缓解因素:需
require_admin + 需已知 hold_key + 单条读 ⇒ 中风险,非超卖面。 - ⇒ 建议小齐补(Q2 后续批次):
get_hold / release_hold 同样收敛(release 目前也未传 destination_id)。
1.3 Q2 批2 —— 实现正确但未接线(本轮最硬发现)
- 实现:
services/inventory.py:222 confirm(conn, hold_key, destination_id=None),destination_id 非 None 时做归属校验、跨目的地 403。 - 🔴 唯一调用点未传参:
routers/inventory.py:131 row = await inv.confirm(conn, hold_key) —— 不传 destination_id ⇒ 恒走 None 分支(:228)⇒ 归属校验零生效,跨目的地 hold_key 照样 confirm。 - 且该端点签名
confirm_hold(hold_key, user) 没有 destination 上下文来源(不像 admin 三域有 resolve_destination)⇒ 即便想传也无参可传。 - ⇒ 定性:批2 已实现、未接线(与我在 WIP-352 报的「admin 隔离是声明式非授权式」同族:能力在库里,调用方没用上)。
- ⇒ 判据影响:335 第四幕若含「库存 confirm 跨目的地应 403」的判据,当前必然失败 ⇒ 判 BLOCKED-待接线,不得因「代码里有 403」而判 PASS。
二、A5 基线复核(P0 界定 · error-contract.md §13 待确认项)
A5 原文:P0 界定(P0-A∪P0-B = 91 条)是否认可;影响=完备率分母不成立。
2.1 三处数字打架(脚本实跑为准)
| 出处 | 端点基线 | P0 条数 | 时点 |
role-matrix.md v1.0 | 挂载 407 / 定义 410 | 90 | 2026-09-14 08:12 |
error-contract.md §13 A5 | (沿用 B01) | 91 | 待确认 |
check_role_matrix.py 实跑(本轮) | 挂载 424 / 定义 427 / 模块 64 | 92 | 2026-09-16 01:3x |
2.2 复核结论
- 端点基线已漂移 +17:407 → 424(定义 410 → 427,模块 60 → 64)。⇒ 所有以 407 为分母的比率(含「五维完备率 9%」)当前全部失真,引用前必须重跑。
- P0 计数:脚本实跑 P0-A 34 ∪ P0-B 69 = 92(并集去重 11 条)。旧值 90/91 不是算错,是基于旧端点集过期 ⇒ 建议 A5 以脚本复算值为准(92),并在文档写明「随端点基线滚动」。
- P0 结构风险(A5 应当一并确认):
- P0 中无角色约束(anon/user)42 条;
- 全量 anon 端点 48,其中写方法 5 个(🔴 匿名可写);
- 调用
build_identity() 的端点 181,真正校验 permissions 字符串的端点 0(老账未变)。 - 路由门禁同步复跑:ERROR 仍 2 条(
merchants.py 孤儿 + routers/main.py ORPHAN-APP),本轮新包未引入新孤儿 ✅。
三、对 335 剧本的影响(三条,须回写剧本)
| # | 影响 | 处置 |
| 1 | Q1 使多 active 目的地成立 ⇒ 走 resolve_destination 的端点回落失效、抛 409 | 剧本 N2(多目的地 ops 应 409)从「BLOCKED-环境不满足」转为「可实测」 ✅ |
| 2 | Q1「一律 409」表述过宽 ⇒ 各席可能误改脚本 | 剧本须写明 409 只作用于走目的地解析的端点;config/site、/health 等全局端点不受影响 |
| 3 | 🔴 剧本 2.3「C 端读到 t_demo 品牌」若以 config/site 为出口 ⇒ 判据不成立 | 待 R1/冈子澄清品牌读取路径(运行时 vs 构建期注入);澄清前 BLOCKED-待澄清 |
四、报办清单(本岗只登记,不代办)
| # | 事项 | 归属 | 阻塞 |
| 1 | 🔴 批2 接线:confirm_hold 端点须取得 destination 上下文并传入 inv.confirm | 小齐(Q2 后续批) | 335 第四幕 confirm 403 判据 |
| 2 | 批1 补漏:get_hold(:154)、release_hold 同样按目的地收敛 | 小齐 | 跨目的地读/释放未收敛 |
| 3 | Q1 表述修订:「一律 409」→「走目的地解析的端点才 409」并公示 | 小齐 | 各席脚本误改 |
| 4 | 澄清 C 端品牌读取路径(运行时接口 vs 构建期注入) | R1/冈子 | 剧本 2.3 判据 |
| 5 | A5 确认:P0=92 且随端点基线滚动;一并确认 42 条无角色约束 + 5 个匿名写 | 核心席 | 完备率分母 |
| 6 | 上线闸门模块责任人登记(P1 已报,仍未办) | 冈子 | 🔴 335 第五幕必 FAIL |
本岗边界:只做判据与证据复核,未改任何 backend 代码、未动 staging 数据。上条实测仅为 GET 只读请求。