Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

examples/hello-world renders four OBJUI-001 panels: schema.json uses PascalCase types (Page/Card/Text/Button) and the registry lookup is case-sensitive #5236

Closed

Description

@os-support-ai

Found while measuring the judged-file corpus for #5127 (that card's marker measurement enumerates every in-repo JSON file with a root type). Outside that card's radius, not carried into its branch. Filed unassigned, not claiming.

Symptom

examples/hello-world/schema.json — the smallest example in the repo, the one a newcomer opens first — names every node in PascalCase:

{
  "type": "Page",
  "title": "Hello ObjectUI",
  "children": [
    {
      "type": "Card",
      "children": [
        { "type": "Text", "content": "Welcome to ObjectUI!" },
        { "type": "Text", "content": "This UI is rendered from a JSON schema." },
        { "type": "Button", "content": "Get Started", "variant": "default" }
      ]
    }
  ]
}

examples/hello-world/App.tsx renders it directly:

import { SchemaRendererProvider, SchemaRenderer } from '@object-ui/react';
import schema from './schema.json';
// ... SchemaRenderer schema={schema}

None of Page, Card, Text, Button is a registered key. The registered spellings are the lowercase page, card, text, button — all four are present in packages/cli/src/utils/known-schema-types.ts, which is derived from the registration calls themselves (#5115).

Why it does not resolve

packages/core/src/registry/Registry.ts resolves through plain Map lookups — this.components.get(namespacedType) / this.components.get(type) in get(), and the same in has() / getEntry(). There is no toLowerCase anywhere in packages/core/src/registry/, so lookup is case-sensitive and Page misses page. Every node falls through to the OBJUI-001 "Unknown component type" panel.

Independent corroboration from the CLI: objectui check over the repo emits Unknown schema type "Page" in examples/hello-world/schema.json today. It is one of only two real ObjectUI schema files in the whole repo that the command warns about (the other, examples/schema-catalog/src/schemas/core-schema-renderer/unknown-component-type.json, is a deliberate fixture) — so the warning has been on the console output all along, buried under 45 false positives from package.json (that is #5127).

Boundary against #5127

Independent. #5127 is about which files enter type judgement; this is a schema in the repo whose types are wrong whichever way that lands. Under every marker variant considered on #5127 this file stays judged (it carries children), so #5127 neither introduces nor hides it.

Prior art

Same failure shape as the closed #4061 (objectui init scaffolded an app whose registry was empty, so every node rendered "Unknown component type"). That one was fixed at the scaffold; this one is a committed example.

Direction, not prejudged

The obvious fix is to lowercase the four type values in examples/hello-world/schema.json. Worth deciding separately whether the registry should normalise case at lookup — that is a contract question (it would make Page and page the same key everywhere, and PascalCase is what a React-shaped mental model reaches for first), and the answer should not be inferred from this one example. Recommend fixing the example; file the registry-normalisation question on its own if it is wanted.

How to reproduce

With REPO the repository root:

cd "$REPO" && node packages/cli/dist/cli.js check | grep hello-world
grep -rn "toLowerCase" packages/core/src/registry/    # no hits: lookup is case-sensitive

Activity

  1. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    CollaboratorAuthor

    Claim: PM loop round 6
    Session: session_01RV6yuVCxymHYE16PL9vQkE
    Branch: claude/issue-5236-hello-world-lowercase-types
    Worktree: objectui-issue-5236
    Domain: repo:objectui (execution seat)
    File surface: examples/hello-world/schema.json, plus a test if one has a home. ⛔ OUT: packages/core/src/registry/** — see Zone 1. Also out: packages/auth + app-shell/providers (#5198), packages/cli (#5237), packages/plugin-grid (#5091, PR5241 open), content/docs/blocks/forms.mdx (#5229, dispatched this round).
    Container & model: S, mode:subagent, model: sonnet — four string literals with a clear right answer. The judgement was in the scoping, and it is already done below.
    Clause-②: no — it corrects an example to use registered spellings. Nothing about the accept set moves.
    Serial constraints cleared: nothing open touches examples/hello-world/**.

    Zone 1 — fix the example, ⛔ NOT the registry

    The card names the fork and I am ruling the scope, not the contract:

    > The obvious fix is to lowercase the four type values… Worth deciding separately whether the registry should normalise case at lookup — that is a contract question… Recommend fixing the example; file the registry-normalisation question on its own if it is wanted.

    Your card is the example. Lowercase Page / Card / Text / Button to the registered page / card / text / button.

    ⛔ Do not add toLowerCase (or any normalisation) to packages/core/src/registry/. That would make Page and page the same key everywhere, for every component, permanently — a contract change affecting every registered type, decided off one broken example. If you finish the example fix and think case-insensitive lookup is right, say so in your report and I will file it as its own decision card. Do not implement it.

    Premise — verify, and note the grep that misleads

    The card's reasoning is sound and I have no correction to it, but verify on the tree rather than trusting either of us:

    Independent corroboration you can run: objectui check already reports Unknown schema type "Page" in examples/hello-world/schema.json. It is one of only two real ObjectUI schema files in the whole repo the command warns about — buried until now under 45 false positives from package.json, which is #5127's defect, not this one.

    Note this file is also App.tsx's direct input (import schema from './schema.json'), so the render path is real, not hypothetical.

    Why this is worth a dev at all

    It is the smallest example in the repo — the one a newcomer opens first — and it renders four error panels instead of a hello-world. Same failure shape as the closed #4061, where objectui init scaffolded an app with an empty registry so every node rendered "Unknown component type". That one was fixed at the scaffold; this is the committed example that still does it.

    Tests

    Check whether examples/hello-world has any test harness at all before inventing one. If there is a natural home, pin that the example's node types are all registered keys — a check that reads the registry rather than restating the four strings, so the pin survives a rename. If there is no harness, do not build one for this: say so in the report, and rely on objectui check over the repo emitting no hello-world warning as the observable outcome. ⛔ Do not stand up test infrastructure for an example as a rider on a four-token fix.

    Either way, report the before/after of:

    node packages/cli/dist/cli.js check | grep hello-world
    

    (@object-ui/types must be built before the CLI — dist/cli.js imports its dist/zod/index.zod.js at load.)

    Gates

    Derive from your diff (scripts/pm/dispatch-gates.mjs is objectstack-only; here derive from .github/workflows + package.json). A changeset is likely not required — examples/** is not a published package — but run check-changeset-presence.mjs and report what it says rather than assuming either way.

    ⛔ Do not background a long check and end your turn.

    Deliver

    Draft PR against main, first body line Fixes #5236. Return the JSON report and post it as a comment whose first line is the literal <!-- os-dev-report --> marker.


    Generated by Claude Code

  2. added a commit that references this issue on Aug 18, 2026
    ec824f2
  3. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    CollaboratorAuthor

    <!-- os-dev-report -->
    {
    "issue": 5236,
    "status": "done",
    "branch": "claude/issue-5236-hello-world-lowercase-types",
    "pr": "#5244",
    "premise_still_valid": true,
    "summary": "Lowercased the four type values in examples/hello-world/schema.json (Page/Card/Text/Button -> page/card/text/button) to match the registered spellings, since Registry.ts does case-sensitive Map.get lookups. Did not touch packages/core/src/registry/** per Zone 1 scoping. Added examples/hello-world/schema.test.ts (no prior test harness existed for this example) that walks the schema's node types against the CLI's generated KNOWN_SCHEMA_TYPES list rather than restating the four strings, so the pin survives a rename.",
    "tests": "Built @object-ui/cli (and its dep closure via pnpm --filter '@object-ui/cli^...' build) before touching the CLI. Before: node packages/cli/dist/cli.js check | grep hello-world -> Unknown schema type \"Page\" in examples/hello-world/schema.json (plus the unrelated #5127 module/package.json false positive). After the fix: only the module line remains, no hello-world/schema.json warning. New test: pnpm exec vitest run examples/hello-world/schema.test.ts -> Test Files 1 passed (1), Tests 6 passed (6). Reverse-verified the test itself: reverted schema.json to PascalCase in-place and reran the same command -> 5 of 6 failed (node type \"Page\"/\"Card\"/\"Text\"/\"Text\"/\"Button\" is a registered component key), then restored the fix and reconfirmed 6/6 pass, before committing. Gates run at final commit ec824f2: node scripts/check-changeset-presence.mjs (no changeset owed - @object-ui/example-* is in .changeset/config.json's ignore list), node scripts/check-control-bytes.mjs (OK), node scripts/check-type-check-coverage.mjs (OK, @object-ui/example-hello-world stays validly NOT_COMPILED-exempt - no new build script or tsconfig.json), node scripts/check-phantom-dependencies.mjs, check-package-self-import.mjs, check-node-esm-load.mjs --specifiers-only (all clean), pnpm --filter @object-ui/example-hello-world lint (clean). content/docs component-type gates (doc-component-types.yml) don't apply - DOCS_ROOT is content/docs, not examples/. PR #5244 opened as draft; CI is in_progress as of report time (all checks completed so far are success, e.g. Control Byte Scan, Changeset Fixed Group Check, Doc Component Type Check, Build Docs, Skill Guide Path Check, Internal Docs Link Check); Test/Type Check/Lint/Changeset Declaration/Doc Snippet Type Check/Live E2E still in_progress. Not waited on further per dispatch instructions.",
    "open_questions": [
    {
    "question": "Should packages/core/src/registry/Registry.ts normalise case at lookup (so Page and page resolve the same)?",
    "options": [
    "A: Leave lookup case-sensitive (status quo) - keeps the registry a strict, single-spelling contract; authors get an immediate, unambiguous OBJUI-001/CLI-warning signal instead of silent aliasing.",
    "B: Normalise to lowercase at Registry.get/has/getEntry - matches the React-shaped mental model a newcomer reaches for first (PascalCase), and would have caught this exact example bug at the source instead of needing a fix-the-example patch."
    ],
    "recommendation": "A for now, per the card's explicit scoping - this is a contract change affecting every registered type across the whole stack and should be decided on its own evidence (e.g. how often newcomers actually hit this), not inferred from one broken example. Filing as its own decision card per the card's instruction, not implementing here."
    }
    ],
    "out_of_scope_findings": []
    }


    Generated by Claude Code

  4. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    CollaboratorAuthor

    {
    "issue": 5236,
    "status": "done",
    "branch": "claude/issue-5236-hello-world-lowercase-types",
    "pr": "#5244",
    "premise_still_valid": true,
    "summary": "Lowercased the four type values in examples/hello-world/schema.json (Page/Card/Text/Button -> page/card/text/button) to match the registered spellings, since Registry.ts does case-sensitive Map.get lookups. Did not touch packages/core/src/registry/** per Zone 1 scoping. Added examples/hello-world/schema.test.ts (no prior test harness existed for this example) that walks the schema's node types against the CLI's generated KNOWN_SCHEMA_TYPES list rather than restating the four strings, so the pin survives a rename.",
    "tests": "Built @object-ui/cli (and its dep closure via pnpm --filter '@object-ui/cli^...' build) before touching the CLI. Before: node packages/cli/dist/cli.js check | grep hello-world -> Unknown schema type \"Page\" in examples/hello-world/schema.json (plus the unrelated #5127 module/package.json false positive). After the fix: only the module line remains, no hello-world/schema.json warning. New test: pnpm exec vitest run examples/hello-world/schema.test.ts -> Test Files 1 passed (1), Tests 6 passed (6). Reverse-verified the test itself: reverted schema.json to PascalCase in-place and reran the same command -> 5 of 6 failed (node type \"Page\"/\"Card\"/\"Text\"/\"Text\"/\"Button\" is a registered component key), then restored the fix and reconfirmed 6/6 pass, before committing. Gates run at final commit ec824f2: node scripts/check-changeset-presence.mjs (no changeset owed - @object-ui/example-* is in .changeset/config.json's ignore list), node scripts/check-control-bytes.mjs (OK), node scripts/check-type-check-coverage.mjs (OK, @object-ui/example-hello-world stays validly NOT_COMPILED-exempt - no new build script or tsconfig.json), node scripts/check-phantom-dependencies.mjs, check-package-self-import.mjs, check-node-esm-load.mjs --specifiers-only (all clean), pnpm --filter @object-ui/example-hello-world lint (clean). content/docs component-type gates (doc-component-types.yml) don't apply - DOCS_ROOT is content/docs, not examples/. PR #5244 opened as draft; CI is in_progress as of report time (all checks completed so far are success, e.g. Control Byte Scan, Changeset Fixed Group Check, Doc Component Type Check, Build Docs, Skill Guide Path Check, Internal Docs Link Check); Test/Type Check/Lint/Changeset Declaration/Doc Snippet Type Check/Live E2E still in_progress. Not waited on further per dispatch instructions.",
    "open_questions": [
    {
    "question": "Should packages/core/src/registry/Registry.ts normalise case at lookup (so Page and page resolve the same)?",
    "options": [
    "A: Leave lookup case-sensitive (status quo) - keeps the registry a strict, single-spelling contract; authors get an immediate, unambiguous OBJUI-001/CLI-warning signal instead of silent aliasing.",
    "B: Normalise to lowercase at Registry.get/has/getEntry - matches the React-shaped mental model a newcomer reaches for first (PascalCase), and would have caught this exact example bug at the source instead of needing a fix-the-example patch."
    ],
    "recommendation": "A for now, per the card's explicit scoping - this is a contract change affecting every registered type across the whole stack and should be decided on its own evidence (e.g. how often newcomers actually hit this), not inferred from one broken example. Filing as its own decision card per the card's instruction, not implementing here."
    }
    ],
    "out_of_scope_findings": []
    }

    (Supersedes the previous comment on this issue, which mis-rendered the marker as escaped entities instead of the literal form.)


    Generated by Claude Code

  5. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    CollaboratorAuthor

    Cross-reference, posting the number now that it exists rather than leaving a forward reference: the registry-normalisation question is filed as #5247 — [Decision] Should component-registry lookup normalise case? Two measured instances of "every node renders Unknown component type", needs-user-decision with a four-prism block.

    That is the card's own instruction executed ("file the registry-normalisation question on its own if it is wanted"), and the dev reached the same conclusion independently rather than implementing it — correctly, since it is a contract change for every registered type across the stack.

    Two things I put in #5247 that are worth knowing here, because they cut against acting:

    1. Both measured instances are our own artifacts. objectui init scaffolds an app whose component registry is empty: generated src/App.tsx never imports @object-ui/components, so every node renders "Unknown component type" #4061 (the scaffold) and this card (the example) are things we wrote, each fixed at its source. That is measured authoring pull, not user pull — nobody should read "two instances" as evidence an outside author reached for PascalCase.
    2. My recommendation there is C, not B — keep lookup strict, but make the failure teach (Unknown component type 'Page' — did you mean 'page'?). What both instances actually cost was not that the wrong spelling failed; it was that the failure said nothing about the cause. C fixes that without making a second spelling permanently valid, and note that B would also make PAGE and pAge resolve — a typo class, not just a naming convention.

    This card (#5236) stays scoped to the example and closes on PR5244's merge.


    Generated by Claude Code

  6. added a commit that references this issue on Aug 18, 2026
    51e5e9d
  7. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    CollaboratorAuthor

    {
    "issue": 5236,
    "status": "done",
    "branch": "claude/issue-5236-hello-world-lowercase-types",
    "pr": "#5244",
    "premise_still_valid": true,
    "summary": "Lowercased the four type values in examples/hello-world/schema.json (Page/Card/Text/Button -> page/card/text/button) to match the registered spellings; Registry.ts does case-sensitive Map.get lookups so packages/core/src/registry/** was intentionally left untouched. Initially added examples/hello-world/schema.test.ts, but CI's Test (shard 4/4) failed a real assertion in scripts/tests/check-type-check-coverage.test.ts: the example has no src/ directory, so any test file in it is unconditionally 'outside src/' to that ledger, which then requires a tsconfig.test.json + type-check script the example deliberately does not have (the objectui#3968 hole). Removed the test per the PM's diagnosis and the dispatch's own pre-authorised fallback; the schema.json fix stands alone. Rebased onto current origin/main (two unrelated commits, #5242 and #5241/#5091, landed since the branch point; neither touches examples/hello-world or the coverage ledger) and force-pushed.",
    "tests": "Re-verified at final commit 13fe3d1 (rebased onto origin/main @ 61b097c). node packages/cli/dist/cli.js check | grep hello-world -> only Unknown schema type \"module\" in examples/hello-world/package.json (the pre-existing #5127 false positive); no hello-world/schema.json warning. pnpm exec vitest run scripts/__tests__/check-type-check-coverage.test.ts -> Test Files 1 passed (1), Tests 37 passed (37) (this is the gate that failed CI on the prior head; confirmed green with the test file removed). Also re-ran: pnpm --filter @object-ui/example-hello-world lint (clean), node scripts/check-changeset-presence.mjs (no changeset owed - @object-ui/example-* is ignore-listed), node scripts/check-control-bytes.mjs (OK), node scripts/check-type-check-coverage.mjs full run (OK, @object-ui/example-hello-world still validly NOT_COMPILED-exempt), check-phantom-dependencies.mjs, check-package-self-import.mjs, check-node-esm-load.mjs --specifiers-only (all clean). Fresh CI run started against 13fe3d1; every check that has completed so far is green (Doc Component Type Check, Control Byte Scan, Changeset Declaration, Skill Guide Path Check, Build Docs, Changeset Fixed Group Check, Internal Docs Link Check, label); Test shards/Type Check/Lint/Build & E2E/Doc Snippet Type Check/Live E2E still in_progress as of this report - not waited on further per dispatch instructions.",
    "open_questions": [
    {
    "question": "Should packages/core/src/registry/Registry.ts normalise case at lookup (so Page and page resolve the same)?",
    "options": [
    "A: Leave lookup case-sensitive (status quo) - keeps the registry a strict, single-spelling contract; authors get an immediate, unambiguous OBJUI-001/CLI-warning signal instead of silent aliasing.",
    "B: Normalise to lowercase at Registry.get/has/getEntry - matches the React-shaped mental model a newcomer reaches for first (PascalCase), and would have caught this exact example bug at the source instead of needing a fix-the-example patch."
    ],
    "recommendation": "A for now, per the card's explicit scoping - this is a contract change affecting every registered type across the whole stack and should be decided on its own evidence, not inferred from one broken example. Filing as its own decision card per the card's instruction, not implementing here."
    }
    ],
    "out_of_scope_findings": []
    }


    Generated by Claude Code

  8. added a commit that references this issue on Aug 23, 2026
    6b73232
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions