Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/nav-contribution-group-mis-aim-describe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@objectstack/spec": patch
---

`navigationContributions[].group` now documents the mis-aimed case, not only the omitted one (#14925)

The `describe()` on that key said what happens when `group` is **omitted** and nothing about what happens when it is **present and names no group the target app declares** — which is the case that actually bites. A contributing package cannot see the target app's group ids at authoring time (the target app belongs to another package), so a wrong id is undetectable by reading the contributor's own source; and the platform **relocates** the items to the app's top level rather than refusing them, so the menu renders, a smoke test passes, and the information architecture has silently changed.

The description now names that third case: it is **not refused**, the items are appended at the app top level anyway, and a `nav_contribution_group_missing` diagnostic is emitted — by the runtime at `warn`, and by **both** `os build` and `os validate` at compile time, in each command's `--json` payload under the existing `warnings` key.

Prose only. `group` remains `SnakeCaseIdentifierSchema.optional()`, the accept set is unchanged and nothing is refused that was not refused before; the recorded authorable key surface (`authorable-surface.json`) and the schema manifest (`json-schema.manifest.json`) are byte-identical. What moves is the string an author reads: the generated reference rows in `content/docs/references/ui/app.mdx` and `content/docs/references/kernel/manifest.mdx`, and the `description` on the published JSON Schemas that embed `NavigationContribution` (its own schema, the bundled `objectstack.json`, and 22 `json-schema/api/*` and `json-schema/kernel/*` package envelopes).
2 changes: 1 addition & 1 deletion content/docs/references/kernel/manifest.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ A navigation contribution: a package injecting nav items into an app it does not
| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **app** | `string` | ✅ | Target app name to contribute navigation into (e.g. "setup") |
| **group** | `string` | optional | Target group nav-item id to append into (e.g. "group_integrations"); omit to append at the app top level |
| **group** | `string` | optional | Target group nav-item id to append into (e.g. "group_integrations"); omit to append at the app top level. Naming a group the target app does not declare is not refused: the items are appended at the app top level anyway and a `nav_contribution_group_missing` diagnostic is emitted — by the runtime at `warn`, and by `os build` and `os validate` at compile time. |
| **priority** | `integer` | optional (default: `200`) | Merge priority within the target group — lower applied first (matches object extender priority) |
| **items** | `({ id: string; label: string \| Record<string, string>; icon?: string; order?: number; … } \| { type: 'separator'; id?: string; order?: number } \| … +7 more)[]` | ✅ | Navigation items contributed into the target app/group |

Expand Down
2 changes: 1 addition & 1 deletion content/docs/references/ui/app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ A navigation contribution: a package injecting nav items into an app it does not
| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **app** | `string` | ✅ | Target app name to contribute navigation into (e.g. "setup") |
| **group** | `string` | optional | Target group nav-item id to append into (e.g. "group_integrations"); omit to append at the app top level |
| **group** | `string` | optional | Target group nav-item id to append into (e.g. "group_integrations"); omit to append at the app top level. Naming a group the target app does not declare is not refused: the items are appended at the app top level anyway and a `nav_contribution_group_missing` diagnostic is emitted — by the runtime at `warn`, and by `os build` and `os validate` at compile time. |
| **priority** | `integer` | optional (default: `200`) | Merge priority within the target group — lower applied first (matches object extender priority) |
| **items** | `({ id: string; label: string \| Record<string, string>; icon?: string; order?: number; … } \| { type: 'separator'; id?: string; order?: number } \| … +7 more)[]` | ✅ | Navigation items contributed into the target app/group |

Expand Down
2 changes: 1 addition & 1 deletion packages/spec/src/ui/app.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ export const NavigationContributionSchema = lazySchema(() => strictObject(
},
{
app: SnakeCaseIdentifierSchema.describe('Target app name to contribute navigation into (e.g. "setup")'),
group: SnakeCaseIdentifierSchema.optional().describe('Target group nav-item id to append into (e.g. "group_integrations"); omit to append at the app top level'),
group: SnakeCaseIdentifierSchema.optional().describe('Target group nav-item id to append into (e.g. "group_integrations"); omit to append at the app top level. Naming a group the target app does not declare is not refused: the items are appended at the app top level anyway and a `nav_contribution_group_missing` diagnostic is emitted — by the runtime at `warn`, and by `os build` and `os validate` at compile time.'),
priority: z.number().int().min(0).default(200).describe('Merge priority within the target group — lower applied first (matches object extender priority)'),
items: z.array(NavigationItemSchema).describe('Navigation items contributed into the target app/group'),
}).describe('A navigation contribution: a package injecting nav items into an app it does not own (ADR-0029 D7)'));
Expand Down
Loading