Ruled: 5933322270 · letter A · 2026-10-01T14:17Z
Filed by the domain:engine execution seat 2 (seat post #20966 , session_01Ujdtvqs7ree7WyQmEDwEnG, os-litant) from #20822 group 3a's measured stop (os-dev-report 5926452254, open_questions[0]). This card holds only F7's retirement. #20822 group 3a (F6, PR #21105 ) lands without it, and group 3b carries F8. ⛔ Not a claim.
Escalated, not decided in-seat, because the options move a security boundary (what the RLS write check admits), which the PM protocol keeps on the human floor. One option also amends a Tier H ADR.
一句话问题
删掉 formula 里那份手抄的“整日上界”规则(F7)后,一个成员按 RLS 写策略插入一条日期型记录,会被拒(403);而同一条策略下,读出来这条记录又是可见的。写和读对同一条数据给出了相反的答案。
背景
裁决 5902355785(batch 🔗 Broken links detected in documentation #248 ,D4 (b)):"drivers receive the seams' lowered input; no permanent local guards on faces that bypass a seam"。
ADR-0053 D-D1(amended)第 5 条:「No face keeps a permanent copy」;第 9 条:每份副本都有删除卡,且「A copy is idempotent on lowered input」。
第 7 条把 RLS 留成了开放项:「The RLS compile seam reads nothing but the filter today, and its using output reaches typed drivers while its check output reaches matchesFilterCondition; which reading it applies is measured on the card that wires it.」本卡就是这次测量的结果。
测量 (dev 在 #20822 第 3a 组,经 ObjectQL + SecurityPlugin + SqlDriver 实测;PR #21105 正文里有探针表):
RLS 写检查判的是原始写入镜像 (raw post-image),不是落库后的形态。typed 的 RLS 接缝对 date 列不做下沉(item 7)。
删掉 F7 的 lteBound 后:成员在边界当天写入 due_on,无论写成 ISO instant 还是 Date,都被拒 PERMISSION_DENIED/403。同一策略下,该成员的读能看到这行(存储为 2026-01-05)。
保留 lteBound 时,两种写法都放行。
第二处没有接缝下沉的路径:$lte 对一个解析成纯日期的 { $field, addDays } 引用。lowering 对 $field 比较值原样保留。
结论:第 9 条的前提「副本对已下沉输入幂等」在这个面上不成立,所以 F7 按卡片的停止规则停下,没有删。
Governing text: ADR-0053 D-D1(amended)第 5、7、9 条,原文见上;裁决 5902355785 D4 (b)。没有任何裁决规定 RLS 写检查应判原始形态还是落库形态(检索式见下方 Prior rulings 行)。
协议声明 / 是否改协议: A、B、D 不改协议。C 要修订 ADR-0053(Tier H,维护者亲审)。
前提(每条带 re-check):
F7 仍在 main 上:git grep -n "function lteBound" origin/main -- packages/formula/src/matches-filter.ts,应命中 1 处。
RLS 写检查走 matchesFilterCondition:git grep -n "matchesFilterCondition" origin/main -- packages/plugins/plugin-security/src | head。
仓内没有带日期 check 的现成策略(复查命令已改写,原命令的路径 glob 匹配 0 个文件,其零不是读数):git grep -n -E '\b(using|check)\s*:' origin/main -- examples —— 阳性对照:必中 examples/app-showcase/src/security/permission-sets.ts 的 using;判据:命中的 check 行里无 date/datetime/time 列。2026-10-01 总监席重测:2 条 using、1 条 check(owner == current_user.email),0 条日期型。
选项 × 真实代价
选项
做什么
客户可感知的后果
A
RLS 写检查改判落库后的形态 :判之前,先把写入镜像里声明为 date/datetime/time 的列,过一遍 @objectstack/core 的 temporalStorageForm(每个驱动写入时用的同一规则)。随后另开一张删除卡删掉 lteBound,它的 24 个直调用例改走 lowering。
无感:今天放行的写,届时仍放行。读和写对同一行判同一个答案。代价是 security 车道一张卡。
B
RLS 编译接缝对 check 子句的 date 列也做下沉(对日期文本保序等价,using 读不受影响),然后删 lteBound。
日期列的写入无感。但 { $field, addDays } 这半没人兜,那类写入仍会被误拒。
C
保留 lteBound,把它声明为 F7 对写入镜像的永久规则。
零代码,但同一条规则永远存在两处。要修订 ADR-0053(第 5 条禁止永久副本),Tier H。
D
现在就删,接受收窄。
一个普通的 SDK 写法(Date 写日期字段、带日期 check)会被拒 403,而读能看到该行。这是公开入口上的读写不一致,偏严(fail-closed),不泄露数据。已实测。
业务含义直译:
A:门卫按入库后的样子查验,和仓库里登记的样子一致。
B:只修好最常见的日期写法,另一种写法仍可能被误拦。
C:两本规则手册永远并存。
D:先关门,有人能看见自己的东西,却改不了。
四轴(业务立场)
项目长远合理性: A 让写检查判「将要存在的那一行」,第 9 条在 F7 上成立,删副本也就变成机械操作。两年后的样子:写检查与读看到的是同一种类型化数据。PostgreSQL 的 RLS WITH CHECK 就是在列类型转换之后判新行。B 是半量;C 让契约迁就实现;D 留下读写分歧。
实际业务拉动: 今天仓内零个带日期 check 的策略(dev 实测),所以等 A 落地没有代价。但「SDK 用 Date 写日期字段,且有日期 check」是普通写法,D 的收窄会落在它身上。
防 AI 犯错: 原始形态和落库形态之间的差异,作者看不见,AI 写策略时也看不见。A 从结构上消除这个差异。D 出错时是响亮的 403,但会让人误以为是策略写错了。
创业阶段不扩散: A 是一张 security 车道的卡,不加门禁、不改 ADR。C 要修订 ADR,并永久维护两处规则。
os-decision-facets
① 长远合理性:A 收敛到一条规则、一种形态,删除副本变为机械操作;C 扩大特例(永久副本),D 留下读写分歧。
② 实际业务拉动:今天无仓内策略踩到;但 SDK 的 Date 写日期字段是常见形态,D 会让它在带日期 check 的策略下被拒。
③ 防 AI 犯错:A 消除作者看不见的「原始 vs 落库」分歧;D 是响亮拒绝但会误导;C/B 保留隐性双规则或半条路径。
④ 创业阶段不扩散:A 一张卡、无新门禁、无 ADR 修订;C 要 Tier H ADR 修订与永久维护。
Prior rulings read: "RLS check post-image stored form", "lteBound", "ADR-0053 D-D1 item 7 RLS check" → 0 hits beyond 5902355785 and ADR-0053 D-D1 itself; ADR-0053 D-D1 items 5, 7, 9; thread: #20822 (5926452254), seat 1's in-seat answers 5918373748 (A, the RLS twin for using).
推荐:A。 只看①选 A;②③④ 是否翻转:否(②零拉动只影响时序,A 落地前 F7 的副本照留,不回退)。
回退: 若 A 被否决,选 B,并另立一张卡兜 $field 那一半;⛔ 不选 D。
置信缺口:
没有实测真实 Postgres / MySQL 上 time 列的写检查;
没有实测 datetime 列的 ISO 带时区写法在 temporalStorageForm 下的边界;
仓外的策略作者是否依赖今天的宽松读法,看不见。
裁后执行
裁 A: 在 domain:services(plugin-security)立一张卡:RLS 写检查判落库形态,带 dev 的探针表作为 pin,覆盖 ISO instant、Date、纯日期三种,以及一行读写对照。该卡落地后,#5930 step 4 (domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula, having); the memory reference matcher retires (D6) #20822 第 3b 组(或一张单独的删除卡)删除 lteBound,24 个直调用例改走 lowering。在 A 落地之前,F7 的副本保持原样。
裁 B: 在本车道开一张 RLS 编译接缝的卡,再加一张 $field 半边的卡。
裁 C: 席位起草 ADR-0053 修订(Tier H 四件套),F7 标为永久副本。
裁 D: #5930 step 4 (domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula, having); the memory reference matcher retires (D6) #20822 第 3b 组直接删除,changeset 以 BREAKING 申报这次收窄。
相关
#5930 step 4 (domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula, having); the memory reference matcher retires (D6) #20822 (父卡,第 3a 组 PR fix(driver-mongodb): MongoDBDriver compiles the whole-day comparison it is handed; formula's copy stops on a measured answer move #21105 ,第 3b 组未认领)
[finding] 仓内存在 5 个独立的过滤器→谓词编译器,每次语义裁决成本 ×5 —— 值得立「谓词编译收敛」调查程序(#5298 成本清单副产品) #5930 (谓词编译收敛程序;#5930 step 4 (domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula, having); the memory reference matcher retires (D6) #20822 是其第 4 步)
ADR-0053
裁决 5902355785
PR fix(plugin-security,driver-sql,driver-turso): lower type-blind at the RLS seam without a guard, then delete the F1/F2 whole-day and NOT-rewrite copies (#5930 step 4, group 2) #20988 (第 2 组,RLS using 孪生)
[finding] $contains / $notContains on a declared multi-valued or JSON-stored field still answer SUBSTRING on five faces, the analytics RLS read scope among them (u1 admits a row storing u10) #20987 (formula $contains 一面,由第 3b 组承接)
Generated by Claude Code
Ruled: 5933322270 · letter A · 2026-10-01T14:17Z
Filed by the
domain:engineexecution seat 2 (seat post #20966,session_01Ujdtvqs7ree7WyQmEDwEnG,os-litant) from #20822 group 3a's measured stop (os-dev-report 5926452254, open_questions[0]). This card holds only F7's retirement. #20822 group 3a (F6, PR #21105) lands without it, and group 3b carries F8. ⛔ Not a claim.Escalated, not decided in-seat, because the options move a security boundary (what the RLS write check admits), which the PM protocol keeps on the human floor. One option also amends a Tier H ADR.
一句话问题
删掉 formula 里那份手抄的“整日上界”规则(F7)后,一个成员按 RLS 写策略插入一条日期型记录,会被拒(403);而同一条策略下,读出来这条记录又是可见的。写和读对同一条数据给出了相反的答案。
背景
usingoutput reaches typed drivers while itscheckoutput reachesmatchesFilterCondition; which reading it applies is measured on the card that wires it.」本卡就是这次测量的结果。测量(dev 在 #20822 第 3a 组,经 ObjectQL + SecurityPlugin + SqlDriver 实测;PR #21105 正文里有探针表):
date列不做下沉(item 7)。lteBound后:成员在边界当天写入due_on,无论写成 ISO instant 还是Date,都被拒PERMISSION_DENIED/403。同一策略下,该成员的读能看到这行(存储为2026-01-05)。lteBound时,两种写法都放行。$lte对一个解析成纯日期的{ $field, addDays }引用。lowering 对$field比较值原样保留。Governing text: ADR-0053 D-D1(amended)第 5、7、9 条,原文见上;裁决 5902355785 D4 (b)。没有任何裁决规定 RLS 写检查应判原始形态还是落库形态(检索式见下方 Prior rulings 行)。
协议声明 / 是否改协议: A、B、D 不改协议。C 要修订 ADR-0053(Tier H,维护者亲审)。
前提(每条带 re-check):
git grep -n "function lteBound" origin/main -- packages/formula/src/matches-filter.ts,应命中 1 处。matchesFilterCondition:git grep -n "matchesFilterCondition" origin/main -- packages/plugins/plugin-security/src | head。git grep -n -E '\b(using|check)\s*:' origin/main -- examples—— 阳性对照:必中examples/app-showcase/src/security/permission-sets.ts的using;判据:命中的check行里无 date/datetime/time 列。2026-10-01 总监席重测:2 条using、1 条check(owner == current_user.email),0 条日期型。选项 × 真实代价
@objectstack/core的temporalStorageForm(每个驱动写入时用的同一规则)。随后另开一张删除卡删掉lteBound,它的 24 个直调用例改走 lowering。check子句的date列也做下沉(对日期文本保序等价,using读不受影响),然后删lteBound。{ $field, addDays }这半没人兜,那类写入仍会被误拒。lteBound,把它声明为 F7 对写入镜像的永久规则。Date写日期字段、带日期 check)会被拒 403,而读能看到该行。这是公开入口上的读写不一致,偏严(fail-closed),不泄露数据。已实测。业务含义直译:
四轴(业务立场)
WITH CHECK就是在列类型转换之后判新行。B 是半量;C 让契约迁就实现;D 留下读写分歧。Date写日期字段,且有日期 check」是普通写法,D 的收窄会落在它身上。os-decision-facets
Date写日期字段是常见形态,D 会让它在带日期 check 的策略下被拒。Prior rulings read: "RLS check post-image stored form", "lteBound", "ADR-0053 D-D1 item 7 RLS check" → 0 hits beyond 5902355785 and ADR-0053 D-D1 itself; ADR-0053 D-D1 items 5, 7, 9; thread: #20822 (5926452254), seat 1's in-seat answers 5918373748 (A, the RLS twin for
using).推荐:A。 只看①选 A;②③④ 是否翻转:否(②零拉动只影响时序,A 落地前 F7 的副本照留,不回退)。
回退: 若 A 被否决,选 B,并另立一张卡兜
$field那一半;⛔ 不选 D。置信缺口:
time列的写检查;datetime列的 ISO 带时区写法在temporalStorageForm下的边界;裁后执行
domain:services(plugin-security)立一张卡:RLS 写检查判落库形态,带 dev 的探针表作为 pin,覆盖 ISO instant、Date、纯日期三种,以及一行读写对照。该卡落地后,#5930 step 4 (domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula,having); the memory reference matcher retires (D6) #20822 第 3b 组(或一张单独的删除卡)删除lteBound,24 个直调用例改走 lowering。在 A 落地之前,F7 的副本保持原样。$field半边的卡。domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula,having); the memory reference matcher retires (D6) #20822 第 3b 组直接删除,changeset 以 BREAKING 申报这次收窄。相关
domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula,having); the memory reference matcher retires (D6) #20822(父卡,第 3a 组 PR fix(driver-mongodb): MongoDBDriver compiles the whole-day comparison it is handed; formula's copy stops on a measured answer move #21105,第 3b 组未认领)domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula,having); the memory reference matcher retires (D6) #20822 是其第 4 步)using孪生)$contains/$notContainson a declared multi-valued or JSON-stored field still answer SUBSTRING on five faces, the analytics RLS read scope among them (u1admits a row storingu10) #20987(formula$contains一面,由第 3b 组承接)Generated by Claude Code