Repository navigation
Commit 1e8b628
fix(spec,metadata-protocol)!: the /meta door no longer authors sharing rules; Setup lists declared sharing rules (#24599)
Closes #24550
Clause-②: yes (narrowing)
The console half is objectstack-ai/objectui#13050 (Setup's
declared-rules page). This PR is the server half: it closes the third
authoring door and adds the Setup nav entry that page needs.
## What changed
**1. The `/meta` door no longer authors sharing rules (BREAKING
narrowing, launch-window `minor`).**
`sharing_rule` had no metadata-type registry entry. Both `/meta` doors
read that absence as "runtime-creatable": `GET /meta/types` advertised
`allowRuntimeCreate: true`, and `PUT /meta/sharing_rule/:name` stored an
environment-wide item that `GET /sharing/rules` then served and
enforced. That item bypassed the same-name guard and the organization
wall.
- **Mechanism, measured.** The position and permission-set seal
(`refusePackagedBaseOverride`, `allowEnvironmentOverlay: false`) refuses
writes over a *packaged* name only, and both types keep
`allowRuntimeCreate: true`. So it cannot refuse a new name. The
security-catalog namespace rule judges package registration, not a
`/meta` save. The mechanism that fits is the code-only pair `capability`
uses (#5961): `sharing_rule` joins `MetadataTypeSchema` and
`DEFAULT_METADATA_TYPE_REGISTRY` with `allowRuntimeCreate: false` and
`allowEnvironmentOverlay: false`. Its `SharingRuleSchema` binding moves
into the kind map. The listing and the save door now read one
declaration.
- **The refusals,** on every kernel, in publish and `?mode=draft`:
- a new name gets `403 NOT_CREATABLE`;
- a declared rule's name gets `403 NOT_OVERRIDABLE`.
- **What they say.** `sharing_rule` gains an ADR-0126 Regime C row in
`PACKAGED_BASE_REGIME`: the clone is `POST /api/v1/sharing/rules`, and
the switch is `POST /api/v1/security/_activation/sharing_rule/:name`.
Both refusals name the two sanctioned paths. Neither prescribes the
`OS_METADATA_WRITABLE` hatch, because for a Regime C type the hatch
would re-open the source the regime closes. Both stay under the REST
door's 500-character bound (`truncateClientMessage`). The first cut did
not: the showcase boot showed the switch route cut off, and it was
fixed.
- **ADR-0087:** semantic entry `sharing-rule-runtime-create-withdrawn`.
The changeset carries FROM → TO and the one-line fix: "author an
organization rule, or clone the declared one".
**2. The Setup nav entry.** plugin-sharing adds
`nav_declared_sharing_rules`, a `type: 'url'` entry like
`nav_permission_sets`. It points at
`/apps/setup/metadata/sharing_rule?scope=environment` and sits beside
`nav_sharing_rules`, with the same `manage_platform_settings`
requirement. Its labels are in `platform-objects`' Setup translations
(`en`, `zh-CN`, `ja-JP`, `es-ES`), with source hashes recorded, the same
way the plugin's other entries are labelled.
**Derived artifacts:** `meta-url-data.generated.ts`, the reference docs,
the metadata-form i18n bundles (translated by hand in the three
locales), the engine-double ledger, and the overlay-table count in
`metadata-lifecycle.mdx` (with a `sharing_rule` row).
## Item 3: measured, not built
- **The ledger's reading on `/meta/sharing_rule` items.** The metadata
protocol reads `sys_metadata_activation` for no type. `/meta/position`,
`/meta/permission`, `/meta/flow` and `/meta/action` carry no ledger
state either. Adding it for one type is a new cross-layer seam, so it
does not meet "removes a client read without a new surface". Not built.
Measured on the showcase: after the switch-off, the `/meta` item still
reads `active: true`.
- **`GET /sharing/rules/:name` for a switched-off declared rule.** It
answers `404 RULE_NOT_FOUND` (measured on the showcase). `getRule` falls
through to `declaredRules()`, which drops ledger-off rules. That filter
is right for enforcement, because `listRules` feeds every enforcement
path. Reported only, with a recommendation in the report.
## Verification (head `47f50805`; the gate battery ran at `03ec6356`,
and only the changeset text and one CLI test changed after it — their
families were re-run at `47f50805`)
- **HTTP-door pin.**
`packages/runtime/src/meta-sharing-rule-door.test.ts` drives the real
`HttpDispatcher`, protocol and repository on both kernel shapes. It
covers a new name (publish and draft): 403 `NOT_CREATABLE`, no row,
nothing registered, both routes named, under 500 characters. It covers a
declared name: 403 `NOT_OVERRIDABLE`, no row. It covers `/meta/types`:
`allowRuntimeCreate: false`. The control is a new position, which still
saves (200). Result: 10/10.
- **Ablation.** The registry entry was deleted through
`ablation-replace.mjs`, spec was rebuilt, and `ablation-dist-preflight
--absent` confirmed the marker was gone from 232 built files. Then **6
red / 4 green**: the create cases answered `200 "Saved sharing_rule
'probe_meta_rule' (env-wide, state=active)"`, and the listing returned
`allowRuntimeCreate: true`. That is the reported defect, reproduced. The
declared-name case stayed green under ablation, because the package door
already sealed declared names before this change. The restore was
confirmed by a blob hash match and a clean tree, then a rebuild with the
marker present in 16 files: 10/10 green.
- **Showcase boot** (`pnpm dev -- --fresh`):
- The door refuses with the two messages above.
- `/meta/types` lists `sharing_rule` with `allowRuntimeCreate: false`.
- A new position saves (200).
- `GET /meta/app/setup` serves `nav_declared_sharing_rules` in
`group_access_control`, between `nav_sharing_rules` and
`nav_record_shares`, and its `zh-CN` label is served.
- Both sanctioned paths still work: `POST /sharing/rules` answers 201,
and its same-name guard answers 409.
- The rendered console was NOT MEASURED: this container has no console
build. objectstack-ai/objectui#13050 renders the page.
- **Tests:**
- spec: full suite, then the re-judged files, 216/216.
- metadata-protocol: full suite, 20725 passed.
- platform-objects: full suite, then the two re-judged files, 73/73.
- plugin-sharing: full suite.
- objectql: `protocol-meta*`, 100/100.
- rest: `meta-unknown-type-read-refusal`, 21/21.
- runtime: the new pin plus `meta-managed-content-seal`.
- CLI: the unit-tier registry-parity tests, 40/40. The integration-tier
`metadata-type-schema-gate` (8/8, after classifying `sharing_rule` as
gated at `sharingRules:`) and `organization-ownership-apply` were run
locally because they enumerate the registry.
- metadata, rest, runtime, lint and client: the 16 files that read the
registry, 364/364.
- **Typecheck:** spec, metadata-protocol, plugin-sharing,
platform-objects, runtime and objectql, all clean.
- **Gates:** every family in `dispatch-gates.mjs --commands`, plus the
34 artifact-roster rows, with exit codes captured before any pipe: 158
of 164 exit 0. The other six are NOT MEASURED, not findings: four
PR-context guards that read the workflow event
(`check-closing-target-claim`, `check-partof-closing-keyword`,
`check-single-claim-paths`, `check-governed-queue-guard`), and two
refusals on this shallow clone (`check-engine-split-ratio`,
`check-plugin-teardown-shape --self-test`). On the first battery, three
real reds were fixed: `check:engine-double-contract` (ledger `--write`),
`check:i18n` (bundles regenerated, then translated), and
`check:overlay-whitelist-table` (registry count 28 → 29, plus a row).
## Acceptance notes
- **The hatch.** `OS_METADATA_WRITABLE=sharing_rule` still opens a
create, as it does for every code-only type. It is not prescribed in any
refusal. It is also the repair path for an item stored through the old
door on an environment kernel, where `DELETE /meta/sharing_rule/:name`
otherwise answers `403 NOT_CREATABLE`. A host-config kernel deletes such
an item without it (measured).
- **Items already stored through the old door** stay served until
deleted, so a database created by 18.0 keeps its data (R2). Nothing
rewrites them.
- **File surface.** The claim named `plugin-sharing/**` and "the
metadata door's seal". The seal lives in `packages/spec` (the registry)
and `packages/metadata-protocol` (the refusal text and the regime row).
The nav labels live in `packages/platform-objects`. The derived ledgers
and docs follow from those. Tests re-judged: spec, metadata-protocol,
objectql and platform-objects pins that asserted the open door or a
registry count. Nothing in `plugin-webhooks` changed, and #24529 touches
none of these files.
---
_Generated by [Claude
Code](https://claude.ai/code/session_013BWJEDZYcJKmZYj6ApCCa7)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 9a7838e commit 1e8b628
38 files changed
Lines changed: 677 additions & 99 deletions
File tree
- .changeset
- content/docs
- concepts
- references
- api
- kernel
- examples/app-showcase/src
- packages
- cli/test
- metadata-protocol/src
- objectql/src
- platform-objects/src/apps/translations
- plugins/plugin-sharing/src
- runtime/src
- spec/src
- kernel
- meta-spelling
- migrations/entries/semantic
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
118 | 118 | | |
119 | 119 | | |
120 | 120 | | |
| 121 | + | |
121 | 122 | | |
122 | | - | |
| 123 | + | |
123 | 124 | | |
124 | 125 | | |
125 | 126 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
648 | 648 | | |
649 | 649 | | |
650 | 650 | | |
651 | | - | |
| 651 | + | |
652 | 652 | | |
653 | 653 | | |
654 | 654 | | |
| |||
715 | 715 | | |
716 | 716 | | |
717 | 717 | | |
718 | | - | |
| 718 | + | |
719 | 719 | | |
720 | 720 | | |
721 | 721 | | |
| |||
747 | 747 | | |
748 | 748 | | |
749 | 749 | | |
| 750 | + | |
750 | 751 | | |
751 | 752 | | |
752 | 753 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
179 | 179 | | |
180 | 180 | | |
181 | 181 | | |
182 | | - | |
| 182 | + | |
183 | 183 | | |
184 | 184 | | |
185 | 185 | | |
| |||
250 | 250 | | |
251 | 251 | | |
252 | 252 | | |
| 253 | + | |
253 | 254 | | |
254 | 255 | | |
255 | 256 | | |
| |||
263 | 264 | | |
264 | 265 | | |
265 | 266 | | |
266 | | - | |
| 267 | + | |
267 | 268 | | |
268 | 269 | | |
269 | 270 | | |
| |||
304 | 305 | | |
305 | 306 | | |
306 | 307 | | |
| 308 | + | |
307 | 309 | | |
308 | 310 | | |
309 | 311 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
167 | 167 | | |
168 | 168 | | |
169 | 169 | | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
170 | 177 | | |
171 | 178 | | |
172 | 179 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
98 | 102 | | |
99 | 103 | | |
100 | 104 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
58 | | - | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
59 | 63 | | |
60 | | - | |
| 64 | + | |
61 | 65 | | |
62 | 66 | | |
63 | 67 | | |
| |||
198 | 202 | | |
199 | 203 | | |
200 | 204 | | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
201 | 213 | | |
202 | 214 | | |
203 | 215 | | |
| |||
308 | 320 | | |
309 | 321 | | |
310 | 322 | | |
311 | | - | |
312 | | - | |
| 323 | + | |
| 324 | + | |
313 | 325 | | |
314 | 326 | | |
315 | 327 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
169 | 169 | | |
170 | 170 | | |
171 | 171 | | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
172 | 189 | | |
173 | 190 | | |
174 | 191 | | |
| |||
285 | 302 | | |
286 | 303 | | |
287 | 304 | | |
288 | | - | |
| 305 | + | |
289 | 306 | | |
290 | 307 | | |
291 | 308 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
41 | | - | |
| 41 | + | |
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| |||
156 | 156 | | |
157 | 157 | | |
158 | 158 | | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
159 | 173 | | |
160 | 174 | | |
161 | 175 | | |
| |||
247 | 261 | | |
248 | 262 | | |
249 | 263 | | |
250 | | - | |
| 264 | + | |
251 | 265 | | |
252 | 266 | | |
253 | 267 | | |
| |||
257 | 271 | | |
258 | 272 | | |
259 | 273 | | |
260 | | - | |
| 274 | + | |
261 | 275 | | |
262 | 276 | | |
263 | 277 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
542 | 542 | | |
543 | 543 | | |
544 | 544 | | |
545 | | - | |
| 545 | + | |
546 | 546 | | |
547 | 547 | | |
548 | 548 | | |
| |||
0 commit comments