Skip to content

Commit 184f6b0

Browse files
hotlongclaude
andauthored
docs(adr): ADR-0130 addendum — the permission matrix is outside the package boundary's payoff (#14487) (#14498)
Records the maintainer's 2026-09-02 ruling (option B on #14454 item 3): permission sets stay whole in the `type: app` package, and the 30 x 9 x 6 permission matrix §1.3(a) measures is NOT part of the payoff §4 claims for this boundary. Measured, from the HotCRM split plan (objectstack-ai/hotcrm#1449): four of the six permission sets span five or six of the six planned modules, and not one is confined to a single module — a set grants per role, not per module, so no module owns it. Per-package composition of grants is filed as #14488 for the phase in which a module ships on its own, with no commitment; the section records the three constraints that phase inherits (ADR-0086 D4 stands until amended; D4's conflict-freedom argument assumes one namespace per package, which D1 relaxes; and which Access door edits a split product's app-owned sets is unmeasured). No decision text changes: D1-D8, §1 and §3's non-goal on grouping keys stand as written. The Status line gains a pointer to the addendum, per the ADR-0006/0085 precedent for a record whose scope an addendum bounds. Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4b4d5a3 commit 184f6b0

1 file changed

Lines changed: 93 additions & 0 deletions

File tree

docs/adr/0130-release-artifact-as-co-ownership-boundary.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
**Status**: Proposed (2026-09-01) — awaiting the maintainer's hand-merge, which is itself the
44
acceptance act for a governed surface (Prime Directive #14). ⛔ Nothing below is settled until
55
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.
610
**Deciders**: ObjectStack maintainer, 2026-09-01, live PM chat, verbatim and untranslated:
711
「立 ADR 起草卡派发」and 「14122 作为epic 任务集中跟踪」— approving the proposal in
812
[#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:
507511
`packages/objectql/src/plugin.ts`, `packages/core/src/plugin-order.ts`,
508512
`packages/spec/src/stack.zod.ts`, `packages/spec/src/kernel/manifest.zod.ts`,
509513
`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

Comments
 (0)