|
| 1 | +--- |
| 2 | +"@objectstack/spec": minor |
| 3 | +--- |
| 4 | + |
| 5 | +feat(spec): `user:profile` is explicitly not author-placeable — refused by name at the schema door (#14159, ADR-0049) |
| 6 | + |
| 7 | +<!-- adr-0087: not-required (no-migration-prescription) The retired row declared zero keys, so there is no key to strip and no old shape to rewrite into a new one; the only edit an author can make is deleting the `user:profile` node, which the conversion layer deliberately does not do (the `element-filter-removed` docblock rules deleting authored page nodes out of a mechanical conversion — it is a layout decision, not a rewrite); and a whole-repo sweep measured zero authored instances across examples, packages, docs and stored metadata (Studio's palette has excluded the type since objectui 5e8965c). Nothing mechanical to prescribe and nothing to prescribe it to — the #7596 disposition, one surface over. --> |
| 8 | + |
| 9 | +**BREAKING** accept-set narrowing, landing after the v17.0.0 cut (the lockstep |
| 10 | +launch-window convention ships it as `minor`, as the `element:filter` / |
| 11 | +`element:form` element-grain retirements and the `targetVariable` key |
| 12 | +retirement did; the 17.0.0 cut itself carried the `group` / `guest` recipient |
| 13 | +removal and the `$in` / `$nin` / `$between` reference-position removal under |
| 14 | +`major` because that release was the major). |
| 15 | + |
| 16 | +`user:profile` was declared in `PageComponentType` and carried an empty |
| 17 | +`ComponentPropsMap` row, and no renderer for it ever existed anywhere — not in |
| 18 | +objectui, framework or cloud (objectui#7135 measured the zero with a positive |
| 19 | +control in the same query shape; only the opt-in `PlaceholderRenderer` |
| 20 | +scaffold, which `apps/console` alone registers, ever drew it). objectstack#12183 |
| 21 | +closed the same gap for its four siblings with renderers because real pages |
| 22 | +used them; this member had zero measured pull, and the director ruling of |
| 23 | +2026-09-01 (maintainer verbatim 「同意」) chose option B of that ask: a user |
| 24 | +profile is shell chrome — the signed-in user's avatar menu — which no mainstream |
| 25 | +product makes a page-placeable component, so the honest declaration is that it |
| 26 | +cannot be placed, not a renderer nobody asked for. Until now an authored |
| 27 | +`user:profile` node validated clean and drew `SchemaRenderer`'s red |
| 28 | +unknown-type panel in front of an end user in every host except the console |
| 29 | +(the ADR-0078 shape). |
| 30 | + |
| 31 | +**What is refused:** an authored `user:profile` component node — at |
| 32 | +`PageComponentSchema.type` (so `definePage()`, `PageSchema`, and every stack |
| 33 | +door that parses pages: `os validate`, `os build`, `os lint`, the metadata |
| 34 | +door), with a located issue (`code: 'custom'`, `params.retiredComponentType`, |
| 35 | +the node's own path) whose message is the retirement prescription. The name is |
| 36 | +also refused by `PageComponentType`'s own error map when the enum is parsed |
| 37 | +alone, and `ComponentPropsMap['user:profile']` refuses every props bag — |
| 38 | +`{}` included — with the same prescription for the readers that dispatch on |
| 39 | +the row (the #5068 props gate, `check-yaml-examples`, the type vocabulary's |
| 40 | +known set). One prescription string (`RETIRED_PAGE_COMPONENT_TYPES`, |
| 41 | +`@objectstack/spec/ui`), three doors. |
| 42 | + |
| 43 | +**What stays accepted:** every other member of `PageComponentType` and |
| 44 | +`ComponentPropsMap`, byte-identically — `global:search` and |
| 45 | +`global:notifications` (the two shipped shell singletons), `app:launcher`, |
| 46 | +`nav:menu`, `nav:breadcrumb`, and the whole open string arm: custom and |
| 47 | +plugin-registered types keep parsing, stored documents keep loading. `user:` |
| 48 | +is no longer a namespace the enum populates, so the `component-type-unknown` |
| 49 | +authoring rule no longer claims it; the only string refused is the retired |
| 50 | +name itself. |
| 51 | + |
| 52 | +**Fix:** delete the `user:profile` component node. There is nothing to write in |
| 53 | +its place — the app shell renders the profile menu on every page without an |
| 54 | +authored element. A future application that needs a page-placeable profile |
| 55 | +component files a feature card with its consumer; the refusal then flips |
| 56 | +additively (option A of the same ask). objectui's `PALETTE_EXCLUSIONS` entry is |
| 57 | +unchanged (correct either way — the ruling's point 3). |
| 58 | + |
| 59 | +The retirement kit: |
| 60 | + |
| 61 | +- the retired-type map + enum error map + node-level check |
| 62 | + (`packages/spec/src/ui/page.zod.ts`), the refusing row |
| 63 | + (`packages/spec/src/ui/component.zod.ts`) |
| 64 | +- pin tests (`component.test.ts` — `code` + `path` + first sentence at each of |
| 65 | + the three doors, positive controls, preservation of the other shell |
| 66 | + singletons, the open arm; `component-type-vocabulary.test.ts` — `user:` |
| 67 | + leaves the reserved-namespace derivation) |
| 68 | +- generated baselines/docs follow the schema (`authorable-surface/`, |
| 69 | + `json-schema.manifest/`, `api-surface/`, reference docs); the hand-written |
| 70 | + `content/docs/ui/pages.mdx` component list says the truth |
| 71 | +- no ADR-0087 conversion, by the disposition above: the row had no keys to |
| 72 | + strip, and a mechanical conversion does not delete authored page nodes. |
0 commit comments