From 3e094b774316ed59172dc470a054154d7cd4a870 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 07:52:09 +0000 Subject: [PATCH 1/2] docs: finish the ADR-0080 page-source styling retraction across the remaining 8 prose sites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADR-0080's 2026-06-30 header amendment (under ADR-0065, Accepted) retracted the "HTML + Tailwind" framing for a page's `source`: source is runtime metadata, the console's Tailwind is compiled at build time by scanning the console's own `src` with no safelist, so an authored utility class produces CSS only by coincidence and otherwise nothing, with no error anywhere. objectui#5461 corrected 3 sites; a multiline census finds 8 more. The tiers, parse-never-execute, the untrusted-author safety argument and the deprecated 'jsx' alias are all unchanged — only the styling primitive is corrected, to the wording already used by content/docs/guide/react-pages.md §Styling and by the `page-source-className-tailwind` rule in @objectstack/lint@11.5.0. Consumer-facing sites name the real primitive; the four source/test docstrings just drop the Tailwind half of the compound. CHANGELOG.md hits are untouched — immutable release history. --- content/docs/components/basic/div.mdx | 7 ++++++- content/docs/components/basic/span.mdx | 7 ++++++- .../div-deprecation-provenance.test.tsx | 2 +- .../span-deprecation-provenance.test.tsx | 2 +- .../src/renderers/basic/html-elements.tsx | 2 +- .../components/src/renderers/layout/page.tsx | 12 ++++++++--- packages/react-runtime/README.md | 21 +++++++++++++++++-- packages/sdui-parser/src/types.ts | 2 +- 8 files changed, 44 insertions(+), 11 deletions(-) diff --git a/content/docs/components/basic/div.mdx b/content/docs/components/basic/div.mdx index 6b177b59b4..efe1beaa3e 100644 --- a/content/docs/components/basic/div.mdx +++ b/content/docs/components/basic/div.mdx @@ -17,12 +17,17 @@ description: "Generic container element - use Shadcn components instead" The Div component is a generic container element. **It is now deprecated in favor of semantic Shadcn-based components** that provide better accessibility, consistency, and design system integration. **Scope of this deprecation: JSON-authored pages.** A `kind:'html'` page is written as -constrained JSX/Tailwind text that the engine compiles (parses, never executes) into +constrained JSX text that the engine compiles (parses, never executes) into nodes, tag name straight through — there, the plain box tag is part of that tier's own vocabulary and stays fully supported, because no other spelling of it exists for an author to migrate to. The dev-build deprecation notice is therefore reported for JSON-authored nodes only, and never for what the html tier compiled from its own source. +Styling on that tier is the blocks' own structured props (``, +``) plus a JSON `style` object — **not** Tailwind utility classes, which +produce no CSS at all when authored in page `source`. `os validate` reports that as +`page-source-className-tailwind`. See the React Pages guide, §Styling. + ## Migration Guide Instead of using `div`, use these Shadcn alternatives: diff --git a/content/docs/components/basic/span.mdx b/content/docs/components/basic/span.mdx index cf6a16199b..e9d449a328 100644 --- a/content/docs/components/basic/span.mdx +++ b/content/docs/components/basic/span.mdx @@ -19,12 +19,17 @@ import { DemoGrid } from '@/app/components/ComponentDemo'; The Span component is an inline container. **It is now deprecated in favor of semantic Shadcn-based components** that provide better accessibility and design system integration. **Scope of this deprecation: JSON-authored pages.** A `kind:'html'` page is written as -constrained JSX/Tailwind text that the engine compiles (parses, never executes) into +constrained JSX text that the engine compiles (parses, never executes) into nodes, tag name straight through — there, the plain inline tag is part of that tier's own vocabulary and stays fully supported, because no other spelling of it exists for an author to migrate to. The dev-build deprecation notice is therefore reported for JSON-authored nodes only, and never for what the html tier compiled from its own source. +Styling on that tier is the blocks' own structured props (``, +``) plus a JSON `style` object — **not** Tailwind utility classes, which +produce no CSS at all when authored in page `source`. `os validate` reports that as +`page-source-className-tailwind`. See the React Pages guide, §Styling. + ## Migration Guide Instead of using `span`, use these Shadcn alternatives: diff --git a/packages/components/src/__tests__/div-deprecation-provenance.test.tsx b/packages/components/src/__tests__/div-deprecation-provenance.test.tsx index 09cfe964fb..6f015e9fb3 100644 --- a/packages/components/src/__tests__/div-deprecation-provenance.test.tsx +++ b/packages/components/src/__tests__/div-deprecation-provenance.test.tsx @@ -9,7 +9,7 @@ /** * The `div` deprecation notice is scoped BY PROVENANCE (objectui#4000). * - * A `kind:'html'` page is authored as constrained JSX/Tailwind text that our own + * A `kind:'html'` page is authored as constrained JSX text that our own * parser compiles (never executes) into SDUI nodes, tag name straight through. * So an author writing the plain box tag in that tier gets a node the DEPRECATED * renderer serves — and the notice fired at them, recommending replacements that diff --git a/packages/components/src/__tests__/span-deprecation-provenance.test.tsx b/packages/components/src/__tests__/span-deprecation-provenance.test.tsx index d1ed7f423c..5d8df8b0aa 100644 --- a/packages/components/src/__tests__/span-deprecation-provenance.test.tsx +++ b/packages/components/src/__tests__/span-deprecation-provenance.test.tsx @@ -10,7 +10,7 @@ * The `span` deprecation notice is scoped BY PROVENANCE (objectui#4917, * applying the ruling made for `div` in objectui#4000). * - * A `kind:'html'` page is authored as constrained JSX/Tailwind text that our own + * A `kind:'html'` page is authored as constrained JSX text that our own * parser compiles (never executes) into SDUI nodes, tag name straight through. * So an author writing the plain inline tag in that tier gets a node the * DEPRECATED renderer serves — and the notice fired at them, recommending diff --git a/packages/components/src/renderers/basic/html-elements.tsx b/packages/components/src/renderers/basic/html-elements.tsx index bc57c508a7..5149d3dc4d 100644 --- a/packages/components/src/renderers/basic/html-elements.tsx +++ b/packages/components/src/renderers/basic/html-elements.tsx @@ -7,7 +7,7 @@ * * Safe native HTML element passthrough renderers (ADR: kind:'html'). * - * A `kind:'html'` page is authored as a constrained JSX/Tailwind string that is + * A `kind:'html'` page is authored as a constrained JSX string that is * PARSED (never executed) into the SDUI tree. For that tier to live up to its * name, the everyday HTML tags an author reaches for — headings, paragraphs, * lists, links, images, emphasis — must each resolve to a renderer (otherwise diff --git a/packages/components/src/renderers/layout/page.tsx b/packages/components/src/renderers/layout/page.tsx index eae4f5eed1..0c14df03c0 100644 --- a/packages/components/src/renderers/layout/page.tsx +++ b/packages/components/src/renderers/layout/page.tsx @@ -538,9 +538,15 @@ export const PageRenderer: React.FC<{ if (kind === 'react') { return ; } - // `kind:'html'` (formerly 'jsx') — author-written constrained JSX/HTML+Tailwind - // compiled (parsed, never executed) to a SchemaNode tree and rendered. The - // legacy 'jsx' value is still accepted as a deprecated alias. + // `kind:'html'` (formerly 'jsx') — author-written constrained JSX compiled + // (parsed, never executed) to a SchemaNode tree and rendered. The legacy + // 'jsx' value is still accepted as a deprecated alias. + // Styling on this tier is the blocks' own structured props + // (``, ``) plus a JSON `style` object — + // NOT Tailwind utility classes. `source` is runtime metadata, so the build's + // Tailwind scan never sees it and an authored class produces no CSS and no + // error anywhere; `os validate` reports `page-source-className-tailwind`. + // (ADR-0065; ADR-0080's 2026-06-30 amendment.) if (kind === 'html' || kind === 'jsx') { const src = (schema as { source?: string }).source ?? ''; const { tree, diagnostics } = compile(src, getJsxManifest()); diff --git a/packages/react-runtime/README.md b/packages/react-runtime/README.md index 0d5903e59d..705061bb09 100644 --- a/packages/react-runtime/README.md +++ b/packages/react-runtime/README.md @@ -14,8 +14,8 @@ lazy-load it behind a capability flag. > and everything in scope. It is not isolated, not restricted, and not > validated. Only run source you would run as first-party code. > -> For untrusted authors use **`kind:'html'`** instead: constrained JSX/HTML + -> Tailwind, parsed into a schema tree and never executed. See +> For untrusted authors use **`kind:'html'`** instead: constrained JSX, parsed +> into a schema tree and never executed. See > [React pages](../../content/docs/guide/react-pages.md). ## Installation @@ -86,6 +86,23 @@ that reads `scope.import`: Anything not provided there throws `Module not found`. +## Styling + +**Do not author Tailwind utility classes in page `source`** — on either tier. A +page's `source` is *runtime metadata*: the console's Tailwind is compiled at +build time by scanning the console's own `src`, and there is no safelist, so it +never sees your page. An authored utility class produces CSS only by coincidence +(when objectui already ships that exact class) and otherwise produces nothing, +with no error anywhere. `os validate` reports it as +`page-source-className-tailwind`, a warning on both tiers. (ADR-0065; ADR-0080's +2026-06-30 amendment.) + +Style a `kind:'react'` page with inline `style` objects, and a `kind:'html'` page +with the blocks' own structured props (``, ``) +plus a JSON `style` object. Colors on both tiers come from the theme as +`hsl(var(--token))`, so a page follows light/dark and whatever theme the +deployment installs. + ## Stable scope identity matters Every evaluation produces a **new** component function — a new element *type* — diff --git a/packages/sdui-parser/src/types.ts b/packages/sdui-parser/src/types.ts index 0f83034f73..78c9bac5d4 100644 --- a/packages/sdui-parser/src/types.ts +++ b/packages/sdui-parser/src/types.ts @@ -2,7 +2,7 @@ * ObjectUI — SDUI JSX-source parser (ADR-0080) * * Types shared by the constrained JSX-source compiler. The parser turns a - * constrained JSX/HTML+Tailwind *text* into the existing SDUI `SchemaNode` + * constrained JSX *text* into the existing SDUI `SchemaNode` * tree. It PARSES — it never executes. No `import`, no `eval`, no JS. */ From 4060df5238b5edad2cf045bf1c1a97d71b6da48e Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 07:59:46 +0000 Subject: [PATCH 2/2] changeset: patch @object-ui/react-runtime, sdui-parser and components for the prose retraction Each entry is justified against the package's BUILT artefact rather than assumed: the react-runtime README ships to npm, and the corrected headers of sdui-parser/src/types.ts and components/src/renderers/basic/html-elements.tsx both project verbatim into their published .d.ts files. --- ...e-source-tailwind-prose-retraction-5469.md | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .changeset/page-source-tailwind-prose-retraction-5469.md diff --git a/.changeset/page-source-tailwind-prose-retraction-5469.md b/.changeset/page-source-tailwind-prose-retraction-5469.md new file mode 100644 index 0000000000..f125f38941 --- /dev/null +++ b/.changeset/page-source-tailwind-prose-retraction-5469.md @@ -0,0 +1,51 @@ +--- +'@object-ui/react-runtime': patch +'@object-ui/sdui-parser': patch +'@object-ui/components': patch +--- + +Documentation no longer teaches the "JSX/HTML + Tailwind" framing for a page's +`source`, which ADR-0080's own 2026-06-30 header amendment (under ADR-0065, +Accepted) retracted. objectui#5461 corrected three sites; a multiline census +found eight more, in three spellings a line-oriented grep could not see. + +A page's `source` is *runtime metadata*. The console's Tailwind is compiled at +build time by scanning the console's own `src`, and there is no safelist, so it +never sees your page: an authored utility class produces CSS only by coincidence +(when objectui already ships that exact class) and otherwise produces nothing, +with no error anywhere. That is the ADR-0065 "works only by coincidence" failure +mode, and it is how a modal's `bg-black/50` backdrop reached production fully +transparent. `os validate` reports it as `page-source-className-tailwind`, a +warning on kinds `html`, `react` and `jsx`, shipped in `@objectstack/lint@11.5.0`. + +The tiers themselves are unchanged and every load-bearing claim survives — +parse-never-execute, the untrusted-author safety argument for `html`, and the +deprecated `'jsx'` alias. Only the styling primitive is corrected, to the wording +`content/docs/guide/react-pages.md` §Styling already uses: + +| `kind` | Style with | +|---|---| +| `"html"` | The blocks' own structured props (`` `` ``, `` `` ``) plus a JSON `style` object. | +| `"react"` | Inline `style` objects. | + +Colors on both tiers come from the theme as `hsl(var(--token))`. + +Why each package has an entry — each was measured against its built artefact, not +assumed: + +- **`@object-ui/react-runtime`**: `README.md` is published to npm (npm includes + `README.md` in the tarball regardless of `files`). Its "no sandbox" callout is + the paragraph that routes untrusted-author work to the `html` tier, and it + carried the retracted framing line-wrapped across `:17-18`. It also gains the + §Styling section it was missing — the absence is why the framing survived here. +- **`@object-ui/sdui-parser`**: the corrected header of `src/types.ts` projects + verbatim into the published `dist/types.d.ts`. +- **`@object-ui/components`**: the corrected header of + `src/renderers/basic/html-elements.tsx` projects verbatim into the published + `dist/renderers/basic/html-elements.d.ts`. The `kind === 'html'` dispatch-arm + comment in `src/renderers/layout/page.tsx` does **not** project (it is inside a + function body) and is included here only because the same package already owes + an entry. + +No behaviour change: this is prose only. `CHANGELOG.md` occurrences are +deliberately untouched — immutable release history.