Repository navigation
[Decision] 「非托管」安装复制带 _lock 的打包项时:去掉锁(A)、拒绝这类包(B),还是原样保留锁(C)?(ADR-0131 D6 × ADR-0010 保护模型) #22971
Description
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 ACCEPT6117037795: a package item authored with_lock: 'full'is copied as written by anunmanagedinstall. On a showcase boot, the nextPUT /api/v1/meta/view/NAMEanswered403 ITEM_LOCKED. examples/: zero_lock:occurrences (the S2 dev), so no shipped package hits this today.- The vendor's consent: a package opts into
unmanagedexplicitly through itsinstallModes(S2's manifest key), so the vendor chose to let environments take copies.
Governing text
- ADR-0131 D6 (
docs/adr/0131-…mdnear:414): "Unmanaged. The package's metadata is copied once into the environment definition ledger as environment-provenance items — from then on it is the environment's own metadata, editable in Studio like anything authored there … Salesforce's unmanaged package." - ADR-0010 (Metadata Protection Model): L3 per-item
_lock→403 item_locked. Package-levelmetadataDefaults.lock, for examplelockReason: 'Core admin UI — tenant edits can lock users out', is resolved into each artifact's_lockby the loader. - Ruling on feat(spec,objectql,cli): the template install mode — a package copied once into the environment ledger, fully editable, refused on shared-database multi-tenant postures (ADR-0131 D6) #15213: B, spelled
unmanaged(6108509158, and the spelling note in ADR-0131:380). - Triage's rule: loosening a protection boundary always escalates. That is why this is not answered in the retriage.
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
objectstack-fleet commentedon Oct 12, 2026
Ruling: batch #325 item 1 · letter A · maintainer 「同意」 2026-10-12T07:24Z
Director seat, summon #37,
session_01LqNgdPZB2Jnr5HpGbaqLeB(GitHubos-zhuang; written asobjectstack-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 onorigin/mainin 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;:388definesmanaged/unmanagedas 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_lockwith_lockSource: 'package';examples/carries zero_lock; S2 (PR #22916) is still a draft and does not wait on this card; #15213 is open (pm:blockedon #22949, assigneeos-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.
_lock,_lockReason,_lockSourceon every item the import copies, whether the lock was authored per item or resolved frommetadataDefaults.lockby the loader (both arrive as the same L3 shape).<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.unmanagedexplicitly throughinstallModes, 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".403 ITEM_LOCKEDto contradict the "editable" promise at save time.os-decision-facets
_lock包;S3 编写页写明「非托管 = 锁随复制去掉」。Prior rulings read: feat(spec,objectql,cli): the template install mode — a package copied once into the environment ledger, fully editable, refused on shared-database multi-tenant postures (ADR-0131 D6) #15213 B (6108509158); ADR-0131 D6 (
:414–:419), the:380spelling note,:388; ADR-0010 §3.2 (metadataDefaults.lock→_lock,_lockSource: 'package'), §3.3 L3; S2 report 6116157070; ACCEPT 6117037795; retriage 6118956122.After this ruling
completedas the decision record. The strip lands in feat(spec,objectql,cli): the template install mode — a package copied once into the environment ledger, fully editable, refused on shared-database multi-tenant postures (ADR-0131 D6) #15213's track (S3, or the S2 follow-up, whichever thedomain:specseat carries first); a pointer goes there.objectstack-fleet commentedon Oct 12, 2026
Closed
completedon 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.docs(changeset,spec,cloud-connection,metadata-protocol): the _lock st…