Repository navigation
permission-set backfill (ADR-0094 D4) 现在 100% 失败:行里的 active 存储列喂进了 #4001 之后严格化的 permission spec #4669
Copy link
Copy link
Closed
Labels
bugSomething isn't workingSomething isn't workingpm:dispatchedpm:queuepriority:p2Medium: important, M3Medium: important, M3
Description
Activity
- addedbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3
on Aug 3, 2026 🔒 认领 —— 第 2 轮(发布窗口 bug 批)
- 会话:
session_015Br2xsJsczFsTR9bvbh2Ny(PM 循环) - 分支:
claude/issue-4669-permission-backfill-strict-spec - Worktree:
objectstack-issue-4669
⚠️ 共用身份,session ID 不符即本单已被占,请另选。两个方向的 PM 裁定(维护者可否决):选投影侧挑键(正文方案 1)。理由:
active的现有消费面(表列 +highlightFields+ 两个启停动作的bodyExtra)全是行状态语义 —— 它是运行时开关,不是作者声明的能力边界;进 spec(方案 2)等于把状态提升为契约,方向不对,且是窗口内禁的 spec 变更、属对侧车道。permissionSetBodyFromRow()改为显式挑 spec 认的键(白名单),存储列(active、时间戳、managed_by等)全部不进 metadata body。白名单从 spec 的 schema 键表派生而不是手抄一份,否则 spec 加键时这里又静默漏。
第二半交付(与修复同 PR):这个
catch+warn正是 #4632 刚定的规则里的第二类降级 —— backfill 全线停摆但测试全绿、无任何自动信号。按新规则(AGENTS.md「Degradation log levels」节)把它变响亮:失败计数进结果、级别提到error、文案含后果与修复动作。若check:durability-log-level的词表覆盖不到这类投影写入,在 PR 里说明(那是闸门已声明的局限,不是你的债)。约束:⛔
packages/spec/**零改动(白名单派生用运行时可及的 schema 导出,不改 spec);⛔content/docs/releases/不碰;资源纪律照旧。cloud 侧复现属参考,本单不碰 cloud 仓。验收:backfill 对带
active列的行成功(backfilledIntoMetadata计数增长);两个启停动作行为不变;真失败时响亮(测试钉住);正文 WARN 在同场景下消失。
Generated by Claude Code
- 会话:
✅ PM 验收通过 —— PR #4755,CI 全绿(18 success + 2 skipped,0 失败),已转 ready 并入合并队列
复核对着 GitHub:
- 白名单从
PermissionSetSchema.shape派生(首用解析 + 缓存,不拆 lazySchema 代理),照裁定;覆盖面比 backfill 大 —— 未知键静默剥离仍是全仓默认:把 #3405 的 strict 收紧从一个 schema 推广到整个可授权面(ADR-0078 完整性闸门) #4001 前落库、body 仍带active的历史 overlay 同闸口被滤 - 测试真的抓得住:mock
saveMetaItem换成跑真 schema(与resolveOverlaySchema同一 422 信封)—— 此前 mock 什么都收,套件全绿而真实 backfill 全灭,这个替身升级本身就是修复的一半;缺陷回填 6 红,报错逐字是 issue 正文那条 - 双向钉住:只含行状态的 PATCH 放行给驱动(不再造假 overlay);投影不再从 body 读
active(陈旧 body 不会把刚停用的 set 重新打开) - 响亮化按 [convention] best-effort 降级导致"看起来正常、实则不持久"时不应记 warn——把 #4460 的点状修复定成规则 #4632 规则落地:error 级 + 后果 + 修复动作 + 说一次;
backfillFailed进结果结构;汇总行在有失败时不再 INFO 盖脸 - 真实 stack e2e:遗留行 boot reconcile →
backfilledIntoMetadata: 1,WARN 消失,列不动 - CI 一轮红的判定纠正记录在案:非 DTS OOM,是
spec/cloud/tenant.test.ts贴着 5s 默认超时(spec 双源清账 C16:TenantPlan(./cloud ≠ ./system)—— 路线 B:删 system 侧 provisioning 家族,2 条 #4739/feat(spec)!: 删除./system的 declared-only tenant-provisioning 家族 —— C16 双源清账,基线 12 → 10 (#4739) #4752 车道带入),合 main 重跑后全绿 —— dev 的诊断比 PM 的第一判断更准,超时余量隐患已记在 PR 评论
场外发现处置
saveMetaItem是 #4632 词表覆盖不到的持久性接缝:8 处 catch 完全静默吞掉元数据写入失败 #4754(saveMetaItem进 durability 词表 → 8 处全静默 catch 待清账)→ tooling 入队,留下轮派发(本会话暂停)
Generated by Claude Code
- 白名单从
- added 3 commits that reference this issue
on Aug 3, 2026 - added a commit that references this issue
on Oct 9, 2026
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingpm:dispatchedpm:queuepriority:p2Medium: important, M3Medium: important, M3
发现于:cloud 侧把 framework pin 从
ad5fe25前移到462b713(cloud#1010)后跑全量测试时,日志里出现的 WARN。核实基线:
objectstack@462b713,cloud@e14553d未认领 —— 只是记录,谁接手谁 assign。
症状
ee-group-showcase/security-enterprise的测试里,每次 permission-set backfill 都打出这条:测试是绿的。 失败在
permission-set-projection.ts:770-773被catch成一条logger.warn,backfilledIntoMetadata不加一,然后继续。所以没有任何 gate 会因此变红。因果链
sys_permission_set有一个active存储列 —— 是 framework 自己声明的,sys-permission-set.object.ts:33把它放进highlightFields,还有两个动作靠bodyExtra: { active: true }/{ active: false }来启停一个 set。它是完全正当的运行时状态。permissionSetBodyFromRow(row),把数据库行转成 metadata body ——active跟着进去了。#4001把 permission-set 的 spec 形状封成严格键。active从来不是 spec 上的键,此前被静默 strip,所以第 2 步一直"能用"。saveMetaItem对每一个没有 declared body 的 permission set 抛invalid_metadata,backfill 全线失效。不是 showcase 数据特有的问题:任何走这条路径的 set 都会命中,因为
active来自表结构,不是作者写的。为什么值得单独立一条
这正是
#4001报错文案自己描述的那类事故,只是发生在 framework 内部而非授权侧:一个存储列被当成 spec 键送去校验,严格化之后整条投影路径静默停摆。catch+warn的处理让它没有任何自动信号 —— 我是在读一次无关的 bump 日志时偶然看见的。顺带一提,cloud 那边新加的
audit-spec-changes.mjs(cloud#995)也抓不到它:审计只扫spec-changes.json登记过的 surface,而 permission-set 的严格化没有对应条目。可能的修法(未验证,留给接手的人判断)
permissionSetBodyFromRow()里显式挑出 spec 认的键,而不是把整行带过去 —— 存储列(active、时间戳、managed_by等)本来就不该进 metadata body;active确实应当是 permission set 的声明语义(而不只是行状态),那就该在 spec 上正式加回来,而不是靠 strip 苟活。先判断哪一边才是它真正的归属,再动手 —— 这个键同时被表列和两个动作使用,不能只看 backfill 这一处。
复现