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

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. 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

  2. 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

  3. 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

  4. 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

  5. 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

  6. 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

  7. 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

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions