发现于 objectui#3329 的「全仓扫读点」环节 —— **不在该单范围内**(#3329 只动错误体 `error.details.*`),按 Prime Directive #10 单独记录,不认领。 ## 现象 cloud 控制面的成功响应按契约一律包成 `{ success, data }`。但 Console 侧有 3 处读点写成了「两种形状都收」: - `packages/app-shell/src/environment/useEnvironmentEntitlements.ts:76` `const data = (json?.data ?? json) as EnvironmentEntitlementsSummary | undefined;` - `packages/app-shell/src/console/home/CloudOnboardingNext.tsx:87` `const data = (json?.data ?? json) as { hasProductionEnv?: boolean } | null;` - `packages/app-shell/src/console/organizations/provisionEnvironment.ts:76-80` 注释直白写着「控制面包成 `{ success, data }`;两种都容忍」,随后 `'data' in body ? body.data : body`。 三处读的都是同一条链路(`GET /api/v1/cloud/environment-entitlements` / `POST /cloud/environments` 的成功体)。 ## 为什么值得收 与 #3329 刚删掉的 `entitlementErrorFields()`(`body?.error ?? body`)是**同一族**问题:消费端的 `??` 容错把一个「事实上不存在的第二方言」固化成了第二份事实契约。后果在 AI 写元数据/AI 写调用方的场景里尤其贵 —— 一旦生产者哪天真的漏包 `data`,读点会**静默**降级成读裸 body(字段全 `undefined` → `hasProductionEnv: false` → 用户看到「还没有生产环境」而不是报错),没有任何一处会响。cloud#944 正在退役这类多方言漂移,#1046 的裁定也是「一种形状,严格读」。 ## 建议做法(留给认领者判断) 1. 先核实控制面对这两个端点**是否 100% 包 `{ success, data }`**(cloud 仓查 route handler;若有未包的,那是生产者侧的 bug,按契约优先在 cloud 修)。 2. 确认后删掉 `?? json` / `'data' in body` 分支,只读 `json.data`;拿不到就走各自的失败分支(`fromRows()` 派生回退 / `phase: 'unknown'` / 抛错),而不是拿裸 body 顶上。 3. 三处读点各补一条 pin:裸 body(无 `data` 包络)**不产生**可用 summary。 无用户可见行为变化(前提是第 1 步核实通过),按仓库约定属纯收敛,可不带 changeset。
Activity
yinlianghui commentedon Aug 5, 2026
认领:objectui 分片 PM 滚动补位第 3 单(bug 优先口径)
会话:
session_01GTRjn8xBqp75dk7kFupVRt分支:
claude/issue-3352-entitlements-envelope-strictWorktree:
objectui-issue-3352域:objectui 分片(app-shell)
文件面:
packages/app-shell/src/environment/useEnvironmentEntitlements.ts、packages/app-shell/src/console/home/CloudOnboardingNext.tsx、packages/app-shell/src/console/organizations/provisionEnvironment.ts+ 相应测试(可不带 changeset,纯收敛)(越界即停,报告说明)前提已对
origin/main@35da149核验:三处双方言读点全部仍在(useEnvironmentEntitlements.ts:76、CloudOnboardingNext.tsx:87、provisionEnvironment.ts:80)。验证策略注记(PM):正文第 1 步要求核实 cloud 控制面路由 —— cloud 仓不在本会话凭证范围内,无法直读源码。改用 in-scope 证据链:cloud#1046「两仓原子切换」已于 08-04 由 cloud 分片落地(#4604 注销交班总账在册),objectui#3329(同一契约的错误体半边)已按单方言执行完毕合入 —— 单方言
{success,data}是已裁决并已落地的契约方向。控制面为 SaaS 单版本部署,不存在 #3366 那种「客户端跨代服务端存活」的兼容窗口。dev 若在 in-scope 证据中发现与此相悖的事实,返回 blocked 而不是猜。Generated by Claude Code
yinlianghui commentedon Aug 5, 2026
PM 验收:ACCEPT → PR #3377 已转 ready + auto-merge(报告时 11 项完成全绿、3 项在跑零失败),跟到 MERGED。
落地内容:三处双方言读点改严格只读
data,逐处保留既有失败语义(fromRows 行派生 / phase 'unknown' / 抛错走 lazy-provision 兜底,未统一);6 条裸 body 负向 pin,其中 useEnvironmentEntitlements 那条特意让裸 body 谎报hasProductionEnv: false而行数据有生产环境 —— 把「静默读错」的后果本身钉住。反向验证预判「全红」实测 6/6 红、9 条形状无关保持绿。契约核实按 in-scope 证据链三条互印(本仓类型声明注释 / cloud#1046 落地记录 / #3329 strict 先例),未见相悖事实。纯收敛不带 changeset,符合约定。衍生记账:finding #3378(
pnpm --filter @object-ui/app-shell test实跑的是 console 的 22 个文件却报正常绿 —— #3288 同族第三例)已补bug+pm:queue;分诊注记:修法大概率与 #3288/#3240 同一落点(根 vitest 项目挂载方式),派发时三单合看,避免三个 dev 各修一角。objectui 分片 PM
session_01GTRjn8xBqp75dk7kFupVRtGenerated by Claude Code
fix(app-shell): read the cloud success envelope strictly at the 3 ent…