Skip to content

docs(react-pages): state the html tier's registered-name rule and scope the PascalCase one - #13734

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-12650-html-tier-kebab-case
Aug 31, 2026
Merged

docs(react-pages): state the html tier's registered-name rule and scope the PascalCase one#13734
os-project-manager merged 1 commit into
mainfrom
claude/issue-12650-html-tier-kebab-case

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes #12650

What was wrong

content/docs/ui/react-pages.mdx is the documentation home for both source-authoring
tiers — content/docs/ui/pages.mdx sends the html-tier reader here for "the html and
react source-authoring tiers in full" — but everything from the security-gate section
down is react-tier material carrying no tier marker. The naming sentence was unqualified:

Blocks are referenced by the PascalCase form of their registered type: object-form
to ObjectForm, list-view to ListView, object-chart to ObjectChart.

So an author who reads the page top to bottom and then writes a kind:'html' page copies
ListView, is rejected at save time with "is not an allowed component", and finds nothing
on the page naming the rule they broke. The html-tier section already said "only tags in
the public block manifest are accepted" and "an unknown tag is a hard error at save time"
without ever saying how those tags are spelled — that is the exact gap.

Evidence from the registration code

The html tier's whitelist is the registry's own type names, compared by exact string:

  • packages/sdui-parser/src/index.tscompile() builds
    const allowedTags = new Set(Object.keys(manifest.components)).
  • packages/sdui-parser/src/index.tsmanifestFromConfigs() keys the manifest by the
    registry config's own type: components[c.type] = { type: c.type, ... }.
  • packages/sdui-parser/src/parse.ts:61 — the check is
    !this.opts.allowedTags.has(tag). An exact Set.has; there is no case folding
    anywhere in the parser, and the parsed node keeps type: tag verbatim.
  • sdui.manifest.json (objectui's registry-inputs dump, 57 components) — zero keys
    begin with an uppercase letter. list-view present, ListView absent; object-form
    present, ObjectForm absent.
  • packages/spec/src/ui/react-blocks.tsReactBlockDef.tag is documented as "PascalCase
    name the author writes in JSX" and schemaType as "The registry/render type, e.g.
    object-form". PascalCase is a react-tier projection, not a registered name.

Compiled against that real manifest (compile(source, sdui.manifest.json)):

tag in source ok diagnostic
ListView false ListView is not an allowed component
list-view true tag accepted
ObjectForm false ObjectForm is not an allowed component
object-form true tag accepted
RecordRelatedList false RecordRelatedList is not an allowed component
record:related_list tag accepted (fails later on a required prop, not on the tag)
flex true tag accepted

One correction to the card's wording

"kebab-case" is the shape of the plain block names but not the whole rule: 28 of the 57
registered names carry a namespace prefix (record:, page:, element:, action:), and
four are snake_case after the colon — record:related_list, record:line_items,
record:quick_actions, record:reference_rail. Writing only "kebab-case" would have sent
an author to record:related-list, which is not registered either. The page therefore says
registered type names, written verbatim, with kebab-case named as the shape and a
namespaced example shown.

The change

Two body edits, no restructuring of either tier section:

  1. The html-tier section gains one paragraph naming the registered spelling (with the
    plain, namespaced and layout-container examples) and naming the error a borrowed
    PascalCase tag produces.
  2. The react-tier naming sentence is scoped with "On this tier" and points at the html
    spelling.

Headings, frontmatter and every table are untouched — this stays clear of epic #12243's
content/docs/** frontmatter/headings slice.

Verification

pnpm check:doc-anchors, check:doc-authoring, check:docs-single-h1,
check:doc-frontmatter, check:react-page-adapter-contract and the rest of the derived
family: 25 GREEN, 0 RED, 1 NOT MEASURED, run at 6c5a1a754 (the final commit). The
26-family list came from node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
re-derived after the commit; NOT MEASURED is scripts/check-test-completeness.mjs, which
prints "PREREQUISITE NOT MET" because it grades a saved turbo run test log that no local
run produced — its own text says to record it as NOT MEASURED locally.

check:nul-bytes green (7572 files); the edited file also scanned directly for raw ASCII
control bytes, none found. The MDX itself compiles (@mdx-js/mdx compile() on the edited
file, frontmatter stripped, output 33002 chars) — worth checking because the added text puts
tag names with angle brackets and a colon inside inline code spans.

Declared narrowing — repo-wide ESLint. pnpm lint was not run whole. Measured instead:
eslint --no-inline-config --format json content/docs/ui/react-pages.mdx reports 1 entry,
0 errors, and its single message is "File ignored because no matching configuration was
supplied" — the population comes from ESLint's own config, not my guess, so this .mdx
path is outside the linted set entirely. The diff touches that one file and no ESLint
config, and no type-aware linting is involved, so no untouched file's verdict can move.

Not addressed here

Docs-only, so no changeset — the diff publishes nothing from any package, and the
skip-changeset label carries that (recent content/docs/**-only merges land the same
way). objectstack-ai/objectui#6598, the html-tier columns binding defect from the same
recon, is out of scope: this documents naming only and papers over nothing.


Generated by Claude Code

…pe the PascalCase one

The html tier's allowed tags are the registry's own type names: `compile()` in
`@objectstack/sdui-parser` builds its whitelist as `Object.keys(manifest.components)`
and `parse.ts` matches the tag against it by exact string, with no case folding. All
57 keys in `sdui.manifest.json` are lowercase — `list-view` is there, `ListView` is
not — so a PascalCase tag borrowed from the react tier is rejected at save time with
"is not an allowed component".

The page never said so. Its PascalCase sentence was unqualified while the page is
also the documentation home for the html tier, so an author reading top to bottom
had no way to learn the naming rule before hitting the error.

Two body edits, no restructuring:
- the html-tier section now names the registered spelling, including the namespaced
  and layout forms, and names the error a borrowed PascalCase tag produces;
- the react-tier sentence is scoped to that tier and points at the html spelling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 31, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Aug 31, 2026
@os-project-manager
os-project-manager marked this pull request as ready for review August 31, 2026 09:09
@os-project-manager
os-project-manager added this pull request to the merge queue Aug 31, 2026
Merged via the queue into main with commit 00a5e74 Aug 31, 2026
35 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-12650-html-tier-kebab-case branch August 31, 2026 09:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(react-pages): html tier requires kebab-case registered names (<list-view>) — PascalCase table reads as if it applies to both tiers

2 participants