|
3 | 3 | **Status**: Proposed (2026-09-01) — awaiting the maintainer's hand-merge, which is itself the |
4 | 4 | acceptance act for a governed surface (Prime Directive #14). ⛔ Nothing below is settled until |
5 | 5 | this record merges; the implementation cards are cut **from** the merged ADR, never ahead of it. |
| 6 | +**Scope bounded by the 2026-09-02 addendum** |
| 7 | +([#14487](https://github.com/objectstack-ai/objectstack/issues/14487)): the permission matrix |
| 8 | +§1.3(a) measures is **not** part of this boundary's payoff — permission sets stay whole in the |
| 9 | +`type: app` package. |
6 | 10 | **Deciders**: ObjectStack maintainer, 2026-09-01, live PM chat, verbatim and untranslated: |
7 | 11 | 「立 ADR 起草卡派发」and 「14122 作为epic 任务集中跟踪」— approving the proposal in |
8 | 12 | [#14122](https://github.com/objectstack-ai/objectstack/issues/14122) into the ADR-drafting lane |
@@ -507,3 +511,92 @@ a reader deserves to know which of its anchors were re-measured: |
507 | 511 | `packages/objectql/src/plugin.ts`, `packages/core/src/plugin-order.ts`, |
508 | 512 | `packages/spec/src/stack.zod.ts`, `packages/spec/src/kernel/manifest.zod.ts`, |
509 | 513 | `packages/cli/src/commands/compile.ts` |
| 514 | + |
| 515 | +--- |
| 516 | + |
| 517 | +## Addendum (2026-09-02, #14487) — the permission matrix is outside this boundary's payoff; permission sets stay whole in the app package |
| 518 | + |
| 519 | +**Provenance.** Maintainer ruling, 2026-09-02, live PM chat, recorded the same day on |
| 520 | +[#14454](https://github.com/objectstack-ai/objectstack/issues/14454#issuecomment-5507189677) |
| 521 | +and quoted here in the words that record carries — the PM seat's, not a transcript of the |
| 522 | +maintainer's:「第 3 项(权限集)维护者 2026-09-02 拍板:取 B。」The same comment names what this |
| 523 | +section must say:「权限集整体留在 app 包,权限矩阵不在包边界收益范围内」. The question ruled |
| 524 | +on is item 3 of [#14454](https://github.com/objectstack-ai/objectstack/issues/14454) (carried |
| 525 | +verbatim onto |
| 526 | +[#14457](https://github.com/objectstack-ai/objectstack/issues/14457) as its decision card), |
| 527 | +raised by the HotCRM split plan |
| 528 | +[objectstack-ai/hotcrm#1449](https://github.com/objectstack-ai/hotcrm/pull/1449), |
| 529 | +§上游缺口 / Upstream gaps item 3, which asked the maintainer to *"decide whether permission sets |
| 530 | +can be composed per package (a module contributing its own object grants into a role the app |
| 531 | +owns), or record that the permission matrix is explicitly out of scope for the boundary ADR-0130 |
| 532 | +creates."* **B is the second half of that sentence, and this section is that record.** |
| 533 | + |
| 534 | +This section lands while the record is still **Proposed**: it bounds what the record claims and |
| 535 | +settles nothing else — the maintainer's hand-merge remains the acceptance act, exactly as the |
| 536 | +Status line says. |
| 537 | + |
| 538 | +### What §1.3(a) measured, and what this boundary does not fix |
| 539 | + |
| 540 | +§1.3(a) counts, among the three measurable consequences of having no boundary, *"a permission |
| 541 | +matrix of 30 rows × 9 CRUD columns × 6 permission sets that interleaves `客户/联系人/商机` with |
| 542 | +`运费标准/等级政策/工厂成本`"*, and §4 draws the payoff from that section: *"Studio's scope is the |
| 543 | +package, so package boundaries **are** the grouping Studio has never had (§1.3a)"*. **The payoff |
| 544 | +does not extend to the permission matrix.** Splitting a product into co-owning packages leaves |
| 545 | +that matrix exactly as flat as §1.3(a) found it. This is said here, in the record, because |
| 546 | +§1.3(a) lists the matrix as a pain and §4 answers §1.3(a) as a whole — a reader is otherwise |
| 547 | +entitled to read a promise this record cannot keep. |
| 548 | + |
| 549 | +**Why — measured, not reasoned.** A permission set grants across domains *by nature*: it is |
| 550 | +authored per **role**, not per module, so no module owns it. hotcrm#1449 measured the standard |
| 551 | +HotCRM product against its six planned modules — `core`, `sales`, `cpq`, `service`, `marketing`, |
| 552 | +`activity`, all inside the one `crm` namespace D1 makes co-ownable, with the `type: app` package |
| 553 | +declaring no objects at all. Of its **six** permission sets, **four span five or six of the six |
| 554 | +modules** (`sales_rep`, `sales_manager` and `system_admin` at six; `service_agent` at five); the |
| 555 | +remaining two span four (`marketing_user`) and two (`guest_portal`). **Not one is confined to a |
| 556 | +single module.** The split therefore has nothing to distribute — whatever the module boundaries |
| 557 | +are, every set still names objects on both sides of them. This is a second instance, independent |
| 558 | +of the 黑猫 fork §1.3(a) measured: two products, the same shape. |
| 559 | + |
| 560 | +**Where the sets live, and what Studio shows.** The six sets stay **whole in the `type: app` |
| 561 | +package**. That is not a new rule but the standing one: |
| 562 | +[ADR-0086](./0086-authz-metadata-config-boundary-and-cross-package-composition.md) D3 gives a |
| 563 | +permission set exactly one owning `packageId` (implemented — `spec/security/permission.zod.ts`, |
| 564 | +tagged `[ADR-0086 D3]`), so a set is in one package or in another and cannot be in several. In |
| 565 | +Studio's **Access** pillar — the matrix of |
| 566 | +[ADR-0084](./0084-application-builder-information-architecture.md), reached per package through |
| 567 | +ADR-0086 D7's package door — the sets therefore appear **under the app package only**, and their |
| 568 | +matrix stays as wide as the product. Modules group Data, Automation and Interface; they do not |
| 569 | +group Access. |
| 570 | + |
| 571 | +⛔ This section changes no decision: D1–D8, §1 and §3's non-goal on grouping keys stand exactly |
| 572 | +as written. In particular **no `module` or grouping key is added to a permission set** — §1.4 |
| 573 | +rejected that key on measured cost, and nothing here reopens it. |
| 574 | + |
| 575 | +### What was NOT decided |
| 576 | + |
| 577 | +Per-package composition of grants — a module contributing **its own** objects' grants into a role |
| 578 | +the app package owns, by analogy with `navigationContributions` — is the other half of |
| 579 | +hotcrm#1449's question. It is **filed, not decided**: |
| 580 | +[#14488](https://github.com/objectstack-ai/objectstack/issues/14488), for the phase in which a |
| 581 | +module ships on its own (the §1.3(c) CPQ case, where a module's objects would otherwise arrive |
| 582 | +with no grants at all). It is out of this release and carries **no commitment** — neither that it |
| 583 | +will be built, nor that the contribution shape is the one it will take. |
| 584 | + |
| 585 | +Three inputs it inherits, recorded here because they are this record's own and would otherwise be |
| 586 | +rediscovered: |
| 587 | + |
| 588 | +- **ADR-0086 D4 stands until amended.** D4 chose Shape B — a package ships its own sets — and |
| 589 | + states flatly: *"A package never writes into a shared/foreign record."* A contribution |
| 590 | + mechanism is exactly such a write, so #14488 is an **amendment to that decision**, not an |
| 591 | + addition beside it. |
| 592 | +- **D4's conflict-freedom argument does not survive co-ownership unexamined.** It is |
| 593 | + conflict-free *"because each set only grants `objects.<own-namespace>_*` keys"* — one namespace |
| 594 | + per package. D1 lets N packages co-own one namespace, so inside one artifact that |
| 595 | + discriminator is gone and #14488 must supply its own. (Both hotcrm#1449 and #14488 propose |
| 596 | + **refusing** a doubly-contributed `(set, object)` rather than unioning it — a shape to measure, |
| 597 | + not a decision this section makes.) |
| 598 | +- **Which door edits a split product's app-owned sets is unmeasured.** ADR-0086 D7 scopes the |
| 599 | + package Access door to *"this package's own object slice"* and keeps the cross-package |
| 600 | + all-objects matrix at the environment-admin door. After a split the app package owns the sets |
| 601 | + but no objects, so where a *packaged* cross-module set's grants are authored is a UI question |
| 602 | + this record does not answer and #14488 inherits. |
0 commit comments