Uh oh!
There was an error while loading. Please reload this page.
docs(core,guide,plugins): name the shape eight props tables describe - #6168
Merged
Merged
Conversation
Eight property tables across seven pages never said what they described, so a reader could not reach the declaration behind them. Each now names its shape, following `api/schema-reference.md`'s `### TypeName` convention where the section documents exactly one shape, and with a lead sentence naming the shape and its declaring package where several grouped tables partition one shape. Every binding was made by READING the page and the declaration, not by a mechanical binder — an earlier mechanical pass bound 9 of 14 such tables to the wrong shape. - `core/app-schema.mdx` (two tables) - `AppComponentSchema` (`packages/types/src/app.ts`). - `core/report-schema.mdx` - `ReportComponentSchema` (`packages/types/src/reports.ts`), the name the page's own example imports. - `guide/notifications.md` - `NotificationSystemConfig` (`packages/react/src/context/NotificationContext.tsx`). This one REPLACES a name rather than adding one: the lead said "the spec `NotificationConfigSchema`", and `@objectstack/spec` declares no such symbol. - `plugins/plugin-charts.mdx` - `BarChartSchema`. - `plugins/plugin-editor.mdx` - `CodeEditorSchema`. - `plugins/plugin-markdown.mdx` - `MarkdownSchema`, qualified to the plugin's own copy because `@object-ui/types` declares the same name differently. - `plugins/plugin-report.mdx` - the spec's `Report` (`ReportSchema`). Ten further tables were left alone and reported instead: two describe an anonymous inline object, three sit on a name declared four times with disagreeing shapes, one is a keyboard-shortcut table and not a props table at all, two already name their shape, one describes an unnamed intersection declared at a registration site, and one has no candidate that agrees with it. No fenced block changed: the fenced-block extraction over all seven files is byte-identical before and after. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
This was referenced Aug 24, 2026
yinlianghui-tw
marked this pull request as ready for review
August 24, 2026 22:16
Uh oh!
There was an error while loading. Please reload this page.
yinlianghui-tw pushed a commit
that referenced
this pull request
Aug 24, 2026
The page asserted `FormField` is "declared once, in `@object-ui/types`". That is a closure claim and it is false: `@objectstack/spec` ships a same-named `FormField` in `json-schema/ui/FormField.json`. Qualify the name to the copy the page means, following the shape PR #6168 used for `MarkdownSchema` on plugin-markdown.mdx. The 21-row table is unchanged — it restates the `@object-ui/types` copy exactly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
yinlianghui-tw pushed a commit
that referenced
this pull request
Aug 24, 2026
The page called its subject `ReportSchema` in four prose/frontmatter sites while its own example fence, its property tables (PR #6168) and the actual declaration all say `ReportComponentSchema` (packages/types/src/reports.ts:359). `ReportSchema` is not a dead name: `@objectstack/spec` exports it for the dataset-bound report shape (json-schema/ui/Report.json — name / label / dataset / rows / columns / values), which is what content/docs/plugins/plugin-report.mdx documents. A reader following the old name landed on a real but wrong declaration. `@object-ui/types` already re-exports that spec symbol under the prefixed name `SpecReportSchema` "to avoid collision", so the prose was the last place using the bare name for the component shape. Prose and frontmatter only. No source change, no fence touched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #6086 — the card stays open for the deferred scoped-A
DeclaredKeyscomponent.Round 3 of #6086, executing the PM ruling. Two bounded deliverables: name the shape on the property tables that named none, and enumerate which restatements are spec-owned. No gate, no parser, no component — Option B is rejected and blanket A and C with it.
Why this is not "enabling the gate"
The gate is rejected. The justification for this change is narrower and stands on its own: a props table that never says what it describes is worse documentation on its own terms — a reader cannot reach the source of truth from it. So this optimises for reader clarity, not machine parseability. Preserved optionality is a side effect, not the reason.
1. The eight tables named — and what I read to bind each
Every binding was made by reading the page and the declaration. The mechanical binder from round 2 is not trustworthy here: hand audit found it wrong on 9 of 14 tables outside
api/schema-reference.md.content/docs/core/app-schema.mdxAppComponentSchemaimport type { AppComponentSchema } from '@object-ui/types'); declared atpackages/types/src/app.ts:355, and all 6 claimed keys are memberscontent/docs/core/app-schema.mdxAppComponentSchemalayoutis a membercontent/docs/core/report-schema.mdxReportComponentSchemaReportComponentSchema; declared atpackages/types/src/reports.ts:354, all 4 claimed keys are memberscontent/docs/guide/notifications.mdNotificationSystemConfigpackages/react/src/context/NotificationContext.tsx:215; its 7 members are the table's 5 rows plus the two legacy spellings the prose below the table already coverscontent/docs/plugins/plugin-charts.mdxBarChartSchemapackages/plugin-charts/src/types.ts:37, whose own JSDoc example is the page's fence; all 6 claimed keys are members (classNameviaBaseSchema)content/docs/plugins/plugin-editor.mdxCodeEditorSchemapackages/plugin-editor/src/types.ts:35; all 6 claimed keys are memberscontent/docs/plugins/plugin-markdown.mdxMarkdownSchemapackages/plugin-markdown/src/types.ts:15; both claimed keys are memberscontent/docs/plugins/plugin-report.mdxReport(ReportSchema)@objectstack/specshipsjson-schema/ui/Report.json; all 12 claimed keys are properties of it, and the page's own quick start callsdefineReportfrom@objectstack/spec/uiTwo of those need saying out loud:
guide/notifications.mdREPLACES a name rather than adding one. The lead read "NotificationProvider'sconfigis the specNotificationConfigSchema".@objectstack/specdeclares no such symbol — itsNotification*declarations areNotificationChannelSchema,NotificationPositionSchema,NotificationPreferencesSchema,NotificationSchema,NotificationSeveritySchema,NotificationTypeSchema, and no shipped JSON Schema carriesdefaultPositionorpauseOnHover. The shape that does declare those five keys isNotificationSystemConfigin@object-ui/react. Back this out if you would rather the wrong name stayed and the correction went to its own card.plugin-markdown.mdxnames an ambiguous identifier, so the sentence qualifies it:@object-ui/typesdeclares a differentMarkdownSchema(contentrequired, plussanitizeandcomponents) from the plugin's own. The page documents the plugin, so the naming points there and says so.Two shapes were applied deliberately rather than one: the
### TypeNameheading where the section documents exactly one shape (charts, editor, markdown), and a lead sentence naming the shape and its declaring package where several grouped tables partition one shape (app-schema, report-schema) or where the heading carries real information a type name would destroy (The authoring shape,Configuring the system). Renaming both ofapp-schema.mdx's group headings to### AppComponentSchemawould have produced duplicate anchors and deleted the grouping.No naming sentence asserts closure. Under the ruling's adopted definition, "declares a / b / c" would have converted eight honest subset tables into eight omission defects. Where the tables are subsets, the sentence says so.
2. Ten tables stopped and reported — no heading invented, no type minted
core/theme-schema.mdx:265Theme.borderRadiusis an anonymous inline object type (packages/types/src/theme.ts:173). Naming it needs minting a type.core/theme-schema.mdx:280Theme.shadowsis inline and anonymous (theme.ts:184).guide/flow-designer.md:51Key. A lexical false positive of the round-2 extractor; it restates no declared surface.plugins/plugin-chatbot.mdx:132packages/plugin-chatbot/src/renderer.tsx:62types the node asChatbotSchemaintersected with an anonymous object carryingshowTimestamp,userAvatarUrl,maxHeight,autoResponse,onSendand the rest.surfacecomes fromChatbotEnhancedProps.plugins/plugin-dashboard.mdx:295optionsDashboardWidgetOptionsSchema, and the table is deliberately the renderer read set, not the declared key set. Round 2 recorded this as unnamed; that was my error, caused by keying the resolver on JSON Schema file names (DashboardWidgetOptions.json) while the prose uses the zod export name.plugins/plugin-grid.mdx:102ListColumnis declared by@objectstack/spec/ui(ListColumnSchema)". Round 2 recorded this as unnamed; that was my error too — the mechanical binder attachedPaginationConfigand the audit recorded the rejection, not the reading.plugins/plugin-kanban.mdx:94KanbanSchemais declared twice with disagreeing shapes (packages/types/src/complex.ts:100vspackages/plugin-kanban/src/types.ts:61), and the table'slimitis on neither.plugins/plugin-kanban.mdx:103KanbanColumndeclared four times — #6155, left for triage. Three of the four are inside@object-ui/plugin-kanbanitself, so a package qualifier does not disambiguate it either.plugins/plugin-kanban.mdx:113KanbanCard, same four-way split, same reason.plugins/plugin-timeline.mdx:113TimelineSchema, and it disagrees on 7 of 8 rows: it declaresevents/orientation/position, the table listsvariant/items/dateFormat/timeScale/rowLabel/minDate/maxDate. The renderer reads that undeclared vocabulary throughBaseSchema's index signature. NamingTimelineSchemahere would have manufactured exactly the defect this card is about.⭐ Correction to the round-2 measurement: "18 tables name no shape at all" was two too high.
plugin-dashboard.mdx:295andplugin-grid.mdx:102both name their shape in prose; my round-2 hand audit recorded anullfor each because the mechanical binder's answer was wrong, which is not the same finding. The honest count is 16 tables that name no shape, of which 8 are named here and 8 could not be.3. The spec-owned enumeration — the candidate surface for the deferred component
Owner determined per shape, checking
@objectstack/spec's shipped JSON Schemas under both the shape name and its zod-export spelling (the suffix trap: spec'sReportSchemaships asReport.json). Of 55 bound restatements (8 inline enumerations, 43 key tables, 4 closure claims), 7 are spec-owned:DeclaredKeyscandidate?guide/layout.md:288PageHeaderPropsui/PageHeaderProps.jsonlayout/page-header.mdx:66PageHeaderPropsui/PageHeaderProps.jsondomain:uilane, ⛔ not touched hereplugins/plugin-grid.mdx:102ListColumnui/ListColumn.jsonplugins/plugin-report.mdx:45Reportui/Report.jsondescriptionplus 8 protection/provenance envelope keysplugins/plugin-grid.mdx:322PaginationConfigui/PaginationConfig.jsonshowSizeChanger"). A generated key list cannot express an absenceguide/slotted-pages.md:89RecordRelatedListPropsui/RecordRelatedListProps.jsonplugins/plugin-dashboard.mdx:295DashboardWidgetOptionsui/DashboardWidgetOptions.json⭐ Two results that bear on the deferred decision:
api/schema-reference.mdtables are@object-ui/types-owned, not spec-owned — every one resolves topackages/types/src/*, none to a spec JSON Schema. The ruling's "do not extend it toapi/schema-reference.md" is not merely a scope line: that page is not in the candidate surface at all. The one near miss wasActionSchema, where spec does shipui/Action.json— but the table's 17 rows match the@object-ui/typesdeclaration exactly (0 unmatched) and the spec shape on only 6 of 17, so it restates the types copy.guide/layout.mdis.md, and zero.mdpages incontent/docsuse JSX with no remark transclusion plugin configured — the same constraint round 2 measured. So scoped A reacheslayout/page-header.mdx,plugin-grid.mdxandplugin-report.mdxas-is, and needs a.mdanswer for the fourth.Verification
Round-2 sweep re-run, before and after — the only thing that moved is the count this change was meant to move:
S2 bound rises by exactly 8, the number named. A per-table diff of the binder output confirms exactly 8 rows changed and each binds to the shape I intended —
AppComponentSchema,AppComponentSchema,ReportComponentSchema,NotificationSystemConfig,BarChartSchema,CodeEditorSchema,MarkdownSchema,Report— and no other table's binding moved.The fenced-block population is byte-identical before and after, so the snippet gate's judged surface is untouched. Extraction of every fenced block from all 7 files at the merge-base versus at HEAD: 1268 lines each,
diffexit 0. Non-vacuity, because an empty diff proves nothing without a positive control: planting one line inside a fence in the base copy flipped that samediffto exit 1 and the marker appeared in the extraction; restoring undertrap ... EXIT INT TERMprintedTRAP_RESTORE_RAN, agrepfor the marker across the base copy andcontent/exits 1, and the identity reading returns.Gates, at the final commit
71c77888a,git status --porcelainempty, each exit code captured by redirecting before any pipe, each line quoted from the gate's own output:check-control-bytescheck-control-bytes: OK (scanned 5093 tracked text file(s); skipped 85 binary).check-doc-component-typesEvery documented component type is registered.check-doc-linksLinks are valid across 15 scan roots.check-doc-snippet-typesEvery covered documentation snippet compiles against the built types.(250 of 250 blocks judged, 0 failed)check-changeset-presenceNo source of a released package changed in this range, so no changeset is owed.check-doc-snippet-typeswas run for real, not narrowed away: its 20-package build was produced withturbo run build ... --concurrency=2as its workflow does, andpackages/fields/distandpackages/types/distwere confirmed present in this worktree before the gate ran.Root vitest, over every test file that mentions
content/docs— 33 files, the full population by that criterion, not a sample:Exit 0. Declared narrowing: the root suite was scoped to those 33 files. The population was derived by grep rather than assumed, and three of them read the pages this PR edits (
check-doc-links.test.ts,doc-version-claims.test.ts,owner-retired-contract-twins.test.ts). CI runs the whole farm regardless.⛔ Out of scope and untouched, as ordered:
guide/layout.md'sPageHeaderPropsdefect (#5923 / PR #6082, live on main),layout/page-header.mdx(#6083),api/schema-reference.md, #6155, and any gate, parser or component.Generated by Claude Code