Skip to content

Commit 3e21cf0

Browse files
docs(spec): stop restating a plugin-local union's members, and name the mis-aimed nav-group case (#16958)
`AutomationResult.status`'s docblock carried a copy of plugin-approvals' `StrandedRunState` members (`'missing' | 'failed'`). That union has since split `'failed'` three ways, so the copy contradicted the type. Removed rather than refreshed: the union is plugin-local and the spec pin test excludes it on purpose, so a member list here is unpinned prose. `NavigationContributionSchema`'s JSDoc documented only the omitted-`group` case while the `.describe()` below it already named the mis-aimed one; the JSDoc now uses the same spelling. The `app-multi-package` fixture comment credited only `os build` for a finding both `os build` and `os validate` report. Card relationships are declared in the PR body, not here. Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x Co-authored-by: Claude <noreply@anthropic.com>
1 parent 22c0279 commit 3e21cf0

4 files changed

Lines changed: 36 additions & 11 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
Two spec docblocks now say what the tree does: `StrandedRunState` is no longer given a member list here, and the `navigationContributions[].group` JSDoc names the mis-aimed case (#16708, #16507)
6+
7+
**`contracts/automation-service.ts`** — the `AutomationResult.status` docblock explains why plugin-approvals' `StrandedRunState` is deliberately *not* promoted to this status, and it did so through a parenthetical copy of that union's members, `'missing' | 'failed'`. The plugin has since split `'failed'` into `'repairable'`, `'snapshot_dropped'` and `'unrepairable'` (the #15358 discriminator), so the copy described a shape the type contradicted — a spec docblock telling a reader the type cannot express a distinction the platform had already published. The copy is **removed rather than refreshed**: the union is plugin-local, is declared and documented member by member on the type itself, and `automation-result-status.pin.test.ts` excludes it from its pins *on purpose*, so any member list restated in this package is unpinned prose with nothing to keep it honest. The docblock now names where the members live instead of counting them.
8+
9+
**`ui/app.zod.ts`** — the JSDoc above `NavigationContributionSchema` documented only the case where `group` is **omitted**, while the `.describe()` a few lines below it (corrected in #14925) also names the case where `group` is **present and names no group the target app declares**. The two halves of one key's authoring-time documentation disagreed, and they disagreed on the case an author cannot detect from their own source — the target app belongs to another package. The JSDoc now carries that case in the spelling the `.describe()` and `content/docs/ui/setup-app.mdx` already use: not refused, items appended at the app top level anyway, a `nav_contribution_group_missing` diagnostic emitted by the runtime at `warn` and by `os build` and `os validate` at compile time.
10+
11+
Prose only, in both files. No type, no schema, no accept set and no exported name moves; nothing that reaches a generated artefact changed, so the reference pages, the authorable surface and the JSON-Schema manifest are byte-identical. The changeset exists because both strings **ship**: `src/**/*.zod.ts` is in this package's `files[]`, and both docblocks are emitted into the published `dist/*.d.ts`.
12+
13+
One private fixture comment rides along, outside any published package: `examples/app-multi-package/src/packages/orders/index.ts` credited only `os build` with the compile-time finding, where `findNavGroupDiagnostics` has been folded into both `os build` and `os validate` since #14920.

examples/app-multi-package/src/packages/orders/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ import { defineStack } from '@objectstack/spec';
4444
* ⚠️ `group` names `sales_group`, a container the CORE package declares. A
4545
* module cannot see that id at authoring time, and a typo in it does not fail:
4646
* the runtime RELOCATES the items to the app's top level and says so
47-
* (`nav_contribution_group_missing`, at `warn`), and `os build` reports the
48-
* same finding at compile time. This fixture is where that is measured — keep
49-
* the id spelled correctly here, so a build of this example stays clean and the
50-
* pin that typos it has something to differ from.
47+
* (`nav_contribution_group_missing`, at `warn`), and `os build` and
48+
* `os validate` report the same finding at compile time. This fixture is
49+
* where that is measured — keep the id spelled correctly here, so a build of
50+
* this example stays clean and the pin that typos it has something to differ
51+
* from.
5152
*/
5253
export default defineStack({
5354
manifest: {

packages/spec/src/contracts/automation-service.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,15 @@ export interface AutomationResult {
342342
* something to repair. This member is the ruling's contract half; the
343343
* engine begins stamping it when #13937's services half (the re-arm verb
344344
* and the catch-arm stamp in `resumeInternal`) lands. plugin-approvals'
345-
* `StrandedRunState` (`'missing' | 'failed'`) is a report-only label over
346-
* a request's run and is deliberately NOT promoted to this status (same
347-
* ruling): it classifies WHY a request's run is unrecoverable, this names
348-
* the run's own lifecycle verdict.
345+
* `StrandedRunState` is a report-only label over a request's run and is
346+
* deliberately NOT promoted to this status (same ruling): it classifies
347+
* WHY a request's run is unrecoverable, this names the run's own lifecycle
348+
* verdict. ⛔ Its members are deliberately NOT restated here: the union is
349+
* plugin-local — declared, and documented member by member, on the type
350+
* itself in `plugins/plugin-approvals/src/approval-service.ts` — and
351+
* `automation-result-status.pin.test.ts` excludes it from its pins on
352+
* purpose, so a member list copied into this file is unpinned prose that
353+
* goes stale the next time the plugin splits an arm.
349354
*
350355
* `'refused'` names the run that reached an `end` node declaring
351356
* `outcome: 'refused'` (#14945; maintainer ruling 2026-09-05, option 2′):

packages/spec/src/ui/app.zod.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -753,9 +753,15 @@ export const NavigationItemSchema: z.ZodType<NavigationItem, NavigationItemInput
753753
* The runtime merges all contributions into the owning app's `navigation`
754754
* tree by **target group id + priority** (lower priority applied first,
755755
* mirroring object extender ordering). When `group` is omitted the items are
756-
* appended at the app's top level. Contributed items keep the normal nav
757-
* gating fields (`requiresObject` / `requiredPermissions` / `visible`), so an
758-
* uninstalled capability simply contributes nothing and its slot stays empty.
756+
* appended at the app's top level. Naming a group the target app does not
757+
* declare is not refused either: the items are appended at the app top level
758+
* anyway and a `nav_contribution_group_missing` diagnostic is emitted — by the
759+
* runtime at `warn`, and by `os build` and `os validate` at compile time. That
760+
* second case is the one an author cannot detect from their own source,
761+
* because the target app belongs to another package. Contributed items keep
762+
* the normal nav gating fields (`requiresObject` / `requiredPermissions` /
763+
* `visible`), so an uninstalled capability simply contributes nothing and its
764+
* slot stays empty.
759765
*
760766
* @example
761767
* {

0 commit comments

Comments
 (0)