Skip to content

Commit be50633

Browse files
docs(adr),refactor(plugin-security): restate the ADR text that names C3-retired security machinery; delete the unreachable audience-anchor binding gate (#23412)
Fixes #23403 Clause-②: no Restates the ADR text that still names security machinery C3 (#15204) has retired, and deletes one gate that has been unreachable since stage 8. A sub-card of #22975. It cites 7a's deletions (#23368) as done, so the seat lands it after 7a. ## 维护者速读(草稿) ### 改了什么 - 修订五份 ADR(0138、0094、0126、0131、0103)中仍在描述已退役安全机制的文字,让每一处都与 main 当前行为一致。 - 删除一个已经不可能被触发的安全检查(「受众锚点绑定闸门」),连同它的调用点和 3 个测试用例,共删约 120 行代码;并修正其他包里仍把它当作「在运行」来描述的注释。 - ADR-0138 执行对照表里「锚点绑定层级」一行的状态,从 `enforced` 改为「`everyone` 已执行;`guest` 待后续 F4」。这是状态更正,不是新的决定。 ### 为什么改 - 阶段 8 下线了 `sys_position_permission_set` 表。这个闸门只检查对这张表的写入,此后再也不会执行,但 ADR 仍写着「由它负责拦截」,读者会误以为这层防护还在起作用。 - 对 `everyone` 锚点,同样的高权限检查实际在「确认建议」和「重新推导」两处执行,ADR 现在如实写明。对 `guest`,目前没有任何入口能绑定权限集,ADR 也写明了这一点。 ### 风险与代价(含回滚) - 运行行为没有任何变化:被删的闸门自阶段 8 起就没被调用过,删掉的也不是对外导出。 - ADR 改动只是更正描述,不改变任何决定。 - 回滚:revert 本 PR 即可,没有数据迁移。 ### 席位意见 ### 你要做的 审阅后批准合并(Tier H:改动了受管路径 `docs/adr/**`)。 ## What this changes **Code: `@objectstack/plugin-security`, patch.** - `SecurityPlugin.assertAudienceAnchorBindingGate` is deleted, with its call in the security middleware and its three cases in `security-plugin.test.ts`. The two imports only it used (`describeAnchorForbiddenBits`, `AnchorBindingContext`) go too. - The gate returned on anything but a write to `sys_position_permission_set`. Stage 8 (#23222) unregistered that object, so no write has reached the gate since. - The anchor tier itself is unchanged and still applied where a binding is made: - `confirmAudienceBindingSuggestion` and the `everyone` derivation (`readAcceptedEveryoneSets`), both in `suggested-audience-bindings.ts`; - for `guest`, no door binds a set. - Not an entry export. The changeset is `.changeset/23403-audience-anchor-binding-gate-retired.md`. **ADRs.** Each item was checked first against `a581c57eae` (#23362), which recorded stage 8's retirement. - **ADR-0138:** - **:171** drops the anchor to the deleted gate. It now says the `guest` tier has no caller on `main` until item 5's bind door. - **Item 4 (:371)** says where the predicate runs today: `everyone` on confirm and on every derivation; `guest` by the bind door when built. - **Item 5's re-read note (:395)** and **the conformance row (:578)** are restated the same way. The row now reads "enforced for `everyone`; `guest`: follow-up F4". - `a581c57eae` did not touch this ADR. - **ADR-0094:** `a581c57eae` already restated the TL;DR, D1–D4 and the addendum. Three lines still pointed at the module as living: - the RETIRED banner's "stays in the tree until stage 7a deletes it"; - the unit-case citation of `permission-set-projection.test.ts`; - the Implementation line. All three now record the deletion by stage 7a (#23368). - **ADR-0126:** "Three real mechanisms" gains a path note: stage 8 retired the `sys_permission_set` row whose `active` column carried the row state, and stage 7a deleted the module. This follows the ADR's existing path-note convention, and the path is kept as the record of what the section measured. - **ADR-0131:** both lists are dated evidence (re-verified at `2514d49f3`), so they are annotated rather than rewritten. - The Consumers line (:59) gains a note: the five bootstrap seeders went with stages 6a and 6b, and `permission-set-projection.ts` with 7a. - The framework code list (:993) gains a note naming the four deleted seeder files and the projection. - **ADR-0103 (:52):** the provenance note said `assertSystemRowWriteGate` guards `sys_sharing_rule`, `sys_position` and `sys_capability`. Measured on `main`, its map (`SYSTEM_ROW_PROVENANCE`) holds `sys_position` and `sys_capability` only. `sys_sharing_rule` is deliberately ungated: plugin-sharing's provenance hook (`sharing-rule-provenance.ts`) stamps an edited row `customized` instead. And since stage 8 unregistered both objects, no write reaches that gate. The note now says this. ## Acceptance notes - **Out of scope, found:** `assertSystemRowWriteGate` is unreachable for the same reason as the deleted gate, since its two objects are unregistered. It stays here because this card names only the anchor gate; it belongs with 8-post's residue or its own card. - **Prose left for 8-post's comment sweep:** two comments still describe the deleted gate: - the `declared-capability-context.ts` docblock ("all three runtime consumers", "the gate the engine middleware re-enforces on the insert"); - `examples/app-showcase/src/security/permission-sets.ts:360`. - `plugin-sharing/CHANGELOG.md` names the gate as history and is not edited. - **Comments that described the gate as live, now restated** (comments and one note string only, no code): - the preview docblocks in `security-plugin.ts` (about `:6151`) and `objectql/src/engine.ts` (about `:5518`); - the engine's referential-integrity docblock (about `:8859`) and its sandbox gate list (about `:20842`); - `integrity/dangling-reference-audit.ts` (about `:375`), and the same phrase in two test comments (`engine-lookup-referential-integrity.test.ts`, `dangling-reference-audit.test.ts`); - `lint/src/validate-security-posture.ts` (about `:37`); - the `position-active` row's `note` in `qa/dogfood/test/authz-conformance.matrix.ts` (prose: no test reads `note`). ## Verification On `64c2e41049` (`main` `dac99c2277`'s successor merged once, at `bd13bf7808`, to sit on 7a; not re-merged since): - `check:adr-symbol-anchors` and `check:adr-links`: exit 0. - Typecheck of `plugin-security`, `objectql`, `lint` and the dogfood package: exit 0. - `authz-conformance.test.ts` (the matrix row changed): 61/61. - On `bd13bf7808`, before this round's comment-only changes: - `plugin-security` suite: 185/185 files, 3,773 passed; - `check:scripts-symbol-anchors` and `check:spec-docblock-symbol-anchors`: exit 0. - On `59761d4a71`: the derived gate sweep, 74 derived, 74 run, all exit 0, with `--ran` reconciling at 0 NOT-MEASURED and 0 UNRUN. --- _Generated by [Claude Code](https://claude.ai/code/session_01287UbjvrigpWwNfGDmdwpS)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 04a3148 commit be50633

14 files changed

Lines changed: 79 additions & 162 deletions
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@objectstack/plugin-security': patch
3+
---
4+
5+
refactor(plugin-security): the audience-anchor binding gate on `sys_position_permission_set` is deleted
6+
7+
Clause-②: no
8+
9+
`SecurityPlugin`'s private engine-middleware gate that refused binding a high-privilege permission set to the `everyone` or `guest` position guarded writes to `sys_position_permission_set` only. C3 stage 8 (#23222) unregistered that object, so no write has reached the gate since. The gate, its call in the middleware and its three unit cases are removed.
10+
11+
No behaviour changes, and nothing exported changes. The anchor tier itself (`describeAnchorForbiddenBits` from `@objectstack/spec/security`) still applies wherever a binding is made: when an `everyone` suggestion is confirmed (`confirmAudienceBindingSuggestion`), and on every derivation of the `everyone` anchor. No door binds a set to `guest`.

‎docs/adr/0094-sys-permission-set-pure-projection.md‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ ADR-0005 rollback landed by #6483 / PR #6608)
1616
> **RETIRED 2026-10-13 (#15204 stage 8, `66949b7729`, by execution of [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D2/D3/D13).**
1717
> The `sys_permission_set` row object is no longer registered, and the machinery that kept it a
1818
> projection — the write-through (D3), the `permission` projector (D2) and the boot reconcile and
19-
> backfill (D4) — is unwired; its module stays in the tree until #15204 stage 7a deletes it. D1
19+
> backfill (D4) — is unwired, and #15204 stage 7a (#23368) deleted its module (`permission-set-projection.ts`, with the seed-name lookup and the refusal sink). D1
2020
> stands. Read the rest of this summary, D2–D4 and the Consequences in the past tense.
2121
2222
A permission-set **definition** (label, description, the six facet groups, `adminScope`,
@@ -184,9 +184,10 @@ is `managed_by:'admin'` while its definition ships as a platform artifact, and i
184184
data-door edit is **refused** — the record's provenance column was never what the gate
185185
read. The mirror case is `twodoors_pkgset`, whose row is `managed_by:'package'` while its
186186
definition lives in `sys_metadata` (that materialization is pinned in the same file);
187-
that an edit of such a row still **lands** is pinned as a unit case in
187+
that an edit of such a row still **lands** was pinned as a unit case in
188188
`packages/plugins/plugin-security/src/permission-set-projection.test.ts`, whose protocol
189-
stub models this gate.
189+
stub modelled this gate, until #15204 stage 7a (#23368) deleted that suite with the
190+
projection it pinned.
190191

191192
The refusal is left to the producer deliberately: `plugin-security` does not re-derive
192193
artifact-backing to pre-empt it. That rule belongs to the metadata protocol
@@ -395,9 +396,11 @@ other write.
395396
`packages/metadata-protocol/src/protocol.ts` (`saveMetaItem` /
396397
`deleteMetaItem` tier gates) and
397398
`packages/metadata-protocol/src/sys-metadata-repository.ts` (`assertAllowed`).
398-
- Implementation: `packages/plugins/plugin-security/src/permission-set-projection.ts`,
399-
`packages/metadata-protocol/src/protocol.ts` (`registerMutationProjector`),
400-
`packages/plugins/plugin-security/src/security-plugin.ts` (wiring).
399+
- Implementation: `packages/plugins/plugin-security/src/permission-set-projection.ts`
400+
(deleted by #15204 stage 7a, #23368, after stage 8 unwired it),
401+
`packages/metadata-protocol/src/protocol.ts` (`registerMutationProjector`, the seam that
402+
stays), `packages/plugins/plugin-security/src/security-plugin.ts` (the wiring, removed by
403+
stage 8).
401404

402405
---
403406

‎docs/adr/0103-managedby-write-policy-and-engine-write-guard.md‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,14 @@ write policy **expressible and enforced** without breaking the writable set.
4949

5050
> **Not to be confused with** the row-level `managed_by` *provenance* column
5151
> (`'platform' | 'package' | 'admin'`) on `sys_sharing_rule` / `sys_position` /
52-
> `sys_capability`, guarded by `assertSystemRowWriteGate` (ADR-0066). That is a
53-
> per-row provenance axis; this ADR is about the per-object schema bucket. The
54-
> shared word is a coincidence.
52+
> `sys_capability` (ADR-0066). That is a per-row provenance axis; this ADR is about
53+
> the per-object schema bucket. The shared word is a coincidence. Of the three
54+
> objects named here, only `sys_sharing_rule` is still registered on `main`, and its admin
55+
> edits are stamped `customized` by plugin-sharing's provenance hook
56+
> (`packages/plugins/plugin-sharing/src/sharing-rule-provenance.ts`), not refused.
57+
> `SecurityPlugin.assertSystemRowWriteGate` guarded `sys_position` and
58+
> `sys_capability` (never `sys_sharing_rule`), and no write reaches it since
59+
> #15204 stage 8 unregistered both.
5560
5661
> **Note (2026-10-14) — three objects named above are retired.** `sys_position_permission_set`
5762
> (item 2), `sys_position` and `sys_capability` are no longer registered since #15204 stage 8

‎docs/adr/0126-packaged-metadata-customization-model.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Three real mechanisms operate across those tiers, each invented separately:
9494
- **Clone-to-customize** (#11513, permission sets only): server-side lock on the packaged base
9595
(`packaged-permission-set-lock.ts`), a clone action demanding a new name, and — the piece this
9696
ADR generalizes — the ruling that **switching a packaged artifact off is row state, not a
97-
definition write** (`packages/plugins/plugin-security/src/permission-set-projection.ts`, #4669).
97+
definition write** (`packages/plugins/plugin-security/src/permission-set-projection.ts`, #4669; *Path note, 2026-10: #15204 stage 8 retired the `sys_permission_set` row whose `active` column carried that row state, and stage 7a (#23368) deleted the module; the path is kept as the record of what this section measured*).
9898
- **Extend** (`objectExtensions`, `packages/spec/src/data/object.zod.ts`; navigation
9999
contributions, ADR-0029 D7): a package adds fields/validations/indexes to another package's
100100
object, or nav items to another package's app, merged at boot. Package-grain, additive,

‎docs/adr/0131-total-organization-ownership-no-null-organization-id.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ seeders, `bootstrap-platform-admin.ts`, `permission-set-projection.ts`), `plugin
6363
`plugin-audit`, `service-storage`, `plugin-approvals`, `service-automation`, `objectui` (Setup /
6464
Studio / pickers — D7), and in their own repository `cloud`'s control plane and `objectos-ee`.
6565

66+
> **Note (2026-10-14) — C3 retired the `plugin-security` consumers it names.** The five bootstrap
67+
> seeders went with #15204 stages 6a and 6b (ADR-0131 D2), and `permission-set-projection.ts` with
68+
> stage 7a (#23368), after stage 8 (`66949b7729`) unwired it. `tenant-layer.ts`,
69+
> `per-organization-catalog.ts` and `bootstrap-platform-admin.ts` remain. The list above is the
70+
> consumer set as this record was written.
71+
6672
---
6773

6874
## TL;DR
@@ -999,6 +1005,10 @@ fate 2 after a verified rewrite; no surface builds a merged server-paged list of
9991005
`packages/plugins/plugin-email/src/template-loader.ts`;
10001006
`packages/metadata-core/src/meta-write-org-scope.ts`;
10011007
`packages/spec/src/data/injected-system-columns.ts`; `scripts/check-tenant-chokepoint.mjs`.
1008+
*Note (2026-10-14):* of the `plugin-security` files above, `bootstrap-declared-permissions.ts`,
1009+
`bootstrap-declared-positions.ts`, `bootstrap-builtin-positions.ts` and
1010+
`bootstrap-system-capabilities.ts` were deleted by #15204 stages 6a and 6b, and
1011+
`permission-set-projection.ts` by stage 7a (#23368). The list is kept as measured at `2514d49f3`.
10021012
- Code (cloud, `main` `3856fbf7`): `packages/service-cloud/src/control-plane-platform-global.ts`;
10031013
`packages/service-cloud/src/control-plane-org-scope-plugin.ts`;
10041014
`packages/service-cloud/src/migrations/org-id-backfill.ts`;

‎docs/adr/0138-guest-model-anonymous-principal-doors-grants-and-organization.md‎

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,10 @@ re-checked at the same head, shape the decisions:
167167
enforcing reader keys on the string `'guest'`: the envelope
168168
(`packages/core/src/security/assemble-execution-context.ts#entryFields`), explain's `EXTERNAL` floor
169169
(`packages/plugins/plugin-security/src/explain-engine.ts#derivePosture`), the anchor binding tier
170-
(`packages/spec/src/security/high-privilege.ts#describeAnchorForbiddenBits`, called from
171-
`packages/plugins/plugin-security/src/security-plugin.ts#SecurityPlugin.assertAudienceAnchorBindingGate`),
170+
(`packages/spec/src/security/high-privilege.ts#describeAnchorForbiddenBits`; at `7b926f7600` an
171+
engine write gate on `sys_position_permission_set` called it, and that table was retired by #15204
172+
stage 8 and the gate deleted by #23403, so on `main` its `guest` tier has no caller until item 5's
173+
bind door),
172174
and delegated administration (`packages/plugins/plugin-security/src/delegated-admin-gate.ts#ANCHOR_POSITIONS`).
173175
- **Two guest values are declared with nothing behind them.** A package may suggest a `guest`
174176
binding (`packages/plugins/plugin-security/src/objects/sys-audience-binding-suggestion.object.ts#anchor`),
@@ -367,8 +369,12 @@ unchanged. **Card**: E2.
367369
three.
368370
4. **The binding tier stands.** A set bound to `guest` must pass the strictest anchor tier:
369371
explicit objects only, no wildcard, read-mostly with create case by case, no view-all or
370-
modify-all, no system permissions (ADR-0090 D9; `describeAnchorForbiddenBits`, enforced by
371-
`SecurityPlugin.assertAudienceAnchorBindingGate`). A delegated administrator never binds an anchor
372+
modify-all, no system permissions (ADR-0090 D9; `describeAnchorForbiddenBits`). The predicate
373+
runs where a binding is made: for `everyone`, when a suggestion is confirmed
374+
(`confirmAudienceBindingSuggestion`) and on every derivation of the anchor
375+
(`readAcceptedEveryoneSets`); for `guest`, no door binds a set today (item 5), and the bind door
376+
runs it when built. The engine gate that once applied it to `sys_position_permission_set` rows
377+
retired with that table (#15204 stage 8; the gate was deleted by #23403). A delegated administrator never binds an anchor
372378
(ADR-0090 D12; `ANCHOR_POSITIONS`). Unchanged.
373379
5. **How a deployment grants: implementation-first.** The bind door is built when a named
374380
deployment needs to grant the guest on a public surface (a site or portal) and the class-1 form
@@ -391,9 +397,9 @@ unchanged. **Card**: E2.
391397
so ⛔ opening that door (`PUT /meta/position/guest`) is refused: it reverses the seal and misses
392398
environment kernels. The row half stays item 6: share links and, when built, an explicit guest
393399
sharing rule (read-only, criteria-based, the strictest lint tier), the only shape in which D8's
394-
retired `guest` recipient returns. **Re-read when the door is built:** item 4's guest tier of
395-
`assertAudienceAnchorBindingGate`, which guards `sys_position_permission_set` rows that no
396-
binding reader reads, and objectui's pin that a guest row offers no Accept
400+
retired `guest` recipient returns. **Re-read when the door is built:** item 4's guest tier, which
401+
no door runs today (the engine gate that carried it guarded `sys_position_permission_set` rows,
402+
retired by #15204 stage 8, and was deleted by #23403), and objectui's pin that a guest row offers no Accept
397403
(`objectui:packages/app-shell/src/components/SuggestedBindingsPanel.tsx`). Amended by ruling C
398404
on [#23267](https://github.com/objectstack-ai/objectstack/issues/23267)
399405
([`6159279205`](https://github.com/objectstack-ai/objectstack/issues/23267#issuecomment-6159279205)).
@@ -575,7 +581,7 @@ that card lands; no row is declared without an enforcer.
575581
| no `system` flow behind an anonymous flow door | D2b | the publish path, in both directions | card E2 |
576582
| the guest's grants, and deny-all when none | D3 | the anonymous branch of `resolveAuthzContext` | card E1 |
577583
| no door binds a set to `guest` until the bind door is built | D3 item 5 (amended) | the anchors' seal (`NOT_OVERRIDABLE`; the package door's built-in names) and `confirmAudienceBindingSuggestion`'s refusal of a `guest` row | enforced; the door is follow-up F4 |
578-
| the anchor binding tier | ADR-0090 D9; D3 | `describeAnchorForbiddenBits`, through `assertAudienceAnchorBindingGate` | enforced |
584+
| the anchor binding tier | ADR-0090 D9; D3 | `describeAnchorForbiddenBits`: for `everyone` through `confirmAudienceBindingSuggestion` and `readAcceptedEveryoneSets`; for `guest`, through the bind door when it is built (no door binds a set to `guest`, the row above) | enforced for `everyone`; `guest`: follow-up F4 |
579585
| no delegated binding of an anchor | ADR-0090 D12 | `ANCHOR_POSITIONS` | enforced |
580586
| the guest's organization | D4 | the guest entry's organization step, with `resolveSystemWriteOrganization`'s predicate | card E1 |
581587
| the form doors' organization | D4, clarification (1) | `anonymousFormIntakeUnavailability`; the engine's write derivation | enforced |

‎packages/lint/src/validate-security-posture.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@
3333
* an operator binds to `guest` at install time is a decision ADR-0090 D9
3434
* ("a package may suggest bindings … the admin confirms each individually")
3535
* puts past authoring, so this rule is not — and cannot be — coverage for an
36-
* app-authored anchor set bound to `guest` (#16110). That binding is held by
37-
* the runtime's own `describeAnchorForbiddenBits(set, 'guest')` gate instead.
36+
* app-authored anchor set bound to `guest` (#16110). No runtime door binds a
37+
* set to `guest` today; ADR-0138 D3 item 5's bind door runs
38+
* `describeAnchorForbiddenBits(set, 'guest')` when it is built.
3839
*
3940
* `security-cbp-ambiguous-relation` used to be the one exception: the runtime
4041
* did not refuse two candidate masters, it silently PICKED one by field

‎packages/objectql/src/engine-lookup-referential-integrity.test.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
* {"title":"…","project":"proj_does_not_exist","status":"backlog"} → 200
1717
*
1818
* On the RBAC link tables a dangling row is a security-surface record that
19-
* resolves to nothing: the audience-anchor gate has to resolve that permission
20-
* set to evaluate the grant, so the binding is an unevaluable gate input.
19+
* resolves to nothing: a grant naming a permission set nothing serves. (The
20+
* audience-anchor gate that once had to resolve such a set retired with
21+
* `sys_position_permission_set`, C3 stage 8.)
2122
*/
2223

2324
import { describe, it, expect, beforeEach } from 'vitest';

‎packages/objectql/src/engine.ts‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5514,9 +5514,10 @@ export class ObjectQL implements IObjectQLEngine {
55145514
* - **The remaining PRE-RESOLUTION gates, which run beside the two named
55155515
* above.** Two judge a row's PROVENANCE, which the preview holds no row to
55165516
* carry: the ADR-0086/0094 package-managed write gate and the ADR-0066
5517-
* system-row write gate. Two judge a payload VALUE: the ADR-0066 D1
5518-
* curated-capability-name refusal and the ADR-0090 D5/D9 audience-anchor
5519-
* binding guard. And the ADR-0056 `publicFormGrant` scope, which admits
5517+
* system-row write gate. One judges a payload VALUE: the ADR-0066 D1
5518+
* curated-capability-name refusal (the ADR-0090 D5/D9 audience-anchor
5519+
* binding guard retired with `sys_position_permission_set`, C3 stage 8).
5520+
* And the ADR-0056 `publicFormGrant` scope, which admits
55205521
* create plus read-back on exactly the granted object and refuses
55215522
* everything else — not asked because no wire caller and no constructor
55225523
* in the tree presents that grant here (only the public form-submit route
@@ -8856,9 +8857,10 @@ export class ObjectQL implements IObjectQLEngine {
88568857
*
88578858
* On the RBAC link tables that is a security-surface record that resolves to
88588859
* nothing: an administrator auditing permissions sees a binding whose target
8859-
* cannot be inspected, and the audience-anchor gate has to resolve that very
8860-
* set to evaluate the grant — so a dangling row is an unevaluable gate input,
8861-
* not merely an untidy one.
8860+
* cannot be inspected, and the audience-anchor gate had to resolve that very
8861+
* set to evaluate the grant — so a dangling row was an unevaluable gate input,
8862+
* not merely an untidy one. (That gate and `sys_position_permission_set` are
8863+
* retired since C3 stage 8; the check stands for the link tables that remain.)
88628864
*
88638865
* ## Scope, deliberately narrow
88648866
*
@@ -20839,7 +20841,8 @@ export class ObjectRepository implements IScopedObjectRepository {
2083920841
* middleware (`:1616`, `canExport` at `:4573`); the ADR-0103 engine-owned/
2084020842
* append-only write guard (`system-write-guard.ts:96,120`, called at
2084120843
* `security-plugin.ts:1736`); the package-managed / system-row /
20842-
* curated-capability-name / audience-anchor write gates
20844+
* curated-capability-name write gates (and, until C3 stage 8, the
20845+
* audience-anchor gate)
2084320846
* (`security-plugin.ts:1690-1724`); the referential-integrity check
2084420847
* (`:5892` in this file) and the tenant-audit mute (`:3773`) — in addition
2084520848
* to the static `readonly`/runtime-owned strip on BOTH update paths

‎packages/objectql/src/integrity/dangling-reference-audit.test.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,7 @@ describe('[#4551] dangling stored references are reported, never rewritten', ()
122122
it('finds a dangling reference and reports its FULL location', async () => {
123123
// The residual #4441 left: a system write put a permission-set id here that
124124
// names no row. On an RBAC link table that is a security-surface record
125-
// resolving to nothing — the audience-anchor gate has to resolve exactly
126-
// that set to evaluate the grant.
125+
// resolving to nothing: a grant naming a permission set nothing serves.
127126
const port = makePort({
128127
objects: [binding],
129128
rows: {

0 commit comments

Comments
 (0)