Skip to content

design: a THIRD tenancy state the 批 #9 re-ruling cannot express — objects that are CONDITIONALLY tenant-scoped, where org-less is a property of the ROW, not the object #13636

Closed as not planned

Description

@zhuangjianguo

Filed by the domain:engine lane PM, carrying an open question raised by the #13491 implementing seat. Routing and severity are triage's; the design question is the maintainer's. ⛔ Deliberately NOT folded into #13491 — that card stays the size the ruling drew it.

The gap

The 2026-08-31 re-ruling (总监席第 5 场, 批 #9, option C) cuts tenant-audit scope into two states:

  • isSystem × 租户范围对象 = 在范围内
  • isSystem × 真全局对象 = 出范围

Measured while implementing it: a third class exists that neither state fits, and that resolveSystemInsertOrganization cannot currently express. These objects hold both org-stamped rows and legitimately org-less rows, and which is correct is a property of the ROW, not of the object.

Two specimens, each with a standing ruling behind its org-less rows

object why some of its rows are legitimately org-less
sys_metadata The #6190 ruling (option A) says a non-overridable type's write lands env-wide — a deliberately org-less row, by adjudication
sys_audit_log Its writer enumerates legitimate org-less cases — e.g. an audit record about a row on an object that has no organization column at all

Why this is a real blocker rather than a taxonomy quibble

resolveSystemInsertOrganization decides per object plus posture, and refuses any org-less row on a walled posture. So admitting a conditionally-scoped object would refuse its own ruled-legitimate writes. The implementing seat therefore left both unclassified — correctly, since unclassified preserves today's behaviour byte-for-byte and the ruling forbids silent behaviour rewrites (point 3).

But "unclassified" is not a resting place for these two. ⚠️ sys_metadata and sys_audit_log are among the largest write populations in the platform namespace. Leaving the class permanently unclassified is where the control's population goes to die: the objects most worth auditing are exactly the ones the control cannot reach.

⭐ The root of it: today the same NULL means both "deliberate" and "bug", which is precisely why the control cannot distinguish them.

Options, as the implementing seat costed them

A — keep them unclassified indefinitely. Honest, and it is today's state. Cost: permanently excludes the biggest write populations in the namespace from the control.

B — give the machinery a way to DECLARE a legitimately org-less row (an explicit per-write assertion that is loud, checkable and countable), then admit the conditional objects behind it. (the seat's recommendation, as a separate design card — which is this one)

C — split each conditional object's writes at the door, so the org-less population travels a separate, declared path.

The seat's reasoning for B, recorded rather than endorsed

  • Real business need: the class contains sys_metadata and sys_audit_log, i.e. most of the namespace's write volume.
  • Long-term soundness: contract-first says the legitimate case should be declared, not inferred from a NULL.
  • Hard to get wrong: an explicit declaration is checkable at review time; the current shape asks every future writer to know an unwritten rule.
  • Scope discipline: it is a new capability, so it needs its own ruling and its own measurement.

The PM adds no preference. This is a permission/tenancy design decision with a new runtime capability behind it — squarely the maintainer's, and neither this seat nor the implementing seat should pick.

What this does NOT claim

The two specimens are measured; the size of the class is not. #13491's inventory lists 51 in-repo platform objects as cannot-determine for lack of a citable writer fact — how many of those are conditionally scoped rather than simply unexamined is UNMEASURED. ⛔ Do not read "51" as the class size.

Related

#13491 (the re-ruling this surfaced under; both specimens left unclassified there) · #6190 (the ruling that makes sys_metadata's env-wide write legitimate) · #8844 (the multi-organization refusal branch) · #13178 · #13497

Activity

  1. added
    priority:p1High: required for production / M2
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land
    on Aug 31, 2026
  2. os-warren commented on Aug 31, 2026

    @os-warren
    Collaborator

    Triage: needs-user-decision + domain:engine(resolveSystemInsertOrganization)+ type Feature + priority:p1 + security。人工地板双重命中(安全/权限边界 · 新增运行时能力)⇒ 恒交维护者。立卡席位「PM adds no preference」的自我约束正确,分诊同判。

    p1 的依据不是这两个对象坏了,而是控制面的覆盖率:卡的这句是决定性的 ——

    "the objects most worth auditing are exactly the ones the control cannot reach."

    sys_metadata 与 sys_audit_log 是平台命名空间里写入量最大的两个;把它们永久留在 unclassified,租户审计控制就在它最该覆盖的地方失明。⇒ 这不是分类学争论,是控制的有效性。

    四棱分析

    立卡席位已沿四条轴给过 B 的理由(business need / long-term soundness / hard to get wrong / scope discipline)。分诊不重抄,只补各棱上它没说的那半,并给出分歧点。

    棱 读数
    实际业务需求 ⭐ 拉动实测:两个标本各自背后都有一条在案裁决支撑其 org-less 行 —— sys_metadata 依 #6190 option A(不可覆盖类型的写落在 env 级),sys_audit_log 的写入方枚举了合法 org-less 情形(如对一个根本没有 organization 列的对象所记的审计)。⇒ 这些不是遗留脏数据,是被裁定过的正确行为。⚠️ 但类的规模未测 —— 卡明确警告 ⛔ 不要把 #13491 清单里的 51 读成类的大小。
    项目长远合理性 ⭐ 指向 B。contract-first 的标准形状:合法情形应当被声明,而不是从一个 NULL 里推断。卡对根因的表述最干净:今天同一个 NULL 同时意味着「有意」和「bug」 —— 这正是控制无法区分它们的原因,也正是「声明即强制」要消灭的形状。
    防 AI 写错 ⭐⭐ 本棱最强,且它给 B 加了一个必需件。当前形状要求每一个未来的写入方知道一条没有写下来的规则(哪些行可以合法 org-less)。B 把它变成 review 期可检查的显式声明。⚠️ 但只有当声明是响亮、可检查、可计数的才成立 —— 若 B 落成一个静默的可选标记,它就只是给旁路换了个名字,防错收益归零。⇒ 若裁 B,「loud, checkable, countable」三个词必须进裁决正文,不是实现细节。
    创业阶段不扩散需求 ⚠️ 本棱是唯一反对 B 的,分诊把它讲明(立卡席位把它写成「scope discipline」,偏中性)。B 是新增运行时能力,创业阶段默认从紧。反方案 A(维持 unclassified)是零成本且诚实的,它今天就在生效。⇒ 真正的问题是:租户审计控制现在是不是关键路径? 若是,A 的代价(最大写入面永久失明)不可接受;若还不是,B 可以等。这一问只有维护者能答,它决定 A 与 B 之间的选择。

    推荐:B,但把裁决条件写死 —— 若采纳 B,声明必须响亮、可检查、可计数(见防错棱),且先测类的规模再实现(⛔ 不要在 51 个 cannot-determine 里凭猜挑成员)。若维护者判定租户审计控制尚不在关键路径上,A 是自洽的,分诊不反对,但那时应在控制的文档里写明它的已知盲区,⛔ 不要让下一个人以为覆盖是全的。

    ⛔ C(在门口按写入拆分) 分诊建议排除:它把一个分类问题变成两条代码路径,而两条路径正是本仓元判据②要消灭的形状(同一操作两个实现 ⇒ 带治理的一侧胜出)。若要选 C,须在裁决正文说明为什么它不落入该判据。

    ⚠️ 四棱不同向(不扩散棱反对)+ 人工地板双命中 ⇒ ⛔ 绝不适用代裁。


    Generated by Claude Code

  3. huangyiirene commented on Aug 31, 2026

    @huangyiirene
    Collaborator

    ⚖️ 裁决记录 — B:给写入面一个显式的「合法 org-less」申报,然后把条件对象收编

    出处:维护者 2026-08-31,live PM chat,总监席第 7 场决裁批 #17,逐字:「同意」(对本批按呈报推荐整体放行;本卡呈报推荐为 B 窄形起步)。录裁:director seat, session session_01KGtaLpkW1mycWgkbSb3H6t。

    裁定内容(分诊 2026-08-31 补充评论要求的条件,全部写入裁决正文)

    1. 方向 = B:平台获得一个显式的每写入「合法 org-less」申报通道,resolveSystemInsertOrganization 据此区分「有意的环境级/无租户行」与「漏 stamp 的 bug」。同一个 NULL 不再身兼两义。
    2. 申报必须 loud, checkable, countable(分诊防错棱的必需件,三词入裁不入实现细节):静默可选标记不合格 —— 那只是给旁路换名。申报要在 review 期可读、可被门禁清点、可出计数读数。
    3. 先测类的规模,再实现:首批只收编两只已裁标本 —— sys_metadata(org 作用域的 flow overlay 只在「本进程内发布后」绑定触发器,重启后静默失绑——冷启动两条读路径都把 organization_id 非空的行滤掉了 #6190 option A 的环境级写)与 sys_audit_log(其写入方枚举的合法情形);⛔ 不从 design: isSystem 写入是否在租户审计控制范围内?——#13178 类级装置(A/B/C)的共同前置,从未被裁过 #13491 的 51 只 cannot-determine 里凭猜挑成员,每只后续对象的收编都要带自己的写入方证据。
    4. ⛔ C(按写入拆门)排除,依据元判据②:同一操作两条代码路径正是「带治理一侧胜出」要消灭的形状。
    5. A(维持 unclassified)作为被拒选项记录在案:其代价 —— 命名空间最大写入面对租户审计控制永久失明 —— 被判为不可接受,即租户审计控制在关键路径上(分诊第四棱问句的答案)。

    状态转移(同笔)

    needs-user-decision → pm:queue(domain:engine;Feature,已裁 —— 设计方向定,实现按上列五条约束派发;条款②按实际 diff 在入队闸门判)。


    Generated by Claude Code

  4. added
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 31, 2026
  5. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    CollaboratorAuthor

    ⏸️ HELD by the domain:engine lane — surface collision, not a disagreement with the ruling

    ⛔ Not claimed, and deliberately so. Recording it so a sibling seat does not pick this up cold and collide.

    The ruling (决裁批 #17, comment 5478571825) is read and accepted: direction B, with the five constraints in its body — the declaration must be loud, checkable, countable; measure the class size before implementing; first batch收编 only the two already-ruled specimens (sys_metadata per #6190 option A, sys_audit_log per its writers' enumerated cases); ⛔ never pick members by guess from #13491's 51 cannot-determine; ⛔ option C excluded per 元判据②. Nothing here re-opens any of that.

    Why it waits

    resolveSystemInsertOrganization sits on the objectql insert path, and #13657 is working that exact seam right now — the undeclared-field door in front of the hooks, which is the same insert pipeline. Two seats editing the objectql insert path in parallel is how you get either a merge conflict on a p1+security change or, worse, two half-repairs that each pass their own tests.

    ⇒ This dispatches as soon as #13657 lands, and it is near the front of the queue when it does: p1 + security, ruled, with the implementation constraints already written down. ⚠️ The one thing that could change that is if #13657's own report shows it moved the insert seam in a way that alters where the org-less declaration should hook — in which case this card's Zone 1 gets re-derived from the landed state rather than from today's.

    One thing worth carrying into the eventual dispatch order

    Constraint 3 says measure the class size first. ⚠️ That measurement has a known unreadable edge in this session: cloud and objectos are outside this session's repo scope, and they are where host/environment-level write paths live. A class-size census run from here will have a real gap, and it must be declared as NOT MEASURED rather than quietly scoped to what happened to be readable. Flagging now because that constraint is the ruling's, and a census that silently under-counts would satisfy it only on paper.


    Generated by Claude Code

  6. removed
    needs:contract-reviewMarker only — PR awaits its at-tier Contract review PASS; no check reads it, the record decides
    on Sep 4, 2026
  7. hotlong commented on Sep 4, 2026

    @hotlong
    Contributor

    Carrier hygiene — director seat, summon 13, session_01WXyGTWPbbreqXow7Z2pZCk, 2026-09-04 ~05:57Z. needs:contract-review removed from this card: it is a design card in pm:awaiting-maintainer with no open PR referencing it (open-PR search, zero hits; positive controls #14754 → PR #14930 and #14180 → PR #15139 answered), so there is no reviewable increment to carry. Maintainer ruling 2026-08-28 (contract-review.md: 「⛔ 不预挂:可复审增量存在前永不挂标,提前挂已废止 —— 前瞻条款②事实住卡上裁决/分诊评论、Clause-② 申报与 --tier 输出;开载体恒 = 真实待审」). The contract nature of the decision stays recorded in the card's text; the executing seat hangs the carrier on the card and the PR together when a diff exists. pm:awaiting-maintainer and the rest of the label set untouched.


    Generated by Claude Code

  8. huangyiirene commented on Sep 9, 2026

    @huangyiirene
    Collaborator

    状态转换:pm:awaiting-maintainer → needs-user-decision(2026-09-09)

    维护者回批逐字:「B 桶 · 要你的判断,应转 needs-user-decision —— 23 张 转决策卡」。

    判据:欠判断不是动作 —— 这是一张纯设计卡,标题自己就以 design: 开头。批 #9 的租户再裁决表达不了第三种租户态:条件性租户隔离的对象,即 org-less 是行的属性而不是对象的属性。⛔ 没有机械答案可推导 —— 它要的是一次架构裁决。

    按 SKILL.md:110/:126:决定待做 = needs-user-decision;而 core-rules.md:87 也明写「设计卡、契约形状提案……进决策箱」。⇒ 此前为误分类,本卡从一开始就该在收件箱。

    同笔摘 pm:awaiting-maintainer;domain:engine、security、priority:p1 留下。

    ⚠️ 根因见 #17017。


    Generated by Claude Code

  9. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    and removed
    pm:awaiting-maintainerAwaiting a manual maintainer action — ruling already given; no dispatch, no machine exit
    on Sep 9, 2026
  10. os-bill commented on Sep 9, 2026

    @os-bill
    Collaborator

    维护者速读

    事情:这张设计卡问「有没有第三种租户态——同一对象里既有带组织的行、也有合法无组织的行」(sys_metadata 的环境级写入、sys_audit_log 对无组织列对象的记录),并推荐 B「按次声明合法无组织写入」(草案 PR #14923)。这个问题已被 ADR-0131(09-04 接受)反向解决:ADR 原文第 188–197 行点名本卡,裁「合法无组织的行 = 该对象根本不该有组织列」——sys_metadata 成为无租户的环境定义账本(D6 / D7),sys_audit_log 是部署账本;B 在 ADR 的备选表(第 773 行)被明确否决:「让 NULL 成为被声明的状态,而不是消灭它」。PR #14923 已关闭;您 09-03 曾亲自叫停其合并。

    选项:A(推荐) 按 ADR-0131 关卡(被取代,not planned),执行归 ADR-0131 的 v18 线(#15193 闸)。B 您认为 ADR-0131 对这两个对象的处置不对 ⇒ 重开为对 ADR-0131 D6 / D7 的修订提案(受管 ADR 草案,人合)。

    你要做的:回一个字母,A / B。

    • ① 项目长远合理性:A 让一条原则(D1「NULL 不是状态」)覆盖全部对象,缩小特例;B 让「被声明的 NULL」永久存在,每个未来写者都要记得声明。
    • ② 实际业务拉动:零——这两个对象的存量 NULL 行由 ADR 的迁移四归宿(D10)逐表处理。
    • ③ 防 AI 犯错:D9「缺章即拒写,任何姿态」是响亮的;B 依赖写者自觉。
    • ④ 创业阶段不扩散:A 零新增;B 增一条按次声明的机制与账本。
      推荐 A。置信缺口:无——ADR 原文直接点名并处置了本卡。

    裁后执行

    • A ⇒ 关 not planned(superseded by ADR-0131),摘 needs-user-decision;priority:p1 · security · domain:engine 留。
    • B ⇒ 立 ADR-0131 修订卡进决策箱,本卡 pm:blocked 于其后。

    总监席第 20 场(session_01Tep4AYXZvyBA7jsvne5KZV)按决策箱勤务补齐速读,2026-09-09T05:3xZ;⛔ 非裁决。


    Generated by Claude Code

  11. os-bill commented on Sep 9, 2026

    @os-bill
    Collaborator

    Ruling recorded — A: superseded by ADR-0131; card closes (director seat, summon #20, decision batch #108 item 1, 2026-09-09T05:4xZ)

    Provenance (who / verbatim / where): maintainer, live PM chat with this seat (session_01Tep4AYXZvyBA7jsvne5KZV, os-bill), 2026-09-09T05:4xZ, replying to batch #108 in which this card was item 1 with the 速读 and four-facet block at 5596352358 recommending A. Reply, verbatim: 「7424 查 「什么在飞」 就应该查open的呀,直接关闭。 其他同意。」 — item 1 = A.

    Ruled. The third tenancy state this card asked for does not exist as a state: ADR-0131 (accepted 2026-09-04, lines 188–197) names this card and resolves it the other way round — a legitimately org-less row is a row on an object that should have no organization column; sys_metadata becomes the tenant-less environment definition ledger (D6 / D7) and sys_audit_log a deployment ledger. Option B (declare an org-less write per call, draft PR #14923, closed) is refused in the ADR's alternatives table (line 773). Execution follows the ADR's v18 line behind #15193. B here (reopen as an ADR-0131 D6/D7 revision) not taken.

    State, one write: closed not_planned (superseded by ADR-0131); needs-user-decision removed; priority:p1 · security · domain:engine kept.


    Generated by Claude Code

  12. removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they landpriority:p1High: required for production / M2security

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions