Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
7a5ef33
wip(plugin-security): retire the declared-permission seeder, drift, r…
claude Oct 11, 2026
77ad5f2
wip(plugin-security,cli): the platform-admin bootstrap writes no cata…
claude Oct 11, 2026
7f18550
wip(examples,plugin-security): delete the example binders; drift_stat…
claude Oct 11, 2026
8d2baa4
wip: zero-row boot pin, everyone re-derivation pin, changeset (#15204…
claude Oct 11, 2026
facb9fd
chore(plugin-security): regenerate the translation bundles without dr…
claude Oct 11, 2026
47f0b55
test(plugin-security): fixtures modelling an existing database write …
claude Oct 11, 2026
206cdd1
docs(changeset): state the migration in prose under the runtime-inter…
claude Oct 11, 2026
173f4c1
docs(changeset): no-migration-prescription disposition (#15204 stage …
claude Oct 11, 2026
6e67a32
chore: liveness verdicts and the tenant-audit census follow the retir…
claude Oct 11, 2026
c89e15d
chore: the engine-double ledgers drop the retired suites and pin the …
claude Oct 11, 2026
274040f
docs(changeset): os meta resync and the example binders carry their o…
claude Oct 11, 2026
7d870d1
test(dogfood): fixtures read the security catalog, not a seeded sys_p…
claude Oct 11, 2026
6c849ce
test(dogfood): catalogPermissionSet answers any, as the findOne it re…
claude Oct 11, 2026
8b9fb77
chore(docs-audit): the CLI command-anchor specimen is os meta registe…
claude Oct 11, 2026
a574a24
refactor(plugin-security)!: delete the organization-scope helpers the…
claude Oct 11, 2026
fcaedfd
test(plugin-security): tighten the stage's new test and comment text …
claude Oct 11, 2026
1d5c2b2
Merge commit 'refs/s8/d' into claude/issue-15204-s8-catalog-objects
claude Oct 12, 2026
813dfed
test: the stage-8 test half — suites stop depending on the four catal…
claude Oct 12, 2026
dbae752
feat(plugin-security)!: retire the four security-catalog row objects …
claude Oct 12, 2026
a805619
Merge origin/main (f931e765b7) into the S8-T branch: after D, the sta…
claude Oct 13, 2026
9d55c05
test(plugin-security): the uninstall-cleanup suite hands the sweep D'…
claude Oct 13, 2026
c211fdd
Merge origin/main (287fd6e5d0) into the S8 branch: stage 8 resolved o…
claude Oct 13, 2026
008ca32
test: suites main brought in since S8-T was built stop depending on t…
claude Oct 13, 2026
ef8dba8
chore(regen): regenerate the artifacts the main merge deferred, on th…
claude Oct 13, 2026
89b48dc
Merge S8-T (claude/issue-15204-s8t-tests @ 008ca32a75) into the S8 br…
claude Oct 13, 2026
d288550
Merge remote-tracking branch 'origin/main' into claude/issue-15204-s8…
claude Oct 13, 2026
9af05b5
docs(plugin-security): the published README stops naming the retired …
claude Oct 13, 2026
b3f643b
docs(changeset): stage 8's changeset states the uninstall and walled-…
claude Oct 13, 2026
31933c0
docs(changeset): stage 8 declares Clause-② no (narrowing)
claude Oct 13, 2026
c0dc292
test: the suites main's D and wall changes touched span stage 8 as well
claude Oct 13, 2026
d426f92
test(plugin-security): the walled builtin-positions golden leaves the…
claude Oct 13, 2026
48e3a38
Merge S8-T (claude/issue-15204-s8t-tests @ d426f922ed) into the S8 br…
claude Oct 13, 2026
34f4f77
Merge remote-tracking branch 'origin/main' into claude/issue-15204-s8…
claude Oct 13, 2026
08524a1
test(plugin-auth): the grant-reader suites register the retired sys_p…
claude Oct 13, 2026
e40fe49
test(plugin-auth): the legacy-table helper takes the manifest's untyp…
claude Oct 13, 2026
75b2892
Merge S8-T (claude/issue-15204-s8t-tests @ e40fe491c1, final) into th…
claude Oct 13, 2026
857bdb7
Merge remote-tracking branch 'origin/main' into claude/issue-15204-s8…
claude Oct 13, 2026
9d9bdd9
test(plugin-security): restore the walled data-door suite; builtin-po…
claude Oct 13, 2026
1d2407d
Merge S8-T (claude/issue-15204-s8t-tests @ 9d9bdd96b2) into the S8 br…
claude Oct 13, 2026
e3d00e1
test(plugin-security): the walled catalog data-door suite goes with t…
claude Oct 13, 2026
016d329
Merge remote-tracking branch 'origin/main' into claude/issue-15204-s8…
claude Oct 13, 2026
5bd2d8d
docs(adr): ADR-0086's D3 status row stops anchoring to the retired sy…
claude Oct 13, 2026
891d2d5
Merge remote-tracking branch 'origin/main' into claude/issue-15204-s8…
claude Oct 13, 2026
f850dd1
test(plugin-security): the principal-as-person Explain suite takes th…
claude Oct 13, 2026
a29bede
test(cli): the unmanaged-table sweep's plugin-declared negative contr…
claude Oct 13, 2026
976023f
test(cli): the host-composition migrate suite pins its drift and cove…
claude Oct 13, 2026
d9f53a6
fix(spec): the walled-catalog ADR-0087 entry stops promising a data-d…
claude Oct 13, 2026
5a1e88a
docs(changeset): stage 8 names PLATFORM_OBJECT_TENANCY's lost key and…
claude Oct 13, 2026
68121eb
chore(scripts): the keyed-text-bounds record names the tree its five …
claude Oct 13, 2026
b22a9ee
Merge remote-tracking branch 'origin/main' into claude/issue-15204-s8…
claude Oct 13, 2026
7c01d30
Merge origin/main (6d7f4df3c9) into the S8 branch
claude Oct 13, 2026
17ab8fc
chore(regen): regenerate the tenant-audit census page and counts ledg…
claude Oct 13, 2026
23e450a
chore(scripts): the keyed-text-bounds record's ref is the final merge…
claude Oct 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .changeset/15204-s8-catalog-row-objects-retired.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
'@objectstack/plugin-security': minor
'@objectstack/platform-objects': minor
'@objectstack/spec': minor
'@objectstack/core': minor
'@objectstack/metadata-protocol': patch
'@objectstack/objectql': minor
'@objectstack/plugin-sharing': patch
'@objectstack/lint': patch
'@objectstack/service-settings': patch
---

feat(plugin-security)!: the four security-catalog row objects are retired — `sys_position`, `sys_permission_set`, `sys_position_permission_set` and `sys_capability` (ADR-0131 D3)

Clause-②: no (narrowing)

<!-- adr-0087: registered catalog-row-objects-retired -->

**BREAKING**, shipped as `minor` under the repo's launch-window convention for breaking changes.

Positions, permission sets and capabilities live in the security catalog — the environment registry, fed by package declarations and by environment metadata saved through `/api/v1/meta` (ADR-0131 D3). The four row objects that mirrored them are no longer registered, so their data and REST routes and their Setup object pages are gone. No table is dropped and no row is deleted.

FROM → TO:

- `GET|POST|PATCH|DELETE /api/v1/data/sys_permission_set` → `GET|PUT|DELETE /api/v1/meta/permission/:name`; to copy a set, `POST /api/v1/security/permission-sets/:name/clone` with `{ name, label }`.
- `… /api/v1/data/sys_position` → `/api/v1/meta/position/:name`. A position's permission sets are its definition's `permissionSets`.
- `… /api/v1/data/sys_position_permission_set` → the position definition's `permissionSets` (`PUT /api/v1/meta/position/:name`).
- `… /api/v1/data/sys_capability` → read-only `GET /api/v1/meta/capability`; a package declares a capability with `defineCapability` (`stack.capabilities`).
- Setup → Access Control → Positions / Capabilities / Permission Sets now open Setup's catalog lists (`/apps/setup/metadata/<type>?scope=environment`) instead of the object pages; the `sys_position` record page (`SysPositionDetailPage`) is removed.
- An object permission on one of the four names in a permission set grants nothing and can be deleted.

What else changes:

- `sys_user_permission_set.permission_set_id` is a plain text column now, not a lookup: same column, same stored ids, same indexes. It is not written and grants nothing; a grant names its set by `permission_set`.
- A permission set saved through the metadata door is written to no row: the `permission` mutation projector, the `sys_permission_set` and `sys_position` data-door write-throughs and the row-only position backfill are no longer registered.
- On a fresh `single`-posture database the first human is promoted to platform administrator without reading any catalog row. An unscoped grant written before `sys_user_permission_set.permission_set` existed (it names no set) still withholds the promotion until the organization-ownership migration names it.
- Uninstalling a package still revokes every grant naming a permission set the package declared, by the names the uninstalling door captures before the withdrawal (`declared`, `captureUninstallDeclared`), and now by those names alone: the cleanup reads and removes no `sys_permission_set` or `sys_position_permission_set` row, so the `sets` and `positionBindings` counts on its outcome are always 0. A grant written before `sys_user_permission_set.permission_set` existed names no set and is not reached; the organization-ownership migration names it.
- On a `group` or `isolated` deployment the data-door half of the walled catalog refusal goes with the objects: a data-door insert, update or delete on `sys_position`, `sys_permission_set` or `sys_capability` answers `404 OBJECT_NOT_FOUND` for every caller instead of `403 PERMISSION_DENIED` below the platform operator. The refusal at the `/meta` write doors, the permission-set clone door and the `/packages` write doors is unchanged.
- `capability-reference-unknown` no longer counts a `sys_capability` seed row as a declared capability — no runtime reader consults one. Declare the capability with `defineCapability`.
- On an existing database `os migrate plan`'s unmanaged-table sweep now lists the `sys_position`, `sys_permission_set`, `sys_position_permission_set` and `sys_capability` tables: they keep their rows and no object declares them any more. The sweep only reports; nothing is dropped, and the tables stay for the organization-ownership migration.

Removed exports, no replacement:

- `@objectstack/plugin-security`: the object definitions `SysPosition`, `SysPermissionSet`, `SysPositionPermissionSet`, `SysCapability` (from `./objects`); `securityObjects` lists the remaining three.
- `@objectstack/platform-objects/pages`: `SysPositionDetailPage`.
- `@objectstack/spec`: `SystemObjectName.POSITION`, `SystemObjectName.PERMISSION_SET`; the four names leave `PLATFORM_OBJECTS_BY_PACKAGE['plugin-security']` and `PLATFORM_PROVIDED_OBJECT_NAMES`.
- `@objectstack/core`: `isRowActive` and `ActivatableRow` — a catalog row's `active` column decides nothing; deactivation is the activation ledger's (`sys_metadata_activation`).
- `@objectstack/objectql`: the published `PLATFORM_OBJECT_TENANCY` record loses its `sys_permission_set` key (the other three names were never in it). A removed key of an exported constant is a narrowing, so `@objectstack/objectql` takes `minor` under the launch-window convention for breaking changes.
12 changes: 6 additions & 6 deletions content/docs/permissions/tenant-audit-census.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ cannot read, and they are neither in nor out.
| write call sites on the application surface | **228** |
| …whose object name is statically decidable | 155 |
| …whose object name is chosen at run time | 73 |
| …against an object with tenancy ENABLED | 154 |
| …against an object with tenancy ENABLED | 151 |
| …against an object that declares tenancy off | 1 |
| threading a tenant context | 167 |
| PROVABLY carrying none (options read, no context key) | **8** |
Expand All @@ -240,9 +240,9 @@ cannot read, and they are neither in nor out.
| how the instrument reached the site | count |
| :--- | ---: |
| receiver carried a readable engine type | 186 |
| receiver erased, placed by the object NAME | 30 |
| receiver erased, placed by the object NAME | 27 |
| receiver erased, placed by an `object: string` PARAMETER | 7 |
| receiver erased, placed by an `UNTYPED_RECEIVERS` row | 5 |
| receiver erased, placed by an `UNTYPED_RECEIVERS` row | 8 |

| object name spelled inline | 103 |
| object name spelled through a `const` | 52 |
Expand Down Expand Up @@ -297,13 +297,13 @@ holds still. They are required to be HERE and to say WHEN they were true;
their values are not compared. The reasoning, and the measurement behind it,
are in `scripts/check-tenant-audit-census.mjs`.

Measured on 2026-10-13 at `ae14c39c5`.
Measured on 2026-10-13 at `7c01d30c9`.

| corpus scale (not enforced) | count |
| :--- | ---: |
| tracked non-test sources scanned | 654 |
| tracked non-test sources scanned | 650 |
| engine-shaped types recognised | 73 |
| declared objects in the registry | 120 |
| declared objects in the registry | 116 |
| same-named calls subtracted as non-engine | 160 |

{/* END GENERATED: tenant-audit-census */}
2 changes: 1 addition & 1 deletion content/docs/references/security/permission.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ const result = AdminScopeSchema.parse(data);
| :--- | :--- | :--- | :--- |
| **name** | `string` | ✅ | Permission set name, unique per organization (lowercase snake_case) |
| **label** | `string` | optional | Display label |
| **description** | `string` | optional | Human-readable description shown in Setup (persisted as sys_permission_set.description) |
| **description** | `string` | optional | Human-readable description shown in Setup |
| **packageId** | `string` | optional | [ADR-0086 D3] Owning package id for a package-shipped set (absent = env-authored) |
| **managedBy** | `Enum<'package' \| 'platform' \| 'user'>` | optional | [ADR-0086 D3] Record provenance: package (upgrade-owned metadata) vs platform/user (env config) |
| **isDefault** | `boolean` | optional (default: `false`) | [ADR-0090 D5] App baseline for the everyone position: app-level sets are auto-bound at boot (guarded, idempotent); package-level sets become install-time suggestions an admin confirms |
Expand Down
4 changes: 2 additions & 2 deletions content/docs/references/system/auth-config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Advanced / low-level Better-Auth options
| :--- | :--- | :--- | :--- |
| **posture** | `Enum<'invite_only' \| 'email_domain' \| 'open'>` | optional (default: `"invite_only"`) | Who may self-register into this environment: invite_only (default — operator acts only), email_domain (allowlisted email domains), or open (anyone). email_domain forces email verification on; open forces it on unless the deployment explicitly sets emailAndPassword.requireEmailVerification to false. |
| **allowedEmailDomains** | `string[]` | optional | Email domains admitted to self-register under posture email_domain (exact, case-insensitive match; subdomains need their own entries). Required non-empty for email_domain; refused under other postures. |
| **selfRegistrationPermissionSet** | `string` | optional | sys_permission_set name granted to each self-registrant. Required when posture is email_domain or open; refused for invite_only. admin_full_access is refused. |
| **selfRegistrationPermissionSet** | `string` | optional | Name of the permission set granted to each self-registrant. Required when posture is email_domain or open; refused for invite_only. admin_full_access is refused. |


---
Expand Down Expand Up @@ -171,7 +171,7 @@ OIDC / Generic OAuth2 provider configuration for enterprise SSO
| :--- | :--- | :--- | :--- |
| **posture** | `Enum<'invite_only' \| 'email_domain' \| 'open'>` | optional (default: `"invite_only"`) | Who may self-register into this environment: invite_only (default — operator acts only), email_domain (allowlisted email domains), or open (anyone). email_domain forces email verification on; open forces it on unless the deployment explicitly sets emailAndPassword.requireEmailVerification to false. |
| **allowedEmailDomains** | `string[]` | optional | Email domains admitted to self-register under posture email_domain (exact, case-insensitive match; subdomains need their own entries). Required non-empty for email_domain; refused under other postures. |
| **selfRegistrationPermissionSet** | `string` | optional | sys_permission_set name granted to each self-registrant. Required when posture is email_domain or open; refused for invite_only. admin_full_access is refused. |
| **selfRegistrationPermissionSet** | `string` | optional | Name of the permission set granted to each self-registrant. Required when posture is email_domain or open; refused for invite_only. admin_full_access is refused. |

### Nested Shape: `AuthConfig.advanced`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ flagged inline below.
|---|---|---|
| **D1** classification on the provenance axis | **Adopted**; table vocabulary now stale — see "revised table" below | Principle intact. Rows renamed/removed by ADR-0090 (Profile gone, role→position). |
| **D2** DEFINITION↔ASSIGNMENT principle | **Adopted, reinforced** | ADR-0090 D2 leans on it to justify removing Profile; ADR-0091 dates the *assignment* rows only (`valid_from`/`valid_until`), confirming they are env data. |
| **D3** `packageId` + provenance `managedBy` on the set | **Implemented** | `packages/spec/src/security/permission.zod.ts#managedBy` (`packageId`, tagged `[ADR-0086 D3]`) + (`managedBy` enum); record fields `package_id`/`managed_by`/`customized` + index on `packages/plugins/plugin-security/src/objects/sys-permission-set.object.ts#managedBy`. |
| **D3** `packageId` + provenance `managedBy` on the set | **Implemented** | `packages/spec/src/security/permission.zod.ts#managedBy` (`packageId`, tagged `[ADR-0086 D3]`) + (`managedBy` enum); record fields `package_id`/`managed_by`/`customized`; the `sys_permission_set` row object that carried them is retired by C3 stage 8 (ADR-0131 D3; `packages/spec/src/migrations/entries/semantic/18.catalog-row-objects-retired.ts`). |
| **D4** Shape B (packages ship own sets; union; shared slices env-only) | **Adopted, reinforced; subtract layer upgraded** | ADR-0090 D9 / Alt #6 reject package-written shared/builtin sets for the same reasons. Composition is now anchored at the **position** ("bind several packages' sets to one position"), ADR-0094 D5. **Subtract layer changed** — see ⚠️ below. |
| **D5** `bootstrapDeclaredPermissions` | **Implemented; `isDefault` semantics refined by ADR-0090 D5** | `plugin-security/src/bootstrap-declared-permissions.ts` (invoked at `kernel:ready`, `security-plugin.ts`); seeds `managed_by:'package'` + `package_id`, idempotent/upgrade-aware; closes the ADR-0078 inert-metadata smell the D5 header calls out. `isDefault` no longer means "profile fallback": app-level default sets **auto-bind to the `everyone` position**; package-level default sets materialize a `sys_audience_binding_suggestion` an admin confirms (new object). |
| **D6** package Access door under draft/publish | **Implemented** | objectui writes the package door as `mode:'draft', packageId` (`PermissionMatrixEditor.tsx`); env door stays live and, per ADR-0094 D3, that "live" save is itself redirected into a metadata overlay. |
Expand Down
14 changes: 7 additions & 7 deletions docs/audits/2026-08-tenant-audit-write-call-sites.counts.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ silent, and `node scripts/tenant-audit-census.mjs --write` is the resolution.
| Write call sites | 228 |
| Object name statically decidable | 155 |
| Object name chosen at run time | 73 |
| Against a tenancy-enabled object | 154 |
| Against a tenancy-enabled object | 151 |
| Against an object declaring tenancy off | 1 |
| Threading a tenant context | 167 |
| Provably carrying none | 8 |
Expand Down Expand Up @@ -90,13 +90,13 @@ holds still. They are required to be HERE and to say WHEN they were true;
their values are not compared. The reasoning, and the measurement behind it,
are in `scripts/check-tenant-audit-census.mjs`.

Measured on 2026-10-13 at `ae14c39c5`.
Measured on 2026-10-13 at `7c01d30c9`.

| corpus scale (not enforced) | count |
| :--- | ---: |
| tracked non-test sources scanned | 654 |
| tracked non-test sources scanned | 650 |
| engine-shaped types recognised | 73 |
| declared objects in the registry | 120 |
| declared objects in the registry | 116 |
| same-named calls subtracted as non-engine | 160 |

## Every site
Expand Down Expand Up @@ -163,10 +163,10 @@ Measured on 2026-10-13 at `ae14c39c5`.
| `packages/plugins/plugin-security/src/invitation-placement.ts` | `insert` | `sys_user_position` | enabled | elevated | 1 |
| `packages/plugins/plugin-security/src/permission-set-projection.ts` | `insert` | `object` | undecidable | context, elevation undecidable | 1 |
| `packages/plugins/plugin-security/src/permission-set-projection.ts` | `update` | `object` | undecidable | context, elevation undecidable | 1 |
| `packages/plugins/plugin-security/src/permission-set-projection.ts` | `delete` | `sys_permission_set` | enabled | elevated | 1 |
| `packages/plugins/plugin-security/src/permission-set-projection.ts` | `delete` | `sys_permission_set` | undeclared-name | elevated | 1 |
| `packages/plugins/plugin-security/src/position-environment-backfill.ts` | `insert` | `DATA_MIGRATION_FLAG_OBJECT` | undecidable | elevated | 1 |
| `packages/plugins/plugin-security/src/position-write-through.ts` | `delete` | `sys_position` | enabled | elevated | 1 |
| `packages/plugins/plugin-security/src/position-write-through.ts` | `update` | `sys_position` | enabled | elevated | 1 |
| `packages/plugins/plugin-security/src/position-write-through.ts` | `delete` | `sys_position` | undeclared-name | elevated | 1 |
| `packages/plugins/plugin-security/src/position-write-through.ts` | `update` | `sys_position` | undeclared-name | elevated | 1 |
| `packages/plugins/plugin-security/src/suggested-audience-bindings.ts` | `delete` | `sys_audience_binding_suggestion` | enabled | context, elevation undecidable | 1 |
| `packages/plugins/plugin-security/src/suggested-audience-bindings.ts` | `insert` | `sys_audience_binding_suggestion` | enabled | context, elevation undecidable | 1 |
| `packages/plugins/plugin-security/src/suggested-audience-bindings.ts` | `update` | `sys_audience_binding_suggestion` | enabled | context, elevation undecidable | 3 |
Expand Down
13 changes: 10 additions & 3 deletions docs/qa/platform-checklist/areas/access-security.json
Original file line number Diff line number Diff line change
Expand Up @@ -2560,8 +2560,9 @@
"id": "access-security.packaged-permission-set-lifecycle",
"title": "Packaged permission-set lifecycle (#11513) survives ADR-0126 unchanged: locked base at the data door, clone-to-customize with every facet carried, `active` row-state flip — and NONE of it writes a sys_metadata_activation row",
"since": "v16",
"status": "active",
"revision": 1,
"status": "retired",
"retiredReason": "C3 stage 8 (ADR-0131 D3) retired the sys_permission_set row object: its data door, its Activate / Deactivate / Clone row actions and its `active` column are gone. A packaged set's base stays locked at the metadata door, a copy is made with POST /api/v1/security/permission-sets/:name/clone, and a set is switched off in the activation ledger (sys_metadata_activation).",
"revision": 2,
"priority": "P2",
"surface": "mixed",
"personas": [
Expand Down Expand Up @@ -2646,7 +2647,7 @@
"source": [
"packages/plugins/plugin-security/src/packaged-permission-set-lock.ts (classifier + both refusals; the SchemaRegistry-not-managed_by decision)",
"packages/plugins/plugin-security/src/permission-set-projection.ts (insert-path lock + duplicate 409; the #4669 row-state carve-out ordered BEFORE the update-path lock)",
"packages/plugins/plugin-security/src/objects/sys-permission-set.object.ts#bodyExtra (activate/deactivate bodyExtra {active}, clone_permission_set params — the payload contract)",
"packages/runtime/src/domains/permission-set-clone.ts (the clone door that replaced the retired object's clone_permission_set action)",
"docs/adr/0126-packaged-metadata-customization-model.md §1.1 (the #11513 machinery, named as the regime's first instance), §8 item 3 (permission sets converge later; the landed shape stays valid meanwhile)",
"#11513 (lock the base, clone to customize — the 2026-08-24 ruling), #11703 (the three dropped clone facets), #12159 (ruling 2026-08-26: no ledger rows for permission sets pending the convergence card), #12438 (the sweep)"
],
Expand All @@ -2656,6 +2657,12 @@
"date": "2026-08-26",
"change": "new — the landed #11513 surface (data-door lock, clone action, active row-state lifecycle) had no checklist item: readonly-package-locks-studio covers the /meta door on objects and permission-matrix-edit-loop explicitly scopes itself to WRITABLE sets, so the packaged-set data-door lifecycle was uncovered end to end. Authored as the ADR-0126 regression guard with the no-ledger-row wall as its ⭐ clause, per the 2026-08-26 ruling in #12159 (card 已知边界 4): flipping active or cloning must keep writing sys_permission_set state only, never a sys_metadata_activation row",
"ref": "#12438"
},
{
"revision": 2,
"date": "2026-10-12",
"change": "retired — the sys_permission_set row object, its data door and its row actions are retired with C3 stage 8 (ADR-0131 D3)",
"ref": "#15204"
}
]
},
Expand Down
1 change: 0 additions & 1 deletion docs/qa/platform-checklist/coverage.json
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@
"access-security.sharing-rule-authoring-ui",
"access-security.owd-save-gate",
"access-security.share-link-capability-tokens",
"access-security.packaged-permission-set-lifecycle",
"access-security.platform-owner-email-anchor",
"access-security.me-permissions-aggregation-parity",
"api-backend.api-methods-verb-gate"
Expand Down
20 changes: 0 additions & 20 deletions examples/app-showcase/access-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,26 +199,6 @@
"viewAllRecords": false,
"modifyAllRecords": false
},
{
"permissionSet": "showcase_field_ops_delegate",
"object": "sys_permission_set",
"create": false,
"read": true,
"edit": false,
"delete": false,
"viewAllRecords": false,
"modifyAllRecords": false
},
{
"permissionSet": "showcase_field_ops_delegate",
"object": "sys_position",
"create": false,
"read": true,
"edit": false,
"delete": false,
"viewAllRecords": false,
"modifyAllRecords": false
},
{
"permissionSet": "showcase_field_ops_delegate",
"object": "sys_user",
Expand Down
Loading
Loading