diff --git a/docs/adr/0094-sys-permission-set-pure-projection.md b/docs/adr/0094-sys-permission-set-pure-projection.md index d366f5b220..16622c2aa9 100644 --- a/docs/adr/0094-sys-permission-set-pure-projection.md +++ b/docs/adr/0094-sys-permission-set-pure-projection.md @@ -303,7 +303,7 @@ only a seed-not-clobber discipline. | `sys_permission_set` | metadata (`PermissionEvaluator.resolvePermissionSets` → `metadata.list('permission')`, DB row only as fallback) | metadata-authoritative | **Record is a projection — done** (this ADR). | | `sys_sharing_rule` | the record, live (`sharing-plugin.ts` "rule evaluation reads `sys_sharing_rule` live"; `sharing-rule-service` `engine.find`) | **record-authoritative** | **Resolved (#2909 P0/T1)**: declared rules are a **boot seed**; the record is the authority; not projected. Rows carry readonly `managed_by` (unified A4 tri-state) + `customized` provenance; the seeder (`defineRule` in seed mode, `managedBy:'package'`) adopts pristine/legacy rows and keeps updating them, but **never overwrites admin-authored or `customized` rows** — an admin's `active:false` on an over-sharing rule survives redeploys. A `beforeUpdate` hook stamps `customized` on any non-system edit of a seeded row. | | `sys_position` | mixed — position→permission-set resolution is metadata-first for the *sets*, but the `sys_position` **record** (incl. its `permissions` field, bindings, `delegatable`, `admin` gating) is read live by the anchor gate and `DelegatedAdminGate` | **record-authoritative** (bindings and lifecycle), with metadata seeding **identity + display only** | **Resolved (#2909 T2)**: declared positions are seed-only — `bootstrapDeclaredPositions` refreshes `label`/`description` and nothing else; bindings/`active`/`is_default`/`delegatable`/`managed_by` belong to the runtime/admin. Locked by `bootstrap-declared-positions.test.ts`. | -| `sys_capability` | the record (curated registry read for capability existence) | record-authoritative (registry) | **Resolved (#2909 T3)**: seed-not-clobber holds — `label`/`description` are platform-owned and refresh each boot; `managed_by`/`active` were already preserved; `scope` is an admin-editable classification face and is now **seed-once** (insert only). Locked by `bootstrap-system-capabilities.test.ts`. | +| `sys_capability` | the record (curated registry read for capability existence) | record-authoritative (registry) | **Resolved (#2909 T3)**: seed-not-clobber holds — `label`/`description` refresh each boot **for the curated platform definitions** (`PLATFORM_CAPABILITIES`, platform-authored copy); the back-compat **derived** placeholders (`humanize(name)` label, generated `Capability` description) reconcile only rows the derivation itself owns (`managed_by:'platform'`), never a row authored elsewhere — `admin`, `package`, or any other provenance (#5876). `managed_by`/`active` were already preserved; `scope` is an admin-editable classification face and is now **seed-once** (insert only). Locked by `bootstrap-system-capabilities.test.ts`. | Only `sys_permission_set` was both metadata-authoritative **and** carried a harmful, actively-drifting split-brain, which is why it was fixed first and in