Skip to content

ADR-0105 D6 ② 只拦 business_unit 收件人,漏了 unit_and_subordinates —— 同一个跨 org BU 授权,更宽的那个反而放行 #4991

Closed

Description

@xuyushun441-sys

发现于 #4984 的实现过程(那一单只修被拒别名的读法,这条是覆盖面问题,按 Prime Directive #10 单独记账)。

事实

packages/lint/src/validate-org-axis-red-lines.ts 的 ORG_AXIS_CROSS_ORG_BU_GRANT(D6 ②)只对一种收件人类型判红:

const recipientType = str(sharedWith?.type);
if (recipientType !== 'business_unit') return;

而 ShareRecipientType 里有两个业务单元收件人:

  • business_unit —— 正好一个 BU 的成员(无子树);
  • unit_and_subordinates —— 一个 BU 加上其全部后代单元的成员(ADR-0057 D5 子树扩张)。

ADR-0105 D6 ② 的原文点名的恰恰是后者:

Every BU mechanism — unit_and_subordinates sharing, adminScope delegation, depth scopes — operates within one organization. There is no cross-org tree.

后果

在 tenancy.enabled: false(或 systemFields.tenant: false)的平台级对象上:

收件人 现状
sharedWith: { type: 'business_unit', value: 'bu_x' } 判红 ✅
sharedWith: { type: 'unit_and_subordinates', value: 'bu_x' } 放行 ❌

两者的缺陷完全相同 —— 平台级对象没有 organization 列可供 Layer 0 收口,授权跨到库里每一个 organization —— 而漏掉的那个授权面更大(整棵子树而非单个单元)。规则自己的文档注释也只写了 business_unit,所以这不像是有意的取舍,更像是照着一个收件人写完就没回头看枚举。

注:#4984 之前这条规则读的是被拒别名 sharedTo/recipient,所以 ② 对任何 spec 合法的 stack 都从不触发;#4984 修好键名后这个覆盖面缺口才第一次变得可观察。

建议

把判定改为收件人类型 ∈ { business_unit, unit_and_subordinates },并在 message 里保留具体类型名。这是 error 级门禁的扩张,所以没有随 #4984 一起做 —— 需要先确认没有真实元数据踩中。

已核查(#4984 分支上):examples/app-showcase、examples/app-crm 的全部 sharing rule 中只有一条 unit_and_subordinates(share_new_inquiries_with_field_ops → showcase_inquiry),而 showcase_inquiry 没有 tenancy.enabled: false / systemFields.tenant: false,仓库里也没有任何对象关掉 tenancy —— 因此按上述扩张改完,现有真实元数据不会产生新红。

相关:#4984、ADR-0105 D6、ADR-0057 D5。

Activity

  1. added
    bugSomething isn't working
    domain:devxDomain lane — seat card indexed by label:pm:seat
    toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    bugSomething isn't working
    on Aug 3, 2026
  2. xuyushun441-sys commented on Aug 3, 2026

    @xuyushun441-sys
    CollaboratorAuthor

    认领(PM 分派)

    要点:D6 ② 现只拦 business_unit,漏了 ADR-0105 D6 ② 原文点名且授权面更大的 unit_and_subordinates(整棵 BU 子树)。#4984 的 dev 已预核过按此扩张现有真实元数据不产生新红。


    Generated by Claude Code

  3. xuyushun441-sys commented on Aug 3, 2026

    @xuyushun441-sys
    CollaboratorAuthor

    审核通过 — PR #5004 已取消草稿并挂上 auto-merge(SQUASH)

    词表核对做到了本单要求的深度,且放行清单不是猜的:以 ShareRecipientType 五成员枚举为准,拦二放三;放行的 user/team/position 逐一按 expandRecipient 的运行时展开路径复核 —— 恰好只有拦的两个走 BusinessUnitGraphService,其余各走各的扁平展开。差集在规则注释里表格化,没有留未说明的项。position 的斟酌(D6② 原文提的 depth scope 锚在 position 上,但那是 SCOPE 机制不是收件人展开)也写进注释,免得下一个人重走一遍。

    根因防复发是这单最重要的一笔:新增结构性断言"拦截半 ∪ 放行半 == 枚举全集"。本单本身就是"照着一个收件人写完没回头看枚举"的产物 —— 将来加第六个成员会在词表处判红,而不是无声落进没人裁决过的那一桶。这与 #4835 的词表教训同型,这次直接内建了防线。

    运行时契约里那个刻意不可授权的 queue 也记了账并指明将来的回归点。真实元数据是独立重跑而非沿用 #4984 的预核(全仓非测试 sharedWith 只有两个 examples 共 11 条,0 red)。顺带修掉 hint 里指向不存在收件人类型("permission-set audience")的过时措辞,范围正当。

    落点 3 文件全在 packages/lint,20 → 25 测试全绿。


    Generated by Claude Code

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

Metadata

Metadata

Labels

domain:devxDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch looptoolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions