@object-ui/layout 17.5.0 → 17.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,1951 @@
1
1
  # @object-ui/layout
2
2
 
3
+ ## 17.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d6a1a80: feat(layout): a host can hide a `doc` navigation entry the member may not read (objectui#10188)
8
+
9
+ `NavigationRenderer`, `AppSchemaRenderer` and `hasVisibleNavigationItems` take an optional
10
+ `checkDocTarget` — a `DocTargetChecker`, asked `{ book, doc }` for each `type: 'doc'` entry.
11
+ An entry it answers `false` for is not drawn, is not collected into Favorites, and does not
12
+ make its area count as visible: it joins the one guard statement the other item guards
13
+ already share. Without it, `doc` entries draw as before.
14
+
15
+ It is defence in depth. The server is the enforcer (ADR-0046 §6.7): its app read already
16
+ leaves out a `doc` entry the member may not read. This layer holds no audience rules, so the
17
+ host answers from the member's own doc / book reads. `DocNavTarget` and `DocTargetChecker` are
18
+ exported. `CapabilityChecker` is unchanged: it asks whether the runtime has a target, and this
19
+ checker asks whether the member may read it.
20
+ - ad1785c: refactor(layout)!: retire the `page-header` node type key; the header node is `page:header` (objectui#10859, batch 8 phase 2c)
21
+
22
+ **BREAKING (authoring):** `registerLayout()` no longer registers `PageHeader` under `page-header` (and with it `layout:page-header`). `objectui validate` already refused a `page-header` node at `type`, and nothing in this repository authored or emitted it. objectstack's `page-header-subtitle-alias` conversion renames the key `description` → `subtitle` on both header spellings and leaves the type to objectui. A `page-header` node now renders the "Unknown component type" panel. `PageHeader` stays a named export for JSX composition.
23
+
24
+ Migration, measured against `objectui validate` (`page:header` carries its props in `properties`):
25
+
26
+ - `{ "type": "page-header", "title": T, "subtitle": S }` → `{ "type": "page:header", "properties": { "title": T, "subtitle": S } }`;
27
+ - `actions` (action ids) → `properties.actions`, the same id array;
28
+ - `icon` has no `page:header` spelling: the contract refuses `properties.icon` by name (an ADR-0087 D2 tombstone). Drop it, or compose `PageHeader` in JSX, which still takes `icon`;
29
+ - `children` (the right-hand slot) has no `page:header` spelling: the contract refuses a node-level `children` by name, and `properties.children` as an unrecognized key. Put the buttons in `properties.actions` as action ids, or compose `PageHeader` in JSX, which still renders its `children`.
30
+
31
+ `registerLayout()` now registers four keys: `layout:page:card`, `responsive-grid`, `navigation-renderer` and `app-schema-renderer`.
32
+
33
+ **Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner.
34
+
35
+ ⚠️ **Dated note, 2026-10-02 — `responsive-grid` and `navigation-renderer` are retired too — objectui#11441.**
36
+ Later in this same release objectui#11441 (the maintainer's ruling, letters B / B) unregistered both, with their
37
+ `layout:` twins, so `registerLayout()` registers two keys: `layout:page:card` and `app-schema-renderer`. The rest of
38
+ this entry is kept as the reading of this change.
39
+ - e6bc087: feat: a `doc` navigation entry (ADR-0046) validates and draws as a link into the docs portal
40
+
41
+ `@objectstack/spec` 17.5.0 added a tenth navigation item type, `doc` — `{ type: 'doc', book }`
42
+ opens a book, `{ type: 'doc', doc }` opens one page, both opens that page in that book's
43
+ context. `objectui validate` refused it: `NavigationItemTypeSchema` was a hand-written list of
44
+ the nine older types, while the TypeScript `NavigationItemType`, derived from the spec, already
45
+ carried `doc`. And no renderer drew one — `resolveHref` had no `doc` branch, so the entry
46
+ rendered as a dead `#` link.
47
+
48
+ - **`@object-ui/types`** — `NavigationItemTypeSchema` is now read off the discriminator of the
49
+ spec's navigation union instead of hand-listed, so it gains `doc`. A `doc` entry is judged by
50
+ the spec's own `DocNavItemSchema`: it accepts exactly what the spec accepts — at least one of
51
+ `book` / `doc`, a doc NAME (a filename or a path is refused), a snake_case `id`, and the closed
52
+ key set of the spec's `doc` arm — and refuses an empty `label` as every sibling type does. The
53
+ parsed entry is never rewritten. `NavigationEntryItem` gains the spec-derived `book` and `doc`
54
+ members. An unknown `type` is now refused with `invalid_union` at `type` (was `invalid_value`),
55
+ the code the spec's own union answers with.
56
+ - **`@object-ui/layout`** — `resolveHref` sends a `doc` entry to the console docs portal under
57
+ its `basePath`: `/docs/DOC`, `/docs/BOOK` or `/docs/BOOK/DOC`. An unlabelled `doc`
58
+ entry shows the page it opens, else the book. It is gated by the same base keys as its
59
+ siblings (`visible`, `requiredPermissions`, `requiresObject`, `requiresService`); the book
60
+ audience gate stays the server's. The mobile tab bar links it the same way.
61
+ - **`@object-ui/app-shell`** — the app designer's preview keys its navigation kinds by
62
+ `NavigationItemType`, so a `doc` entry is drawn with its target and route instead of being
63
+ dropped (label-less) or badged `untyped`.
64
+ - **`@object-ui/plugin-designer`** — `NAV_TYPE_META` drops the `| 'doc'` key that bridged the
65
+ spec pin lag; it is keyed by `NavigationItemType` alone.
66
+ - **`@object-ui/console`** — the docs portal resolves a path segment that is a book's NAME
67
+ rather than its `slug` — what a `{ type: 'doc', book }` entry links to — and redirects to
68
+ the book's canonical slug URL: `/docs/NAME` opens the book, `/docs/NAME/DOC` reads that page
69
+ with the book's sidebar. It is looked up after a book's slug and an installed doc's name, so
70
+ every URL that resolved before answers as it did; only former "Documentation not found"
71
+ answers change.
72
+ - 770cc5b: feat(layout): a navigation label written as an inline locale map renders in the viewer's locale; three inert resolver props retire (objectui#11299)
73
+
74
+ **Breaking for a consumer that passes the retired props or calls `resolveNavItemLabel` with six arguments** — a compile error, never a silent change of what renders.
75
+
76
+ - **New: `NavigationRenderer`'s optional `locale` prop**, and a trailing `locale`
77
+ argument on `resolveNavItemLabel`. A present entry label written as an inline locale
78
+ map (`{ en: 'Accounts', 'zh-CN': '客户' }`) renders the entry for that locale, through
79
+ the spec's own `resolveI18nLabel`; when the map has no entry for it, that resolver's
80
+ fallback order applies. objectui#11201 rendered such a map's `en` entry for every
81
+ viewer; pass the viewer's language as `locale` to show theirs. Without `locale` the
82
+ map still reads its `en` entry. A plain-string label and an absent label are
83
+ unaffected.
84
+ - **Retired: `NavigationRenderer`'s `resolveObjectLabel`, `resolveDashboardLabel` and
85
+ `resolveViewLabel` props.** objectui#11201 stopped reading them and kept them as
86
+ no-ops; they are removed now. Delete them from your `NavigationRenderer` call. An
87
+ unlabelled entry's localized text comes from `resolveTargetLabel`, as before.
88
+ - **Changed signature: `resolveNavItemLabel(item, t?, targetLabel?, locale?)`.** The
89
+ 2nd, 4th and 5th arguments (the same three resolvers) are gone. A call written
90
+ `resolveNavItemLabel(item, undefined, t, undefined, undefined, targetLabel)` becomes
91
+ `resolveNavItemLabel(item, t, targetLabel, locale)`.
92
+
93
+ Marked `minor`, not `major`: this repository's fixed release group follows the
94
+ `@objectstack` major, so a breaking change of its own is declared `minor` with the
95
+ break spelled out here.
96
+ - 9d1c0bf: refactor(layout)!: retire the `navigation-renderer` and `responsive-grid` node type keys; navigation is application metadata, and the breakpoint grid is `grid` (objectui#11441)
97
+
98
+ **BREAKING (authoring):** `registerLayout()` no longer registers `NavigationRenderer` under `navigation-renderer` or `ResponsiveGrid` under `responsive-grid` (and with them `layout:navigation-renderer` and `layout:responsive-grid`). This executes the maintainer's ruling on objectui#11441 (letters B / B) as one more batch of objectui#10859. `objectui validate` already refused both keys at `type`, and nothing in this repository or in objectstack authored or emitted either node. A node of either type now renders the "Unknown component type" panel. `registerLayout()` now registers two keys: `layout:page:card` and `app-schema-renderer`.
99
+
100
+ `NavigationRenderer` and `ResponsiveGrid` stay named exports for JSX composition. `NavigationRenderer` is what the console's sidebar and `AppSchemaRenderer` mount. `ResponsiveGrid` had no in-repo consumer other than the retired registration, and it stays because the same ruling keeps objectui#7580's vocabulary half: `BreakpointColumnMap` stays declared in this package as the type of its `columns` prop.
101
+
102
+ Migration, measured against `objectui validate` on both of its faces:
103
+
104
+ - `{ "type": "responsive-grid", "columns": C, "gap": G }` → `{ "type": "grid", "columns": C, "gap": G }`. `grid` accepts the same breakpoint `columns` object (`xs` … `2xl`) and a `gap` number, and refuses an unknown breakpoint key as an unrecognized key (`unrecognized_keys` on `columns`). Unlike `responsive-grid`, which drew `not-a-container` and rendered no authored child list, `grid` draws its `children`;
105
+ - `{ "type": "navigation-renderer", "items": I }` has no page-node replacement: navigation is application metadata. Put `I` in the app document's `navigation` (`{ "type": "app", "name": N, "navigation": I }` validates on both faces), and the shell draws it: the console's sidebar, or `AppSchemaRenderer` in JSX;
106
+ - `basePath` has no app-document spelling: the strict face refuses it as an unrecognized key. It belongs to the shell, as `AppSchemaRenderer`'s `basePath` prop.
107
+
108
+ **Clause-②: yes** — two registrations leave the runtime (narrowing), released as `minor` with this banner.
109
+
110
+ ⚠️ **Dated note, 2026-10-02 — `grid` takes one of ten `gap` steps, not any number — objectui#11474.** At this change `grid` accepted any `gap` number; now it accepts one of 0, 1, 2, 3, 4, 5, 6, 8, 10 and 12, the steps the `grid` renderer maps, and `objectui validate` refuses any other `G` at `gap` on both faces with that set named: 7, 9, 11, a number above 12, a negative number or a fraction. For such a number `grid` drew no gap anyway, because the class it built at runtime is in no compiled stylesheet. So in the migration above `G` must be one of those ten steps; each step `ResponsiveGrid`'s own class map drew (0 to 6 and 8) is one of them. `.changeset/11474-layout-spacing-sets.md` states what ships. The rest of this entry is kept as the reading of this change.
111
+
112
+ ⚠️ **Dated note, 2026-10-02 — `grid` takes column counts 1 to 12, not any number — objectui#11491.** At this change `grid` accepted any count in the breakpoint `columns` object; now each count is one of 1 to 12, the counts the `grid` renderer maps, and `objectui validate` refuses any other count in `C` at `columns` on both faces with that set named. For such a count `grid` drew no column class at that breakpoint anyway. So in the migration above every count in `C` must be one of 1 to 12; each count `ResponsiveGrid`'s own class map drew (1, 2, 3, 4, 6 and 12) is one of them. `.changeset/11491-grid-columns-set.md` states what ships. The rest of this entry is kept as the reading of this change.
113
+ - fcdc8ec: An `app-schema-renderer` node draws the app document it carries under `schema` (objectui#11494, triage ruling A).
114
+
115
+ **Breaking for a node that writes the app document's keys flat on itself** (shipped as `minor`, per this repository's version policy). `SchemaRenderer` hands every registered component the node itself as its `schema` prop, and `registerLayout()` registered `AppSchemaRenderer` directly, so the component took the node for its app document: a document nested under the node's `schema` key drew an empty shell, and only app keys written flat on the node (`navigation`, `title`, …), which no schema declares, drew. `registerLayout()` now registers the key against an adapter that hands `node.schema` to `AppSchemaRenderer`:
116
+
117
+ - `{ "type": "app-schema-renderer", "schema": { "type": "app", "name": "crm", "navigation": [ … ] } }` draws the document's branding and navigation.
118
+ - The same keys written flat on the node are no longer read. Move them under `schema`, with `"type": "app"`. No producer in objectui or objectstack authors them flat.
119
+ - A node without `schema` draws the shell with no branding and no navigation, as it did before.
120
+
121
+ Unchanged: `basePath` and `mobileNavMode` are read off the node, the registration's three declared `inputs`, and `AppSchemaRenderer` itself, whose JSX hosts pass `schema={appDocument}` directly. A node's `children` are still not rendered.
122
+ - 969ba84: Renderers for the `app:launcher` and `nav:menu` page blocks.
123
+ Phase 1 of the 2026-08-26 maintainer ruling on objectstack#12183 — the two
124
+ `PageComponentType` members that are purely metadata-driven, so nothing had to
125
+ ship before their renderers could. Phase 2 (`global:search` /
126
+ `global:notifications`) landed in `f99932a42` and set the pattern this
127
+ follows.
128
+
129
+ A page that declared either member drew a dashed box. The two symptoms were not
130
+ the same, which is worth recording because it decides what "fixed" looks like
131
+ for each:
132
+
133
+ - `nav:menu` is in `PALETTE_PLACEHOLDER_BLOCKS`, registered eagerly, so it drew
134
+ the literal "Component Placeholder" scaffold in every host.
135
+ - `app:launcher` is only in `PROTOCOL_COMPONENTS`, registered when a host opts
136
+ in via `registerPlaceholders()` — which just `apps/console` does. So it drew
137
+ the scaffold in the console and `SchemaRenderer`'s red OBJUI-001 "Unknown
138
+ component type" panel everywhere else.
139
+
140
+ Neither block adds a data layer — each mounts plumbing that was already live,
141
+ and neither issues a request or touches an adapter:
142
+
143
+ - `app:launcher` reads the metadata app registry (`useMetadata().apps`, which
144
+ `MetadataProvider` fetches eagerly) through the shared `filterActiveApps`
145
+ predicate, and draws it with `HomeAppsStrip` — the console's own launcher
146
+ grid — so an authored launcher and the Home launcher cannot drift into two
147
+ looks for one thing.
148
+ - `nav:menu` reads the active app's navigation tree from that same registry and
149
+ renders it as page content, taking every derived fact from `@object-ui/layout`:
150
+ hrefs from `resolveHref`, labels from `resolveNavItemLabel`, the active row
151
+ from `resolveActiveNavItem`, and the item-level guards (`visible`,
152
+ `requiredPermissions`, `requiresObject` / `requiresService`) in the order
153
+ `NavigationItemRenderer` applies them, wired to the same console providers
154
+ `UnifiedSidebar` wires them to. `action` items dispatch through
155
+ `useNavActionDispatch`, so framework#4509's "renders but dead-clicks" shape is
156
+ not reintroduced.
157
+
158
+ `nav:menu` does not mount `NavigationRenderer` itself: that renders through
159
+ `SidebarMenuButton`, whose `useSidebar()` throws outside the shell's
160
+ `SidebarProvider`, and a page block has to render standalone. `@object-ui/layout`
161
+ therefore exports `resolveNavItemLabel`, which was module-private — an additive
162
+ export with no behaviour change, so the sidebar and an authored menu cannot show
163
+ one nav entry under two names.
164
+
165
+ Both registrations publish **no** `inputs`: `ComponentPropsMap` declares an empty
166
+ shape for each, and both use `skipFallback: true` so neither claims the bare
167
+ `launcher` / `menu` keys. This does not change the Studio page palette —
168
+ `app:launcher` remains recorded there as a shell singleton, which is a palette
169
+ decision independent of whether a declared type renders.
170
+
171
+ Three new strings — the launcher's and the menu's accessible names, and the
172
+ menu's empty state — are declared under `console.nav` in `en.ts` and its nine
173
+ sibling packs. An inline `defaultValue` alone is not a fix: it renders English
174
+ at one call site and leaves the string untranslatable everywhere
175
+ (objectui#3517).
176
+ - e62c44e: Re-home the breakpoint layout vocabulary and delete the two dead responsive
177
+ implementations (objectui#7580, maintainer ruling 2026-09-04, option A).
178
+
179
+ **Breaking, deliberately, in one direction only.** `@objectstack/spec` retired its whole
180
+ `ui/responsive` vocabulary in objectstack#11027 — `ResponsiveConfigSchema`,
181
+ `BreakpointName`, `BreakpointColumnMapSchema` and `BreakpointOrderMapSchema` — on the
182
+ stated ground that the four types "had no other authorable carrier". That ground is
183
+ measurably false on the renderer side: `responsive-grid` is a REGISTERED SDUI component
184
+ whose authorable `columns` input is typed by `BreakpointColumnMap` and applied by
185
+ `resolveColumnClasses` on the render path, and `BreakpointName` types four live readers in
186
+ `@object-ui/mobile`. The tombstone's own return condition — the vocabulary "returns if and
187
+ when a renderer implements it" — is already met here, so the two types a renderer reads
188
+ are re-homed rather than retired.
189
+
190
+ What survives, under the same names and the same members:
191
+
192
+ - `BreakpointName` (`xs`…`2xl`) is now declared in `@object-ui/types` (`mobile.ts`) instead
193
+ of re-exported from the spec. **No consumer change**: same name, same six members, same
194
+ export sites on `@object-ui/types` and `@object-ui/mobile`. Only its provenance moved.
195
+ - `BreakpointColumnMap` is now declared in `@object-ui/layout` (`ResponsiveGrid.tsx`),
196
+ verbatim from the retired `$strict` schema: six optional column counts, no index
197
+ signature. `responsive-grid`'s `columns` input and its resolver are unchanged.
198
+
199
+ What is removed:
200
+
201
+ - `BreakpointOrderMap` (`@object-ui/layout`) — retired with the key, not re-homed. It had
202
+ no read point in the package; it was published only because the retired
203
+ `ResponsiveConfigSchema` paired it with the column map, so an author configuring `order`
204
+ needed the type. With the schema gone there is no order vocabulary for it to be the type
205
+ of, and re-declaring it would be the declare-without-enforce shape ADR-0049 removes.
206
+ - `useResponsiveConfig` (`@object-ui/mobile`), with its `SpecResponsiveConfig` and
207
+ `ResolvedResponsiveState` exports, and `ResponsiveProtocol` (`@object-ui/core`), with
208
+ `resolveResponsiveConfig` / `getVisibilityClasses` / `getColumnClasses` /
209
+ `getOrderClasses` / `shouldHideAtBreakpoint`. Both read the retired
210
+ `ResponsiveConfigSchema` and both were measured at zero callers (objectui#4773).
211
+ - `SpecResponsiveConfig` / `SpecBreakpointName` (`@object-ui/types`) — dead re-exports once
212
+ the two implementations above went, dropped rather than re-declared locally, the same
213
+ disposition the retired i18n names in that file already carry.
214
+
215
+ No behaviour is retired. The live per-breakpoint readers — `useBreakpoint`,
216
+ `ResponsiveContainer`, `BREAKPOINTS` / `BREAKPOINT_ORDER` / `getCurrentBreakpoint`, and
217
+ `responsive-grid` itself — are untouched.
218
+
219
+ **Sequencing.** objectui's next `@objectstack/spec` pin bump must carry `Blocked-by:`
220
+ objectui#7580: the retirement is merged upstream and unreleased, so this must land first.
221
+
222
+ ⚠️ **Dated note, 2026-10-02 — the `responsive-grid` registration is retired — objectui#11441.**
223
+ Later in this same release the maintainer's ruling on objectui#11441 (letter B) unregistered `responsive-grid` (and
224
+ `layout:responsive-grid`). That ruling updates item 2 of this change's ruling: the vocabulary half stands, so
225
+ `BreakpointName` and `BreakpointColumnMap` stay declared here, and `ResponsiveGrid` stays a React export whose
226
+ `columns` prop `BreakpointColumnMap` types. The authorable breakpoint grid is the `grid` node with a breakpoint
227
+ `columns` object, which `BreakpointName` keys. The rest of this entry is kept as the reading of this change.
228
+ - 0ea7054: Remove 37 runtime dependencies that no file in the declaring package consumes, and gate
229
+ the direction so the next one cannot land (objectui#8198).
230
+
231
+ `check:phantom-deps` judges imports that are not declared; nothing judged the reverse,
232
+ so a declaration could outlive its last consumer indefinitely. That is what happened to
233
+ `recharts` in `@object-ui/components` after objectui#7397 deleted its only importer — it
234
+ was removed by hand on objectui#7625, and nothing would have reported the next one. The
235
+ new `pnpm check:unused-deps` asks the reverse question over `dependencies` and
236
+ `optionalDependencies` of every released package.
237
+
238
+ **Potentially breaking, for consumers relying on hoisting.** Nothing these packages ship
239
+ changes: their Vite `external` predicates are path-based and never read `dependencies`,
240
+ so no built artifact moves. What changes is the install graph — a project that imports
241
+ one of the removed packages while depending only on the ObjectUI package that used to
242
+ drag it in will no longer resolve it. Declare it directly; that is the correct
243
+ dependency edge in either case. The removals, by package:
244
+
245
+ - `@object-ui/plugin-designer`: `@dnd-kit/core`, `@dnd-kit/sortable`, `@dnd-kit/utilities`, `@object-ui/fields`
246
+ - `@object-ui/plugin-chatbot`: `react-markdown`, `react-syntax-highlighter`, `remark-gfm` (and the orphaned `@types/react-syntax-highlighter`)
247
+ - `@object-ui/plugin-report`: `@object-ui/plugin-grid`, `clsx`, `react-i18next`, `tailwind-merge`
248
+ - `@object-ui/plugin-map`: `@objectstack/spec`, `lucide-react`, `zod`
249
+ - `@object-ui/runner`: `class-variance-authority`, `clsx`, `tailwind-merge`
250
+ - `@object-ui/core`: `lodash`, `zod`
251
+ - `@object-ui/layout`: `clsx`, `tailwind-merge`, and `react-dom` — which it pinned at an exact version in `dependencies` while also declaring it as a peer range, i.e. a library hard-depending on the renderer it asks its host to supply
252
+ - `@object-ui/plugin-dashboard`: `clsx`, `tailwind-merge`, and the same `react-dom` defect
253
+ - `@object-ui/plugin-ai`: `@object-ui/react`, `clsx`, `tailwind-merge`
254
+ - `@object-ui/fields`: `clsx`, `tailwind-merge`
255
+ - `@object-ui/console`: `@object-ui/react-runtime`, `sucrase`
256
+ - `@object-ui/auth`: `@object-ui/types`
257
+ - `@object-ui/plugin-calendar`: `@object-ui/fields`
258
+ - `@object-ui/plugin-editor`, `@object-ui/plugin-markdown`: `@object-ui/react`
259
+ - `@object-ui/react`: `react-hook-form`
260
+
261
+ Every one was verified by a whole-package grep before removal — the name appeared nowhere
262
+ under the package but its own manifest and CHANGELOG — and the whole workspace builds,
263
+ type-checks and tests green afterwards.
264
+ - a8198de: feat(types,layout,app-shell): a navigation entry with no `label` shows its target's current label, resolved at render time (objectui#9868)
265
+
266
+ `@objectstack/spec` 17.5.0 made a navigation entry's `label` optional on every
267
+ entry arm of its `NavigationItemSchema` (the separator still carries none), with
268
+ a declared semantic (the cloud#2021 letter-A ruling): absent ⇒ the entry
269
+ shows the CURRENT label of what it opens — the view's label when it names a
270
+ labelled view, else the object's / dashboard's label; present ⇒ rendered
271
+ verbatim. Nothing is stored for the absent case, so a renamed target shows its
272
+ new name on the next render.
273
+
274
+ - `@object-ui/types` (widening): `NavigationEntryItem.label` is optional, and
275
+ `NavigationItemSchema` accepts a label-less entry of every type the spec does,
276
+ filling nothing in at parse time. `id` is still required. An EMPTY label is
277
+ still refused — `''` is a present label that would render empty text — and the
278
+ message says to omit the key instead. `menuItemToNavigationItem` no longer
279
+ turns a missing legacy label into `''`.
280
+ - `@object-ui/layout` (additive public surface): `resolveNavItemLabel`
281
+ resolves an absent label through a new `resolveTargetLabel` resolver
282
+ (`NavigationRenderer` prop, types
283
+ `NavLabelTarget` / `NavTargetLabelResolver`), walking view → object /
284
+ dashboard, and falls back to the target's machine name (`viewName`,
285
+ `objectName`, `dashboardName`, `pageName`, `reportName`, `url`,
286
+ `componentRef`, the action name; a group shows its `id`). An authored label is
287
+ never replaced by the target's label, including one spelled like the machine
288
+ name. Action entries, the search filter and `AppSchemaRenderer`'s mobile tab
289
+ bar read the label through the same function, so an unlabelled entry no longer
290
+ throws there.
291
+ - `@object-ui/app-shell`: the sidebar, the `nav:menu` block, the ⌘K command
292
+ palette and the full-page search all name a nav entry through
293
+ `resolveNavItemLabel` with one hook over the metadata cache the shell already
294
+ holds (object schema, merged list views, dashboards) — no request per nav
295
+ entry. Read raw, a label-less entry drew a blank palette row searched as
296
+ `undefined`, and the search page listed it by its machine name.
297
+ Navigation sync stops writing `label: pageName` / `label: dashboardName` for an
298
+ unnamed page or dashboard; an author label is still written, and stored labels
299
+ are kept.
300
+ - 5ea623e: fix(sdui-parser,components,layout,types): containment is the declared `children` slot, not `isContainer` (objectui#9910)
301
+
302
+ `validateTree`'s `not-a-container` diagnostic now reads exactly one declaration:
303
+ an input named `children` in the component's registration `inputs`. Ten
304
+ registrations already carried such an input — `slot`-typed on `tooltip` and the
305
+ four `page:*` containers, `array`-typed on the five page kinds — and the
306
+ predicate reads the NAME, so both count. `isContainer` is no longer
307
+ consulted and is not a fallback — new exports `acceptsChildren` and
308
+ `CHILD_LIST_KEY` in `@object-ui/sdui-parser` spell the predicate, and the
309
+ retired `body` dialect follows the same reading.
310
+
311
+ Why: the flag was hand-kept and drifted from the renderers four times; after
312
+ objectui#6771 converged a dozen `schema.body` readers onto `children`, and with
313
+ objectui#6804 ruling the flag OFF for that population (it means layout
314
+ containment, and declaring it deletes a public tag from every react page's JSX
315
+ scope), the diagnostic landed FALSE on the one key `button`, `badge`, `alert`
316
+ and the `sidebar-*` parts render. The maintainer ruled declare-and-pin
317
+ (2026-09-24).
318
+
319
+ What is declared: every renderer under `@object-ui/components` and
320
+ `@object-ui/layout` that puts `schema.children` on the page — 65 registrations
321
+ measured bare plus `sidebar` and `sidebar-menu-button` in their provider
322
+ context — now declares the `children` slot; the 34 flow/inline HTML tags, the
323
+ seven sectioning tags, the layout primitives, `button` / `badge` / `alert` /
324
+ `toggle` (label and description fallbacks), `span` (read ahead of `value`),
325
+ `div`, `form`, `scroll-area`, the ten `sidebar-*` parts and `page-header`. Nine public blocks
326
+ gain the slot in `sdui.manifest.json`; a `slot` input emits no JSX attribute, so
327
+ the generated `.d.ts` is unchanged. `isContainer` is kept everywhere it was
328
+ declared and re-described on every published face (`ComponentMeta`,
329
+ `RuntimeWidgetManifest`, `ComponentMetaSchema`, the manifest types) as LAYOUT
330
+ containment — the react-page scope builder keeps reading it unchanged.
331
+
332
+ The runtime containment census is re-pointed from the flag to the input in both
333
+ directions (declared ⇔ actually renders, with named context probes for the
334
+ provider-scoped and portal renderers), `scripts/container-declaration-baseline.json`
335
+ is at zero, and a registration that is a layout container but renders no
336
+ authored list (`page:tabs`, `page:accordion`, `responsive-grid`) now draws the
337
+ TRUE `not-a-container` the flag used to silence.
338
+
339
+ ⚠️ **Dated note, 2026-10-02 — `page-header` is retired — objectui#10859.**
340
+ Later in this same release objectui#10859 batch 8 (phase 2c) unregistered `@object-ui/layout`'s
341
+ `page-header` (and `layout:page-header`), so its `children` slot declaration left with it; authors write
342
+ `page:header`. The rest of this entry is kept as the reading of this change.
343
+
344
+ ⚠️ **Dated note, 2026-10-02 — `responsive-grid` is retired — objectui#11441.**
345
+ Later in this same release objectui#11441 unregistered `@object-ui/layout`'s `responsive-grid` (and
346
+ `layout:responsive-grid`), so it no longer draws `not-a-container`: a node written with it renders the "Unknown
347
+ component type" panel. Authors write `grid` with a breakpoint `columns` object. The rest of this entry is kept as the
348
+ reading of this change.
349
+
350
+ ⚠️ **Dated note, 2026-10-02 — the ten `sidebar-*` parts are retired — objectui#10859.**
351
+ Later in this same release objectui#10859 batch 8 (phase 2d) unregistered the ten `sidebar-*` parts, so their
352
+ `children` slot declarations left with them. `sidebar` keeps its declaration, and it now mounts its own provider
353
+ when none is above it, so the containment census measures it bare and its provider-scoped context probe is
354
+ gone, as is `sidebar-menu-button`'s. The rest of this entry is kept as the reading of this change.
355
+ - 73a3c89: Nav `visible`: an ancestor's predicate now reaches the whole subtree, and a group no longer outlives its children
356
+
357
+ The card reported that an app navigation item's `visible` CEL predicate was served to the
358
+ browser and then ignored, so the entry rendered for every user. That headline no longer
359
+ reproduces: measured on today's `main`, a leaf and a group whose predicate is `false` for the
360
+ session are both absent, and the same predicate evaluating `true` renders both — one run,
361
+ two sessions, asserted as a difference rather than as an absence. `evaluateVisibility`
362
+ routes the served `{ dialect, source }` envelope to the CEL engine, and `NavigationRenderer`
363
+ applies it per item.
364
+
365
+ Two paths into the same subtree did NOT apply it, and both are fixed here.
366
+
367
+ - **A pinned descendant escaped its hidden ancestor.** The Favorites section collects pinned
368
+ items by walking `children`, and that walk asked nothing about the node it was descending
369
+ through. So an author could gate a group with `visible`, watch the group disappear from the
370
+ tree, and still find a pinned entry from inside it rendered under Favorites — the predicate
371
+ evaluated, answered `false`, and changed nothing the excluded user could see. `visible`,
372
+ `requiredPermissions` and the `requiresObject` / `requiresService` capability gates all
373
+ leaked the same way, because the collection applied none of them. It now stops at a
374
+ gated-away node. A Favorites section whose every entry is gated away is no longer rendered
375
+ as a heading over an empty list.
376
+
377
+ - **A group whose children were all hidden rendered as an empty disclosure.** A labelled
378
+ collapsible that opens onto nothing is a dead affordance, and it contradicted
379
+ `hasVisibleNavigationItems` — the predicate the area switcher elects areas by, which already
380
+ scores such a group as contributing nothing and documents that it "can never disagree with
381
+ the rendered navigation". The renderer now asks that same predicate, so the sidebar and the
382
+ area list agree about what a user can reach. A group authored with no children at all
383
+ derives the same way, as it already did for area election.
384
+
385
+ The per-item guard sequence was written out twice and omitted once; it is now a single
386
+ `passesNavItemGuards` statement that `NavigationItemRenderer`, `hasVisibleNavigationItems`
387
+ and the Favorites collection share, so the three cannot drift again.
388
+
389
+ **Presentation, not authorization.** Hiding a nav entry is a UI affordance; the server still
390
+ enforces object and record permissions on every route an entry would have led to, and no
391
+ server-side check is touched. A user who types the URL directly gets the same answer as
392
+ before.
393
+
394
+ **Failure direction: fail-open, unchanged and now pinned.** A predicate that cannot be
395
+ evaluated still renders the entry, which is this tier's shipped policy. Hiding on error would
396
+ silently delete a user's navigation with no way to notice; showing on error leaves an entry
397
+ the server still refuses, and the unresolvable-predicate diagnostic still names the source.
398
+
399
+ ### Patch Changes
400
+
401
+ - cd7b728: `useAppShellBranding` now puts the previous favicon back when the shell unmounts
402
+ (objectui#10040), the same way it already puts the previous tab title back
403
+ (objectui#8637).
404
+
405
+ The hook's effect makes two branded writes to the document: `document.title` and the
406
+ `href` of the page's icon link. The title write was scoped to the mount; the favicon
407
+ write was not, so a branded `favicon` stayed on the icon link after the shell went
408
+ away unless something else happened to re-apply an icon. In the console that something was
409
+ `FaviconSync`, which wrote the icon only when an operator favicon was configured (until
410
+ objectui#10379 removed that write) — so on a deployment without one, the icon link kept
411
+ a branded app's URL after the user left the app.
412
+
413
+ When `branding.favicon` is set and the page has an icon link (`#favicon`, otherwise
414
+ `link[rel="icon"]`), the hook now records that link and its `href` attribute before
415
+ writing the branded URL, and restores the recorded attribute in the same cleanup that
416
+ restores the title — so switching from one branded app to another and then leaving
417
+ puts back the icon from before the first one. The attribute is captured rather than
418
+ the `href` property, because the property resolves an empty `href=""` (the console's
419
+ icon link before an operator favicon exists) to the page's own URL; an icon link that
420
+ had no `href` attribute is left without one. A shell with no `favicon`, or a page with
421
+ no icon link, is untouched in both directions, and the hook still never creates an
422
+ icon link.
423
+
424
+ As with the title, the restore replays the captured value unconditionally: an icon
425
+ written by something else while the shell is mounted is overwritten when it unmounts.
426
+ - c58b8e4: `ResponsiveGrid`'s component docblock no longer attributes its column map to the
427
+ spec's retired `BreakpointColumnMapSchema` (objectstack#11027 retired it; objectui#7580
428
+ re-homed the six-key shape as this package's own `BreakpointColumnMap`). The docblock
429
+ now names that local type. Text only: no member is added and no behaviour changes.
430
+ - f976774: An app's `branding.logo` now shows in the console, and it is the only logo spelling
431
+ (objectui#10827).
432
+
433
+ **The console renders it.** The designer (`AppCreationWizard`, `BrandingEditor`) writes an
434
+ app's `branding.logo` and previews it, but nothing mounted in the console drew it. Its only
435
+ reader was `AppSidebar`, which was never mounted and has since been removed. `UnifiedSidebar`,
436
+ the console's sidebar, now reads the active app's `branding.logo` and shows it as an image in a
437
+ header at the top of the sidebar. The image's alt text is the app's label. An app without a
438
+ logo gets no header, so its sidebar looks the same as before. The header appears only inside
439
+ an app. On Home the sidebar's fallback app is not the screen's app, so no logo is shown there.
440
+ `AppShellBranding` is unchanged: objectui#4818 removed its `logo` key, and this change does not
441
+ add it back.
442
+
443
+ **One spelling — breaking for a top-level `logo`.** `@objectstack/spec` declares the app logo
444
+ only as `branding.logo` (a URL). Its app schema refuses a top-level `logo` and suggests
445
+ `branding`. objectui had a second spelling of its own: `AppComponentSchema.logo`, described as
446
+ "Logo URL or icon name". This change retires it:
447
+
448
+ - `@object-ui/types`: `AppComponentSchema.logo` is now `never` on the TypeScript face, and the
449
+ zod mirror refuses a top-level `logo` by name, answering "Did you mean `logo` → `branding`?".
450
+ It is a named refusal rather than a deletion because the node is `.passthrough()`, and a
451
+ deleted key would be kept without any error. `wizardDraftToAppSchema` no longer copies the
452
+ draft's logo to the top level. The logo goes into `branding` only.
453
+ - `@object-ui/layout`: `AppSchemaRenderer`'s default sidebar header draws `branding.logo` as
454
+ an image. This includes site-relative paths and `data:` URIs, which the old read skipped
455
+ because it drew an image only for values starting with `http`. The header's icon now comes
456
+ from the app's `icon`.
457
+ - `@object-ui/runner`: `LayoutRenderer`'s sidebar brand mark does the same. It draws
458
+ `branding.logo` as an image and takes an icon name from `icon`. It no longer guesses the kind
459
+ of value from a `/` or `.`.
460
+
461
+ Migration: move a top-level `logo` URL to `branding: { logo: '…' }`. An icon name that was
462
+ written as `logo` belongs in `icon`. The published 17.6.0 changelog entry that removed
463
+ `AppShellBranding.logo` says the top-level `logo` is "rendered directly by
464
+ `AppSchemaRenderer`'s default sidebar header". That is no longer true: the header reads
465
+ `branding.logo`.
466
+ - 25cb364: The Studio's app wizard saves an app the platform accepts, and the app favicon has one
467
+ spelling, `branding.favicon` (objectui#10842).
468
+
469
+ **Creating an app is no longer refused.** The console's "create app" and "edit app" pages save through
470
+ `client.meta.saveItem('app', …)`, and the platform judges that document with
471
+ `@objectstack/spec`'s strict `AppSchema`. `wizardDraftToAppSchema` wrote four top-level keys the
472
+ spec does not declare (`type`, `title`, `favicon` and `layout`), so the save was refused with
473
+ `422 INVALID_METADATA` (`unrecognized_keys`). It now writes only declared keys: the draft's
474
+ title as `label`, the logo and favicon inside `branding`, and no `type` or `layout`. The spec
475
+ has no app layout, so the wizard's layout choice is not saved.
476
+
477
+ - `@object-ui/types` — **breaking:** `wizardDraftToAppSchema` now returns the app document
478
+ (the spec's `App` shape, with objectui's `NavigationItem[]` as `navigation`) instead of an
479
+ `AppComponentSchema` renderer node. It has no `type`, `title`, top-level `favicon` or `layout`.
480
+ Code that read `result.title` reads `result.label`. Code that fed the result to
481
+ `AppSchemaRenderer` builds the renderer node itself (`type: 'app'`, `title`).
482
+ - `@object-ui/types` — **breaking:** `AppComponentSchema.favicon` is now `never` on the
483
+ TypeScript face, and the zod mirror refuses a top-level `favicon` by name, answering "Did you
484
+ mean `favicon` → `branding`?". This is the objectui#10827 rule that retired the top-level
485
+ `logo`: the spec refuses the key, and the console reads only `branding.favicon`.
486
+ - `@object-ui/layout`: `AppSchemaRenderer` puts `branding.favicon` on the tab. It read the
487
+ top-level `favicon` before, and never `branding.favicon`.
488
+ - `@object-ui/plugin-designer`: `EditAppPage` keeps the keys the wizard does not maintain, but
489
+ only keys the spec's `AppSchema` declares, read from that schema. A row stored before the
490
+ schema closed is served with the old wizard's top-level keys, and echoing them made every
491
+ edit of such an app fail the same way. Its pre-fill no longer falls back onto a top-level
492
+ `logo`, `favicon` or `title`; it reads `branding.logo`, `branding.favicon` and `label`.
493
+
494
+ Migration: move a top-level `favicon` URL to `branding: { favicon: '…' }`.
495
+
496
+ ⚠️ **Dated note, 2026-09-28 — the wizard has no layout choice — objectui#10867.**
497
+ Later in this same release the wizard's Layout control was removed, with `AppWizardDraft.layout`, so there is no
498
+ layout choice left to not save. The rest of this entry still holds.
499
+ - 7343376: fix(types,plugin-designer)!: the Studio app wizard saves a document the platform accepts, and an edit keeps the stored `accentColor` (objectui#10867)
500
+
501
+ ⚠️ **BREAKING (authoring)**, marked `minor` under this repository's version-alignment rule (a `major` in the fixed group would move all of it off the `@objectstack` major). Two published `@object-ui/types` members narrow: a navigation separator no longer takes a `label`, and `AppWizardDraft.layout` is removed. A TypeScript literal that writes either no longer compiles. `NavigationItem` is now a union type alias, not an interface. So code that reads `label` off an unnarrowed `NavigationItem` into a `string` slot (its type is now `string | undefined`; objectui#11299, in the same release, widens it to the spec's `I18nLabel` or `undefined`, see `.changeset/11299-types-nav-label-locale-map.md`) also stops compiling, as does code that spreads an entry-only key onto one, and an `interface` that `extends NavigationItem` or augments it (extend `NavigationEntryItem` instead). `objectui validate` now refuses a separator `label` too: the zod mirror's `NavigationItemSchema` refuses every key on a separator that the spec's separator does not declare. The four `appDesigner` layout keys also leave the published `@object-ui/i18n` packs and `DESIGNER_DEFAULT_TRANSLATIONS`, so an application that calls `t()` with one of them now renders the raw key (unless the call passes a `defaultValue`).
502
+
503
+ **Clause-②: yes (narrowing)** — the separator arm of `NavigationItem` loses `label`, and `AppWizardDraft` loses `layout`.
504
+
505
+ - **A separator carries only `type`, `id` and `order`.** `@objectstack/spec`'s separator branch declares exactly those keys, and its `AppSchema` refuses anything else. `NavigationItem` required a `label` on every item, so the wizard's "Add separator" wrote `{ id, type: 'separator', label: '' }`, and the console's create-app and edit-app saves were refused with `422 INVALID_METADATA` (`unrecognized_keys` `['label']` at `navigation.N`). `NavigationItem` is now a union of two arms, discriminated by `type`. `NavigationEntryItem` holds every other nav type and keeps its required `label`. `NavigationSeparatorItem` admits `type`, `id` and `order`, and every other entry key is `?: never` on it. Both arms are exported. Reading an entry-only key off an unnarrowed item still compiles, but its type now includes `undefined` (a `label` is `string | undefined`; objectui#11299, in the same release, makes it the spec's `I18nLabel` or `undefined`, see `.changeset/11299-types-nav-label-locale-map.md`), so passing it where a `string` is required does not. Narrow on `item.type === 'separator'` before relying on `label`. `menuItemToNavigationItem` maps a legacy separator to `{ id, type: 'separator' }` and drops its label. `spec-derived-unions.test.ts` no longer pins the separator `label` as a blocker. It asserts, at both spec tiers, that the separator arm admits the spec separator's keys and no others.
506
+ - **`@object-ui/plugin-designer`: the wizard and `NavigationDesigner` write a separator as `{ id, type }`.** `NavigationDesigner` no longer writes a `label` onto a new separator, and its label, icon and visibility patchers skip one.
507
+ - **`@object-ui/layout` narrows on the separator arm; nothing it renders changes.** `resolveNavItemLabel` answers `''` for every separator. A stored separator carrying a non-empty `label`, which `menuItemToNavigationItem` produced before this change, used to resolve to that label. No renderer asks it for a separator's label. The mobile bottom nav's leaf list, which already skipped separators, is now typed as entries.
508
+ - **`@object-ui/app-shell` narrows the same way; nothing it renders changes.** `useNavPins` registers a favorite only for an entry and leaves a separator as it is, and the Studio sidebar's navigation walk passes a separator through unchanged.
509
+ - **`@object-ui/plugin-designer`: `EditAppPage` keeps the stored branding.** The wizard maintains the logo, primary colour and favicon, and its `branding` replaced the stored block, so a stored `accentColor` was dropped on every edit. The console reads that key. The save now keeps every stored `branding` key the spec's `AppBrandingSchema` declares, read from that schema. The wizard's values win for the keys it maintains. A stored key the spec does not declare is still left out.
510
+ - **The wizard's Layout control is removed, with `AppWizardDraft.layout`.** The spec declares no app `layout`, no console surface reads one, and since objectui#10842 the save wrote none. The control persisted nothing. `EditAppPage` no longer reads a stored `layout` into the draft. The Basic Info step's description now reads "Name, title, and icon".
511
+ - **`@object-ui/i18n`:** the four `appDesigner` layout keys (`layout`, `layoutSidebar`, `layoutHeader` and `layoutEmpty`) are removed from all ten packs, and `appDesigner.stepBasicDesc` no longer names a layout.
512
+
513
+ **Migration:** write a separator as `{ id, type: 'separator' }`, with an optional `order`. Remove `layout` from any `AppWizardDraft` you build. Code that spreads an entry-only key (`label`, `visible`, `requiredPermissions` and the rest) onto a value typed `NavigationItem` narrows it first (`item.type !== 'separator'`) or types it `NavigationEntryItem`: the separator arm refuses those keys. `AppComponentSchema.layout`, the renderer node's own layout strategy, is a different member and is unchanged.
514
+
515
+ Pinned in `packages/types/src/__tests__/app-wizard-separator-layout-10867.test.ts` and `packages/plugin-designer/src/__tests__/AppWizard.specDocument-10867.test.tsx`.
516
+ - 1ccb5ba: fix(layout): a present navigation label renders as written, with no exception, and an inline locale-map label renders its text (objectui#11201)
517
+
518
+ A navigation entry's text now follows one rule. A present label is shown as written. An absent label
519
+ shows the current, localized label of what the entry opens.
520
+
521
+ - **Visible change.** An entry whose stored label is its target's machine name (for example
522
+ `account`, `sales_overview`) used to be translated, because the sidebar looked that text up as
523
+ the object's, view's or dashboard's name. It now shows the name as written, in every locale.
524
+ **To fix such an entry:** clear its label so it inherits the target's localized label, or set the
525
+ text you want shown. Stored navigation is not converted, and no notice is sent.
526
+ - An entry label written as an inline locale map (`{ en: 'Accounts', 'zh-CN': '客户' }`) used to
527
+ render as empty text. It now renders the map's text. objectui#11201 did not tell the sidebar the
528
+ viewer's locale, so it read the `en` entry, then `default`, then any entry; objectui#11299, in the
529
+ same release, gives the sidebar the viewer's locale (`.changeset/11299-layout-nav-label-locale.md`).
530
+ - `NavigationRenderer`'s `resolveObjectLabel`, `resolveDashboardLabel` and `resolveViewLabel` props,
531
+ and the matching arguments of `resolveNavItemLabel`, are no longer read. objectui#11201 still
532
+ accepted them, so no caller broke; objectui#11299, in the same release, removes them
533
+ (`.changeset/11299-layout-nav-label-locale.md`). An unlabelled entry's localized text comes from
534
+ `resolveTargetLabel`.
535
+ - c18a075: fix(layout): the mobile tab bar opens the same page as the sidebar (objectui#11211)
536
+
537
+ With `mobileNavMode: 'bottom_nav'`, `AppSchemaRenderer`'s bottom tab bar used to
538
+ build each tab's link itself, so some navigation entries opened a different page
539
+ there than in the sidebar:
540
+
541
+ - a record deep link (`recordId`) opened the object's list instead of the record;
542
+ - an entry with `filters` opened the list without its filter;
543
+ - an entry with `runAction` opened the list without running its action;
544
+ - a `metadata:*` component entry opened the generic component route instead of
545
+ the metadata page;
546
+ - a `page` entry dropped its `params`, and `recordMode: 'edit'` was ignored.
547
+
548
+ Every tab now links to exactly the page its sidebar row links to. Two related
549
+ behaviours follow the sidebar too: the highlighted tab is the one whose sidebar
550
+ row is highlighted (at most one tab lights, and a filtered or quick-action tab
551
+ lights on its own page), and a `url` entry with `target: '_blank'` opens in a
552
+ new browser tab.
553
+ - 5ad9f5d: fix(layout): the mobile tab bar draws only the entries its sidebar draws
554
+
555
+ `AppSchemaRenderer` with `mobileNavMode: 'bottom_nav'` drew its tab bar from the
556
+ navigation tree with no entry guard. An entry the author hid with `visible: false`,
557
+ or gated with `requiredPermissions` the viewer lacks, was hidden in the sidebar and
558
+ still drawn as a tab, and an `action` entry became a tab linking to the root. The
559
+ five-tab cap was applied before any guard, so a hidden entry also took the place of
560
+ one that should have shown.
561
+
562
+ The bar now asks the sidebar's own guard about every node, through
563
+ `hasVisibleNavigationItems` (the predicate the area list already uses, built on
564
+ `passesNavItemGuards`), with the same evaluator, permission checker, capability
565
+ checker and doc-target checker the sidebar gets. The guard runs before the cap, and a
566
+ group the viewer may not see takes its entries with it, as in the sidebar. An
567
+ `action` entry is drawn the sidebar's way, as a button that hands the whole item to
568
+ `onAction`, and is left off the bar when no `onAction` is wired, which is when the
569
+ sidebar hides it too.
570
+
571
+ These are UI visibility gates, not data access: a route behind a wrongly drawn tab
572
+ still answered with its own server-side checks.
573
+ - 7728c67: fix(layout): the mobile tab bar draws its tabs in the sidebar's order, and shows an entry's badge
574
+
575
+ `AppSchemaRenderer` with `mobileNavMode: 'bottom_nav'` drew its tab bar in authored
576
+ position and never read `order`. Two entries written `Zeta` (`order: 2`) then
577
+ `Ypsilon` (`order: 1`) came out `Ypsilon, Zeta` in the sidebar and `Zeta, Ypsilon` on
578
+ the bar. With more than five entries, the five-tab cap kept the first five by authored
579
+ position rather than the five the sidebar lists first.
580
+
581
+ The bar now sorts each level with the sidebar's own comparator before it flattens:
582
+ first the top level, then each group's children. The guard and the five-tab cap run
583
+ after the sort, so the five tabs are the first five entries the sidebar draws. The
584
+ comparator lives in one internal module, and the sidebar's two sort sites use it too.
585
+ It is not exported, so the package's public API does not change. An entry with no
586
+ `order` still sorts as `0`, and entries with equal `order` keep their authored order,
587
+ as in the sidebar before.
588
+
589
+ The bar also dropped an entry's `badge` and `badgeVariant`. It now draws them on the
590
+ tab with the same `Badge` component and the same variant the sidebar row uses.
591
+ - d9a0490: Correct the `AppShellBranding.title` doc comment. It read "Page title
592
+ suffix (sets document.title)" while `useAppShellBranding` assigns `document.title = title`
593
+ wholesale — nothing is appended; the caller composes the whole string (the console passes
594
+ `"App label — Product name"`). That comment ships in `dist/index.d.ts` and is the only
595
+ description a consumer sees on editor hover, so a reader who followed it passed a
596
+ suffix-only fragment and got a truncated title with no error. The comment now carries the
597
+ same wording as `content/docs/layout/app-shell.mdx`, and agrees with the `AppShellProps`
598
+ tables in the package README and `content/docs/guide/layout.md`. No runtime behaviour
599
+ changes; the wholesale assignment and the four-surface agreement are now pinned by tests.
600
+ - 63a8828: Record headers: give the title column a width floor so a wide action tail can no
601
+ longer starve it.
602
+
603
+ Two headers repeated the title/action width arbitration objectui#7244 fixed on
604
+ `page:header`. Both were measured in Chromium at a 799px viewport with three
605
+ labelled `record_header` actions, before and after:
606
+
607
+ | header | before | after |
608
+ | --- | --- | --- |
609
+ | `DetailView` (`type: 'detail'`, the header that renders when the host supplies no `page:header`) | h1 6.17px of a 218px title | 218.39px, tail wrapped to its own line |
610
+ | `PageHeader` (`@object-ui/layout`) | h1 170.59px of a 265px title | 751.00px, tail wrapped to its own line |
611
+
612
+ `DetailView` gets the precedent's two utilities, both `sm:`-scoped so the
613
+ sub-640px column layout is untouched: `sm:flex-wrap` on the row and
614
+ `sm:min-w-64` on the title column. The floor is one step above the precedent's
615
+ `sm:min-w-48` because this title column carries the 40px back button and a 12px
616
+ gap inside it, so 256px is what leaves the h1 the same ~192px readable floor.
617
+
618
+ `PageHeader`'s row already wrapped, so it needed only the floor — and that floor
619
+ is unconditional rather than `sm:`-scoped, because this row has no
620
+ breakpoint-scoped direction change and the squeeze measures worse just below
621
+ `sm` (639px: h1 10.59px of a 212px title). `min-w-48` replaces `min-w-0` rather
622
+ than joining it: an explicit min-width overrides a flex item's automatic
623
+ min-content minimum exactly as `min-w-0` did, so long titles still ellipsise
624
+ (measured at 799px: 751px rendered of a 1682px title, no horizontal overflow).
625
+
626
+ Wide viewports are unchanged: at 1440px both headers keep the tail on the
627
+ title's line with the title unclipped, before and after alike.
628
+ - c6198c2: **Breaking for authored metadata:** `ComponentInput.label`, `ComponentInput.defaultValue` and
629
+ `ComponentInput.advanced` are RETIRED on both faces (objectui#7493 item ① and objectui#7781;
630
+ maintainer ruling A of 2026-09-06, immediate, no deprecation window; ADR-0049 enforce-or-remove).
631
+ They are the three keys the manifest serializer does not forward, and nothing read them on any
632
+ publication or consumption path.
633
+
634
+ No manifest ever published them, so no consumer could ever have read them. `sdui-parser`'s
635
+ serializer (`packages/sdui-parser/src/index.ts`) forwards exactly seven keys per input — `name`,
636
+ `type`, `of`, `required`, `enum`, `binding`, `description` — so a value authored under any of the three
637
+ never reached `sdui.manifest.json`, the generated JSX `.d.ts`, or a diagnostic; its boundary type
638
+ has no slot for them; the registry's data-source seam reads `name` only; and neither the designer
639
+ nor the app-shell inspectors consult registry `inputs` at all. A structural census over every
640
+ `inputs:` array in the repository (re-measured on this change's merge-base, `name` 951 and `type`
641
+ 951 as the controls) counted the writes: `label` 908, `defaultValue` 245, `advanced` 9 — written on
642
+ nearly every registration, read by nothing.
643
+
644
+ FROM → TO, per key — all three **TOMBSTONED, not removed**, because the route was measured on
645
+ the built face before it was chosen: `ComponentInputSchema` is a non-strict `z.object`, and an
646
+ undeclared key parses GREEN and is silently STRIPPED, so a deletion would have swallowed 1,162
647
+ authored values in silence. The tombstone is what makes the refusal loud and by name.
648
+
649
+ - `label?: string` → `label?: never` on the interface, `retirementTombstone()` on the Zod mirror.
650
+ Migration: delete the key. An input is identified by its `name` on every path that reaches it;
651
+ nothing ever rendered a label for it.
652
+ - `defaultValue?: any` → `defaultValue?: never` / `retirementTombstone()`. Migration: delete the
653
+ key. The renderer's own fallback read IS the default; tell the author about it in `description`,
654
+ which IS published. (Tightening the type to `unknown` was ruled out: it closes no error class,
655
+ since nothing reads the value.)
656
+ - `advanced?: boolean` → `advanced?: never` / `retirementTombstone()`. Migration: delete the key.
657
+ No designer surface ever hid an "advanced" input; there is nothing to write instead.
658
+
659
+ The retirement kit: `?: never` on `ComponentInput` (`packages/types/src/base.ts`), so authoring one
660
+ is a `tsc` error at the registration site; `retirementTombstone()` on `ComponentInputSchema`
661
+ (`packages/types/src/zod/base.zod.ts`), so an authored value is REFUSED at parse time with
662
+ `code: 'invalid_type'`, the key named in the issue `path`, and the migration note as the message
663
+ (one string, both channels). Pinned in
664
+ `packages/types/src/__tests__/component-input-retired-keys-7493.test.ts`, which also holds a
665
+ tree-scoped absence census over every `inputs:` array under `packages/**` and `apps/**`.
666
+
667
+ Accept-set change, stated plainly for reviewers: a document that sets any of the three keys on a
668
+ `ComponentInput` used to parse GREEN (the value was then dropped by the serializer) and now parses
669
+ RED. Every in-repo authoring site — 1,199 keys across 110 registration files, the three standalone
670
+ `ComponentInput[]` arrays and the two named input arrays `tsc` found included — is deleted in the same change, as the ruling's split rule
671
+ requires; the `WidgetRegistry` seam no longer copies the widget-manifest values onto the synthesized
672
+ `ComponentInput` (they fed nothing), and the data-source declaration `ELEMENT_DATA_SOURCE_INPUT`
673
+ drops its `label`. The patch entries on the other packages record exactly that: their registrations
674
+ stop authoring inert keys, with no runtime or published-manifest change.
675
+
676
+ The nine test files that read `defaultValue` off a registration were re-pinned against the
677
+ renderer's ACTUAL default (its own fallback read, or the `defaultProps` it ships) instead of the
678
+ declaration that went away; two assertions that only restated the shadow default were dropped with
679
+ the reason on the line.
680
+
681
+ The in-repo zero is what was measured. Whether anything OUTSIDE this repository writes these keys
682
+ is not measurable from here (the objectui#5674 limit); converting such a write from a silent drop
683
+ into a named refusal is exactly what the tombstones buy. `WidgetInput`'s own `label` /
684
+ `defaultValue` / `advanced` (the widget-manifest face) stay declared and writable — nothing has
685
+ ruled on that face; that it now has no reader either is recorded as objectui#7911.
686
+ - f4abff4: `@object-ui/layout` and `@object-ui/plugin-dashboard` no longer install a React of their
687
+ own. `react` moves from `dependencies` to `devDependencies` at the same pin (`19.2.8`);
688
+ `peerDependencies` is untouched, so both packages still ask their host for
689
+ `^18.0.0 || ^19.0.0` (objectui#8303).
690
+
691
+ Both manifests were making two contradictory statements at once: asking the host for React
692
+ as a peer, and pinning an exact React 19 of their own. The peer range is the one a consumer
693
+ reads; the pin is the one their installer acts on. A consumer on React 18 therefore
694
+ satisfied the peer range and **still** got a second, pinned React 19 pulled into their
695
+ graph on these two packages' account. Two React copies in one tree is the classic cause of
696
+ `Invalid hook call`, and the failure is not at install time — it is at first render, in the
697
+ consumer's own component, with nothing pointing back at these manifests.
698
+
699
+ Re-measured on `origin/main` at `348725a7c` across all four `pnpm-workspace.yaml` globs
700
+ (46 packages), rather than inherited from the card:
701
+
702
+ declares a react peer AND pins react in dependencies 2 layout, plugin-dashboard
703
+ declares a react-dom peer AND pins it in dependencies 0 (objectui#8198 took that half)
704
+ pins react in dependencies with NO react peer 5 runner, site, 3 examples
705
+
706
+ The last row is the control that keeps the fix narrow. Those five are applications that
707
+ supply React rather than libraries that ask for it: one statement, not two, and correctly
708
+ untouched. Against the 20+ sibling libraries the two packages fixed here were the only
709
+ outliers, so this converges on the existing house shape — `app-shell`, `auth`,
710
+ `collaboration`, `i18n`, `mobile` and `permissions` already carry `react` in
711
+ `devDependencies` at exactly this pin.
712
+
713
+ `scripts/__tests__/react-peer-range-norm-3741.test.ts` gains the invariant so a regression
714
+ goes red rather than being re-found by a consumer. That file already owns React manifest
715
+ norms across the fixed version group, already walks the workspace globs, and already
716
+ governs `react` + `react-dom`, so this is a second assertion on an existing guard rather
717
+ than a new one. It asserts the CONTRADICTION, not "React in `dependencies`" — widening it
718
+ further would go red on the five applications above for doing the right thing.
719
+
720
+ Two gates are green on this shape by construction and neither green was a reading of it.
721
+ `check:unused-deps` asks whether a declared runtime dependency has a consumer, and `react`
722
+ is imported by both packages — which is exactly why objectui#8198 could see and remove the
723
+ `react-dom` half here and could not see this one. `check-changeset-presence.mjs` reads an
724
+ eight-field allowlist that includes `peerDependencies` and deliberately excludes
725
+ `dependencies`; its own docblock states the trade ("a runtime dependency bump can be just
726
+ as user-visible as any of the eight, and this gate still does not see it"). This changeset
727
+ is therefore owed by the house rule, not demanded by the gate.
728
+ - 0febe1a: The console tab title no longer reverts to the bare product name after an in-app
729
+ navigation (objectui#8637).
730
+
731
+ Two effects wrote `document.title` on different keys. The console's `BrandingSync`
732
+ was keyed on `useLocation()` and assigned the bare product name on **every route
733
+ change**; `useAppShellBranding` assigns the composed `"App label — Product name"`
734
+ from an effect keyed on that string, so it fires when the title changes and not on
735
+ navigation. Both run on the commit that mounts the shell, and the composed title
736
+ wins — which is why the tab looked right and the defect stayed hidden. Navigating
737
+ between two pages of the same app moved `location` and not the composed title, so
738
+ only the route-keyed writer ran and the tab fell back to the bare product name.
739
+ Measured in a real browser, not inferred.
740
+
741
+ The repair is one writer rather than two careful ones. `useAppShellBranding` now
742
+ owns `document.title` for as long as a shell is mounted: it captures whatever the
743
+ tab already said, writes `title` over it, and puts the captured string back when the
744
+ shell unmounts or `title` changes. That is what let the console's route-keyed writer
745
+ drop its title assignment entirely — it had doubled as the reset that took the app
746
+ label back off the tab on the way out — and it became `FaviconSync`, which kept only
747
+ the favicon write until objectui#10379 removed that too.
748
+
749
+ For hosts of `@object-ui/layout`: the forward assignment is unchanged, and a shell
750
+ with no `title` still leaves the tab untouched in both directions. What is new is the
751
+ restore, so a shell mounted over part of a route tree hands the title back on exit
752
+ instead of stranding it. The restore replays the captured string unconditionally, so
753
+ a surface that writes the tab title from **inside** a mounted shell has its value
754
+ overwritten on unmount; keep such surfaces outside the shell.
755
+ - fe76ece: The typings both packages publish now carry an explicit extension on every relative specifier, so a consumer on `moduleResolution: nodenext` can follow them.
756
+
757
+ `vite-plugin-dts` emits one declaration file per source file, and TypeScript
758
+ copies a module specifier into the declaration verbatim. `export * from './ui'`
759
+ therefore shipped extensionless in `dist/index.d.ts` — 21 such re-exports in
760
+ `@object-ui/components`, 7 in `@object-ui/layout`, 128 across the two emitted
761
+ trees. Node16/NodeNext resolution does not extension-search a relative
762
+ specifier, so the compiler could follow none of the hops and every symbol they
763
+ carried read as absent from the package:
764
+
765
+ ```
766
+ error TS2305: Module '"@object-ui/components"' has no exported member 'Badge'.
767
+ ```
768
+
769
+ Measured on `@object-ui/app-shell`, the largest consumer and the one that pulls
770
+ in both packages: 880 TS2305 across 162 files (864 from `components`, 16 from
771
+ `layout`), plus 215 TS7006 as fallout from the imports that stopped resolving.
772
+ On `@object-ui/fields`, 178 TS2305 and 57 TS7006. Both are zero now.
773
+
774
+ The emitted `.js` never had the defect — rolldown resolves the same specifier
775
+ away — which is why `pnpm check:esm-specifiers`, whose verdict is about
776
+ specifier-preserving `.js` builds, correctly never scanned either package. The
777
+ fix is therefore in the declaration EMIT (`scripts/vite-dts-explicit-extensions.ts`,
778
+ shared by both `vite.config.ts` files), not in the sources: the same source line
779
+ produces a clean `.js` and a broken `.d.ts`, so no source edit can express the
780
+ difference. The rewriter resolves each specifier against the source tree the
781
+ output mirrors — a file hop becomes `./x.js`, a directory hop `./x/index.js` —
782
+ throws on anything it cannot resolve, and after the build re-parses the emitted
783
+ declarations to assert every relative specifier both carries an extension and
784
+ names a file the build really emitted.
785
+
786
+ `packages/fields` takes the `nodenext` pin as a result — the same two lines
787
+ `packages/react` has carried since objectui#4538 — so the property is enforced by
788
+ the compiler on the consumer side rather than by review. `packages/app-shell`
789
+ does not: it type-checks clean without the pin and still shows 23 errors with it,
790
+ none of them from these two packages. That residue is filed separately.
791
+ - fb336df: Move `lucide-react` from `^1.31.0` to `^1.43.0` in every package that declares it, and
792
+ repair what the jump breaks, so icons resolved from a STRING keep drawing a glyph.
793
+
794
+ Measured once against the installed 1.43.0 artifact when this change was made; nothing in
795
+ the repository re-derives these readings. Across the jump lucide removes no runtime export,
796
+ no public type name and no `lucide-react/dynamic.mjs` name, and every name this repository
797
+ imports from `lucide-react` resolves. Exactly one key leaves the runtime `icons` record:
798
+ `Trash2`, retired in favour of `trash`.
799
+
800
+ What a user sees change:
801
+
802
+ - Icons the lazy icon seam draws (`resolveIcon`, objectui#9251) get their path data again.
803
+ lucide 1.43.0 icon modules export their path data inside `__iconData` and no longer
804
+ export `__iconNode`; the seam now reads both. Reading only `__iconNode` against 1.43.0
805
+ leaves every such glyph an empty box, with nothing thrown or logged.
806
+ - `DetailView`'s delete action and three schema-catalog examples spell their icon
807
+ `trash`, not `trash-2`, so they keep resolving. The glyph is unchanged: 1.43.0's `trash`
808
+ path data is byte-identical to the `trash-2` path data of 1.31.0 and 1.35.0. Anything
809
+ that already authored `trash` now draws that same artwork, because lucide moved it under
810
+ the `trash` name; a few other glyphs were also redrawn upstream.
811
+ - Icons imported as COMPONENTS carry lucide 1.43.0's own classes: one class per declared
812
+ alias (a spinner renders `class="lucide lucide-loader-circle lucide-loader-2 ..."`), and
813
+ no longer the class lucide used to derive from the PascalCase key where that differs
814
+ (`ArrowDown01` no longer carries `lucide-arrow-down01`). The canonical
815
+ `lucide-<icon name>` class is still there, so a `.lucide-loader-circle` selector still
816
+ matches.
817
+ - Icons resolved from a STRING through the seam keep the classes they had: `lucide`, the
818
+ canonical `lucide-<icon name>` class and the key-derived class. They do not carry
819
+ lucide's per-alias classes. That is a maintainer ruling (objectui#8941, option C): the
820
+ alias list lives only inside each lazily loaded icon module, and it was not moved into
821
+ the eager name list. A selector that targets an alias class matches a component-imported
822
+ icon and not a string-resolved one. This also dates the example in the objectui#9251
823
+ entry: `trash-2` no longer resolves as a string, so no seam-drawn glyph carries
824
+ `lucide-trash2 lucide-trash-2`; a digit-bearing name that still resolves, such as
825
+ `arrow-down-0-1`, carries `lucide-arrow-down01 lucide-arrow-down-0-1`.
826
+ - Updated dependencies [7b10bef]
827
+ - Updated dependencies [97abedc]
828
+ - Updated dependencies [b46c58f]
829
+ - Updated dependencies [ad694ac]
830
+ - Updated dependencies [6f96fca]
831
+ - Updated dependencies [0aacecc]
832
+ - Updated dependencies [777fca2]
833
+ - Updated dependencies [c131d9e]
834
+ - Updated dependencies [5f00ff4]
835
+ - Updated dependencies [c9e073a]
836
+ - Updated dependencies [7b395d8]
837
+ - Updated dependencies [0879812]
838
+ - Updated dependencies [8cedb0d]
839
+ - Updated dependencies [162621b]
840
+ - Updated dependencies [4c6f549]
841
+ - Updated dependencies [6cc910b]
842
+ - Updated dependencies [061f5e8]
843
+ - Updated dependencies [2dd4d3f]
844
+ - Updated dependencies [4ab4f1b]
845
+ - Updated dependencies [e3ea4f9]
846
+ - Updated dependencies [8b1f066]
847
+ - Updated dependencies [af243c1]
848
+ - Updated dependencies [cff4b77]
849
+ - Updated dependencies [961ceaa]
850
+ - Updated dependencies [f3f4e4c]
851
+ - Updated dependencies [a05c350]
852
+ - Updated dependencies [2b5f509]
853
+ - Updated dependencies [808f339]
854
+ - Updated dependencies [6cf5999]
855
+ - Updated dependencies [274e14a]
856
+ - Updated dependencies [8c10f4f]
857
+ - Updated dependencies [90dac98]
858
+ - Updated dependencies [6096f20]
859
+ - Updated dependencies [544aca2]
860
+ - Updated dependencies [ea02938]
861
+ - Updated dependencies [a14fb23]
862
+ - Updated dependencies [ae98f1d]
863
+ - Updated dependencies [f98eddf]
864
+ - Updated dependencies [ce6bd99]
865
+ - Updated dependencies [a5b08c9]
866
+ - Updated dependencies [86982ac]
867
+ - Updated dependencies [cdefa2a]
868
+ - Updated dependencies [0961d5e]
869
+ - Updated dependencies [6276478]
870
+ - Updated dependencies [ff14e29]
871
+ - Updated dependencies [9b28151]
872
+ - Updated dependencies [64563a9]
873
+ - Updated dependencies [1a5003f]
874
+ - Updated dependencies [09ab32b]
875
+ - Updated dependencies [8acc51b]
876
+ - Updated dependencies [93a689d]
877
+ - Updated dependencies [e5f4343]
878
+ - Updated dependencies [3261e64]
879
+ - Updated dependencies [f5178a2]
880
+ - Updated dependencies [2ad3671]
881
+ - Updated dependencies [d22b37b]
882
+ - Updated dependencies [1daf477]
883
+ - Updated dependencies [3d614ea]
884
+ - Updated dependencies [6c2f3c5]
885
+ - Updated dependencies [fb13e85]
886
+ - Updated dependencies [c2d8659]
887
+ - Updated dependencies [e0f8202]
888
+ - Updated dependencies [9fbbb17]
889
+ - Updated dependencies [c3a26cc]
890
+ - Updated dependencies [a66e58e]
891
+ - Updated dependencies [d89492c]
892
+ - Updated dependencies [9a5f998]
893
+ - Updated dependencies [9327397]
894
+ - Updated dependencies [17cc3a3]
895
+ - Updated dependencies [02e6d36]
896
+ - Updated dependencies [4758b33]
897
+ - Updated dependencies [4758b33]
898
+ - Updated dependencies [9c78ebe]
899
+ - Updated dependencies [9c78ebe]
900
+ - Updated dependencies [12809a5]
901
+ - Updated dependencies [7afc81d]
902
+ - Updated dependencies [f9c06ef]
903
+ - Updated dependencies [5ad3b88]
904
+ - Updated dependencies [f9d772b]
905
+ - Updated dependencies [97b6c21]
906
+ - Updated dependencies [26ca2ad]
907
+ - Updated dependencies [41ae65b]
908
+ - Updated dependencies [baac95a]
909
+ - Updated dependencies [13220af]
910
+ - Updated dependencies [29b45f6]
911
+ - Updated dependencies [39b8d51]
912
+ - Updated dependencies [17b323e]
913
+ - Updated dependencies [b956e69]
914
+ - Updated dependencies [33e58d8]
915
+ - Updated dependencies [256b4c9]
916
+ - Updated dependencies [c5ec15c]
917
+ - Updated dependencies [fec3b1a]
918
+ - Updated dependencies [b8e0941]
919
+ - Updated dependencies [0c50f18]
920
+ - Updated dependencies [1dae95a]
921
+ - Updated dependencies [e32dae1]
922
+ - Updated dependencies [30b11ad]
923
+ - Updated dependencies [4aebea0]
924
+ - Updated dependencies [f976774]
925
+ - Updated dependencies [3d6badf]
926
+ - Updated dependencies [25cb364]
927
+ - Updated dependencies [a60539b]
928
+ - Updated dependencies [de1b879]
929
+ - Updated dependencies [c6678b1]
930
+ - Updated dependencies [0638322]
931
+ - Updated dependencies [e3782d2]
932
+ - Updated dependencies [db0beb2]
933
+ - Updated dependencies [997ce38]
934
+ - Updated dependencies [ae0b9d3]
935
+ - Updated dependencies [ad1785c]
936
+ - Updated dependencies [3b469c8]
937
+ - Updated dependencies [990a2d6]
938
+ - Updated dependencies [1c84036]
939
+ - Updated dependencies [1c84036]
940
+ - Updated dependencies [6650259]
941
+ - Updated dependencies [4f8b7f8]
942
+ - Updated dependencies [9e6619f]
943
+ - Updated dependencies [f6ae5e2]
944
+ - Updated dependencies [7343376]
945
+ - Updated dependencies [b2683a2]
946
+ - Updated dependencies [dded788]
947
+ - Updated dependencies [b45d463]
948
+ - Updated dependencies [54a7830]
949
+ - Updated dependencies [f3135a4]
950
+ - Updated dependencies [b5696d3]
951
+ - Updated dependencies [3f9d926]
952
+ - Updated dependencies [e978ed5]
953
+ - Updated dependencies [6a7f24e]
954
+ - Updated dependencies [b3c96d6]
955
+ - Updated dependencies [8d0ca91]
956
+ - Updated dependencies [c30c8dd]
957
+ - Updated dependencies [deca847]
958
+ - Updated dependencies [328abeb]
959
+ - Updated dependencies [dd0d78f]
960
+ - Updated dependencies [24d3e65]
961
+ - Updated dependencies [95a7c8d]
962
+ - Updated dependencies [e227156]
963
+ - Updated dependencies [cc4e476]
964
+ - Updated dependencies [92970c4]
965
+ - Updated dependencies [d570eaa]
966
+ - Updated dependencies [4b742f4]
967
+ - Updated dependencies [42687ba]
968
+ - Updated dependencies [6cd8f66]
969
+ - Updated dependencies [24a0f14]
970
+ - Updated dependencies [797a30f]
971
+ - Updated dependencies [b4075c0]
972
+ - Updated dependencies [9b85600]
973
+ - Updated dependencies [99878d8]
974
+ - Updated dependencies [3c13675]
975
+ - Updated dependencies [63ab761]
976
+ - Updated dependencies [0eb9f36]
977
+ - Updated dependencies [ae582b7]
978
+ - Updated dependencies [a4b017e]
979
+ - Updated dependencies [559a2e2]
980
+ - Updated dependencies [db11afd]
981
+ - Updated dependencies [154075a]
982
+ - Updated dependencies [582edef]
983
+ - Updated dependencies [19f484f]
984
+ - Updated dependencies [0a78a20]
985
+ - Updated dependencies [615346d]
986
+ - Updated dependencies [75dcc81]
987
+ - Updated dependencies [55a12a8]
988
+ - Updated dependencies [edfcf5a]
989
+ - Updated dependencies [0a3e540]
990
+ - Updated dependencies [c021b35]
991
+ - Updated dependencies [f61dab1]
992
+ - Updated dependencies [b0a05dd]
993
+ - Updated dependencies [dd5ff19]
994
+ - Updated dependencies [81f8498]
995
+ - Updated dependencies [a782fa7]
996
+ - Updated dependencies [0645133]
997
+ - Updated dependencies [76e9df0]
998
+ - Updated dependencies [0ecaa7d]
999
+ - Updated dependencies [b24f93a]
1000
+ - Updated dependencies [6158e4c]
1001
+ - Updated dependencies [c27b575]
1002
+ - Updated dependencies [84b275c]
1003
+ - Updated dependencies [0e6e76b]
1004
+ - Updated dependencies [bf43afa]
1005
+ - Updated dependencies [858eafb]
1006
+ - Updated dependencies [0ffc423]
1007
+ - Updated dependencies [3cc4fe5]
1008
+ - Updated dependencies [cd5b19a]
1009
+ - Updated dependencies [cd5b19a]
1010
+ - Updated dependencies [17dc167]
1011
+ - Updated dependencies [20d23be]
1012
+ - Updated dependencies [20d23be]
1013
+ - Updated dependencies [2e3da72]
1014
+ - Updated dependencies [1263e40]
1015
+ - Updated dependencies [e6bc087]
1016
+ - Updated dependencies [8bab157]
1017
+ - Updated dependencies [a7557a7]
1018
+ - Updated dependencies [7d074ba]
1019
+ - Updated dependencies [6158e4c]
1020
+ - Updated dependencies [6158e4c]
1021
+ - Updated dependencies [52aad5c]
1022
+ - Updated dependencies [18d1a0a]
1023
+ - Updated dependencies [7fed09d]
1024
+ - Updated dependencies [58da8ae]
1025
+ - Updated dependencies [a8b9889]
1026
+ - Updated dependencies [138ad45]
1027
+ - Updated dependencies [138ad45]
1028
+ - Updated dependencies [5262f7d]
1029
+ - Updated dependencies [6aa029b]
1030
+ - Updated dependencies [2124d04]
1031
+ - Updated dependencies [be52115]
1032
+ - Updated dependencies [770cc5b]
1033
+ - Updated dependencies [1a88ce2]
1034
+ - Updated dependencies [a1a44d6]
1035
+ - Updated dependencies [e0a9c67]
1036
+ - Updated dependencies [5638529]
1037
+ - Updated dependencies [5638529]
1038
+ - Updated dependencies [c476be0]
1039
+ - Updated dependencies [c82ff39]
1040
+ - Updated dependencies [6c3da53]
1041
+ - Updated dependencies [31987bd]
1042
+ - Updated dependencies [3c3ce15]
1043
+ - Updated dependencies [063119f]
1044
+ - Updated dependencies [e100589]
1045
+ - Updated dependencies [304f611]
1046
+ - Updated dependencies [e46ee77]
1047
+ - Updated dependencies [f9c8c4e]
1048
+ - Updated dependencies [6e9c8d2]
1049
+ - Updated dependencies [9547063]
1050
+ - Updated dependencies [3f6efd6]
1051
+ - Updated dependencies [c4ab6d0]
1052
+ - Updated dependencies [0e9058b]
1053
+ - Updated dependencies [5988b6b]
1054
+ - Updated dependencies [6158e4c]
1055
+ - Updated dependencies [00ccdf7]
1056
+ - Updated dependencies [9d9ed54]
1057
+ - Updated dependencies [4a1adb7]
1058
+ - Updated dependencies [50c73fe]
1059
+ - Updated dependencies [ca3de72]
1060
+ - Updated dependencies [83e3f83]
1061
+ - Updated dependencies [401611b]
1062
+ - Updated dependencies [2c0ddf2]
1063
+ - Updated dependencies [4abc0aa]
1064
+ - Updated dependencies [f560ded]
1065
+ - Updated dependencies [2b188fa]
1066
+ - Updated dependencies [b654d4e]
1067
+ - Updated dependencies [f68e0a0]
1068
+ - Updated dependencies [aea682a]
1069
+ - Updated dependencies [fcdc8ec]
1070
+ - Updated dependencies [2d576e4]
1071
+ - Updated dependencies [8366acc]
1072
+ - Updated dependencies [95e58a3]
1073
+ - Updated dependencies [9d7419b]
1074
+ - Updated dependencies [fc7db05]
1075
+ - Updated dependencies [9ed8d0f]
1076
+ - Updated dependencies [c73cdb5]
1077
+ - Updated dependencies [6f5719e]
1078
+ - Updated dependencies [64dae8e]
1079
+ - Updated dependencies [06a8af5]
1080
+ - Updated dependencies [6a91586]
1081
+ - Updated dependencies [a04d7c6]
1082
+ - Updated dependencies [5ccc500]
1083
+ - Updated dependencies [f3c2bb0]
1084
+ - Updated dependencies [978507b]
1085
+ - Updated dependencies [778138e]
1086
+ - Updated dependencies [9801765]
1087
+ - Updated dependencies [9cebfca]
1088
+ - Updated dependencies [460575f]
1089
+ - Updated dependencies [d796c8d]
1090
+ - Updated dependencies [1b1d772]
1091
+ - Updated dependencies [d88e20f]
1092
+ - Updated dependencies [2d7304d]
1093
+ - Updated dependencies [636b236]
1094
+ - Updated dependencies [4172589]
1095
+ - Updated dependencies [d6d8fb9]
1096
+ - Updated dependencies [64d624d]
1097
+ - Updated dependencies [053fdc8]
1098
+ - Updated dependencies [ae476b8]
1099
+ - Updated dependencies [39f4309]
1100
+ - Updated dependencies [95bad12]
1101
+ - Updated dependencies [d2fb6ef]
1102
+ - Updated dependencies [7cd3987]
1103
+ - Updated dependencies [ee3b878]
1104
+ - Updated dependencies [e304a4e]
1105
+ - Updated dependencies [fda49e5]
1106
+ - Updated dependencies [490d9a9]
1107
+ - Updated dependencies [fc62bb4]
1108
+ - Updated dependencies [41df893]
1109
+ - Updated dependencies [0cba1b7]
1110
+ - Updated dependencies [00f3eb5]
1111
+ - Updated dependencies [1ec291c]
1112
+ - Updated dependencies [453dbaa]
1113
+ - Updated dependencies [f8cdbf2]
1114
+ - Updated dependencies [69a2163]
1115
+ - Updated dependencies [24e027e]
1116
+ - Updated dependencies [2c3cd1b]
1117
+ - Updated dependencies [e176053]
1118
+ - Updated dependencies [e30ed15]
1119
+ - Updated dependencies [90665e0]
1120
+ - Updated dependencies [194fae1]
1121
+ - Updated dependencies [7e19d03]
1122
+ - Updated dependencies [1e946c9]
1123
+ - Updated dependencies [546ddf7]
1124
+ - Updated dependencies [864154e]
1125
+ - Updated dependencies [b023625]
1126
+ - Updated dependencies [75bd83d]
1127
+ - Updated dependencies [44d075b]
1128
+ - Updated dependencies [40c479a]
1129
+ - Updated dependencies [971d387]
1130
+ - Updated dependencies [ee851c3]
1131
+ - Updated dependencies [6414dfd]
1132
+ - Updated dependencies [a8d5c71]
1133
+ - Updated dependencies [905b21f]
1134
+ - Updated dependencies [88e9109]
1135
+ - Updated dependencies [2c45966]
1136
+ - Updated dependencies [db3a600]
1137
+ - Updated dependencies [3a3db76]
1138
+ - Updated dependencies [0d723a3]
1139
+ - Updated dependencies [0c95d3d]
1140
+ - Updated dependencies [3e4fa2c]
1141
+ - Updated dependencies [b5b928a]
1142
+ - Updated dependencies [6fd2cf7]
1143
+ - Updated dependencies [52a43de]
1144
+ - Updated dependencies [195052f]
1145
+ - Updated dependencies [e4559d1]
1146
+ - Updated dependencies [2c71482]
1147
+ - Updated dependencies [129bcc5]
1148
+ - Updated dependencies [a26b9e4]
1149
+ - Updated dependencies [5ef9c4f]
1150
+ - Updated dependencies [46f0bb4]
1151
+ - Updated dependencies [06b82b8]
1152
+ - Updated dependencies [8ec11e1]
1153
+ - Updated dependencies [6f81384]
1154
+ - Updated dependencies [22ba927]
1155
+ - Updated dependencies [f8c70f4]
1156
+ - Updated dependencies [8f1d995]
1157
+ - Updated dependencies [f9c34df]
1158
+ - Updated dependencies [dddb942]
1159
+ - Updated dependencies [29754cf]
1160
+ - Updated dependencies [d7de534]
1161
+ - Updated dependencies [3c2b6f7]
1162
+ - Updated dependencies [6e88630]
1163
+ - Updated dependencies [b84dc18]
1164
+ - Updated dependencies [ac8abb0]
1165
+ - Updated dependencies [9d86e1d]
1166
+ - Updated dependencies [3a5817f]
1167
+ - Updated dependencies [99a3c2d]
1168
+ - Updated dependencies [5961030]
1169
+ - Updated dependencies [f24de8b]
1170
+ - Updated dependencies [c8ea8af]
1171
+ - Updated dependencies [3190414]
1172
+ - Updated dependencies [4e480f5]
1173
+ - Updated dependencies [38a123c]
1174
+ - Updated dependencies [299102e]
1175
+ - Updated dependencies [30c73cd]
1176
+ - Updated dependencies [830ed58]
1177
+ - Updated dependencies [d7acad6]
1178
+ - Updated dependencies [45a9aeb]
1179
+ - Updated dependencies [713db46]
1180
+ - Updated dependencies [c71e14d]
1181
+ - Updated dependencies [bf3a03c]
1182
+ - Updated dependencies [cb55718]
1183
+ - Updated dependencies [748494b]
1184
+ - Updated dependencies [5967be0]
1185
+ - Updated dependencies [831be72]
1186
+ - Updated dependencies [29cb85b]
1187
+ - Updated dependencies [3e028c8]
1188
+ - Updated dependencies [d0889e2]
1189
+ - Updated dependencies [ce503e5]
1190
+ - Updated dependencies [f20dcf0]
1191
+ - Updated dependencies [12402a9]
1192
+ - Updated dependencies [aff3d7a]
1193
+ - Updated dependencies [4ca30d0]
1194
+ - Updated dependencies [7a5da14]
1195
+ - Updated dependencies [2c1c967]
1196
+ - Updated dependencies [9486ac6]
1197
+ - Updated dependencies [9486ac6]
1198
+ - Updated dependencies [4d5f9b4]
1199
+ - Updated dependencies [d6ceb8d]
1200
+ - Updated dependencies [dc4365c]
1201
+ - Updated dependencies [e321d52]
1202
+ - Updated dependencies [4c68077]
1203
+ - Updated dependencies [7977ff9]
1204
+ - Updated dependencies [3beef6d]
1205
+ - Updated dependencies [06b8c42]
1206
+ - Updated dependencies [46b9bc9]
1207
+ - Updated dependencies [b97790a]
1208
+ - Updated dependencies [7c9b044]
1209
+ - Updated dependencies [d47de51]
1210
+ - Updated dependencies [3fe6463]
1211
+ - Updated dependencies [31ab372]
1212
+ - Updated dependencies [846889b]
1213
+ - Updated dependencies [2acd8e1]
1214
+ - Updated dependencies [26896c6]
1215
+ - Updated dependencies [67fc3b0]
1216
+ - Updated dependencies [33a3b3c]
1217
+ - Updated dependencies [b87f15b]
1218
+ - Updated dependencies [045d20b]
1219
+ - Updated dependencies [a2d2515]
1220
+ - Updated dependencies [c18d099]
1221
+ - Updated dependencies [adb2a86]
1222
+ - Updated dependencies [03380aa]
1223
+ - Updated dependencies [4562ea5]
1224
+ - Updated dependencies [3619792]
1225
+ - Updated dependencies [3561bd2]
1226
+ - Updated dependencies [bf97b98]
1227
+ - Updated dependencies [b0d308d]
1228
+ - Updated dependencies [40f34b4]
1229
+ - Updated dependencies [8063bcb]
1230
+ - Updated dependencies [b74a859]
1231
+ - Updated dependencies [d4493fd]
1232
+ - Updated dependencies [240b80f]
1233
+ - Updated dependencies [77cb489]
1234
+ - Updated dependencies [bfaa158]
1235
+ - Updated dependencies [777e5c6]
1236
+ - Updated dependencies [0c386dd]
1237
+ - Updated dependencies [9e37d9b]
1238
+ - Updated dependencies [5ad86dd]
1239
+ - Updated dependencies [16a725f]
1240
+ - Updated dependencies [4dfdcc3]
1241
+ - Updated dependencies [6a449fc]
1242
+ - Updated dependencies [446d93d]
1243
+ - Updated dependencies [ecd9cb2]
1244
+ - Updated dependencies [98d4108]
1245
+ - Updated dependencies [0e3b3be]
1246
+ - Updated dependencies [a29ae2d]
1247
+ - Updated dependencies [00d3f09]
1248
+ - Updated dependencies [4388f71]
1249
+ - Updated dependencies [0b1ac58]
1250
+ - Updated dependencies [c93b4d5]
1251
+ - Updated dependencies [c1fe272]
1252
+ - Updated dependencies [3cab570]
1253
+ - Updated dependencies [8ad218d]
1254
+ - Updated dependencies [3e41187]
1255
+ - Updated dependencies [5f78953]
1256
+ - Updated dependencies [639114c]
1257
+ - Updated dependencies [1f31d3a]
1258
+ - Updated dependencies [d1842ab]
1259
+ - Updated dependencies [78ca238]
1260
+ - Updated dependencies [351eb31]
1261
+ - Updated dependencies [20c04b2]
1262
+ - Updated dependencies [48c19bd]
1263
+ - Updated dependencies [a6d8b8d]
1264
+ - Updated dependencies [4b5bb95]
1265
+ - Updated dependencies [b652514]
1266
+ - Updated dependencies [adbda1b]
1267
+ - Updated dependencies [adbda1b]
1268
+ - Updated dependencies [e2b3826]
1269
+ - Updated dependencies [2e32ed4]
1270
+ - Updated dependencies [3ed3eec]
1271
+ - Updated dependencies [7c3df8f]
1272
+ - Updated dependencies [b9f5ff1]
1273
+ - Updated dependencies [e75f4c9]
1274
+ - Updated dependencies [19f1639]
1275
+ - Updated dependencies [4704aa4]
1276
+ - Updated dependencies [47547d0]
1277
+ - Updated dependencies [1bee5d0]
1278
+ - Updated dependencies [858cd72]
1279
+ - Updated dependencies [cfc9b6d]
1280
+ - Updated dependencies [554f2b6]
1281
+ - Updated dependencies [72f55c9]
1282
+ - Updated dependencies [26e06d7]
1283
+ - Updated dependencies [669d71b]
1284
+ - Updated dependencies [ed27d7c]
1285
+ - Updated dependencies [52c8cf7]
1286
+ - Updated dependencies [2ceb43a]
1287
+ - Updated dependencies [7cdd2b9]
1288
+ - Updated dependencies [52c8cf7]
1289
+ - Updated dependencies [71a4a53]
1290
+ - Updated dependencies [7bf244b]
1291
+ - Updated dependencies [f0bb9fa]
1292
+ - Updated dependencies [81a2eb1]
1293
+ - Updated dependencies [caa0cd3]
1294
+ - Updated dependencies [caa0cd3]
1295
+ - Updated dependencies [25c7d58]
1296
+ - Updated dependencies [00d2fa6]
1297
+ - Updated dependencies [c6198c2]
1298
+ - Updated dependencies [721d1e0]
1299
+ - Updated dependencies [1237ae4]
1300
+ - Updated dependencies [2f61238]
1301
+ - Updated dependencies [51eb515]
1302
+ - Updated dependencies [c354ce5]
1303
+ - Updated dependencies [8fe8e5c]
1304
+ - Updated dependencies [feac439]
1305
+ - Updated dependencies [9ae871d]
1306
+ - Updated dependencies [efbd566]
1307
+ - Updated dependencies [9587fc9]
1308
+ - Updated dependencies [e62c44e]
1309
+ - Updated dependencies [daf9d57]
1310
+ - Updated dependencies [c15d7ec]
1311
+ - Updated dependencies [5d0876c]
1312
+ - Updated dependencies [f7ace0a]
1313
+ - Updated dependencies [b041b9c]
1314
+ - Updated dependencies [ce2aaef]
1315
+ - Updated dependencies [544ecba]
1316
+ - Updated dependencies [2ce2612]
1317
+ - Updated dependencies [bc640ec]
1318
+ - Updated dependencies [1e215c4]
1319
+ - Updated dependencies [da6e191]
1320
+ - Updated dependencies [3e377c9]
1321
+ - Updated dependencies [a3eb5d0]
1322
+ - Updated dependencies [4ce14f1]
1323
+ - Updated dependencies [aef97e5]
1324
+ - Updated dependencies [2af1fa7]
1325
+ - Updated dependencies [c14d3a0]
1326
+ - Updated dependencies [a137d0c]
1327
+ - Updated dependencies [caf477f]
1328
+ - Updated dependencies [f6375da]
1329
+ - Updated dependencies [967e5d8]
1330
+ - Updated dependencies [a4611b3]
1331
+ - Updated dependencies [20316ba]
1332
+ - Updated dependencies [d3499b3]
1333
+ - Updated dependencies [309c75e]
1334
+ - Updated dependencies [c9f9bae]
1335
+ - Updated dependencies [18897a4]
1336
+ - Updated dependencies [8b7ea39]
1337
+ - Updated dependencies [dcbf0b2]
1338
+ - Updated dependencies [52cac38]
1339
+ - Updated dependencies [93fea2e]
1340
+ - Updated dependencies [1422a92]
1341
+ - Updated dependencies [d05fe17]
1342
+ - Updated dependencies [a480f79]
1343
+ - Updated dependencies [f08d1a8]
1344
+ - Updated dependencies [64a252d]
1345
+ - Updated dependencies [786bc91]
1346
+ - Updated dependencies [75fca96]
1347
+ - Updated dependencies [7ca6ddd]
1348
+ - Updated dependencies [f1cd290]
1349
+ - Updated dependencies [5a41ce7]
1350
+ - Updated dependencies [8d50bc2]
1351
+ - Updated dependencies [604476d]
1352
+ - Updated dependencies [d1bebb0]
1353
+ - Updated dependencies [95bf128]
1354
+ - Updated dependencies [335abea]
1355
+ - Updated dependencies [edea22a]
1356
+ - Updated dependencies [0f5cadf]
1357
+ - Updated dependencies [4f9f1ee]
1358
+ - Updated dependencies [66e8b2a]
1359
+ - Updated dependencies [aa083cd]
1360
+ - Updated dependencies [12b5992]
1361
+ - Updated dependencies [b93e245]
1362
+ - Updated dependencies [c842594]
1363
+ - Updated dependencies [290de37]
1364
+ - Updated dependencies [8c8da45]
1365
+ - Updated dependencies [8cd8eb5]
1366
+ - Updated dependencies [cf1d29e]
1367
+ - Updated dependencies [1bd79c8]
1368
+ - Updated dependencies [af9e957]
1369
+ - Updated dependencies [b1030c7]
1370
+ - Updated dependencies [c974edf]
1371
+ - Updated dependencies [ad852b6]
1372
+ - Updated dependencies [7fb22a1]
1373
+ - Updated dependencies [ad66d79]
1374
+ - Updated dependencies [ee4d19f]
1375
+ - Updated dependencies [496d31d]
1376
+ - Updated dependencies [0ea7054]
1377
+ - Updated dependencies [9a853f2]
1378
+ - Updated dependencies [cb847fd]
1379
+ - Updated dependencies [ee70287]
1380
+ - Updated dependencies [3e98e13]
1381
+ - Updated dependencies [fc32921]
1382
+ - Updated dependencies [4eaa835]
1383
+ - Updated dependencies [8f9d87a]
1384
+ - Updated dependencies [b1777ae]
1385
+ - Updated dependencies [24845c4]
1386
+ - Updated dependencies [6f864cf]
1387
+ - Updated dependencies [24d1edd]
1388
+ - Updated dependencies [645087c]
1389
+ - Updated dependencies [33f4a19]
1390
+ - Updated dependencies [4a292d2]
1391
+ - Updated dependencies [5323168]
1392
+ - Updated dependencies [841dd2b]
1393
+ - Updated dependencies [3014fc0]
1394
+ - Updated dependencies [dacb402]
1395
+ - Updated dependencies [846cec0]
1396
+ - Updated dependencies [91facae]
1397
+ - Updated dependencies [b38014e]
1398
+ - Updated dependencies [474797d]
1399
+ - Updated dependencies [704e695]
1400
+ - Updated dependencies [a407bd6]
1401
+ - Updated dependencies [317dbce]
1402
+ - Updated dependencies [3a43a15]
1403
+ - Updated dependencies [868e825]
1404
+ - Updated dependencies [f76f436]
1405
+ - Updated dependencies [ce45a03]
1406
+ - Updated dependencies [421544b]
1407
+ - Updated dependencies [fb01022]
1408
+ - Updated dependencies [e9d9212]
1409
+ - Updated dependencies [ecfb693]
1410
+ - Updated dependencies [abc1b18]
1411
+ - Updated dependencies [81a51db]
1412
+ - Updated dependencies [67749c7]
1413
+ - Updated dependencies [507b61b]
1414
+ - Updated dependencies [512c84b]
1415
+ - Updated dependencies [c300267]
1416
+ - Updated dependencies [fb3a101]
1417
+ - Updated dependencies [d4733f2]
1418
+ - Updated dependencies [1570eac]
1419
+ - Updated dependencies [f391ede]
1420
+ - Updated dependencies [f5cfbbd]
1421
+ - Updated dependencies [f5cfbbd]
1422
+ - Updated dependencies [8b532cb]
1423
+ - Updated dependencies [64c3cdd]
1424
+ - Updated dependencies [4d65991]
1425
+ - Updated dependencies [c42554e]
1426
+ - Updated dependencies [555b4ec]
1427
+ - Updated dependencies [1ccfc23]
1428
+ - Updated dependencies [542718f]
1429
+ - Updated dependencies [7f27bc5]
1430
+ - Updated dependencies [0a174f3]
1431
+ - Updated dependencies [f95b140]
1432
+ - Updated dependencies [541ce4e]
1433
+ - Updated dependencies [6479086]
1434
+ - Updated dependencies [d79f525]
1435
+ - Updated dependencies [d1865d2]
1436
+ - Updated dependencies [f1190b0]
1437
+ - Updated dependencies [561abef]
1438
+ - Updated dependencies [6a4680b]
1439
+ - Updated dependencies [c3a4273]
1440
+ - Updated dependencies [abf710d]
1441
+ - Updated dependencies [093af32]
1442
+ - Updated dependencies [1bd1be7]
1443
+ - Updated dependencies [d234fa9]
1444
+ - Updated dependencies [adf5812]
1445
+ - Updated dependencies [e36acd4]
1446
+ - Updated dependencies [5058336]
1447
+ - Updated dependencies [2f6b2bf]
1448
+ - Updated dependencies [2028b31]
1449
+ - Updated dependencies [63601ab]
1450
+ - Updated dependencies [c372b29]
1451
+ - Updated dependencies [152f0a7]
1452
+ - Updated dependencies [8693b85]
1453
+ - Updated dependencies [e82dad1]
1454
+ - Updated dependencies [58b7b3d]
1455
+ - Updated dependencies [84defab]
1456
+ - Updated dependencies [681d3f1]
1457
+ - Updated dependencies [969d4f2]
1458
+ - Updated dependencies [f3bc481]
1459
+ - Updated dependencies [b79aac2]
1460
+ - Updated dependencies [93fc0e7]
1461
+ - Updated dependencies [a4b723f]
1462
+ - Updated dependencies [2b10ca0]
1463
+ - Updated dependencies [7db4a81]
1464
+ - Updated dependencies [19a0b0e]
1465
+ - Updated dependencies [526fc11]
1466
+ - Updated dependencies [f8e3e9a]
1467
+ - Updated dependencies [b9d47ec]
1468
+ - Updated dependencies [3b6bc69]
1469
+ - Updated dependencies [6214db6]
1470
+ - Updated dependencies [6732df4]
1471
+ - Updated dependencies [fe9e0d0]
1472
+ - Updated dependencies [63fb72c]
1473
+ - Updated dependencies [804831c]
1474
+ - Updated dependencies [279e48e]
1475
+ - Updated dependencies [8700d6d]
1476
+ - Updated dependencies [8db2a0f]
1477
+ - Updated dependencies [689953a]
1478
+ - Updated dependencies [30443fb]
1479
+ - Updated dependencies [8d3dbb2]
1480
+ - Updated dependencies [efc1c9c]
1481
+ - Updated dependencies [da45e6b]
1482
+ - Updated dependencies [7533465]
1483
+ - Updated dependencies [835f0f3]
1484
+ - Updated dependencies [a9d97be]
1485
+ - Updated dependencies [ed35b44]
1486
+ - Updated dependencies [9ba7e9c]
1487
+ - Updated dependencies [729e851]
1488
+ - Updated dependencies [96919a4]
1489
+ - Updated dependencies [345e24a]
1490
+ - Updated dependencies [20b507a]
1491
+ - Updated dependencies [2e471dc]
1492
+ - Updated dependencies [6748587]
1493
+ - Updated dependencies [be50942]
1494
+ - Updated dependencies [775e079]
1495
+ - Updated dependencies [7e8b3c0]
1496
+ - Updated dependencies [53374dc]
1497
+ - Updated dependencies [f6fb83f]
1498
+ - Updated dependencies [2049b03]
1499
+ - Updated dependencies [7cbc724]
1500
+ - Updated dependencies [7098eed]
1501
+ - Updated dependencies [3df7c5c]
1502
+ - Updated dependencies [fb91ac9]
1503
+ - Updated dependencies [fb91ac9]
1504
+ - Updated dependencies [641fb55]
1505
+ - Updated dependencies [8524372]
1506
+ - Updated dependencies [7cbefa5]
1507
+ - Updated dependencies [72d6587]
1508
+ - Updated dependencies [a272a4f]
1509
+ - Updated dependencies [55f39ee]
1510
+ - Updated dependencies [0ce32d5]
1511
+ - Updated dependencies [0970a0e]
1512
+ - Updated dependencies [e427e9c]
1513
+ - Updated dependencies [bbc9dc3]
1514
+ - Updated dependencies [02f1813]
1515
+ - Updated dependencies [1ef89c0]
1516
+ - Updated dependencies [ba0b61a]
1517
+ - Updated dependencies [ba0b61a]
1518
+ - Updated dependencies [ac716ff]
1519
+ - Updated dependencies [f0f3cd5]
1520
+ - Updated dependencies [ab856ed]
1521
+ - Updated dependencies [20f3e65]
1522
+ - Updated dependencies [bbba098]
1523
+ - Updated dependencies [87af769]
1524
+ - Updated dependencies [3be720e]
1525
+ - Updated dependencies [43c0d17]
1526
+ - Updated dependencies [c3df43a]
1527
+ - Updated dependencies [d16d0e9]
1528
+ - Updated dependencies [bbe57fd]
1529
+ - Updated dependencies [272a530]
1530
+ - Updated dependencies [1779e8d]
1531
+ - Updated dependencies [f7fcc2c]
1532
+ - Updated dependencies [f0f4d6c]
1533
+ - Updated dependencies [4128188]
1534
+ - Updated dependencies [b253c4e]
1535
+ - Updated dependencies [78a9c67]
1536
+ - Updated dependencies [4a7ef0d]
1537
+ - Updated dependencies [4598f6d]
1538
+ - Updated dependencies [dea17b4]
1539
+ - Updated dependencies [89bb77a]
1540
+ - Updated dependencies [06611e4]
1541
+ - Updated dependencies [3939545]
1542
+ - Updated dependencies [66abbde]
1543
+ - Updated dependencies [dc3893d]
1544
+ - Updated dependencies [1bbaa16]
1545
+ - Updated dependencies [6ee259a]
1546
+ - Updated dependencies [7649f43]
1547
+ - Updated dependencies [e708426]
1548
+ - Updated dependencies [3b6d53b]
1549
+ - Updated dependencies [276d174]
1550
+ - Updated dependencies [2982ed9]
1551
+ - Updated dependencies [a8198de]
1552
+ - Updated dependencies [0c789a4]
1553
+ - Updated dependencies [05a49f2]
1554
+ - Updated dependencies [b234a84]
1555
+ - Updated dependencies [a78cd37]
1556
+ - Updated dependencies [5ea623e]
1557
+ - Updated dependencies [5eabe86]
1558
+ - Updated dependencies [ca5d671]
1559
+ - Updated dependencies [32bf2d6]
1560
+ - Updated dependencies [ff0c384]
1561
+ - Updated dependencies [af4fb29]
1562
+ - Updated dependencies [ff5ef1c]
1563
+ - Updated dependencies [befd40c]
1564
+ - Updated dependencies [9a97800]
1565
+ - Updated dependencies [6bca0e4]
1566
+ - Updated dependencies [81c0bc4]
1567
+ - Updated dependencies [3c76801]
1568
+ - Updated dependencies [60500cb]
1569
+ - Updated dependencies [2fcefb9]
1570
+ - Updated dependencies [b55a346]
1571
+ - Updated dependencies [065bba7]
1572
+ - Updated dependencies [dd19463]
1573
+ - Updated dependencies [6791717]
1574
+ - Updated dependencies [100547e]
1575
+ - Updated dependencies [6d1c155]
1576
+ - Updated dependencies [d7573b3]
1577
+ - Updated dependencies [bf3edfe]
1578
+ - Updated dependencies [2c8474c]
1579
+ - Updated dependencies [0e05aac]
1580
+ - Updated dependencies [ae61ad4]
1581
+ - Updated dependencies [5aed9e4]
1582
+ - Updated dependencies [83c77dc]
1583
+ - Updated dependencies [18a8e7d]
1584
+ - Updated dependencies [e7957ab]
1585
+ - Updated dependencies [f7e34ca]
1586
+ - Updated dependencies [e719ebd]
1587
+ - Updated dependencies [516583b]
1588
+ - Updated dependencies [f9e4f91]
1589
+ - Updated dependencies [6ef48b1]
1590
+ - Updated dependencies [fa429cf]
1591
+ - Updated dependencies [ed8df3e]
1592
+ - Updated dependencies [fe76ece]
1593
+ - Updated dependencies [8b446f5]
1594
+ - Updated dependencies [8e74b27]
1595
+ - Updated dependencies [7102b20]
1596
+ - Updated dependencies [8ebd57f]
1597
+ - Updated dependencies [617707a]
1598
+ - Updated dependencies [58770f3]
1599
+ - Updated dependencies [aefe428]
1600
+ - Updated dependencies [485f096]
1601
+ - Updated dependencies [7357447]
1602
+ - Updated dependencies [199d31b]
1603
+ - Updated dependencies [b655a9d]
1604
+ - Updated dependencies [3e01cb5]
1605
+ - Updated dependencies [7138bc1]
1606
+ - Updated dependencies [cef27e2]
1607
+ - Updated dependencies [4e8622b]
1608
+ - Updated dependencies [dffd752]
1609
+ - Updated dependencies [06973aa]
1610
+ - Updated dependencies [50798f3]
1611
+ - Updated dependencies [105f3c5]
1612
+ - Updated dependencies [3ccd9e8]
1613
+ - Updated dependencies [689b979]
1614
+ - Updated dependencies [c70f865]
1615
+ - Updated dependencies [e546222]
1616
+ - Updated dependencies [fd13f52]
1617
+ - Updated dependencies [d7bd274]
1618
+ - Updated dependencies [98c3a74]
1619
+ - Updated dependencies [ebce5a3]
1620
+ - Updated dependencies [fb336df]
1621
+ - Updated dependencies [9d9040d]
1622
+ - Updated dependencies [0fce2ef]
1623
+ - Updated dependencies [42df928]
1624
+ - Updated dependencies [0e2ddd4]
1625
+ - Updated dependencies [b7479ab]
1626
+ - Updated dependencies [9850c6e]
1627
+ - Updated dependencies [b2ea297]
1628
+ - Updated dependencies [5b5a5c3]
1629
+ - Updated dependencies [14582b8]
1630
+ - Updated dependencies [51e144e]
1631
+ - Updated dependencies [ab92940]
1632
+ - Updated dependencies [a691c0b]
1633
+ - Updated dependencies [0b1326d]
1634
+ - Updated dependencies [af3861f]
1635
+ - Updated dependencies [515f171]
1636
+ - Updated dependencies [1f4e029]
1637
+ - Updated dependencies [4f14ad7]
1638
+ - Updated dependencies [258d264]
1639
+ - Updated dependencies [cac64b3]
1640
+ - Updated dependencies [8033ad1]
1641
+ - Updated dependencies [fa140b8]
1642
+ - Updated dependencies [71cba28]
1643
+ - Updated dependencies [190fbd0]
1644
+ - Updated dependencies [c00bf28]
1645
+ - Updated dependencies [93127bd]
1646
+ - Updated dependencies [f2158ec]
1647
+ - Updated dependencies [759606e]
1648
+ - Updated dependencies [72ffc34]
1649
+ - Updated dependencies [a51fa0c]
1650
+ - Updated dependencies [51f3d8d]
1651
+ - Updated dependencies [bf28341]
1652
+ - Updated dependencies [78cbdb5]
1653
+ - Updated dependencies [b7543a9]
1654
+ - Updated dependencies [6c6cee7]
1655
+ - Updated dependencies [42887e0]
1656
+ - Updated dependencies [83fe6e7]
1657
+ - Updated dependencies [d1ab06f]
1658
+ - Updated dependencies [f90b8fb]
1659
+ - Updated dependencies [91783c4]
1660
+ - Updated dependencies [982885d]
1661
+ - Updated dependencies [dba7d84]
1662
+ - Updated dependencies [ca39427]
1663
+ - Updated dependencies [bd09957]
1664
+ - Updated dependencies [5a07e67]
1665
+ - Updated dependencies [2d36552]
1666
+ - Updated dependencies [45d8288]
1667
+ - Updated dependencies [490f482]
1668
+ - Updated dependencies [27308c5]
1669
+ - Updated dependencies [8689166]
1670
+ - Updated dependencies [c9327c9]
1671
+ - Updated dependencies [920165d]
1672
+ - Updated dependencies [9101be5]
1673
+ - Updated dependencies [f53a8d0]
1674
+ - Updated dependencies [968dc1e]
1675
+ - Updated dependencies [57f9b07]
1676
+ - Updated dependencies [3c73d99]
1677
+ - Updated dependencies [d91aed9]
1678
+ - Updated dependencies [ed71d9e]
1679
+ - Updated dependencies [7776fc2]
1680
+ - Updated dependencies [e76634c]
1681
+ - Updated dependencies [c86185e]
1682
+ - Updated dependencies [1170ed1]
1683
+ - Updated dependencies [92814db]
1684
+ - Updated dependencies [4d73b07]
1685
+ - @object-ui/react@17.7.0
1686
+ - @object-ui/core@17.7.0
1687
+ - @object-ui/types@17.7.0
1688
+ - @object-ui/components@17.7.0
1689
+
1690
+ ## 17.6.0
1691
+
1692
+ ### Minor Changes
1693
+
1694
+ - 88085e3: Consume the declared nav `runAction` slot; retire the private `?runAction=` string convention
1695
+
1696
+ An `object` navigation item can now declare `runAction: '<actionName>'` and the shell will run that action once on arrival at the object's list surface, through the ordinary execute path — so param dialogs, confirms and entitlement gates all still apply. The slot is `@objectstack/spec`'s `ObjectNavItemSchema.runAction`; objectui now reads it instead of a private convention.
1697
+
1698
+ - `NavigationItem` declares `runAction` (derived from the spec's object-nav variant), and objectui's own nav schema stops stripping it — `objectui validate` previously discarded the key, so an entry carrying a deep link validated clean with the deep link thrown away.
1699
+ - `resolveHref` encodes it onto the list href as the reserved `?runAction=` param, on the list landings only. A `recordId` entry resolves to a record page, which has no list toolbar to answer it, so the slot is not encoded there.
1700
+ - The deep link is honoured on **every** object list, not just the environments list. The action is armed only when it is actually present at `list_toolbar`; a name no action answers to runs nothing and deliberately leaves the URL untouched, so a later mount with fresher metadata can still honour it. Undefined references are rejected upstream at authoring time by `defineStack`.
1701
+ - The param name now has exactly one definition (`NAV_RUN_ACTION_PARAM`, exported from `@object-ui/layout`) and is registered in the console's reserved-param collision check. It was previously a bare literal hand-written at both the producing and consuming ends, declared by no schema and listed in no registry.
1702
+ - `CloudOnboardingNext` takes an optional `properties.createAction` (defaulting to `create_environment`) instead of hand-concatenating its deep link.
1703
+ - 86f633f: Remove the published optional key `logo` from `AppShellBranding` (`@object-ui/layout`).
1704
+
1705
+ The key was declared but never read. `useAppShellBranding` applies only
1706
+ `primaryColor`, `accentColor`, `favicon` and `title`, and `AppShell` installs no
1707
+ context provider at all — so its doc comment, "Logo URL — passed to sidebar/navbar
1708
+ via context", described a mechanism that did not exist. Three call sites were
1709
+ feeding the key a real value that was silently discarded, and all three are removed
1710
+ with it: `AppSchemaRenderer`, `ConsoleLayout` and the console's `useBranding` hook.
1711
+
1712
+ The real logo entry point is unchanged and is where it always was: the app schema's
1713
+ own `branding.logo`, read directly by `AppSidebar` in `@object-ui/app-shell`, plus
1714
+ the app schema's top-level `logo`, rendered directly by `AppSchemaRenderer`'s
1715
+ default sidebar header. Neither path went through `AppShellBranding`, so nothing
1716
+ rendering-visible changes.
1717
+
1718
+ Migration: a consumer that passes `logo` inside an `AppShellBranding` object literal
1719
+ now gets a compile error. Delete the key — it never reached a renderer. To show a
1720
+ logo, set it on the app schema's `branding.logo` instead.
1721
+ - 29167d5: **Breaking (shipped as `minor`, following the `page-header` `description` retirement):**
1722
+ `app-shell` is no longer a component key. `registerLayout()` registered `AppShell` under
1723
+ that key with no `inputs`; the registration is gone (objectui#4841, ADR-0049
1724
+ enforce-or-remove, remove side, maintainer ruling 2026-08-16).
1725
+
1726
+ **What it could never do.** Four of `AppShellProps`' seven keys are `React.ReactNode`
1727
+ slots — `sidebar`, `navbar`, `children`, `rightRail` — and a JSON document can fill none
1728
+ of them, so `{ "type": "app-shell" }` resolved to a component that had exactly two
1729
+ outcomes, neither of them a shell. `children` was dropped in silence: `SchemaRenderer`
1730
+ strips `children` (and `body`) before spreading a node's keys as props, and `AppShell`
1731
+ reads its `children` prop, never `schema.children`, so the `<main>` element rendered
1732
+ empty with nothing logged. A schema written into `sidebar` / `navbar` / `rightRail`
1733
+ arrived as a plain object React refuses to render, replacing the node with an error box.
1734
+ Only `className`, `defaultOpen` and `branding` ever survived the JSON path, i.e. the best
1735
+ result JSON could reach was a shell with no navigation, no top bar and an empty content
1736
+ area. With no `inputs` declared, `sdui-parser` had no declaration face to compare a node
1737
+ against either, so neither outcome was diagnosed.
1738
+
1739
+ **What changes for an author.** The middle state — parses, resolves, renders nothing — is
1740
+ replaced by a named refusal. `SchemaRenderer` now shows its `Unknown component type:
1741
+ app-shell` panel (`OBJUI-001`) and `sdui-parser` reports an `error`-severity
1742
+ `unknown-component` diagnostic before render.
1743
+
1744
+ **FROM → TO.** There is no in-place rewrite, because the node never produced a shell.
1745
+ Schema authors who want the whole shell from metadata use `app-schema-renderer`
1746
+ (`AppSchemaRenderer`), which declares its `inputs` and builds branding and sidebar
1747
+ navigation from an `AppSchema` document: `{ "type": "app-shell", … }` →
1748
+ `{ "type": "app-schema-renderer", "schema": { … } }`. Everyone else composes in React —
1749
+ `AppShell` is **unchanged and still exported** from `@object-ui/layout`, and remains the
1750
+ way to build a shell and render JSON pages inside it.
1751
+
1752
+ Repo-wide scan before removal found no `"type": "app-shell"` node anywhere in
1753
+ `objectstack-ai/objectui` or `objectstack-ai/objectstack` at `origin/main` — no example,
1754
+ catalog schema, fixture or template authored one. `content/docs/guide/layout.md` is
1755
+ updated to state the new fact, and
1756
+ `packages/layout/src/__tests__/app-shell-not-a-component-key.test.tsx` pins it on both
1757
+ faces (source and live registry) plus the rendered diagnostic.
1758
+ - 45f7dcc: **Breaking (shipped as `minor`, following the `app-shell` component-key deregistration):**
1759
+ `app-schema-renderer`'s `mobileNavMode` is now declared as the vocabulary the renderer
1760
+ implements — `enum: ['drawer', 'bottom_nav']` — instead of free-text `string`, and the
1761
+ third member of `MobileNavMode` is retired (objectui#3985, ADR-0049 enforce-or-remove,
1762
+ maintainer ruling 2026-08-10).
1763
+
1764
+ **What used to happen.** The registration declared `{ name: 'mobileNavMode', type:
1765
+ 'string' }`, so `sdui-parser`'s `checkType` asked only whether the value was a string.
1766
+ `mobileNavMode="bottom-nav"` — the hyphenated spelling of the underscored value, and the
1767
+ likeliest typo on this key — passed the manifest gate, passed the parser, reached the
1768
+ renderer, missed its one equality test, and rendered the drawer. Nothing reported
1769
+ anything, at any layer. The declaration was WIDER than the implementation, which is why
1770
+ the `invalid-enum` that should have fired never could.
1771
+
1772
+ **What happens now.** A value outside the vocabulary is an **error**-level `invalid-enum`
1773
+ from `validateTree` / `compile`, so a schema-driven author — very often an AI author — is
1774
+ stopped at the typo instead of debugging a mode that silently did nothing. The generated
1775
+ `sdui-intrinsics.d.ts` narrows from `mobileNavMode?: string` to the two-value union for
1776
+ the same reason.
1777
+
1778
+ **Retirement.** `MobileNavMode` had a third member documented as "collapsed sidebar" with
1779
+ **zero read points** in `AppSchemaRenderer`: the only two reads are the `drawer` default
1780
+ and the `=== 'bottom_nav'` comparison that gates the bottom bar, so the value was
1781
+ behaviourally identical to the default while the union, the JSDoc and `ROADMAP.md`
1782
+ presented it as a capability. It is gone from the union and from the published
1783
+ vocabulary. Making it real behaviour is an implementation card first — the value comes
1784
+ back together with a renderer read point, never as a declaration on its own.
1785
+
1786
+ **Migration.** Both implemented modes are unchanged; no runtime behaviour moves. A
1787
+ TypeScript caller passing the retired literal now fails to compile (it previously
1788
+ compiled and rendered the drawer), and a JSON/JSX author writing it — or any other
1789
+ out-of-vocabulary value — now gets a validation error where they previously got silence.
1790
+ In both cases the value that reproduces the old behaviour exactly is `drawer`.
1791
+ - f923b7c: **Breaking (shipped as `minor`, see below):** `@object-ui/layout`'s `<PageHeader>` retires the legacy `description` prop. `subtitle` is now the only spelling for the secondary line.
1792
+
1793
+ `PageHeader` read `subtitle ?? description`. The alias was not tolerance for a sloppy author — it was the only thing standing between an externally authored `description` and a page that renders its title and silently drops its second line, which is why objectui#3226 refused to delete it: "no in-repo author writes `description`" (true, verified) says nothing about the stored metadata of out-of-repo consumers.
1794
+
1795
+ **FROM → TO.** JSX call sites: `<PageHeader title="X" description="Y" />` → `<PageHeader title="X" subtitle="Y" />`. Schema authors: `{ "type": "page-header", "description": "Y" }` → `{ "type": "page-header", "subtitle": "Y" }`. Stored stack metadata needs no hand edit — `os migrate meta` rewrites it, and a protocol 17 loader rewrites it on the way in.
1796
+
1797
+ **Why the read could go now.** The normalization moved upstream, where a contract belongs: protocol 17's ADR-0087 D2 conversion `page-header-subtitle-alias` rewrites a header node's `properties.description` to `properties.subtitle` as the stack loads. The gate on this side was a measurement, not a date — every position a `page-header` node can occupy had to be shown to pass through that rewrite. It did not, at first: measured 2026-08-08 against `@objectstack/spec@17.0.0-rc.5`, the conversion walk reached `pages[].regions[].components[]` and stopped, leaving seven spec-valid header positions unconverted — including `slots.header` on a `kind: 'slotted'` record page, the shape this repo's own slotted-pages guide prescribes (objectstack#6775). With the walk widened by objectstack#6776 (slots) and objectstack PR #7034 (containers nested to any depth: `properties.children`, `items[].children`, `body`, `footer`), all seven convert. Re-measured against `@objectstack/spec@17.0.0-rc.6`, which this package depends on, before the read was deleted.
1798
+
1799
+ The measurement is now a standing pin rather than a one-off: `packages/layout/src/__tests__/page-header-subtitle-conversion-coverage.test.ts` re-runs all seven positions against the resolved spec build on every test run. If a future spec narrows that reach — or a dependency is pinned back below `17.0.0-rc.6` — it fails there, at the seam, instead of turning into a second line that quietly stops rendering in a consumer's app. The two tests in `page-header-authorable-keys.test.tsx` that pinned the fallback's continued existence were deleted in this same change, as their own SEQUENCING note instructed, and replaced with the opposite assertion: a lone `description` now renders no secondary line.
1800
+
1801
+ **Not affected, despite the shared word:** the `page` renderer's own `description` prop (the page's prose under the page title) is a live declared key of a different node, untouched here. `@object-ui/app-shell`'s separate `<PageHeader>` uses `description` as its only secondary-line prop and is likewise unchanged.
1802
+
1803
+ `minor` rather than `major` is deliberate and follows the repo's retirement precedent (PR #3793): all 39 publishable packages sit in one `fixed` group, so a `major` here would carry the whole family to 18.0.0 against an `@objectstack` still on 17 and break the "same major ⇒ compatible" pin between the two repos (AGENTS.md §版本号策略, enforced by `scripts/check-changeset-no-major.mjs`). objectui's own breaking changes ship as `minor` with the break spelled out in the body — which is what the FROM → TO above is.
1804
+ - 9c60144: **Breaking (published API):** `NavigationRenderer` no longer accepts `resolveGroupLabel` or `resolveItemLabel`. If your build just broke on one of these props, delete the prop — it never did anything.
1805
+
1806
+ Both were id-keyed label resolvers on `NavigationRendererProps` (`@object-ui/layout`), typically wired to `useObjectLabel().navGroupLabel` from `@object-ui/i18n` to translate sidebar group and leaf labels from a client translation pack keyed `{ns}.apps.{appName}.navigation.{nodeId}.label`.
1807
+
1808
+ **They could never fire.** The renderer guards convention-based resolution with `isCustomized` — a case-insensitive "the authored label differs from this branch's comparison target" test. On the `object` / `dashboard` branches the target is the object or dashboard name, and the test is meaningful: it protects an author's custom label (`Projects`) from being overwritten by an `objects.project.label` translation. On the two id-keyed branches the target was the nav node's own **`id`** — `grp_workspace`, `group_sales` — while the label was its text — `Workspace`, `Sales`. Those never compare equal, so the guard was true for every real navigation entry and the resolver beneath it was unreachable. The only node that could have reached it is one whose label is literally its own id.
1809
+
1810
+ Nothing regresses when they go, because nothing was using them to begin with: **app-navigation localization is owned solely by the server-side `/meta` boundary.** `translateApp` (`@objectstack/spec`, `src/system/i18n-resolver.ts`) rewrites every navigation node's `label` by id, and `@objectstack/rest` applies it before the metadata reaches the client — so nav labels arrive already localized and the client-side path was never the one answering. One owner, not two.
1811
+
1812
+ **If you wired these hooks to localize navigation, your labels were never being localized by them.** Move the translation to the server side: add it to the app's i18n bundle that `translateApp` reads, keyed by navigation node id. A client-side pack keyed `apps.*.navigation.*.label` changes nothing in the sidebar.
1813
+
1814
+ Also in this change:
1815
+
1816
+ - `useObjectLabel().navGroupLabel` (`@object-ui/i18n`) is **kept**, but its docstring no longer promises `"Sales" → "销售"` for sidebar groups — that promise was false, and a live docstring describing an unreachable path is how an agent or a developer ends up wiring a translation pack and receiving silent non-localization. It is now documented for what it is: a plain reader for `{ns}.apps.{appName}.navigation.{groupId}.label` with no first-party caller, pointing at the server boundary for anything nav-related.
1817
+ - `UnifiedSidebar` (`@object-ui/app-shell`) drops the two prop wirings, including a `studio` carve-out that existed only to stop `resolveItemLabel` from re-translating an already-translated "Package management" label.
1818
+ - The `object` / `dashboard` / `viewName` branches — `resolveObjectLabel`, `resolveDashboardLabel`, `resolveViewLabel` — are untouched and keep both their resolvers and the `isCustomized` guard.
1819
+
1820
+ ### Patch Changes
1821
+
1822
+ - d442795: AppShell: drop the unused `Sidebar` import. `AppShell` renders the node the caller passes
1823
+ in the `sidebar` prop and never constructs a `Sidebar` itself, so the import was dead
1824
+ (tree-shaken out of every bundle) and only suggested otherwise to readers. No runtime
1825
+ behaviour changes.
1826
+ - 8a9dece: `SidebarNav`'s README example teaches the shape the component actually reads.
1827
+
1828
+ `packages/layout/README.md` — the package's npm landing page, shipped in `files` —
1829
+ spelled every nav item `{ label, path, icon: 'home' }`. `NavItem` declares none of
1830
+ those three keys: the label is `title`, the target is `href`, and `icon` is a
1831
+ `React.ComponentType` rendered as `<item.icon />`, not an icon name. Copied
1832
+ verbatim the example produced a sidebar whose every row was unlabelled
1833
+ (`<span>{item.title}</span>` reading `undefined`), a `NavLink` with
1834
+ `to={undefined}`, and the string `'home'` handed to React as an unknown lowercase
1835
+ tag. Both README examples now use `title` / `href` / imported Lucide components,
1836
+ and annotate the array as `NavItem[]` so the same class of typo becomes a compile
1837
+ error where it is written instead of a blank sidebar at runtime.
1838
+
1839
+ Adds the props tables the README never carried — `SidebarNavProps`, `NavItem`
1840
+ (`badge`, `badgeVariant` and `children` included) and `NavGroup`, plus a grouped
1841
+ and nested example — and pins all of it rather than leaving a second surface free
1842
+ to rot the same way: the examples are real, type-checked code in
1843
+ `readme-sidebar-nav-example.test.ts` asserted to appear verbatim in the README, and
1844
+ the tables are compared against the interface keys read out of `SidebarNav.tsx` on
1845
+ every run. Also corrects a comment in `side-effects-manifest.test.ts` that named
1846
+ `SidebarNav` as the component behind the `navigation-renderer` registration; that
1847
+ key belongs to a different component, and `SidebarNav` is registered under no key
1848
+ at all.
1849
+
1850
+ No runtime change — `SidebarNav.tsx` is untouched. This is `patch` rather than a
1851
+ no-release declaration because the corrected landing page only reaches npm through
1852
+ a publish.
1853
+ - 183d09b: Studio 页面设计器不再为 canonical `page:header` 提供 `icon` 编辑框(objectui#3829)
1854
+
1855
+ `PageHeaderProps.icon` 已在 `@objectstack/spec` 17.0.0 随 ADR-0087 D2 退役
1856
+ (objectstack#6946 / PR objectstack#7115):canonical `page:header` 渲染器从未读过它,
1857
+ 表头的身份由 record chrome(`recordChrome`)与每个 action 自带的 `icon` 承担。退役前
1858
+ 作者填入的值被静默丢弃,退役后平台按名拒绝整个节点 —— 而设计器仍在提供那个输入框,
1859
+ 等于教作者写出解析失败的元数据。本次移除该字段与它此时已成孤儿的两条 i18n 键
1860
+ (en / zh 同一次改动,两张表的键集保持一致),并把「不得回潮」钉在
1861
+ `previews/__tests__/block-config.test.ts`。
1862
+
1863
+ `@object-ui/layout` 的 `page-header` / `layout:page-header` 别名**保留** `icon` 输入,
1864
+ 行为不变:那是另一个渲染器,它真读真画(`PageHeader.tsx`),文档与本仓唯一的活 demo
1865
+ 都写它。变的只是这条声明的**依据** —— 从 spec parity 改述为 renderer-read 事实,并让
1866
+ `page-header-authorable-keys` 守卫在派生 spec 键集时跳过墓碑成员,不再因为
1867
+ `Object.keys(shape)` 仍列着已退役的 `icon` 而假绿。
1868
+ - Updated dependencies [88085e3]
1869
+ - Updated dependencies [516663d]
1870
+ - Updated dependencies [460c4d0]
1871
+ - Updated dependencies [0ae27f7]
1872
+ - Updated dependencies [2533ec5]
1873
+ - Updated dependencies [78c0f9a]
1874
+ - Updated dependencies [bbe8b86]
1875
+ - Updated dependencies [8477be5]
1876
+ - Updated dependencies [279fb13]
1877
+ - Updated dependencies [2e82ab2]
1878
+ - Updated dependencies [ad07b65]
1879
+ - Updated dependencies [41f498b]
1880
+ - Updated dependencies [e1d4251]
1881
+ - Updated dependencies [40d3a33]
1882
+ - Updated dependencies [8b9dc62]
1883
+ - Updated dependencies [1184192]
1884
+ - Updated dependencies [a2a9747]
1885
+ - Updated dependencies [a1609a6]
1886
+ - Updated dependencies [53f23bc]
1887
+ - Updated dependencies [c4533dc]
1888
+ - Updated dependencies [be60815]
1889
+ - Updated dependencies [37f6844]
1890
+ - Updated dependencies [93de4f6]
1891
+ - Updated dependencies [2b50261]
1892
+ - Updated dependencies [384f30d]
1893
+ - Updated dependencies [ac600e5]
1894
+ - Updated dependencies [97fba31]
1895
+ - Updated dependencies [232f61a]
1896
+ - Updated dependencies [d374caf]
1897
+ - Updated dependencies [5673576]
1898
+ - Updated dependencies [c1ef923]
1899
+ - Updated dependencies [911ceaa]
1900
+ - Updated dependencies [98eab36]
1901
+ - Updated dependencies [af5e292]
1902
+ - Updated dependencies [3fbbea1]
1903
+ - Updated dependencies [7f96b10]
1904
+ - Updated dependencies [167ec42]
1905
+ - Updated dependencies [616a2a5]
1906
+ - Updated dependencies [0046d8f]
1907
+ - Updated dependencies [f1d4748]
1908
+ - Updated dependencies [b1119ec]
1909
+ - Updated dependencies [9f23d2b]
1910
+ - Updated dependencies [578e025]
1911
+ - Updated dependencies [af025ee]
1912
+ - Updated dependencies [598c89a]
1913
+ - Updated dependencies [4a0bd17]
1914
+ - Updated dependencies [b8b9af4]
1915
+ - Updated dependencies [31676be]
1916
+ - Updated dependencies [8c0d52e]
1917
+ - Updated dependencies [aff10e2]
1918
+ - Updated dependencies [70a774b]
1919
+ - Updated dependencies [9ce096f]
1920
+ - Updated dependencies [e05db88]
1921
+ - Updated dependencies [7458a41]
1922
+ - Updated dependencies [5ffcc14]
1923
+ - Updated dependencies [d971e51]
1924
+ - Updated dependencies [97abb24]
1925
+ - Updated dependencies [deb157a]
1926
+ - Updated dependencies [d2ce342]
1927
+ - Updated dependencies [9695da7]
1928
+ - Updated dependencies [75444e3]
1929
+ - Updated dependencies [58b8346]
1930
+ - Updated dependencies [2d0bd16]
1931
+ - Updated dependencies [dad51e5]
1932
+ - Updated dependencies [1c9c342]
1933
+ - Updated dependencies [787c738]
1934
+ - Updated dependencies [8396656]
1935
+ - Updated dependencies [dbbd38a]
1936
+ - Updated dependencies [93fe362]
1937
+ - Updated dependencies [dfc6975]
1938
+ - Updated dependencies [3cf4de0]
1939
+ - Updated dependencies [c9dc811]
1940
+ - Updated dependencies [144ef9b]
1941
+ - Updated dependencies [138ab04]
1942
+ - Updated dependencies [a0b9e91]
1943
+ - Updated dependencies [99bd015]
1944
+ - @object-ui/types@17.6.0
1945
+ - @object-ui/react@17.6.0
1946
+ - @object-ui/components@17.6.0
1947
+ - @object-ui/core@17.6.0
1948
+
3
1949
  ## 17.5.0
4
1950
 
5
1951
  ### Minor Changes