Skip to content

[finding] docs/ui/actions.mdx puts rowActions/bulkActions at the defineView CONTAINER top level — strictObject rejects it, and views.mdx warns against exactly this shape #10578

Description

@os-elon

Found by the content/docs/** audit in #10564 (card 2/2, the build-an-app path). Mechanical pass: every authored top-level key in the four in-scope directories checked against its packages/spec type.

The defect

content/docs/ui/actions.mdx:197-201 teaches action-to-view binding with this snippet:

// List views — row and bulk menusdefineView({// ...rowActions: ['complete_task'],bulkActions: ['showcase_bulk_reassign'],});

rowActions and bulkActions are ObjectListView keys, not container keys. A reader who copies this gets a parse-time rejection, because ViewSchema is a strictObject (packages/spec/src/ui/view.zod.ts:2741export const ViewSchema = lazySchema(() => strictObject({) and its authorable key set is exactly:

name, label, object, list, form, listViews, formViews, protection (plus the _lock* / _package* / _provenance door keys)

Verified against packages/spec/authorable-surface/ui.json:

  • ui/View resolves to ['_lock', '_lockDocsUrl', '_lockReason', '_lockSource', '_packageId', '_packageVersion', '_provenance', 'form', 'formViews', 'label', 'list', 'listViews', 'name', 'object', 'protection']
  • ui/ListView contains both rowActions and bulkActions

The correct shape nests them one level down, under list: (or a listViews entry).

Why this one is worth fixing rather than shrugging at

The docs already contradict themselves on it.content/docs/ui/views.mdx:70-76 ships a Callout type="warn" about precisely this mistake class:

> Do not author a flat view object{ name: 'all_tasks', label: 'All Tasks', type: 'grid', columns: [...] } at the top level is not a view container. Nothing registers from it and no view appears in the switcher. Every view must live under list, listViews, or formViews [...]

So the module's view page warns against the shape that the module's action page demonstrates. The page that is wrong is the one a reader opens specifically to learn how to put an action on a list — actions.mdx, section "Bind it to the UI".

The schema's own remedy does not cover it.ViewSchema carries a guidance map that turns this error class into a helpful message, but it is keyed on ['type', 'columns', 'data', 'viewKind', 'filters', 'sort'] only. rowActions / bulkActions are not in that list, so the author gets a bare unknown-key rejection without the "wrap it in list:" prescription — the one case where the doc being wrong is not rescued by a good error message.

It survived because the fence is unchecked.content/docs/ui/actions.mdx has 4 TypeScript fences and 0 os:check markers. Across the four audited directories only 60 of 204 TS fences carry the marker; this snippet sits in the unchecked 144.

Suggested landing (hint for triage, not a routing decision)

Two independent fixes, either or both:

  1. Correct the snippet in actions.mdx to nest under list:, and consider marking the fence with an os:check marker so it cannot regress.
  2. Add rowActions / bulkActions to the guidance key list in packages/spec/src/ui/view.zod.ts so the runtime rejection names the remedy. That closes the whole class rather than this one page.

Dedupe: searched the 30 open finding issues and the 94 issues opened since 2026-08-21T02:00Z; nothing covers defineView container nesting or actions.mdx.

Audit-only card — filed unassigned, not graded or routed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions