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:2741 — export 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:
- Correct the snippet in
actions.mdx to nest under list:, and consider marking the fence with an os:check marker so it cannot regress. - 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.
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 itspackages/spectype.The defect
content/docs/ui/actions.mdx:197-201teaches action-to-view binding with this snippet:rowActionsandbulkActionsareObjectListViewkeys, not container keys. A reader who copies this gets a parse-time rejection, becauseViewSchemais astrictObject(packages/spec/src/ui/view.zod.ts:2741—export const ViewSchema = lazySchema(() => strictObject({) and its authorable key set is exactly:name,label,object,list,form,listViews,formViews,protection(plus the_lock*/_package*/_provenancedoor keys)Verified against
packages/spec/authorable-surface/ui.json:ui/Viewresolves to['_lock', '_lockDocsUrl', '_lockReason', '_lockSource', '_packageId', '_packageVersion', '_provenance', 'form', 'formViews', 'label', 'list', 'listViews', 'name', 'object', 'protection']ui/ListViewcontains bothrowActionsandbulkActionsThe correct shape nests them one level down, under
list:(or alistViewsentry).Why this one is worth fixing rather than shrugging at
The docs already contradict themselves on it.
content/docs/ui/views.mdx:70-76ships aCallout 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 underlist,listViews, orformViews[...]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.
ViewSchemacarries aguidancemap that turns this error class into a helpful message, but it is keyed on['type', 'columns', 'data', 'viewKind', 'filters', 'sort']only.rowActions/bulkActionsare not in that list, so the author gets a bare unknown-key rejection without the "wrap it inlist:" 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.mdxhas 4 TypeScript fences and 0os:checkmarkers. 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:
actions.mdxto nest underlist:, and consider marking the fence with anos:checkmarker so it cannot regress.rowActions/bulkActionsto theguidancekey list inpackages/spec/src/ui/view.zod.tsso the runtime rejection names the remedy. That closes the whole class rather than this one page.Dedupe: searched the 30 open
findingissues and the 94 issues opened since 2026-08-21T02:00Z; nothing coversdefineViewcontainer nesting oractions.mdx.Audit-only card — filed unassigned, not graded or routed.