From 6b366e0620635a7f64a369577e60ee65e76d398b Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Tue, 30 Jun 2026 12:00:06 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat(spec,lint):=20ADR-0081=20=E2=80=94=20k?= =?UTF-8?q?ind:'html'=20(rename)=20+=20trusted=20kind:'react'=20tier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - spec: PageSchema.kind gains 'html' (the renamed constrained tier; 'jsx' kept as a deprecated alias) and 'react' (trusted real-React, executed at render, host-capability gated). Completeness gate requires source for all three. - lint: validate-jsx-pages lints html/jsx; skips react (real JS, not constrained JSX). +tests. - examples: command-center page moves to kind:'html'. - docs: ADR-0081. Co-Authored-By: Claude Opus 4.8 --- .changeset/sdui-react-page-tier.md | 14 ++++ docs/adr/0081-trusted-react-page-tier.md | 65 +++++++++++++++++++ .../src/pages/command-center-jsx.page.ts | 9 +-- packages/lint/src/validate-jsx-pages.test.ts | 8 +++ packages/lint/src/validate-jsx-pages.ts | 15 +++-- packages/spec/src/ui/page.zod.ts | 21 ++++-- 6 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 .changeset/sdui-react-page-tier.md create mode 100644 docs/adr/0081-trusted-react-page-tier.md diff --git a/.changeset/sdui-react-page-tier.md b/.changeset/sdui-react-page-tier.md new file mode 100644 index 0000000000..f8980d7c2b --- /dev/null +++ b/.changeset/sdui-react-page-tier.md @@ -0,0 +1,14 @@ +--- +"@objectstack/spec": minor +"@objectstack/lint": minor +--- + +ADR-0081: split the AI page-authoring surface into honest tiers. + +- `PageSchema.kind` gains `'html'` and `'react'`. `'html'` is the constrained + parse-never-execute tier (the renamed `'jsx'`, kept as a deprecated alias); + `'react'` is the trusted real-React tier (executed at render by + `@object-ui/react-runtime`, gated behind a host capability, enterprise/private + only). The completeness gate now requires `source` for all three. +- `validate-jsx-pages` lints `html`/`jsx` (constrained parse) and intentionally + skips `react` (real JS, not constrained JSX). diff --git a/docs/adr/0081-trusted-react-page-tier.md b/docs/adr/0081-trusted-react-page-tier.md new file mode 100644 index 0000000000..a0b58d396f --- /dev/null +++ b/docs/adr/0081-trusted-react-page-tier.md @@ -0,0 +1,65 @@ +# ADR-0081: A trusted `kind:'react'` page tier — real React executed in the main tree, gated by a host capability; and renaming `kind:'jsx'` → `kind:'html'` + +**Status**: Proposed (2026-06-30) +**Deciders**: ObjectStack Protocol Architects +**Builds on**: [ADR-0080](./0080-ai-authored-ui-jsx-source.md) (AI authors a *constrained* JSX text, parsed-never-executed, into the SDUI tree; the component registry is the contract; capability ≠ contract), [ADR-0033](./0033-ai-assisted-metadata-authoring.md) (AI writes metadata via draft-gated `saveMetaItem` — the human-review boundary), [ADR-0077](./0077-authoring-surface-boundary-hook-flow-validation.md) (route by intent; verifiability tier = friction tier; **code is the flagged escape hatch**), [ADR-0078](./0078-no-silently-inert-metadata.md) (no silently-inert metadata). +**Consumers**: `@objectstack/spec` (`packages/spec/src/ui/page.zod.ts` — `kind` gains `'html'` and `'react'`; `'jsx'` kept as a deprecated alias), `@objectstack/lint` (`validate-jsx-pages` — lints `html`/`jsx`, **skips** `react`), `../objectui` `@object-ui/react-runtime` (**new** — the trusted runtime-React executor) + `@object-ui/core` (the host capability gate) + `@object-ui/components` (PageRenderer routing + the full HTML tag set). + +**Premise**: ADR-0080 shipped `kind:'jsx'` — a *constrained* JSX dialect parsed (never executed) into the SDUI tree. In practice that name oversold it: authors expected "JSX" to mean *any* HTML and *any* JavaScript (`useState`, `.map`, `onClick`), and the constrained, no-execution model categorically cannot do that. Two distinct things were conflated under one name. This ADR splits them: it makes the safe constrained tier **live up to a narrower, honest name (`html`)**, and adds a separate, explicitly-trusted **`react`** tier for the full-power case — available only where the operator accepts running author code. + +> **Trigger**: testing the merged `kind:'jsx'` feature, the author found it "名不副实" (misnamed) — basic HTML tags didn't render and scripts were impossible — and recognized that the real-React capability belongs behind a switch, enabled only in a trusted private/enterprise deployment where "running unsandboxed author code in the main React app" is an acceptable, deliberate trust decision. + +--- + +## TL;DR + +1. **[rename] `kind:'jsx'` → `kind:'html'`.** The constrained, parse-never-execute tier (ADR-0080) is renamed to match what it is: author-written **HTML + Tailwind** (expressed as constrained JSX) compiled to the SDUI tree. `'jsx'` stays as a **deprecated alias** (already-saved pages keep loading); all authored examples/docs move to `'html'`. +2. **[capability] The `html` tier now resolves the full safe native HTML tag set.** Previously only `div/span/table/code/label` + semantic sectioning tags were registered, so `

/

//