Repository navigation
[decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350
Description
Ruled: 6070750378 · letter A · 2026-10-08T23:03Z
Filing gate: ② a decision only the maintainer can make. This is question Q4 from #15206's stage 0 (ADR-0131 C5; the os-dev-report on #15206). Deleting a ruled guard is Clause-②: yes (execution-duties.md), and the guard was ruled on #7780. Filed by domain:engine seat 1 (seat post #6367) · session_01EUBvqtauTDmHi2ZgY759p2. ⛔ Not graded or routed here; ⛔ not a claim.
Who acts on it: the maintainer answers one letter; triage grades it; the domain:engine seat carries the answer into #15206's stage S4 (the protocol refuses organization-scoped writes). Nothing before S4 waits for it.
维护者速读
- Product question: an uninstall with no organizationId deletes EVERY organization's rows for that package (measured 5 of 5, including a foreign org's) #7780 立了一道闸: 卸载一个包时,必须指明是哪个组织(
organizationId),或者明确说"所有组织"(allTenants: true),否则拒绝(TENANT_SCOPE_REQUIRED,400)。当时实测,不带组织的卸载会把每个组织(包括别人的组织)在这个包下的元数据行全删掉。 - C5(feat(metadata-core,metadata-protocol,objectql,plugin-security): the
sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206)落地后,元数据行不再属于任何组织,全部是环境级的。卸载本来就是整个环境的事,"指明哪个组织"已经没有可指的对象。dev 读代码发现:HTTP 卸载门从来不发allTenants,所以今天一个没有当前组织的运维,根本无法通过 HTTP 卸载包。 - 推荐 A: C5 的 S4 阶段一并撤掉这两个请求键和两处
TENANT_SCOPE_REQUIRED。谁能卸载,仍由现有的门禁权限决定(隔离部署下限运维)。回一个字母:A / B / C。
一句话问题
包的元数据不再分组织以后,卸载时还要不要求"指明组织或明确说全部组织"?
Background (read on main, from #15206's stage 0)
- The guard.
metadata-protocol'sdeletePackagerefuses withTENANT_SCOPE_REQUIRED(400) nearprotocol.ts:24123–:24145unless the request namesorganizationIdorallTenants: true. The runtime door has its ownrequireUninstallOrganizationScope(nearruntime's packages domain:479). The semantic migration entry is17.package-uninstall-explicit-all-tenants. - Why it existed. Product question: an uninstall with no organizationId deletes EVERY organization's rows for that package (measured 5 of 5, including a foreign org's) #7780 measured that an uninstall with no
organizationIddeleted every organization's rows for that package, 5 of 5, including a foreign organization's. - What C5 changes. S3 stops the doors threading an organization into metadata writes. S4 refuses every organization-scoped write and deletes the per-organization path. S5 reads environment → code. After those stages, every
sys_metadatarow a package owns is environment-wide, so an uninstall is environment-wide by construction and an organization names nothing. - Today's HTTP door. It never sends
allTenants, so an operator with no active organization cannot uninstall over HTTP at all (dev's reading).
Governing text
- Product question: an uninstall with no organizationId deletes EVERY organization's rows for that package (measured 5 of 5, including a foreign org's) #7780's ruling and the
17.package-uninstall-explicit-all-tenantsentry. - ADR-0131 D6 and D12 (item 7): package operations are environment-wide and operator-gated under a wall.
- ADR-0049: a key with no referent is residue to retire.
选项 × 真实代价
| 选项 | 做什么 | 客户感受到的后果 |
|---|---|---|
| A | S4 撤掉 organizationId / allTenants 两个请求键和两处 TENANT_SCOPE_REQUIRED;卸载即环境级,谁能卸载仍由门禁的运维权限决定 |
运维可以直接卸载,不再被一个已无意义的参数挡住;传了旧键的调用方会被严格请求体拒绝(显式报错,有 ADR-0087 条目说明) |
| B | 保留 allTenants: true,改成每次卸载都必须带的"确认"开关 |
多一步确认,但同一个键换了含义,正是 #22007 B 否掉的做法 |
| C | 保留"必须有当前组织"的要求,而删除的其实是环境级行 | 闸还在,但什么也挡不住,运维多了一道无意义的门槛 |
业务含义直译:
- A:大楼只剩一个业主后,拆东西不用再写"拆哪一户"。
- B:拆东西前多签一张"确认全楼",但表格上那一栏原来的意思被改了。
- C:明明只有一户,还要求先报户号才能拆。
os-decision-facets
- ① 项目长远合理性:A 让卸载的语义与 C5 后的数据模型一致(环境级、运维门禁),撤掉无指涉的键;B 让旧键换含义;C 留一个形同虚设的闸。
- ② 实际业务拉动:今天 HTTP 卸载门从不发
allTenants,没有当前组织的运维无法卸载;C5 之后组织不再指向任何行。 - ③ 防 AI 犯错:A 删掉 AI 调用方会一直白传的参数,传了就显式报错;B 悄悄改了键义;C 是没有效果的闸。
- ④ 创业阶段不扩散:A 立即退休,不留兼容;B、C 保留无用的面。
Prior rulings read: package uninstall, allTenants, TENANT_SCOPE_REQUIRED → #7780 (ruled guard), 17.package-uninstall-explicit-all-tenants, #22007 B (re-meaning a key, not taken); ADR-0131 D6/D12, ADR-0049; thread: #15206 (stage 0).
推荐
A:S4 撤掉这道闸。
- 终态句: 两年后,包是环境级的单元,安装、卸载都是运维对整个环境做的操作,权限只看"谁能卸载",不看"卸哪个组织"。主流平台也是这样:Salesforce 的 managed package 按 org 安装和卸载,卸载就是对整个 org 生效,没有"子租户范围"参数。
- 自检: 只看①选 A;②③④ 是否翻转:否。
- 回退: C 不可取;如不撤,宁可保留现状直到 C7 再议。
- 置信缺口: "HTTP 卸载门从不发
allTenants"是读码,未经真实请求实测;仓库外是否有调用方传allTenants,测不到。
裁后执行
- 选 A: 在 feat(metadata-core,metadata-protocol,objectql,plugin-security): the
sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206 的 S4 PR 中删除两个请求键(packages/spec的请求 schema 跨车道声明)和两处TENANT_SCOPE_REQUIRED,加 ADR-0087 条目,changeset 写明,契约复审档复核。 - 选 B: S4 中把
allTenants改为必填确认,另立 spec 车道卡记录键义变化。 - 选 C: S4 保留现状,本卡挂到 C7(feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211)再议。
Dedupe: MCP search_issues, repo-scoped, open and closed: 「deletePackage organizationId allTenants TENANT_SCOPE_REQUIRED uninstall organization scope retire」 → 15 results. The relevant hits:
- Product question: an uninstall with no organizationId deletes EVERY organization's rows for that package (measured 5 of 5, including a foreign org's) #7780 (closed): the ruling this question revisits.
- [finding]
DELETE /packages/:idthrough the dispatcher removes the package from the live registry, then refuses withTENANT_SCOPE_REQUIRED: a 400 that leaves the uninstall half applied #20492 (closed): the dispatcher's half-applied uninstall that refusedTENANT_SCOPE_REQUIRED, a defect of the same guard. - feat(metadata-core,metadata-protocol,objectql,plugin-security): the
sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206: this question's source. - automation: config.organization '*' fans a packaged scheduled flow out once per installing organization under isolated tenancy (the recorded end state of #20619 ruling A) #20645 (open): a scheduled-flow fan-out, a different question.
- fix(platform-objects,core): sys_metadata_activation ships tenant-less — drop the reserved organization_id before 17.3 is cut (ADR-0126 amended by ADR-0131 D6/D7) #15024 (closed):
sys_metadata_activationtenant-less, a sibling precedent.
None decides this.
Dedupe words: uninstall organization scope guard retire · allTenants TENANT_SCOPE_REQUIRED C5 · deletePackage environment-wide
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 8, 2026
Triage: graded
priority:p1·security·target:v18·domain:engine·area:access(needs-user-decisionkept)Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T20:13Z. ⛔ Not a claim, ⛔ not a dispatch.sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206's S4, and feat(metadata-core,metadata-protocol,objectql,plugin-security): thesys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206 is p1target:v18. Release-priority work is p1.security, and why it is the maintainer's: Product question: an uninstall with no organizationId deletes EVERY organization's rows for that package (measured 5 of 5, including a foreign org's) #7780 ruled this guard after a measured cross-organization deletion. The ruling's words are 「跨租户卸载必须显式声明,缺省缺参永远不等于「全部租户」。」. Retiring a ruled security guard is a loosening, so it escalates.sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206's S4 inmetadata-protocol⇒domain:engine. Under any letter, the spec half stays with S4 as declared cross-lane paths, per stage 0's F12 and F13 reading. That half is a narrowing: the request keys, the error-code ledger rows and the semantic entry.objectstack-fleet commentedon Oct 8, 2026
Ruling: batch #294 item 2 · letter A · maintainer 「其他同意」 2026-10-08T23:01Z
Director seat, summon #35,
session_01VYToj6PQehTEKNrjGM9akg(GitHubos-zhuang; written asobjectstack-fleet[bot]via the relay). Presented in batch #294 from thedomain:engineseat's decision card (the body; triage grade 6068216919): A retire the organization-scope guard in #15206's S4, B keepallTenants: trueas a mandatory confirmation, C keep the current-organization requirement. The seat recommended A; the maintainer answered 「其他同意」. Thread-read: 6068216919. Freshness: no comment since the presentation. Premises re-read onorigin/main43fc50051c:TENANT_SCOPE_REQUIREDatprotocol.ts:24165and:24180; the runtime door's comment that it never sendsallTenants(packages.ts:452-454); the semantic entry17.package-uninstall-explicit-all-tenants.The ruling
A. Once ADR-0131 C5's S4 makes every package-owned
sys_metadatarow environment-wide, an uninstall is environment-wide by construction and an organization names nothing. S4 retires theorganizationIdandallTenantsrequest keys and bothTENANT_SCOPE_REQUIREDrefusals; who may uninstall stays with the package door's operator gate (ADR-0131 D6, D12). A request still carrying the retired keys is refused by the strict request body, with an ADR-0087 entry stating the retirement and the remedy. #7780's guard was ruled for the era in which rows were organization-scoped; C5 removes that premise, so the guard retires with it, which is not a loosening of anything the wall protects. ⛔ Not taken: B (a key kept under a new meaning, the shape #22007 B refused), C (a gate that guards nothing).Prior rulings read: #7780 (the ruled guard; closed),
17.package-uninstall-explicit-all-tenants, #22007 B (no re-meaning of a key), ADR-0131 D6 / D12, ADR-0049, #20492 (closed, a defect of the same guard) → 6 hits; thread: 1 comment. 自检: 只看①选 A;②③④ 是否翻转:否。置信缺口:「HTTP 门从不发allTenants」是读码未经真实请求实测;仓外调用方是否传allTenants测不到。State
needs-user-decision→pm:queue(domain:engine,priority:p1,target:v18) in this act; theRuled:line added to the body. The answer rides feat(metadata-core,metadata-protocol,objectql,plugin-security): thesys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206's S4 PR: the two keys removed from the request schema (packages/spec, declared cross-lane), the two refusals removed, the ADR-0087 entry, the changeset, the contract review at tier. Nothing before S4 waits for it.Generated by Claude Code
objectstack-fleet commentedon Oct 9, 2026
Claim: PM loop round 67 · 2026-10-09T00:26Z
Session:
session_01EUBvqtauTDmHi2ZgY759p2Account:
os-litant(the seat's linked user, asGET /useranswers it; always the card's assignee)Branch:
claude/issue-15206-s4-package-environment-wide(#15206's S4, to be dispatched)Worktree:
objectstack-issue-15206-s4Domain:
domain:engineSeat:
domain:engine#1Provenance:
sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206's Q4.securitytarget:v18(6068216919).sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206's S4 PR. This card has no PR of its own and no dev of its own.File surface (per ruling 6070750378, riding feat(metadata-core,metadata-protocol,objectql,plugin-security): the
sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206's S4):organizationIdandallTenantsrequest keys fromdeletePackage(packages/spec, declared cross-lane), and bothTENANT_SCOPE_REQUIREDrefusals inmetadata-protocol(protocol.ts).Refsline. The seat closes this card with S4's landing record.Container & model: S4's dispatch (
L,mode:subagent).Clause-②: no
TENANT_SCOPE_REQUIRED, is accepted once C5 makes the rows environment-wide. The ruling decides that directly: an organization names nothing there.Responsibility: an organization-scope guard ruled for organization-scoped package rows (Product question: an uninstall with no organizationId deletes EVERY organization's rows for that package (measured 5 of 5, including a foreign org's) #7780) | C5 makes package-owned
sys_metadatarows environment-wide | the guard would then name nothing and refuse a legitimate uninstallThread-read: 6070750378
Serial constraints cleared: S4 waits for S2 (in dev) and S3, per the stage plan (6067844889). Nothing before S4 waits for this card.
objectstack-fleet commentedon Oct 9, 2026
Release:
session_01EUBvqtauTDmHi2ZgY759p2(os-litant,domain:engine#1), releasing claim 6071732822 · 2026-10-09T05:19Z · reason: the seat is clocking off on the maintainer's order in chat (「当前任务处理完,合并后就下班」) · destination:pm:queue, unassigned. This card still rides #15206's S4 PR, as ruling A says (6070750378). The next seat claims it together with S4. No work was started on it.Generated by Claude Code
objectstack-fleet commentedon Oct 9, 2026
Claim: PM loop round 2 · 2026-10-09T13:42Z
Session:
session_01Bw3y2DWhT9RPnrmDsNqEVGAccount:
os-tesla(the seat's linked user, asget_meanswers it; the card's assignee)Branch:
claude/issue-15206-s4-protocol-env-only(#15206's S4; this card has no PR or dev of its own)Worktree: S4's cloud session
Domain:
domain:engineSeat:
domain:engine#2(seat post #20966)Provenance: the ruling is A (6070750378). Seat 1's claim 6071732822 was released at 6074820322, with this card left to ride #15206's S4. The S4 claim on #15206 is posted in the same act.
File surface: per the ruling, within S4. The
organizationIdandallTenantsrequest keys retire from the package delete request (packages/spec, declared cross-lane). BothTENANT_SCOPE_REQUIREDrefusals go: inprotocol.ts(deletePackage) and inruntime'srequireUninstallOrganizationScope. Theerror-code-ledgerrows follow. An ADR-0087 entry states the retirement and the remedy. Who may uninstall stays with the package door's operator gate.Container & model: S4's dispatch (
L,mode:cloud,model: default).Clause-②: yes (narrowing)
Responsibility: n/a — a ruled decision card carried by a stage
Thread-read: 6074820322
Serial constraints cleared: as on the S4 claim on feat(metadata-core,metadata-protocol,objectql,plugin-security): the
sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206. S3 is onmain(7895671162). The S4 PR carriesRefs #22350, and this seat closes the card with S4's landing record.objectstack-fleet commentedon Oct 10, 2026
Landed and closed: PR #22515 →
b389e4355c(#15206 stage S4) carries this card's ruling A (6070750378).domain:engine#2·session_01Bw3y2DWhT9RPnrmDsNqEVG· 2026-10-10T00:42Z.origin/main:deletePackageanswers400 INVALID_REQUESTto a request carryingorganizationIdorallTenants(any value).requireUninstallOrganizationScopeand bothTENANT_SCOPE_REQUIREDrefusals are retired, along with their ledger rows.DeletePackageRequestandUninstallCleanupdrop the retired keys.sys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206; the stage's landing record is on feat(metadata-core,metadata-protocol,objectql,plugin-security): thesys_metadatafamily goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206.NOT_CREATABLEon uninstall. That refusal is loud.objectrow's table survives its uninstall.pm:dispatchedis removed in this act.