范围外发现,出自 #6132 的可达性测量(未在该单内修)。按 Prime Directive #10 记录,不指派。
事实(origin/main 0b63b5677 基线,实测)
packages/spec/src/security/rls.zod.ts:386 的 check 属性 TSDoc 带这条 @example:
@example "status IN ('draft', 'pending')" - Only allow certain statuses
它编译不出来。实测(sqlPredicateToCel + isSupportedRlsExpression + compileCelToFilter,与运行期 RLSCompiler.compileExpression 同一条路径):
@example |
桥接后 |
isSupportedRlsExpression |
compileCelToFilter |
organization_id = current_user.organization_id |
organization_id == current_user.organization_id |
true |
ok {"organization_id":"o1"} |
owner_id = current_user.id |
owner_id == current_user.id |
true |
ok {"owner_id":"u1"} |
status = 'published' |
status == 'published' |
true |
ok {"status":"published"} |
assigned_to_id IN (current_user.team_member_ids) |
assigned_to_id in (current_user.team_member_ids) |
true |
ok {"assigned_to_id":{"$in":["u1","u2"]}} |
1 = 1 |
1 == 1 |
true |
ok {} |
status IN ('draft', 'pending') |
status in ('draft', 'pending') |
false |
FAIL parse-error: Expected RPAREN, got COMMA |
原因:sqlPredicateToCel 只把 IN 这个词换成 in,不改写括号。CEL 的列表字面量是 ['draft', 'pending'](方括号),('draft', 'pending') 在 CEL 里不是合法表达式,于是 parse 失败。单元素的 IN (current_user.xxx) 之所以能过,是因为 (expr) 恰好是合法的括号分组 —— 一进多元素就塌。
影响
不是「示例排版错」那一类。作者照抄 schema 自带示例写出的策略,在运行期走的是:
compileExpression → compileCelToFilter 返回 !ok → 返回 null → compileFilter 里 filters.length === 0 → 返回 RLS_DENY_FILTER。
即该对象上的这条策略拒绝全部行(单策略时是彻底拒绝)。同时 @objectstack/lint 的 validateRlsPredicateEnforceability 也会因 isSupportedRlsExpression 为 false 而报错。所以症状是「按官方示例写,然后 lint 报错 / 数据全空」,自纠成本不低 —— 作者没有理由怀疑 schema 自己的 @example。
这正是 Prime Directive #10 的 declared ≠ enforced 形状:文档广告了一个运行时不提供的能力。
两个修法(留给 triage,不代裁)
- 改文档(最小):把该
@example 改成 CEL 方括号形式 status in ['draft', 'pending'],与 ADR-0058 D1「CEL 是 canonical」一致。using 的几条 @example 也仍是 SQL 风格,但那几条都实测可编译,属于 transitional bridge 的既有面。
- 改桥:让
sqlPredicateToCel 把 IN (a, b, c) 的圆括号列表改写成 CEL 方括号列表。这是扩桥,而 sqlPredicateToCel 的 TSDoc 明写自己是 @deprecated 过渡桥、「只桥历史支持的子集」,方向上与「让 SQL 风格逐步退场」相反。
倾向 1 —— 契约优先:CEL 是 canonical,示例就该是 CEL;把一个已声明 deprecated 的桥加宽,是给要退场的方言追加新面。但这条示例是 check 子句唯一的「枚举取值」范例,改写时值得顺带确认 status in ['draft', 'pending'] 在 check 语义下确实是想表达的意思。
关联
#6132(测量出处)、ADR-0058 D1(一个 canonical 形状闸)、ADR-0056 D4(RLS 谓词形状闸门)。
范围外发现,出自 #6132 的可达性测量(未在该单内修)。按 Prime Directive #10 记录,不指派。
事实(
origin/main0b63b5677基线,实测)packages/spec/src/security/rls.zod.ts:386的check属性 TSDoc 带这条@example:它编译不出来。实测(
sqlPredicateToCel+isSupportedRlsExpression+compileCelToFilter,与运行期RLSCompiler.compileExpression同一条路径):@exampleisSupportedRlsExpressioncompileCelToFilterorganization_id = current_user.organization_idorganization_id == current_user.organization_id{"organization_id":"o1"}owner_id = current_user.idowner_id == current_user.id{"owner_id":"u1"}status = 'published'status == 'published'{"status":"published"}assigned_to_id IN (current_user.team_member_ids)assigned_to_id in (current_user.team_member_ids){"assigned_to_id":{"$in":["u1","u2"]}}1 = 11 == 1{}status IN ('draft', 'pending')status in ('draft', 'pending')原因:
sqlPredicateToCel只把IN这个词换成in,不改写括号。CEL 的列表字面量是['draft', 'pending'](方括号),('draft', 'pending')在 CEL 里不是合法表达式,于是 parse 失败。单元素的IN (current_user.xxx)之所以能过,是因为(expr)恰好是合法的括号分组 —— 一进多元素就塌。影响
不是「示例排版错」那一类。作者照抄 schema 自带示例写出的策略,在运行期走的是:
compileExpression→compileCelToFilter返回!ok→ 返回null→compileFilter里filters.length === 0→ 返回RLS_DENY_FILTER。即该对象上的这条策略拒绝全部行(单策略时是彻底拒绝)。同时
@objectstack/lint的validateRlsPredicateEnforceability也会因isSupportedRlsExpression为 false 而报错。所以症状是「按官方示例写,然后 lint 报错 / 数据全空」,自纠成本不低 —— 作者没有理由怀疑 schema 自己的@example。这正是 Prime Directive #10 的 declared ≠ enforced 形状:文档广告了一个运行时不提供的能力。
两个修法(留给 triage,不代裁)
@example改成 CEL 方括号形式status in ['draft', 'pending'],与 ADR-0058 D1「CEL 是 canonical」一致。using的几条@example也仍是 SQL 风格,但那几条都实测可编译,属于 transitional bridge 的既有面。sqlPredicateToCel把IN (a, b, c)的圆括号列表改写成 CEL 方括号列表。这是扩桥,而sqlPredicateToCel的 TSDoc 明写自己是@deprecated过渡桥、「只桥历史支持的子集」,方向上与「让 SQL 风格逐步退场」相反。倾向 1 —— 契约优先:CEL 是 canonical,示例就该是 CEL;把一个已声明 deprecated 的桥加宽,是给要退场的方言追加新面。但这条示例是
check子句唯一的「枚举取值」范例,改写时值得顺带确认status in ['draft', 'pending']在 check 语义下确实是想表达的意思。关联
#6132(测量出处)、ADR-0058 D1(一个 canonical 形状闸)、ADR-0056 D4(RLS 谓词形状闸门)。