Skip to content

Commit 932e82f

Browse files
os-zhuangclaude
andauthored
docs(adr): ADR-0105 D12 amendment — group posture activation is entitled, not open (#3570) (#3603)
Founder ruling: OS_TENANCY_POSTURE=group is not an open-edition feature. The code was already corrected in #3570 (group probes org-scoping exactly like isolated; no runtime => single + degraded; an os serve boot configured for group fail-fasts). This brings the ADR text in line: - D12 rewritten to the code-vs-activation split: the wall's implementation ships open, posture activation is entitled for BOTH multi-org postures; iron-rule safety is satisfied by refusing to run an unwalled group boot, not by free activation. ADR-0081 D2's commercial line stands. - Amendment block records the original text, why it was wrong (inverted ADR-0081 D2 + the silent-degradation hole), and the #3559 -> #3570 trail. - Consequences clause updated to match; header Status moves to Accepted with the amendment note; Tracking points at #3541 / #3539 / #3540 / cloud #874. Claude-Session: https://claude.ai/code/session_015FebXPaaGrLhGKw1LHPbpL Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5b89711 commit 932e82f

1 file changed

Lines changed: 41 additions & 14 deletions

File tree

docs/adr/0105-group-tenancy-posture-and-first-class-org-scope.md

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# ADR-0105: Group Tenancy Posture — Organization Scope as a First-Class Authorization Dimension
22

3-
**Status**: Proposed (2026-07-25, draft)
3+
**Status**: Accepted (2026-07-27; proposed 2026-07-25) — Phase 0/1 implemented (#3559). Amended 2026-07-27: **D12 correction**`group` posture activation is entitled, not open (#3570; see the D12 Amendment)
44
**Deciders**: ObjectStack Protocol Architects
55
**Builds on**: [ADR-0049](./0049-no-unenforced-security-properties.md) (enforce-or-remove), [ADR-0057](./0057-erp-authorization-core-business-units-and-scope-depth.md) (business units + scope depth), [ADR-0066](./0066-unified-authorization-model.md) (unified authz, superuser bypass), [ADR-0086](./0086-authz-metadata-config-boundary-and-cross-package-composition.md), [ADR-0090](./0090-permission-model-v2-concept-convergence.md) (permission set / position / business unit), [ADR-0091](./0091-grant-lifecycle-and-recertification.md) (validity windows), [ADR-0092](./0092-sys-user-profile-field-delegation.md) (identity write guard + field whitelist), [ADR-0093](./0093-tenancy-mode-and-membership-lifecycle.md) (tenancy service), [ADR-0095](./0095-authz-kernel-tenant-layer-and-posture-ladder.md) (tenant Layer 0, posture ladder), [ADR-0103](./0103-managedby-write-policy-and-engine-write-guard.md); cloud ADR-0016 (open/paid boundary: 强制免费、治理收费), cloud ADR-0081 (`@objectstack/organizations`)
6-
**Tracking**: issue to be filed on acceptance; P0 findings F1/F2 below warrant their own issues immediately
6+
**Tracking**: #3541 (P0 findings F1/F2 became #3539/#3540, closed by #3559); cloud-side tracking cloud #874
77
**Consumers**: `@objectstack/plugin-security`, `@objectstack/core` (`resolve-authz-context`), `@objectstack/plugin-auth` (tenancy service), `@objectstack/plugin-sharing`, `@objectstack/plugin-approvals`, `@objectstack/lint`, dogfood conformance suite, `@objectstack/organizations` (cloud)
88

99
---
@@ -280,16 +280,41 @@ reserves the concept and its place in Phase 2.
280280
with its own ADR.
281281

282282
**D12 — Edition split, per the cloud ADR-0016 iron rule (强制免费、治理收费).**
283-
Enforcement primitives ship open: D3/D4 correctness, the `group` wall + D5
284-
stamping/validation, `accessible_org_ids` resolution, the D6 red-line lints.
285-
An open deployment configured into the group shape must be safe by default —
286-
the wall's correctness is never paid. Commercial (`@objectstack/organizations`
287-
and successors): org lifecycle management, grouping/registry UI, scoped
288-
invitations UX, cross-org approval templates, master-data distribution
289-
management, per-org seed/config replay, org analytics, and the D13 promotion
290-
tooling. (This re-draws the current line, under which the wall itself lives in
291-
the commercial package; the correctness floor moves into the open edition, the
292-
management surface stays commercial.)
283+
*(As amended 2026-07-27, #3570 — see the Amendment below for the original
284+
text and why it was wrong.)* The split is **code vs. activation**, not code
285+
vs. code. The wall's *implementation* ships open — D3/D4 correctness, the
286+
Layer 0 predicates, D5 stamping/validation, `accessible_org_ids` resolution,
287+
the D6 red-line lints — exactly as `isolated`'s wall has always lived in
288+
`plugin-security`. Posture *activation* is entitled: `group` probes the
289+
enterprise `org-scoping` runtime (`@objectstack/organizations`) exactly like
290+
`isolated`; without it the tenancy service resolves the posture to `single` +
291+
`degraded`, and an `os serve` boot configured for `group` **refuses to
292+
start** (the ADR-0093 D5 guard, keyed off the resolved posture) rather than
293+
silently running unwalled. The iron rule guarantees a deployment *running* a
294+
multi-org shape is safe by default; that is satisfied by refusing to run one
295+
unwalled — **open code is not free activation**. ADR-0081 D2's commercial
296+
line stands: both multi-org postures are `@objectstack/organizations`
297+
capability. Commercial surface (unchanged): org lifecycle management,
298+
grouping/registry UI, scoped invitations UX, cross-org approval templates,
299+
master-data distribution management, per-org seed/config replay, org
300+
analytics, and the D13 promotion tooling.
301+
302+
> **Amendment (2026-07-27, #3570).** As proposed, this section read "the
303+
> `group` wall ships open — an open deployment configured into the group
304+
> shape must be safe by default; the wall's correctness is never paid", and
305+
> #3559 implemented that reading: a self-activating `group` posture with no
306+
> entitlement probe. That was the founder decision flagged in #3559, and the
307+
> founder ruled it wrong on review. Two defects in the original reading:
308+
> it made the *stronger* multi-org posture (union wall) free while the
309+
> *weaker* one (`isolated`) stayed entitled — inverting ADR-0081 D2 and
310+
> handing out a free path around the `org-scoping` gate — and it opened a
311+
> silent-degradation hole (`os serve` gated the enterprise package load on
312+
> `OS_MULTI_ORG_ENABLED`, so `OS_TENANCY_POSTURE=group` skipped both the
313+
> load and the ADR-0093 D5 fail-fast, booting single-org without saying so).
314+
> The iron rule's obligation is a *security* property (never run a multi-org
315+
> shape unwalled), not a *packaging* one (give the posture away). #3570
316+
> restored the entitled model above; safety stays free because an unwalled
317+
> `group` boot is refused, not run.
293318
294319
**D13 — Migration along the spectrum; BU-subtree → organization promotion.**
295320
Deployments move `single → group → isolated` without schema rework because
@@ -371,8 +396,10 @@ boundary honest per cloud ADR-0016.
371396
**Negative / costs**: a third posture multiplies the authz test matrix (every
372397
conformance row × posture); `accessible_org_ids` adds a resolver read path
373398
that must respect ADR-0091 validity windows and the existing 60s cache
374-
staleness envelope; the D12 line re-draw moves wall enforcement into the open
375-
edition — a deliberate commercial concession justified by the iron rule; D13
399+
staleness envelope; the D12 split is code-vs-activation — the wall's
400+
implementation is open while both multi-org postures stay entitled (the
401+
original open-activation concession shipped in #3559 and was reverted by
402+
#3570, see the D12 Amendment); D13
376403
promotion is a data migration with real blast radius and needs its own
377404
verification harness.
378405

0 commit comments

Comments
 (0)