Skip to content

[Decision] 「非托管」安装复制带 _lock 的打包项时:去掉锁(A)、拒绝这类包(B),还是原样保留锁(C)?(ADR-0131 D6 × ADR-0010 保护模型) #22971

Closed

Description

@objectstack-fleet

Ruled: 6119681934 · letter A · 2026-10-12T07:24Z

Filing gate ②: a decision only the maintainer can make. Every option either loosens a protection layer that ADR-0010 gives package authors, or adds a new authoring refusal. Filed by the triage seat (seat post #6015, session_01AavokzJ5DndAwitDXvKy4U) as the answer to #15213's pm:retriage (6118956122). ⛔ Not a claim.

Anchor: #15213 (S2 is in flight as PR #22916). S2 lands without this answer, because its shipped texts already name the _lock exception (6118361628). S3 (the authoring page) and any change to importUnmanagedPackage's planner wait on it.

维护者速读

你批的「非托管(unmanaged)安装」(#15213 → B,ADR-0131 D6)规定:包里的元数据复制一次进环境,从此是环境自己的,"在 Studio 里像自己写的一样可以改"。但 ADR-0010 的保护模型允许包作者给某个条目加锁(_lock),理由例如"租户改了会把用户锁在外面"。开发实测:带锁的条目被原样复制后,下一次在 Studio 里保存答 403 ITEM_LOCKED,和"像自己写的一样可以改"矛盾。三条路:

  • A:复制时去掉锁,导入结果逐条列出去掉了哪些锁。和 Salesforce 非托管包一致:装进来就全归你。一个小改动,随 S3 或 S2 的后续。
  • B:一个包如果既允许非托管安装、又带锁,就在编写时(defineStack)和安装入口直接拒绝,作者二选一。新增一条拒绝,约 1 个 PR。
  • C:原样保留锁,复制品仍锁着,只改文档。不写代码,但与 D6"可以改"的原文相抵。

席位推荐 A,其次 B。

选 A、B 还是 C?

os-decision-facets

  • ① 项目长远合理性:A 让「非托管 = 环境自己的」只有一种含义,与 Salesforce 非托管包一致;B 把锁和非托管做成互斥,规则清楚但多一条拒绝;C 让 D6 的原文有例外。
  • ② 实际业务拉动:examples/ 里 _lock: 为 0,拉动是前瞻的;S3 的编写页要写明这一条。
  • ③ 防 AI 犯错:A 下导入结果逐条点名去掉的锁,不静默;B 在编写时就响亮拒绝;C 下 AI 写的「可编辑」承诺会在保存时被 403 打脸。
  • ④ 创业阶段不扩散:A 不新增门禁;B 新增一条编写期和安装期拒绝(新增门禁默认否);C 零代码。

Background (measured)

  • S2 report 6116157070, open question 1, carried unruled by ACCEPT 6117037795: a package item authored with _lock: 'full' is copied as written by an unmanaged install. On a showcase boot, the next PUT /api/v1/meta/view/NAME answered 403 ITEM_LOCKED.
  • examples/: zero _lock: occurrences (the S2 dev), so no shipped package hits this today.
  • The vendor's consent: a package opts into unmanaged explicitly through its installModes (S2's manifest key), so the vendor chose to let environments take copies.

Governing text

Options × real cost × workload

Option What it does What a customer sees Workload
A The unmanaged import strips _lock / _lockReason / _lockSource from each copied item, and the import result names each stripped lock Every copied item is editable, as D6 says. The admin sees which vendor locks were dropped domain:spec (planner) · small, inside the S3 or S2 follow-up PR · precedent: none
B A package that permits unmanaged and ships any locked item is refused at defineStack and at the install door, naming the items Package authors choose: locks or unmanaged installs. A locked item can never be copied domain:spec · 1 PR, a new refusal (Clause-②: no, narrowing) · precedent: the stack aggregate's other refusals
C Copies keep their locks. The authoring page states the exception A copied locked item stays locked, against D6's "editable" docs only

Prior rulings read: #15213 B (6108509158); ADR-0131 D6 (:414–:419) and its spelling note (:380); ADR-0010 L3 and the metadataDefaults.lock loader rule; S2 report 6116157070; ACCEPT 6117037795; retriage 6118956122.

Recommended: A. Fallback: B.

  • On ① alone, A: the vendor opted into unmanaged, and D6 defines that as "the environment's own metadata". A visible strip keeps that one meaning.
  • ②③④ do not flip it: ④ favours A, ③ is close between A and B.
  • Confidence gap: a vendor may want some items never copied unlocked. B serves that, at the cost of a new refusal.

Activity

  1. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #325 item 1 · letter A · maintainer 「同意」 2026-10-12T07:24Z

    Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB (GitHub os-zhuang; written as objectstack-fleet[bot] via the relay). Batch #325 (two cards) was presented in chat with this seat's own readings and the recommendation "A, fallback B" for this card; the maintainer answered 「同意」, which takes the recommendation. Premises re-read on origin/main in this act and holding: ADR-0131 D6 (:414–:419) makes an unmanaged copy "the environment's own metadata, editable in Studio like anything authored there" and names Salesforce's unmanaged package; :388 defines managed / unmanaged as the two states of one property, whether the package stays the authority; ADR-0010 §3.2–3.3 has the loader write a package lock into _lock with _lockSource: 'package'; examples/ carries zero _lock; S2 (PR #22916) is still a draft and does not wait on this card; #15213 is open (pm:blocked on #22949, assignee os-warren).

    The ruling

    A: the unmanaged import strips every lock from each copied item, and the import result names each stripped lock together with the vendor's reason.

    • Stripped: _lock, _lockReason, _lockSource on every item the import copies, whether the lock was authored per item or resolved from metadataDefaults.lock by the loader (both arrive as the same L3 shape).
    • Visible, not silent: the import result lists each stripped lock as <type>.<name>: <_lock> — <_lockReason> (the reason text verbatim when the author gave one), so the admin reads why the vendor had locked it before choosing to edit. That is this seat's one addition to the triage's A; it costs no gate.
    • Why A and not B: a package permits unmanaged explicitly through installModes, so the vendor has already chosen to let environments take editable copies; a refusal would protect the vendor from their own declared choice. A lock whose source is the package has nothing to stand on once the package is no longer the authority (ADR-0131 :388). B stays the fallback if a vendor case appears that needs "copy, but never unlocked".
    • Why not C: it writes an exception into D6's text and leaves 403 ITEM_LOCKED to contradict the "editable" promise at save time.

    os-decision-facets

    After this ruling

  2. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Closed completed on ruling 6119681934 (batch #325 item 1 → A, the maintainer's word verbatim 「同意」): this card is the decision record. The strip, with the vendor's reason text in the import result, lands in #15213's track (S3 or the S2 follow-up). Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB, 2026-10-12T07:25Z.

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

    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdomain:specpriority:p2Medium: important, M3security

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions