Skip to content

Commit 13f9e8e

Browse files
docs(adr): ADR-0152 a SCIM group grants only an ordinary permission set, through a per-connection mapping row (#31636)
<!-- claude-projects-attribution: {"github_login":"os-steve"} --> _Requested by **Steve** · [project thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi92haYJXRXgYVH2zaQ11o5Pd)_ Fixes #30959 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:新增 ADR-0152,记录 SCIM 组映射的已裁决定(映射按 SCIM 连接存为平台对象行、IdP 组永不授予管理员身份、厂商版本 1.7.12),并在 ADR-0134 D4 下加一行指向;ADR 索引随之重新生成。 - 为什么改:卡 #30959 的裁决「以上都同意」第 3 项要求新立 ADR 记录这次决定;功能代码已在 #31443 落地,这是该卡最后一个 PR。 - 风险与回滚:纯文档,不改任何代码与行为;ADR 只记录已裁事项,不做新决定。回滚即撤掉本 PR。 - 先看:`docs/adr/0152-scim-group-grants-only-an-ordinary-permission-set-through-a-per-connection-mapping.md` 的 Decision 一节(三项裁决),`docs/adr/0134-env-side-scim-provisioning.md` D4 下新增的一行。 - 两分钟验证:`pnpm check:adr-symbol-anchors`,预期 152 份记录全部解析通过、退出码 0。 - 需要你做的:批准本 PR(受管面 docs/adr,Tier H)。 ## What changes - **New `docs/adr/0152-scim-group-grants-only-an-ordinary-permission-set-through-a-per-connection-mapping.md`.** It records the three forks the maintainer ruled on #30959 (ruling record [`6718345088`](#30959 (comment)), verbatim 「以上都同意」, accepting the analysis [`6710730984`](#30959 (comment))): - D1, fork 1 = (a): the mapping is one platform-object row per SCIM connection and group, typed columns, written by the platform administrator who mints the SCIM credential. The ruling's build note (the source column also fits an SSO group claim, #30967 item 3) is carried; the SSO half is not decided here. - D2, fork 2 = no: an IdP group never confers administrator standing; a mapping naming a set outside the organization boundary is refused at save; the card's last-admin 403 acceptance line is replaced by "refused at save"; the last-admin guard texts are corrected. - D3, fork 3 = (i): this new ADR plus one pointer line in ADR-0134 D4. - **The mechanism as landed** (facts, not decisions), each clause anchored by symbol into the code #31443 landed (`ed4b8322`): storage object, the two doors, the boundary predicate on the `security` service, the projection (`roles.map`, `roles.exists`, `reconcileUser` through the engine in the SCIM transaction, `APIError` mapping, the reason marker), the guard texts and the pinning test. - **The vendor-version fact, measured** on the installed package: `@better-auth/scim` is pinned at 1.7.12 (package.json, the `pnpm-workspace.yaml` override, the installed `package.json`); the `SCIMProjection` shape; and `runSCIMApplicationCallback`, which passes an `APIError` through and wraps anything else as a SCIM 500 "SCIM projection reconciliation failed". - **What this record does not decide**: SSO claims, multi-organization SCIM, organization-role or admin mapping, a Console surface, anything in `cloud ADR-0071`'s closed half. - **`docs/adr/0134-env-side-scim-provisioning.md`**: one blockquote line under D4 pointing at ADR-0152. D4's text and the status line are unchanged, so the mirror stays equal to `cloud ADR-0071`. - **`docs/adr/README.md`**: regenerated by `pnpm adr:index` (one new row, summary counts 150 → 151). ## Tests None: docs-only diff, nothing to test or ablate. The record's anchors are checked mechanically (Verification). ## Acceptance notes - **ADR number.** `origin/main` ends at ADR-0149; open PRs hold ADR-0150 (#31586) and ADR-0151 (#31615), so this record takes 0152. Both of those PRs also edit `docs/adr/README.md`; whichever lands later regenerates the index (row conflict only). - **Status line.** `Accepted — implemented, 2026-11-08, …` following the README's status-hygiene convention (the implementation landed in #31443 before the record). The maintainer's merge is the acceptance act; if the maintainer prefers `Proposed` until then, it is a one-word change. - **ADR-0134's vendor-version table** still names 1.7.2 as the pin. ADR-0152 restates the fact at 1.7.12 and leaves ADR-0134's dated measurement as written (append-only; outside this card's file surface). - Seat 6's draft at `/mnt/project-files/server-lane-seat6/30959/adr-draft.md` does not exist in project files; the record was written from the card's rulings and the merged code. ## Verification Head `fcd6553c` (branch `claude/project-thread-1at98g`, merge base `69244406` = current `origin/main`). <details><summary>ADR gates</summary> - `pnpm check:adr-symbol-anchors` exit 0: "3297 anchors across 152 records resolve — 873 symbol (846 declaration, 27 literal), 2373 file-level". The same gate on `origin/main` `69244406`: 3273 anchors across 151 records, 856 symbol, 2366 file-level. The delta (+17 symbol, +7 file-level) is this record's anchors, all resolved. - `pnpm check:adr-index` exit 0: "docs/adr/README.md is current, every record parsed". - `pnpm check:adr-anchors` exit 0; `pnpm check:adr-links` exit 0 (1052 relative link destinations resolve). </details> <details><summary>dispatch-gates family list</summary> `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 21 commands for the 3 changed paths; all 21 ran with exit 0 (exit captured before any pipe). `check:doc-formula-expressions` needed the `@objectstack/formula` + `@objectstack/lint` build first (`os-verify-lock` VERDICT command-exit 0, 99 s). `--ran` reconciliation: "21 derived famil(ies) accounted for — 21 run, 0 NOT-MEASURED (a DERIVED zero)". No package touched, so no `pnpm lint` family is owed. </details> --- _Generated by [Claude Code](https://claude.ai/code/session_01ADHkmSoGBrHrzTArx233j6)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0ebb080 commit 13f9e8e

3 files changed

Lines changed: 204 additions & 3 deletions

‎docs/adr/0134-env-side-scim-provisioning.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ The seam is real and is deliberately left empty, on both sides:
207207
That is the decision, not an oversight: a group→role mapping is an authorization contract, and V1
208208
declines to invent one. Filling the seam is a later decision with its own record.
209209

210+
> **Filled by [ADR-0152](./0152-scim-group-grants-only-an-ordinary-permission-set-through-a-per-connection-mapping.md) (2026-11-08, ruling of record `6718345088` on #30959)** — for ordinary permission sets only: a SCIM group grants the set its per-connection `sys_idp_group_mapping` row names, never administrator standing; the text above is unchanged.
211+
210212
### D7 (open half) — SCIM conformance / smoke coverage runs in this repo's CI
211213

212214
The half of D7 whose mechanism is open code: **the provisioning surface is exercised by tests that run
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# ADR-0152: A SCIM group grants only an ordinary permission set, through a per-connection mapping row a platform administrator saves
2+
3+
**Status**: Accepted — implemented, 2026-11-08, recording the maintainer's ruling of 2026-11-08 on [#30959](https://github.com/objectstack-ai/objectstack/issues/30959) (ruling record [`6718345088`](https://github.com/objectstack-ai/objectstack/issues/30959#issuecomment-6718345088), verbatim: 「以上都同意」), which accepted every recommendation of the seat's decision analysis [`6710730984`](https://github.com/objectstack-ai/objectstack/issues/30959#issuecomment-6710730984): fork 1 (a), fork 2 no, fork 3 (i). The mechanism landed before this record, in [#31443](https://github.com/objectstack-ai/objectstack/pull/31443) (merge `ed4b8322`, landing record [`6724527199`](https://github.com/objectstack-ai/objectstack/issues/30959#issuecomment-6724527199)); evidence: `packages/plugins/plugin-auth/src/scim-group-projection.ts` + `packages/plugins/plugin-auth/src/scim-group-projection.test.ts`. `docs/adr/` is Tier H (Prime Directive #14): this record lands by the maintainer's hand.
4+
- **Date**: 2026-11-08
5+
- **Card**: [#30959](https://github.com/objectstack-ai/objectstack/issues/30959) (p1, `domain:server`), the card's second and last PR. The card body's Expected and Acceptance were written before the ruling; where the two differ, the ruling binds ([D2](#d2--an-identity-provider-group-never-confers-administrator-standing)).
6+
- **Decided by**: the maintainer, 2026-11-08, verbatim and untranslated: 「以上都同意」 — given on the evaluation write-up that followed the seat's analysis `6710730984`, and recorded on the card as ruling record `6718345088`. The three forks and the options ruled are the analysis's; [Decision](#decision) restates each in the ruling record's own terms.
7+
- **Builds on**: [ADR-0134](./0134-env-side-scim-provisioning.md) (the open half of `cloud ADR-0071`: `@better-auth/scim` is the mechanism, the env is the Service Provider, and D4 left group→role mapping a declared, unwired seam whose filling is "a later decision with its own record" — this is that record), [ADR-0090](./0090-permission-model-v2-concept-convergence.md) D12 as amended by ruling of record 6228728551 (the organization boundary an organization administrator's assignments stay inside), [ADR-0068](./0068-unified-user-context-and-built-in-identity-roles.md) D2 (the platform-administrator gate both mapping doors run), [ADR-0112](./0112-error-code-vocabulary-and-ledger.md) (the envelope every refusal answers in), `cloud ADR-0024` D5.2 (break-glass, the invariant the last-administrator guard enforces).
8+
- **Amends**: [ADR-0134](./0134-env-side-scim-provisioning.md) D4 — one pointer line under D4 naming this record; D4's text and ADR-0134's status line are unchanged, so the mirror stays equal to `cloud ADR-0071`.
9+
- **Leaves unchanged**: the SCIM user lifecycle of ADR-0134 D3 (`active: false` disables through this platform's `identity.reconcileUser` hook; `DELETE` never erases the user); a provisioned member's organization role (the default standing of ADR-0134 D4); every grant made by hand; the delegated-administration gate an organization administrator's own assignments pass; the last-administrator guard's judgement.
10+
- **Consumers**: `@objectstack/plugin-auth` (the vendor `projection`, the two mapping doors, the last-admin guard's texts), `@objectstack/platform-objects` (`sys_idp_group_mapping`), `@objectstack/plugin-security` (the boundary predicate served on the `security` service), `@objectstack/spec` (one `PLATFORM_OBJECTS_BY_PACKAGE` row and one optional `ISecurityService` member), `objectstack-ai/cloud` (cloud#3667, Enterprise SCIM provisioning, the card's named consumer).
11+
12+
---
13+
14+
## Provenance
15+
16+
The decision was taken on #30959 in four recorded steps, each a comment on the card:
17+
18+
1. **Reading** [`6710719058`](https://github.com/objectstack-ai/objectstack/issues/30959#issuecomment-6710719058) — measured on `origin/main` `658d84f5` through real `AuthManager.handleRequest()` doors: a SCIM group push wrote only `sys_scim_*` rows and granted nothing (R1); the last-administrator guard refuses the revoke direction but not the grant direction (R2); a projection wired by a throwaway probe showed what any mapping must do to work at all (R3).
19+
2. **Analysis** [`6710730984`](https://github.com/objectstack-ai/objectstack/issues/30959#issuecomment-6710730984) — three forks, each with options and a recommendation: where the mapping lives, whether an IdP group may confer administrator standing, and which ADR change records the answer.
20+
3. **Ruling** [`6718345088`](https://github.com/objectstack-ai/objectstack/issues/30959#issuecomment-6718345088) — 「以上都同意」: fork 1 = (a), fork 2 = no, fork 3 = (i).
21+
4. **Build** [#31443](https://github.com/objectstack-ai/objectstack/pull/31443), merged as `ed4b8322` (landing record [`6724527199`](https://github.com/objectstack-ai/objectstack/issues/30959#issuecomment-6724527199)).
22+
23+
⛔ **This record decides nothing the ruling did not.** [Decision](#decision) carries the three ruled forks.
24+
[The mechanism as landed](#the-mechanism-as-landed) records what the build PR implemented as **facts about the
25+
mechanism**, each anchored into code, the way ADR-0134 records its vendor-version fact; a reader who wants to change
26+
one of those facts changes code and this section, not the decision.
27+
28+
---
29+
30+
## Context
31+
32+
ADR-0134 D4 provisioned every IdP-pushed user at the deployment's default standing and left the vendor's
33+
`projection` option unset: "An IdP may push groups; they land, they are visible, and they grant nothing." The card's
34+
named consumer (cloud#3667, Enterprise SCIM provisioning on live Okta / Entra ID) needs the opposite — the IdP's
35+
group decides what a member may do here — and reading `6710719058` R1 measured the gap: a mapped-group assertion
36+
was red on `main` (`expected 0 to be greater than 0`).
37+
38+
Two measured facts shaped every option, and both stay true under the decision:
39+
40+
- **Every SCIM write runs as the system.** The delegated-administration gate that keeps an organization
41+
administrator's assignments inside the organization boundary short-circuits on a system write, so it never sees
42+
a projected grant (`6710730984`, R3 item 5). The card's "grants go through the existing assignment doors" cannot
43+
hold at projection time; the boundary can only be enforced where the mapping is **saved**.
44+
- **The vendor's transaction adapter cannot address the grant table.** A projection that writes
45+
`sys_user_permission_set` through the vendor's `context.database` fails with "Model not found in schema", and the
46+
vendor turns that into a SCIM 500 on every user write (`6710730984`, R3 item 2).
47+
48+
---
49+
50+
## Decision
51+
52+
### D1 — Storage: one platform-object row per mapping, per SCIM connection
53+
54+
Ruled fork 1 = (a). A mapping is a row of a platform object, keyed by the SCIM connection and one group, with typed
55+
columns — never a settings value and never an authorable spec key. Its writer is the platform administrator who
56+
mints the SCIM connection's credential, through the same gate; no new population gains SCIM administration.
57+
58+
The ruling carries one build note: the row's source is shaped so it can also hold an SSO provider's IdP group claim,
59+
so [#30967](https://github.com/objectstack-ai/objectstack/issues/30967) item 3 reuses this object and no second
60+
mapping model grows. The SSO half itself is #30967's and is not decided here.
61+
62+
### D2 — An identity provider group never confers administrator standing
63+
64+
Ruled fork 2 = no. In V1 a mapping names only an ordinary permission set inside the organization boundary. A mapping
65+
that names a set outside it is **refused at save**, judged by the criteria of
66+
`packages/plugins/plugin-security/src/delegated-admin-gate.ts#organizationBoundaryFailure`: `admin_full_access`,
67+
the organization-administrator sets, the MCP agent ceiling sets, a set with a superuser wildcard bit, a set with an
68+
`adminScope`, and a set with a capability not scoped to the organization. No organization-role mapping is offered:
69+
a provisioned member keeps the default standing of ADR-0134 D4.
70+
71+
Two consequences come with the ruling:
72+
73+
- The card's Acceptance line "a mapping that would remove the last admin is refused as a SCIM 403" is replaced by
74+
"a mapping that names an administrator set is refused at save". A projected grant never carries administrator
75+
standing, so the last-administrator guard never fires on one.
76+
- The last-administrator guard's texts that sent an operator to "the SCIM group mapping" are corrected, because no
77+
mapping can move administrator standing.
78+
79+
### D3 — The record: this ADR, plus one pointer line in ADR-0134 D4
80+
81+
Ruled fork 3 = (i). ADR-0134 is a mirror of `cloud ADR-0071` and states that it is not a re-decision, so D4 is not
82+
rewritten in place; it gains one line pointing here. Its own last sentence asks for exactly this: "Filling the seam
83+
is a later decision with its own record."
84+
85+
---
86+
87+
## The mechanism as landed
88+
89+
Facts read on `origin/main` after `ed4b8322`. Each clause names the code that makes it true.
90+
91+
**Storage.** `packages/platform-objects/src/identity/sys-idp-group-mapping.object.ts#SysIdpGroupMapping` declares
92+
`sys_idp_group_mapping`: `source_kind` (closed select, V1 value `scim` — the seam D1's build note names),
93+
`source_id` (the SCIM connection), `group_external_id` or `group_display_name` (a row names exactly one),
94+
`permission_set`, `organization_id`. Its data API is list-only, so the doors below are its only writer. The
95+
platform-object roster gains the row in `packages/spec/src/system/constants/platform-object-names.ts#PLATFORM_OBJECTS_BY_PACKAGE`.
96+
97+
**Writer.** `POST /api/v1/auth/admin/scim/set-group-mapping` and `POST /api/v1/auth/admin/scim/delete-group-mapping`
98+
(`packages/plugins/plugin-auth/src/idp-group-mapping-admin.ts#IDP_GROUP_MAPPING_SET_PATH`,
99+
`packages/plugins/plugin-auth/src/idp-group-mapping-admin.ts#runSetIdpGroupMapping`,
100+
`packages/plugins/plugin-auth/src/idp-group-mapping-admin.ts#runDeleteIdpGroupMapping`) run behind the
101+
platform-administrator gate that guards `/admin/scim/mint-credential`. The grant's organization is the one that owns
102+
the connection's live credentials (`packages/plugins/plugin-auth/src/scim-connection-service.ts#scimCredentialIsLive`),
103+
never a value the caller names; a connection whose live credentials name no organization or two is refused. Saving
104+
or deleting a mapping re-projects the connection's provisioning domains at once
105+
(`packages/plugins/plugin-auth/src/auth-manager.ts#reconcileScimProjectionDomain`, the vendor's
106+
`reconcileSCIMProjection`), so a group's current members gain or lose the set without waiting for their next SCIM
107+
change.
108+
109+
**Admin boundary at save.** The save door asks plugin-security's own predicate, lifted verbatim from a private method
110+
to a module function (`packages/plugins/plugin-security/src/delegated-admin-gate.ts#organizationBoundaryFailure`) and
111+
served as an optional member of the registered `security` service
112+
(`packages/spec/src/contracts/security-service.ts#ISecurityService`). plugin-auth takes no package dependency on
113+
plugin-security and keeps no copy of the list. A refused save answers `400 VALIDATION_FAILED` on `permissionSet`
114+
with code `rule_violation` and stores nothing; with no `security` service to ask, nothing can be shown inside the
115+
boundary and the save is refused `503`.
116+
117+
**Projection.** `scim({ projection })` in `packages/plugins/plugin-auth/src/auth-manager-plugin-list.ts` takes
118+
`packages/plugins/plugin-auth/src/scim-group-projection.ts#createScimGroupProjection`:
119+
120+
- `roles.map` returns the ids of the connection's mapping rows that match the pushed group
121+
(`packages/plugins/plugin-auth/src/scim-group-projection.ts#mappingMatchesGroup`): by external id when the row
122+
names one, else by exact display name. An unmapped group maps to nothing and grants nothing.
123+
- `roles.exists`, and `reconcileUser` again before every insert, re-judge the boundary at grant time, so a set
124+
redefined with an administrator bit after its mapping was saved grants nothing (warned once).
125+
- `reconcileUser` (`packages/plugins/plugin-auth/src/scim-group-projection.ts#reconcileProjectedGrants`) makes the
126+
user's projected grants equal the vendor's desired set, idempotently, writing `sys_user_permission_set` through
127+
the ObjectQL engine inside the SCIM request's engine transaction
128+
(`packages/plugins/plugin-auth/src/objectql-adapter.ts#withSystemContext`), so the audit actor is
129+
`svc:scim:CONNECTION_ID` and a refused write rolls the whole SCIM mutation back. An engine refusal is rethrown as
130+
the vendor's `APIError` (`packages/plugins/plugin-auth/src/objectql-adapter.ts#withValidationErrorMapping`), never
131+
left to become a SCIM 500.
132+
- A projected grant carries the reason marker
133+
`packages/plugins/plugin-auth/src/scim-group-projection.ts#scimGroupProjectionReason` for its provisioning domain.
134+
Reconcile removes only rows carrying that exact marker, so a grant made by hand — the same set included — is never
135+
removed, and a set the user already holds by hand is not written again.
136+
137+
**Last-administrator guard.** `packages/plugins/plugin-auth/src/last-admin-guard.ts#registerLastAdminGuard`'s
138+
refusal texts no longer name a SCIM group mapping as a source of administrator standing; they tell the operator to
139+
grant another account administrator standing first.
140+
141+
**Pins.** `packages/plugins/plugin-auth/src/scim-group-projection.test.ts` drives the real producer
142+
(`AuthManager.handleRequest()` with a real SCIM bearer over the pinned vendor, a real ObjectQL engine, the real
143+
plugin-security `security` service): a mapped push grants and a removal revokes, an administrator set and an
144+
out-of-boundary set are refused at save, an unmapped group grants nothing, hand-made grants are never touched, and a
145+
save or delete applies to current members at once.
146+
147+
---
148+
149+
## The vendor-version fact, measured
150+
151+
The projection is a vendor seam, so its behaviour is a version fact. Measured 2026-11-08 on `origin/main` `69244406`,
152+
in this worktree's installed package:
153+
154+
- **The pin is 1.7.12.** `packages/plugins/plugin-auth/package.json` declares `"@better-auth/scim": "1.7.12"`,
155+
`pnpm-workspace.yaml` overrides `'@better-auth/scim@<2.0.0': '1.7.12'`, and the installed package's own
156+
`package.json` reports `1.7.12`. ADR-0134's version table names 1.7.2 as the pin; that table is ADR-0134's dated
157+
measurement and is left as written.
158+
- **The seam's shape at 1.7.12.** `SCIMProjection` carries an optional `roles` member (`map`, `exists`) and a
159+
required `reconcileUser`, which the vendor documents as receiving "the complete effective state" and as having to
160+
be idempotent.
161+
- **Only an `APIError` reaches the IdP as itself.** The vendor runs the projection inside
162+
`runSCIMApplicationCallback`, which rethrows an `APIError` unchanged and wraps any other throw as a SCIM
163+
`INTERNAL_SERVER_ERROR` with the detail "SCIM projection reconciliation failed". That is why the landed projection
164+
maps an engine refusal to `APIError`: an IdP retries a 500 and treats a 4xx as final.
165+
166+
---
167+
168+
## Consequences
169+
170+
- An organization's IdP group can now drive what its members may do here, without a redeploy and without a
171+
hand-made grant per member, which is what the card's consumer asked for.
172+
- Administrator standing stays decided inside the platform: no IdP group membership, however scoped, mints an
173+
administrator, and a wrong mapping is refused loudly at save instead of silently granting.
174+
- The boundary lives at save and is re-judged at grant time; it does not depend on the delegated-administration gate,
175+
which a system write never reaches.
176+
- The mapping is runtime data in the environment, consistent with ADR-0134 D2's "connections are runtime data, not
177+
boot config".
178+
179+
## What this record does not decide
180+
181+
- ⛔ The SSO half: an SSO provider's group claim feeding the same object is
182+
[#30967](https://github.com/objectstack-ai/objectstack/issues/30967) item 3's.
183+
- ⛔ A multi-organization SCIM mode. A mapping's organization is the one that owns the connection; ADR-0134 D3's
184+
seam stays a seam.
185+
- ⛔ An organization-role mapping, or any mapping that confers administrator standing. Opening either is a new
186+
decision with its own record.
187+
- ⛔ A Console surface for mappings. The two doors are the only writer today.
188+
- ⛔ Anything in `cloud ADR-0071`'s closed half (D5, D6, the closed half of D7).
189+
190+
## References
191+
192+
- [#30959](https://github.com/objectstack-ai/objectstack/issues/30959) — the card; reading `6710719058`, analysis
193+
`6710730984`, ruling record `6718345088`, landing record `6724527199`.
194+
- [#31443](https://github.com/objectstack-ai/objectstack/pull/31443) — the build.
195+
- [ADR-0134](./0134-env-side-scim-provisioning.md) — the SCIM mirror whose D4 seam this record fills.
196+
- [ADR-0090](./0090-permission-model-v2-concept-convergence.md) D12 — the organization boundary.
197+
- `cloud ADR-0071` — *Enterprise Identity — SCIM v1*, the original decision ADR-0134 mirrors.
198+
- `cloud ADR-0024` D5.2 — break-glass.

‎docs/adr/README.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313

1414
## Summary
1515

16-
151 records under `docs/adr/` (146 numbers), 11 under `ui/docs/adr/` (listed separately below).
16+
152 records under `docs/adr/` (147 numbers), 11 under `ui/docs/adr/` (listed separately below).
1717

1818
| Status | Records |
1919
|---|---|
20-
| Accepted | 132 |
20+
| Accepted | 133 |
2121
| Proposed | 5 |
2222
| Superseded | 4 |
2323
| Draft | 3 |
@@ -26,7 +26,7 @@
2626
| Amended | 1 |
2727
| Partially implemented | 1 |
2828
| Revised | 1 |
29-
| **Total** | **151** |
29+
| **Total** | **152** |
3030

3131
## Shared numbers
3232

@@ -218,6 +218,7 @@ A bare `ADR-0006` names the decision; its current text is [0006-project-environm
218218
| [ADR-0148](./0148-recycle-bin-separate-store-restore-under-original-ids-retention-in-days.md) | The recycle bin is a separate store — one entry per delete operation, restore under the original ids, retenti… | Accepted — 2026-11-05, recording the maintainer's ruling of 2026-11-04 on… | 2026-11-05 | — | — |
219219
| [ADR-0149](./0149-ai-answers-business-questions-through-the-dataset-semantic-layer.md) | The AI answers business questions through the dataset semantic layer — synonyms and descriptions on measures… | Accepted — 2026-11-08, recording two rulings of the maintainer: the placem… | 2026-11-08 | — | — |
220220
| [ADR-0150](./0150-behavioural-metadata-addressed-by-package-objects-keep-the-literal-prefix.md) | Behavioural metadata is addressed by (package, name) — objects keep the literal prefix; ADR-0028 re-opened fo… | Proposed — 2026-11-08. `docs/adr/` is Tier H (Prime Directive #14): this r… | 2026-11-08 | ADR-0028 | — |
221+
| [ADR-0152](./0152-scim-group-grants-only-an-ordinary-permission-set-through-a-per-connection-mapping.md) | A SCIM group grants only an ordinary permission set, through a per-connection mapping row a platform administ… | Accepted — implemented, 2026-11-08, recording the maintainer's ruling of 2… | 2026-11-08 | — | — |
221222

222223
## ObjectUI registry — `ui/docs/adr/` (`ui-` prefix)
223224

0 commit comments

Comments
 (0)