Skip to content

Audit sibling declared-metadata↔record two-store types (sys_position, sys_sharing_rule, sys_capability) per ADR-0094 addendum #2909

Description

@os-zhuang

背景

ADR-0094 把 sys_permission_set 做成 metadata 层的纯投影,并在 2026-07-14 addendum 里把该决策提升为一条适用于所有「declared-metadata ↔ queryable-record 两存储类型」的分类规则。三个 sibling 以同样方式 seed(声明 metadata → sys_* 记录,仅 boot/publish 时同步),需要套用该分类:

  • sys_positionbootstrapDeclaredPositions
  • sys_sharing_rulebootstrapDeclaredSharingRules
  • sys_capabilitybootstrapSystemCapabilities

v2(2026-07-15)重写说明:原版是纯审计任务。经落点级核实后重写为「审计 + 一个前置小 feature」——sys_sharing_rule 完全没有 provenance 字段,「seed-not-clobber」在它身上当前不可实现,必须先补 provenance(见 P0)。同时把各 checkbox 从「待查」更新为已核实的结论,并新增一条「须记录的设计取舍」。

分类判据(ADR-0094 addendum,不变)

enforcement 在请求时读哪个 store?

  • Metadata-authoritative → 记录是纯投影(复用 ADR-0094 机制:data-door write-through + awaited registerMutationProjector + registerAuthoringGate + boot reconciliation)。
  • Record-authoritative → 记录是权威,声明 metadata 只是 boot SEED;要做的是 seed-not-clobber 纪律(不覆盖被环境编辑过的行;不把声明体当 live override 读)。不要套投影机制。

已核实现状(2026-07-15,落点级)

类型 enforcement 读哪里 分类 seed 现状
sys_sharing_rule 记录,live(sharing-rule-service.ts ~L100 engine.find('sys_sharing_rule', …)sharing-plugin.ts 规则评估同路径) record-authoritative 每次 boot 都 clobberbootstrapDeclaredSharingRules 按 name 走 defineRule,对已存在行覆盖 label/criteria_json/recipient_*/access_level/activesharing-rule-service.ts ~L105-115)。且整个 plugin-sharing 没有任何 managed_by/customized provenance 字段,无从判定「环境编辑过」。
sys_position 混合:position→permission-set 解析对 sets 是 metadata-first;但 sys_position 记录的 bindings、delegatable/admin gating 由 anchor gate 与 DelegatedAdminGate live 读记录 record-authoritative(定义字段 metadata 只作 seed 身份) 🔶 事实安全但未收口:seed 只刷新 label/descriptionbootstrap-declared-positions.ts ~L82-85),不碰权威字段;但无测试锁定该行为,也未文档化为 seed-only。
sys_capability 记录(curated registry 存在性读取) record-authoritative(registry) ✅ 基本达标:显式 don't-clobber(bootstrap-system-capabilities.ts ~L103-105,仅刷 label/description/scope)。剩余:scope 若属 admin 可编辑面则也在被刷,需确认;行为无测试锁定。

安全动机(为什么 sharing rule 的 clobber 不是洁癖):sharing rule 是授予访问的对象。管理员发现某条声明规则过宽而将其 active:false 停用后,下一次 deploy/boot 会静默复活这条过度共享(over-sharing resurrection)。这与 ADR-0049「不引入未强制的安全属性」同向:管理员的收窄操作必须可持久。

P0 前置:给 sys_sharing_rule 补 provenance(seed-not-clobber 的判定依据)

「never overwrite an env-edited row」隐含前提是能判定一行是否被环境编辑过。没有 provenance 时只剩两个坏选项:朴素 skip-if-exists(包升级永远送不下去)或逐字段 diff seed 快照(复杂度不匹配)。因此:

任务分解

  • T1 — sys_sharing_rule seed-not-clobber(依赖 P0):bootstrapDeclaredSharingRules/defineRulecustomized不覆盖(保留管理员编辑,尤其 active:false);未编辑的 pristine 行继续接受声明更新(包升级可达)。管理员自建行(name 不冲突)不受影响。测试矩阵:pristine 行升级可达 × customized 行不被复活 × 自建行不动。
  • T2 — sys_position 收口:确认 seed 永不触碰权威字段(permissions/bindings/delegatable 等),用测试锁定「seed 只刷 label/description」;在对象定义/文档标注 declared position 为 seed-only(身份 + 展示字段)。
  • T3 — sys_capability 收尾:确认 scope 的归属(若 admin 可编辑则移出刷新集或以 customized 门控);测试锁定 don't-clobber 行为。
  • T4 — ADR-0094 addendum 表定稿:把表中「Audit that…」待办语气改写为 resolved 分类结论(含本 issue 的落点引用),并记录下方的设计取舍。

须记录进 ADR 的设计取舍

为什么 sharing rule 选 seed-only 而不是「写护栏 + 覆盖」(projection-lite)? 存在一个自洽的替代方案:像 #2918 那样对 package 托管行上写护栏(管理员不可改),boot 覆盖即无害。不选它的理由:sys_sharing_rule 与 permission set 不同,它本来就是 Setup 里一等的管理员创作/调整面(含对 seeded 规则的收窄),禁编辑会砍掉产品能力;分类判据(enforcement 读记录)也指向 record-authoritative。此取舍须写入 addendum 表,避免后来者重开争论。

验收

  • P0:sys_sharing_rule 具备 provenance(managed_by + customized),词表与 sibling 一致。
  • 三类型各自的 seed-not-clobber 行为有测试锁定(T1-T3 的矩阵)。
  • 「管理员停用的声明规则不被 boot 复活」有专属回归测试。
  • ADR-0094 addendum 表更新为 resolved 分类 + 取舍记录(T4)。

关联

Filed as the scoped follow-up named in the ADR-0094 addendum (Prime Directive #10). Rewritten v2 after site-level verification.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions