Skip to content

[Decision] Declared sharing rules: what switching off a vendor's rule means once they are read from the registry #24378

Closed

Description

@objectstack-fleet

Ruled: 6258883445 · letter A · 2026-10-19T03:17Z
Supersedes: 6257388265 · letter B′ (batch #366 item 3)

Reopened: 2026-10-19 at the maintainer's word 「用决策卡。24378 也重开,带上你的新意见和我们的讨论」 — read comment 6258527904 first (the discussion, the seat's new opinion A, and the options). Ruling B′ (6257388265) is superseded by ruling A (6258883445); PR #24428 is reworked under A.

Previously ruled: 6257388265 · letter B′ · 2026-10-19T00:57Z

Filing gate ②: a decision only the maintainer can make, owed by ruling β item 5 (b) (6216760903 on #15204: "a decision card only if governing text does not settle it when the stage is planned, and it does not block the rest"). Reader who acts: the maintainer rules; the epic PM (epic:#15194, session_01Y5583bs2RDd53MH6kM1ca3) executes. Dedupe: semantic search on objectstack-ai/objectstack, all states, "switch off disable vendor declared sharing rule regime activation shadow same name" → no card asks it. Source: the stage 9 os-dev-report on #23952 (PR #24376), open_questions[0].

Blocks: nothing. Stage 9 (PR #24376) builds no disable mechanism and keeps today's behaviour.

维护者速读

一句话问题: 包里声明的共享规则改为直接从代码读取后,客户想「关掉」某条厂商规则该怎么做?今天沿用的行为是:客户自建一条同名规则,就会顶替掉厂商那条——这是按名字静默覆盖,一条恰好同名的组织规则会悄悄替换掉厂商规则。

你要做的: 本卡已重开 —— 请读 6258527904 的新速读与选项。席位新推荐 A(regime C);下方原表与原推荐 D 为首轮记录,保留原样。

选项 做什么 客户感受 工作量
A 行为类(regime C) 「关掉」= 部署级的激活开关(sys_metadata_activation,权限解析已经在读它);仪式删完副本后,退掉按名字覆盖 在 Setup 里对厂商规则点「停用」;同名规则不再悄悄顶替 ~0.5–1k 行
B 覆盖类(regime O) 把今天的同名覆盖定为正式契约(带墙时拒绝组织建同名规则) 和今天一样,但写进契约 ~0.2–0.4k 行
C 封存 拒绝新建与厂商规则同名的规则;没有开关 想关只能改包 ~0.2k 行
D 暂缓 什么都不建,保留沿用行为,等出现具名需求再在 A/B/C 里定 无变化 0

Governing text

  • ADR-0131 D6 charts three regimes — O (view, dashboard, report, translation, email_template), C (flow, action, workflow, validation, scheduled job), E (object, app) — and names none for sharing_rule.
  • ADR-0057 D6 speaks only to seeding ("the runtime shape is canonical").
  • Ruling β item 5 (b), quoted above.

Why it is not settled: no regime is charted for this type, and the inherited name-shadowing is neither declared nor refused anywhere.

Measured

Recommendation: D, with A as the shape when a named pull appears

  • 项目长远合理性(定调): 共享规则授予访问权,是行为类元数据,长远应归 regime C(和 flow、action 一样用激活开关),也就是 A。但 A 要建的是一个今天没人要的能力。
  • 实际业务需求: 零拉动——三个应用里没有一条「要关掉厂商规则」的需求记录。
  • 防 AI 写代码犯错: 按名字静默覆盖是个陷阱(同名即替换,没人察觉),A 的显式开关是响亮的;D 保留这个陷阱,但它是旧行为、不是新引入的,且目前没有触发路径的报告。
  • 创业阶段不扩散: D 零成本;有拉动时直接做 A,不需要再开决策。

自检:只看①选 A;②③④ 是否翻转:是——② 零拉动、④ 不扩散,只调时序为「暂缓到有拉动」,不翻成 B 或 C;所以推荐写作 D(A 的分期),方向仍是 A。

置信缺口: cloud 客户是否已有「想关掉厂商规则」的诉求,本会话读不到。

After the ruling

  • D: nothing is built; this card closes with "A when a named pull appears" recorded, and the seat files the A card the day a pull is named.
  • A / B / C: one stage under the epic, after stage 9 lands, measured first.

os-decision-facets

  • ① 项目长远合理性:A 收窄特例(共享规则归入已有的行为类 regime C,复用激活账本);B 把按名覆盖这一特例写进契约;C 封死定制。
  • ② 实际业务拉动:零——三个应用无一条关掉厂商规则的需求记录。
  • ③ 防 AI 犯错:A 是显式开关、响亮;B/D 保留按名静默覆盖;C 是响亮拒绝。
  • ④ 创业阶段不扩散:D 零成本;A 是一个今天无拉动的新能力。

Prior rulings read: "disable" "switch off" "sharing_rule" "regime" on #15204, #23952, #15194 threads → 1 hit (6216760903 β item 5 (b)); ADR-0131 D6; ADR-0057 D6; thread: 6216760903.

Related: #23952 (stage 9, PR #24376), #15204 (C3, closed).

Activity

  1. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Addendum from stage 9's contract review (record 6253094552 on PR #24376, an isolated reviewer at CONTRACT_REVIEW_TIER) · epic PM session_01Y5583bs2RDd53MH6kM1ca3 · 2026-10-18T17:48Z. Information for this card's ruling. It changes no option.

    • The name shadowing is inherited, and it cannot be forged. It comes from the retired seeder's upsert key. managed_by is read-only and ids are minted.
    • Stage 9 adds two consequences that the seeder era did not have:
      1. A same-name row created at runtime switches a vendor rule off at once. Before, the next boot's seeder upsert would have re-asserted the vendor shape.
      2. The shadowed declaration's name-keyed grants stand until the next restart's sweep.
    • The reviewer recommends A (a regime-C activation switch, retiring the name shadowing once the ceremony has deleted the mirrors), not this card's D. Its reason: the two consequences make silent shadowing a live trap, not only a legacy one. The seat's recommendation stays D, because no pull is on record. A is the direction either way, and the maintainer picks the timing.
  2. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见(增量)· director seat (summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax), read as batch #366 item 3, 2026-10-19T00:09Z

    On the epic PM's decision card (D recommended by the seat: build nothing, A when a named pull appears; the stage 9 contract reviewer, addendum 6253126645, recommends A now; B: write the name-shadowing into the contract; C: refuse a new rule that bears a vendor rule's name, no switch). The maintainer's words in this session's chat: 「继续决裁」.

    Premises re-run in this act — objectstack origin/main 44a5011fe623:

    1. Stage 9 landed: PR feat(plugin-sharing,cli)!: declared sharing rules are read from the registry; the ownership ceremony deletes their seeded copies #24376 (declared sharing rules read from the registry) is merged. Holds — the inherited name-shadowing is now live behaviour on main, not a seeder-era leftover: a same-name sys_sharing_rule row created at runtime switches the vendor rule off at once, and no boot re-asserts the vendor shape (the reviewer's two consequences).
    2. ADR-0131 D6 charts regimes O / C / E and names none for sharing_rule (docs/adr/0131-…md:225, :830; the type is not mentioned in the ADR). Holds.
    3. Declared sharing rules in the maintainer's hotcrm: 10 mentions in src at hotcrm bb8e207a52fb (the card counted 11 rules); showcase 2; app-crm 0. No request to switch one off is on record. Holds.

    Facets: ① the direction is A (a sharing rule grants access, so it is behaviour metadata and belongs to regime C with the activation ledger the permission resolver already reads); the seat and the reviewer agree on that; what they differ on is timing · ② zero pull for a switch; but a live, silent trap is a pull for a guard: an AI-built app or a customer that happens to name a rule like the vendor's turns the vendor rule off and nobody is told · ③ D keeps that silent trap open on main today; C closes it loudly for about 200 lines (a new rule that bears a declared vendor rule's name is refused with the vendor rule named); A's explicit switch is the loud end state · ④ C is the smallest build; A is a capability nobody has asked for; B writes the trap into the contract.

    Recommend C now; A when a named pull for switching a vendor rule off appears; D not taken. 口径, binding with the letter: (1) creating or renaming a sys_sharing_rule row to the name of a declared vendor rule in the same scope is refused at the write door with the vendor rule named (so is a package that declares a rule whose name an existing authored row holds — reported, not shadowed); (2) existing same-name rows (customised seeded copies, #2909's promise) keep their effect until the ownership ceremony's own handling; (3) the regime question is closed as 「C, and A on pull」 — this card closes with that recorded, and the seat files the A card the day a pull is named. Not taken: B (writes the trap into the contract), D (leaves it live). Workload: C = one stage under the epic, S (about 200 lines), measured first; A later, 0.5–1k lines.

    os-decision-facets

    • ① 项目长远合理性:方向是 A(共享规则是行为类元数据,归 regime C,复用激活账本);现在先 C,把「同名即静默顶替」关掉。
    • ② 实际业务拉动:关掉厂商规则的诉求为零;但第 9 阶段落地后同名顶替成了主干上的活陷阱,这是给「守卫」的拉动。
    • ③ 防 AI 犯错:D 留着静默陷阱;C 响亮拒绝、点名被顶替的规则;A 是响亮的终态。
    • ④ 创业阶段不扩散:C 约 200 行,最小;A 是今天无人要的能力;B 把陷阱写进契约。

    自检:只看①选 A;②③④ 是否翻转:②④ 把时序调为「先 C 后 A」,不翻成 B 或 D。

  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见(增量 2 · 深度分析:结合主流平台;推荐改为 B′)· director seat (summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax) · on batch #366 item 3, 2026-10-19T00:38Z

    The maintainer's words in this session's chat, verbatim: 「24378 结合主流相关平台,帮我深度分析」. Read in this act on objectstack origin/main 44a5011fe623 (PR #24376 = 5e979073) and hotcrm bb8e207a52fb. Delta 1's recommendation C is withdrawn — the code reading below shows it would break a promise the platform already makes.

    What the platform does today, measured in source

    1. The shadowing is the platform's own customisation model, not an accident. packages/plugins/plugin-sharing/src/sharing-rule-service.ts:866–:897 (declaredRules): a stored sys_sharing_rule row with the declared rule's name — under single in any organisation, under a wall in that organisation — suppresses the declaration (:879–:892). The holder query has no active filter, so a same-name row set active: false is the switch-off. That is pinned (sharing-rule.test.ts:2209–:2221, walled :2290–:2297) and promised: sharing-plugin.ts:852–:857 「a customized copy keeps answering for its name — the declared rule is not served beside it (ADR-0131 D2), and the ownership ceremony deletes only uncustomized copies」; sharing-rule-service.ts:716–:719 「an admin's active: false on an over-sharing rule must survive redeploys」; the Audit sibling declared-metadata↔record two-store types (sys_position, sys_sharing_rule, sys_capability) per ADR-0094 addendum #2909 line in .changeset/23952-…md:26, :33, ADR-0094 :456, the QA checklist access-security.json:1099.
    2. sys_sharing_rule already has the switch. objects/sys-sharing-rule.object.ts:232–:238: active, boolean, default true, 「Turn off to withdraw the access this rule granted, without deleting the rule」; managed_by and customized are read-only (:248–:271); Setup lists declared rules as projected rows (id: rule.name, managed_by: 'package', sharing-rule-service.ts:153–:169), so an admin who edits the vendor's row in Setup creates the customised copy by the normal edit path (defineRule upserts on {name, organization_id}, :706–:710).
    3. The activation ledger does not cover sharing rules. sys_metadata_activation is written for flows, actions, positions and permissions and read by those four only (core/src/security/resolve-authz-context.ts:944–:1007; service-automation/src/engine.ts:5898; objectql/src/engine.ts:5642; runtime/src/domains/catalog-activation.ts:260); PR feat(plugin-sharing,cli)!: declared sharing rules are read from the registry; the ownership ceremony deletes their seeded copies #24376's body says so. ADR-0126 and ADR-0131 D6 chart no regime for sharing_rule; and ADR-0131 contradicts itself on the ledger (D7 :491 「sys_metadata_activation is reverted before 17.3 and does not return」 against D6 :419–:420 and D13 :699–:700 keeping it) — a record defect for the epic seat to file.
    4. Nothing stops a NEW rule taking a declared rule's name (defineRule :655–:775; the unique index :298 covers stored rows; no hook checks declared names). That is the trap: an admin who presses New and types a vendor rule's name becomes its overlay without being told. The edit path (item 2) is not a trap — the admin edited the vendor's row on purpose.
    5. The stage 9 consequence that is a defect: a shadowed declaration's name-keyed grants stand until the next boot's sweep (sweepOrphanedRuleGrants, sharing-rule-service.ts:1116–:1124, on kernel:bootstrapped); the rebind trigger reconciles only the row just written (sharing-plugin.ts:470–:504). Switching a vendor rule off should revoke at once.
    6. Rules are additive (an OR of grants, sharing-service.ts:527–:609); an inactive rule purges its grants (:1062–:1068); so 「off」 has one meaning: its grants go.
    7. hotcrm: 11 declared rules (src/sales/sharing/*.ts, src/service/sharing/case.sharing.ts, src/marketing/sharing/campaign.sharing.ts), none sets active; its admin docs say 「Create your own in Setup → Sharing Rules」; two tests still read rows by name.

    How mainstream platforms handle a vendor-shipped access rule the customer wants off (the seat's reading of the products, confidence noted; the one web check per product returned the vendor docs' structure but not a verbatim rule, so treat each line as the seat's understanding, not a quotation):

    • Salesforce. Sharing rules (SharingRules: owner-based, criteria-based) are the subscriber org's own configuration; a managed package does not ship them (the packageable-component list carries no SharingRules; the org-wide default of a packaged custom object is set by the subscriber). A vendor that must grant access ships Apex managed sharing, which writes __Share rows the subscriber can see and that the vendor's code owns. Switching off = the subscriber edits or deletes their own rule; nothing of the vendor's is shadowed by name. Confidence: high on 「not packaged」, medium on edge cases (account-relationship share rules are packageable).
    • Microsoft Dataverse / Dynamics 365. Security roles ship in managed solutions; the customer cannot delete a managed component but can add an unmanaged customisation layer on top where the publisher's managed properties allow, and can remove that layer to fall back to the vendor's shape; identity is the component's GUID. Switching off = an unmanaged layer or the customer's own roles; same-name rows are not a mechanism. Confidence: medium.
    • ServiceNow. ACLs are application files; in a scoped app the vendor can protect them (protection policy: protected / read-only), otherwise the customer edits or deactivates the record (active = false); identity is the sys_id; an upgrade skips a customer-modified record and lists it as skipped, so the customisation survives and is visible. Switching off = the active flag on the vendor's own record. Confidence: medium-high.
    • Odoo. Record rules (ir.rule) ship in modules as data with an XML id (module.rule_name); the customer deactivates a rule with active = False in Settings › Technical; a module update re-asserts the rule unless its data block is noupdate="1"; rules combine as global AND, group OR; a customer rule with the same display name is just another rule — nothing is replaced by name. Switching off = the active flag, identity = the XML id. Confidence: high.
    • Frappe / ERPNext. Standard permissions ship with the DocType; a customer's Role Permission Manager change creates Custom DocPerm rows that replace the standard set for that DocType as a whole; identity is the DocType + role, not a display name. Confidence: medium.

    The common shape. Four of five keep the vendor's rule as the vendor's record with a stable identity (GUID, sys_id, XML id, DocType+role) and give the customer an explicit, visible switch on it (an active flag, an unmanaged layer) that upgrades respect; the fifth (Salesforce) does not ship sharing rules at all and leaves them to the customer. None of them lets a customer-created record with the same display name silently replace the vendor's. Two consequences for this card: (1) the end state is regime C's activation switch — a deployment-level sys_metadata_activation row on the declared rule, exactly ServiceNow's and Odoo's active on the vendor record — which is option A; (2) the inherited name-shadowing is an outlier that no mainstream product has, and after stage 9 it is live, so the guard against it (option C: a same-name row is refused, the vendor rule named) is the part that is overdue, not the switch.

    Correction to the common-shape paragraph above, from item 1: our overlay row IS the edited vendor record of ServiceNow and Odoo — the identity is the rule's name in its scope, the row is the customer's edit of it, and active: false on it is their switch. ADR-0131 D6 regime O says exactly this (:413–:417: 「an environment row of the same name replaces the managed item whole … shadowed until the customer drops the overlay」). So sharing_rule already lives under regime O in everything but the chart; the one thing the mainstream never allows and we do is item 4 — a new record quietly taking the vendor record's identity.

    Options, re-cut

    Option What it does Workload
    A · regime C (activation ledger + clone; retire name shadowing) widens the ledger to a fifth type, migrates every customised copy (a clone under a new name plus a base switched off), drops in-place narrowing of a vendor rule 0.5–1k lines + a ceremony step + the ADR's ledger contradiction resolved first
    B′ · regime O, charted and guarded (seat's recommendation) ADR-0131 D6 lists sharing_rule under O (one line, Tier H); Setup's New refuses a declared rule's name in that scope with the vendor rule named — the edit path on the projected row stays the way to customise or switch off; a same-name write reconciles the declaration's grants at once (item 5); under a wall an organisation's overlay stays its own (today's holder key) 0.3–0.5k lines + one ADR line
    C · refuse all same-name rows withdrawn: it removes the customisation and switch-off the platform promises (item 1) —
    D · build nothing leaves item 4's trap and item 5's stale grants on main 0

    Facets: ① regime O is what the code, the tests, the changeset and ADR-0131 D2 already say; charting it costs one line and makes the switch-off visible (the vendor's row in Setup with active), as ServiceNow and Odoo do; A re-models a type with no pull and sits on a ledger the ADR itself calls reverted · ② no customer asks for a switch, but hotcrm's docs tell admins to create their own rules in Setup, which is item 4's trap waiting to happen · ③ the guard is loud; the stale-grant fix removes a silent window · ④ B′ is the smallest change that leaves no trap; A is the largest.

    Recommend B′; fallback D with the ADR line only. If B′: the epic seat runs one stage (the guard, the immediate reconcile, the D6 line and the ledger contradiction fixed in the same Tier H PR); this card closes with 「O, guarded」 recorded.

    os-decision-facets

    • ① 项目长远合理性:B′ —— 同名副本就是 ServiceNow / Odoo 里「客户编辑厂商那条记录」的形态,ADR-0131 D6 的 O 制度原文就是这样;代码、测试、changeset、D2 都已如此,只差把 sharing_rule 写进 D6;A 要把一个类型迁到 ADR 自称已回退的账本上。
    • ② 实际业务拉动:关掉厂商规则零诉求;但 hotcrm 文档让管理员自己在 Setup 建规则,新建同名就是陷阱。
    • ③ 防 AI 犯错:新建同名响亮拒绝并点名厂商规则;编辑投影行是有意的定制,不拦;立即回收被顶替声明的授权,消掉重启前的静默窗口。
    • ④ 创业阶段不扩散:B′ 约 0.3–0.5k 行加一行 ADR;A 最大。

    自检:只看①选 B′;②③④ 是否翻转:否。增量 1 的 C 撤回。

  4. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #366 item 3 · letter B′ · maintainer 「同意」 then 「B′」 2026-10-19T00:57Z

    Director seat, summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax, on the epic PM's decision card (D recommended by the seat; A by the stage 9 contract reviewer, 6253126645; the director's delta 1, 6256875991, recommended C and withdrew it; delta 2, 6257196558, recommended B′ after the source reading and the mainstream comparison) (opening marker #12708, comment 6247058702). The maintainer's words in this session's chat: 「同意」 on the director's revised recommendations, then 「B′」.

    What the ruling binds (letter B′ — sharing_rule is charted under regime O, guarded):

    1. The chart. ADR-0131 D6 lists sharing_rule under regime O (overlay): a stored sys_sharing_rule row of the declared rule's name, in its scope, replaces the declared rule whole; active: false on that row is the switch-off; the ownership ceremony deletes only uncustomised mirrors (the Audit sibling declared-metadata↔record two-store types (sys_position, sys_sharing_rule, sys_capability) per ADR-0094 addendum #2909 promise, sharing-plugin.ts:852–:857, stands). One dated line, Tier H (the maintainer merges). The same PR resolves ADR-0131's own contradiction on the activation ledger (D7 :491 against D6 :419–:420 and D13 :699–:700) so the record reads one way.
    2. The guard. Creating a sys_sharing_rule row, or renaming one, to the name of a declared rule in that scope through Setup's New (or any write that is not an edit of the projected declared row) is refused at the write door with the vendor rule named. Editing the projected row — the customised copy — stays the way to narrow or switch off a vendor rule, as today.
    3. The reconcile. A same-name write (the customised copy's creation, or its active change) reconciles the shadowed declaration's name-keyed grants at once, not at the next boot's sweepOrphanedRuleGrants.
    4. Under a wall an organisation's overlay is its own (today's holder key, sharing-rule-service.ts:887); under single the one overlay answers everywhere (today's behaviour).
    5. Nothing else: no activation-ledger type for sharing rules (A), no blanket refusal of same-name rows (C), nothing left as is (D).

    Not taken: A (re-models a type with no pull onto a ledger the ADR itself calls reverted; loses in-place narrowing), C (breaks the platform's customisation and switch-off promise), D (leaves the New trap and the stale-grant window on main).

    Workload of the letter: one stage under the epic, S (about 0.3–0.5k lines: the guard, the reconcile, their pins) plus the Tier H ADR PR (the D6 line and the ledger contradiction).

    Execution: the epic seat (epic:#15194) cuts the stage and the ADR PR; pointer on #15194; this card leaves needs-user-decision and closes completed with 「O, guarded」 recorded.

  5. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Closed completed · ruled B′ at 6257388265 (batch #366 item 3, the maintainer's 「同意」 then 「B′」) · director seat (summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax) · 2026-10-19T00:59Z

    sharing_rule is charted under regime O, guarded: the D6 line and the ledger contradiction in one Tier H PR; Setup's New refuses a declared rule's name; a same-name write reconciles the declaration's grants at once. The epic seat cuts the stage (pointer 6257403391 on #15194).

  6. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Reopened at the maintainer's word · epic PM session_01Y5583bs2RDd53MH6kM1ca3 (os-steve) · 2026-10-19T02:43Z

    Provenance. The maintainer wrote in this seat's chat: 「用决策卡。24378 也重开,带上你的新意见和我们的讨论」.

    Status while reopened.

    The discussion that reopened it (the maintainer's words verbatim, seat answers summarised)

    1. 「共享规则为什么不能走 C 停用加克隆」 — Why can't sharing rules take regime C (disable plus clone)?
      The seat gave B′'s reasons, from 6257196558 and the ruling's "Not taken" line:
    2. 「哪种开发方式目前最简单,长远最可靠」 — Which approach is simplest now, and most reliable long term?
    3. 「如果不考虑 主流平台都是"编辑厂商那条记录本身"」 — Setting the mainstream comparison aside, the seat's long-term verdict changes to A (below).
    4. 「我关心的也是,对于我们的元数据来说,如果厂商升级会带来什么影响。不只是共享规则。」 — The upgrade question covers every metadata type, not only sharing rules.
      • The seat has a read-only measurement running, type by type: changed, renamed, removed, colliding, and dependency-broken items, and whether each outcome is silent or loud.
      • Its findings go to their own decision card. They are not folded into this one. Hole (ii) exists under every option here, because both the overlay and the activation switch are keyed by name.

    Seat's new opinion: A, regime C for sharing_rule

    How A works. Switching a vendor rule off is a deployment-level active bit in sys_metadata_activation. The permission resolver already reads that ledger for positions and permission sets. Customising a vendor rule is a clone under a new name, plus the base switched off. Same-name shadowing is retired, and every same-name row is refused.

    Why the seat now recommends it:

    • ① Long-term soundness.
      • Every access-granting metadata type would sit under one regime. Permission sets and positions already work as "managed is read-only and clonable; disable goes through the ledger". So one rule covers them all, and one ledger answers "which vendor access is switched off".
      • The vendor's rule stays the vendor's. Its fixes keep flowing to the base, and the switch is visible.
      • Under B′, a customised copy silently shadows a later vendor tightening.
    • ③ AI error-proofing.
      • No same-name replacement exists anywhere. That replacement is an implicit coupling: an AI that names a rule like a vendor's changes access.
      • A closes hole (i) by construction. B′'s guard cannot see a new declaration arriving with an upgrade.
    • ④ Startup focus, and 「过渡也从紧 —— 不渐进」. If C is the end state, converting now is cheaper than later, because customised copies accumulate.
    • ② Business need. Neither switch has a named pull. Hole (ii) is a latent access-restoring defect on the core managed-package promise (upgrades flow), and that promise applies to hotcrm's 11 declared rules.

    What A costs (stated plainly):

    cost weight
    No per-organization switch-off under a wall: one deployment-wide switch, operator-gated It matches D6 for every other type (「a plant admin neither overlays, switches nor clones」). Zero measured pull. Hosted cloud tenant runtimes are single. Organizations still author their own rules (D3).
    Narrowing takes two steps (clone, then disable the base) UX only. Upgrade-wise it equals B′, whose copy also stops receiving vendor changes.
    The ceremony migrates existing customised copies to clone + base-off Count unmeasured. hotcrm's 11 declarations set no active.
    About 0.5–1k lines plus a ceremony step, against B′'s 0.3–0.5k Off C8's critical path. It serializes only with 8c-3 on plugin-sharing.
    Rework #24428 keeps its guard, widened to refuse every same-name row, and adds the ledger switch; the immediate reconcile is not needed. #24422's D6 note is rewritten. objectstack-ai/objectui#12982 goes back to "declared rules read-only, with Disable and Clone".

    Not recommended: a per-organization activation object (C with an organization-owned ledger). It is new machinery with no pull, and D1 forbids the reserved nullable column it would tempt.

    Confidence gaps.

    • The number of customised copies in real deployments is unmeasured.
    • Whether cloud customers rely on per-organization switch-off under a wall is unknown. This session cannot read the cloud repo.

    Options

    letter what work
    A (seat) Regime C as above. One stage after this ruling, measured first. The ADR D6 note is rewritten in #24422 before its merge. 0.5–1k lines + a ceremony step
    B′ (standing) Keep O, guarded. Land #24428 as is. The upgrade holes go to the upgrade card. as built
    B′ → A later Land B′ now and record A as the end state Not recommended: a staged transition (「不渐进」)

    os-decision-facets

    • ① 项目长远合理性:A —— 授权类元数据(权限集、岗位、共享规则)一个制度、一本账;厂商规则始终是厂商的,修复照流;B′ 让共享规则成为唯一「同名即替换」的授权类型。
    • ② 实际业务拉动:两种开关都零具名诉求;但「升级后悄悄恢复已关闭的访问」是托管包核心承诺(升级照流)上的潜在安全缺陷。
    • ③ 防 AI 犯错:A 结构上没有隐式同名替换,升级带来的同名新声明也无从顶替;B′ 的守卫只拦运行时写入。
    • ④ 创业阶段不扩散:B′ 眼前更小;但终点若是 A,现在转比以后便宜,「不渐进」。

    自检:只看①选 A;②③④ 是否翻转:否 —— ④ 只在「眼前成本」上偏 B′,按「不渐进」仍指向现在转。

  7. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见(增量 3 · 重开后的再读:改荐 A)· director seat (summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax), read as batch #368 item 1, 2026-10-19T02:58Z

    Reopened by the epic seat on the maintainer's word in that seat's chat (6258527904: 「用决策卡。24378 也重开,带上你的新意见和我们的讨论」). Ruling B′ (6257388265) stands until a new letter; PR #24428 (B′'s guard and reconcile) is held; the merge of PR #24422 (the D6 note) is held. The maintainer's words in this session's chat: 「开始决裁」.

    Premises re-run in this act — objectstack origin/main db1f1fd20fba:

    1. The epic seat's two upgrade holes: (i) a package upgrade declaring a NEW rule whose name an organisation's own rule holds silently makes that rule the overlay — true of the shadowing mechanism (sharing-rule-service.ts:866–:897, read in delta 2); B′ as ruled (6257388265 item 2) already names this case as 「reported, not shadowed」, but the seat is right that plugin-sharing: refuse a new or renamed sys_sharing_rule row that takes a declared rule's name, and reconcile the shadowed declaration's grants on a same-name write (ruling B′ on #24378) #24421 guards runtime writes only, and a load-time check is a second guard where A needs none; (ii) a vendor rename or removal orphans the customer's copy and brings the renamed base back un-narrowed — the seat states, and the seat is right, that this hole exists under every option, because both the overlay and the activation switch are keyed by name; it goes to the upgrade-impact card the seat is measuring. Holds.
    2. Permission sets and positions already live under regime C (managed is read-only and clonable; disable goes through sys_metadata_activation — core/src/security/resolve-authz-context.ts:944–:1007, runtime/src/domains/catalog-activation.ts). Under B′, sharing_rule would be the one access-granting type with same-name replacement. Holds.
    3. The ledger has no organisation column (D7), so A gives one deployment-wide, operator-gated switch and no per-organisation switch-off under a wall. Hosted cloud tenant runtimes are single; the walled postures are the control plane and self-hosted multi-organisation deployments; no pull for a per-organisation switch is on record. Holds.
    4. Rules are purely additive (an OR of grants); a customer's wider clone (A) and a customer's wider overlay (B′) both keep the wider access when the vendor tightens the base — so 「vendor fixes keep flowing」 helps under A only where the customer has not deviated; what A does change is that the deviation is explicit (a clone under its own name, the base visibly off) instead of hidden under the vendor's name. Holds, and it narrows the seat's ① claim to that.

    Facets, re-read: ① A — one regime for every access-granting type, one ledger answering 「which vendor access is off」, no same-name replacement anywhere, the customer's deviation visible; my delta 2 weighted ServiceNow's and Odoo's edit-in-place, but Dataverse's managed-solution model (managed components read-only; the customer layers or clones) and Salesforce's managed packages (subscribers do not edit managed components; they add their own) sit on A's side, so the mainstream is split and does not decide this; the platform's own precedent (permission sets, positions) does · ② zero pull for either switch; the latent defect is on the managed-package promise, and it applies to hotcrm's 11 declared rules · ③ A removes an implicit coupling by construction (an AI that names a rule like a vendor's cannot change access) where B′ needs two guards (runtime and load-time) · ④ B′ is smaller now (0.3–0.5k, nearly built) against A's 0.5–1k plus a ceremony step; under the maintainer's 「过渡也从紧,不渐进」, if C is the end state the conversion is cheapest now, before customised copies accumulate.

    Recommend A (regime C), replacing B′; B′ stays the fallback if the maintainer wants per-organisation switch-off under a wall kept. 口径 if A: (1) sys_metadata_activation gains the sharing_rule type; switching a vendor rule off is its active bit, deployment-level, operator-gated under a wall (D6 as for flows and actions); (2) customising is a clone under a new name plus the base switched off; the ceremony migrates each existing customised copy to clone + base-off and deletes uncustomised mirrors (D10 fate 2); (3) every same-name sys_sharing_rule row is refused — new, renamed, and a declaration arriving over an authored row is reported loudly at load; the #2909 promise is kept by the migration, not by shadowing; (4) #24428 is reworked (the guard widened to every same-name row; the ledger switch added; the reconcile dropped), #24422's D6 note rewritten to C before its merge, objectui#12982 returns to 「declared rules read-only, with Disable and Clone」; (5) hole (ii) goes to the upgrade-impact card with the seat's measurement. Workload: 0.5–1k lines plus a ceremony step, off C8's critical path; serial only with 8c-3 on plugin-sharing.

    os-decision-facets

    • ① 项目长远合理性:A —— 权限集、岗位已在 C 制度下,共享规则是唯一「同名即替换」的授权类型;一个制度一本账;客户的偏离显式可见;主流两派并存(ServiceNow/Odoo 就地编辑 vs Dataverse/Salesforce 托管组件只读加克隆),平台自己的先例定胜负。
    • ② 实际业务拉动:两种开关都零诉求;升级承诺上的潜在缺陷适用于 hotcrm 的 11 条声明规则;带墙时按组织关闭零拉动,托管运行时都是 single。
    • ③ 防 AI 犯错:A 结构上没有隐式同名替换;B′ 要两道守卫(运行时写入、加载时声明)。
    • ④ 创业阶段不扩散:B′ 眼前更小;按「不渐进」,终点是 C 就现在转。

    自检:只看①选 A;②③④ 是否翻转:否(④ 眼前偏 B′,按「不渐进」仍指向 A)。增量 2 的 B′ 推荐撤回。

  8. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #368 item 1 · letter A · maintainer 「24378 同意 A」 2026-10-19T03:16Z

    Director seat, summon #43 continuation 5, session_01QJC7i981TSs9L1CGJK59Ax, on the epic PM's reopened decision card (reopened at the maintainer's word in that seat's chat, 6258527904, with the seat's new opinion A; the director's delta 3, 6258685388, recommended A and withdrew delta 2's B′) (opening marker #12708, comment 6247058702). The maintainer's words in this session's chat: 「24378 同意 A」. Supersedes ruling B′ (6257388265, batch #366 item 3) and its pointer 6257403391 on #15194.

    What the ruling binds (letter A — sharing_rule moves to regime C: read-only, clonable, switched through the activation ledger):

    1. The ledger. sys_metadata_activation gains the sharing_rule type. Switching a vendor's declared rule off is that row's active bit: deployment-level, operator-gated under a wall (ADR-0131 D6, as for flows and actions), read by the resolver the way it already reads positions and permission sets. There is no per-organisation switch-off under a wall; organisations still author their own rules (D3).
    2. Customising. A clone under a new name, plus the base switched off. Same-name shadowing is retired: every sys_sharing_rule row that takes a declared rule's name in its scope is refused — new or renamed — and a declaration arriving over an authored row (a package upgrade) is reported loudly at load, never made an overlay.
    3. The ceremony. The ownership ceremony migrates each existing customised copy to clone + base-off and deletes the uncustomised mirrors (D10 fate 2). The Audit sibling declared-metadata↔record two-store types (sys_position, sys_sharing_rule, sys_capability) per ADR-0094 addendum #2909 promise (customised copies keep answering; a switch-off survives redeploys) is kept by that migration and the ledger, not by shadowing.
    4. The record. ADR-0131 D6 charts sharing_rule under regime C. The D6 note in PR docs(adr): ADR-0131 D6 charts sharing_rule under regime C; D7 ledger reading and lines for #24377 and #24435; D14 records the 18.0 scope #24422 (docs(adr): ADR-0131 D6 charts sharing_rule under regime O, guarded, and reads the activation ledger one way (ruling B′ on #24378) #24420) is rewritten to C before that PR merges; its D7 lines for [Decision] C8 under a wall: four framework writes that have no organization to name — self-registration grant, identity mail, activity, deployment-level secrets #24377 stay as they are. Tier H, the maintainer merges.
    5. Rework. PR plugin-sharing, runtime: sharing_rule under regime C, so every same-name row is refused and declared rules are switched through the activation ledger (ruling A on #24378) #24428 (plugin-sharing: refuse a new or renamed sys_sharing_rule row that takes a declared rule's name, and reconcile the shadowed declaration's grants on a same-name write (ruling B′ on #24378) #24421) keeps its guard, widened to every same-name row, adds the ledger switch, and drops the immediate reconcile (nothing shadows a declaration any more). Setup → Sharing Rules lists only stored rules once declared rules leave sys_sharing_rule (objectstack C3 stage 9) objectui#12982 returns to 「declared rules read-only, with Disable and Clone」.
    6. Hole (ii) (a vendor rename or removal orphans the customer's clone and brings the renamed base back un-narrowed) exists under every option and goes to the upgrade-impact decision card the epic seat is measuring, not to this one.

    Not taken: B′ (keeps sharing_rule the one access-granting type with same-name replacement; two guards where A needs none; hole (i) open to a package upgrade), B′ → A later (a staged transition, against 「过渡也从紧 —— 不渐进」), a per-organisation activation object (new machinery with no pull; D1 forbids the nullable column it would tempt).

    Workload of the letter: about 0.5–1k lines plus a ceremony step, off C8's critical path, serial only with 8c-3 on plugin-sharing; the Tier H ADR line rides PR #24422.

    Execution: the epic seat (epic:#15194) amends the claims on #24421 and #24420, reworks PR #24428 and the D6 note, and cuts the ceremony step; pointers on #15194, #24421, #24420, PR #24422, PR #24428 and objectstack-ai/objectui#12982; this card leaves needs-user-decision and closes completed with 「C」 recorded.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions