…ariant from layout-dsl (objectstack-ai#8402)
The Tabs family in content/docs/protocol/objectui/layout-dsl.mdx taught four
keys that exist on no schema, plus a wrapper shape the form schema rejects.
Measured against packages/spec/authorable-surface/ (7840 authorable keys):
- `lazy` returns 0 hits across the ENTIRE authorable surface, not just ui.
Positive controls, same command shape: `source` 19, `badge` 8,
`badgeVariant` 8, `pagination` 2 - the instrument plainly sees keys.
(A bare grep for `lazy` in packages/spec/src/ui/view.zod.ts hits only the
`lazySchema` import helper - position, not count.)
- All 8 `badge` / `badgeVariant` entries are on NavItem surfaces
(ui/ObjectNavItem and siblings) - app navigation, never a form tab.
None of the 19 `source` entries is a tab or a section.
- ui/ViewTab declares exactly nine keys: filter, icon, isDefault, label,
name, order, pinned, view, visible - and it is a LIST view surface
(ListViewSchema.tabs / UserFiltersSchema.tabs), not a form surface.
- FormViewSchema.layout is a string enum (vertical/horizontal/inline/grid)
and FormViewSchema declares no `tabs` key at all, so the
`layout: {mode: tabbed, tabs: [...]}` wrapper was wrong independently of
the leaf keys. The real shape is `type: tabbed` + `sections`, each section
rendering as its own tab (defaultTab / tabPosition), as
content/docs/protocol/objectui/index.mdx and
examples/app-showcase/src/ui/views/task.view.ts already author it.
ViewTabSchema, FormViewSchema and FormSectionSchema are all strictObject, so
these were parse REJECTIONS, not silent strips.
Fixed by removal/rewrite following PR objectstack-ai#8301's shape on this same page,
including its "loud absence" style - never by widening a schema. The page's
internal inconsistency is gone as a side effect: its ## Performance section
stated an absence an earlier passage demonstrated as working syntax.
Claude-Session: https://claude.ai/code/session_01Jqe56GnYFddggeAyfkZFVz
Co-authored-by: Claude <noreply@anthropic.com>
Fixes #8251
What the page taught
content/docs/protocol/objectui/layout-dsl.mdxcarried a "Performance Considerations" section documenting section-levelvirtualScroll,itemHeight,lazyandsource, plus alayout.renderStrategy: progressiveblock. An author following it wrote metadata that is rejected at parse.Measurement
The instrument was shown to see real keys before any zero was trusted.
Generated authorable-surface anchor (
packages/spec/authorable-surface.base.json):ui/FormSectiondeclares exactly ten authorable keys —collapsed,collapsible,columns,description,fields,label,name,pane,visibleOn,visibleWhen. None of the documented keys is among them.itemHeight0 entries,renderStrategy0,lazy0. Positive control, same command shape:sourcereturns 20 entries andbadgeVariant8 — the instrument plainly sees keys.virtualScrollexists exactly twice, both on list views (ui/ListView,ui/ObjectListView) — a different surface from a form section.Empirical parse against the built spec (
FormSectionSchema.safeParse):lazy+sourceunrecognized_keys [lazy, source]virtualScroll+itemHeightunrecognized_keys [virtualScroll, itemHeight]unrecognized_keyseachFormSectionSchemais built withstrictObject=z.object(...).strict(), so the issue's hedge ("parse-strips or rejects, depending on the shape") resolves to rejects for this family.The fix
Removed the three phantom subsections. In their place, a
## Performancesection that states the absence and points at the one real, consumed switch — the booleanvirtualScrollon a list-shaped view. This mirrors the conventionwidget-contract.mdxalready uses for this exact defect class ("There is no performance block anywhere in this contract … That is the only virtual-scrolling switch objectui reads"), and satisfies "absence must be loud" rather than leaving a silent hole that invites the fiction back.Verified before pointing at it —
ListViewSchema.virtualScrollis authorable and really read by objectui:spec-bridge/bridges/list-view.ts:155,plugin-view/src/ObjectView.tsx:1053,app-shell/src/views/ObjectView.tsx:1745,plugin-list/src/ListView.tsx:1793.Not done, deliberately
domain:speccontract change with its own lane.DetailSectionvirtualScrollprop is NOT documented here. It is real (plugin-detail/src/DetailSection.tsx:90and:123) but no caller supplies it — notSectionGroup.tsx:55, nor any of the fourDetailView.tsxcall sites. Documenting an unsupplied prop would advertise a capability the runtime does not deliver.Gates
check:nul-bytes,check:docs-audit-scope,check:quick-reference-counts,check:role-word,check:doc-formula-expressions— all green locally. Re-derived withscripts/pm/dispatch-gates.mjsagainst the actual changed path: no delta from the dispatch list.Docs-only ⇒
skip-changeset, no changeset.Generated by Claude Code