From c352c0ae20e8558fe8572b04a1cfce615817c18f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 29 Sep 2026 06:33:53 +0000 Subject: [PATCH 1/2] feat(spec): register the ADR-0087 semantic entry ui-html-page-div-refused The protocol-18 step records the html-tier div refusal a manifest-less project meets once the CLI's JSX page gate reaches the manifest @objectstack/console ships: box for a plain wrapper, and how to prove the rewrite done. registry.ts regenerated by gen:migration-registry; spec-changes.json and the upgrade guide regenerate byte-identical, because step 18 is above the current protocol major. Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1 Co-authored-by: Claude --- .changeset/20592-ui-html-page-div-refused.md | 24 ++++++++ .../semantic/18.ui-html-page-div-refused.ts | 56 +++++++++++++++++++ packages/spec/src/migrations/registry.ts | 52 +++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 .changeset/20592-ui-html-page-div-refused.md create mode 100644 packages/spec/src/migrations/entries/semantic/18.ui-html-page-div-refused.ts diff --git a/.changeset/20592-ui-html-page-div-refused.md b/.changeset/20592-ui-html-page-div-refused.md new file mode 100644 index 00000000000..04e67e23786 --- /dev/null +++ b/.changeset/20592-ui-html-page-div-refused.md @@ -0,0 +1,24 @@ +--- +'@objectstack/spec': patch +--- + +feat(spec): the protocol-18 migration step records the html-tier `div` refusal as the semantic entry `ui-html-page-div-refused` (#20592) + +Clause-②: no + +`MIGRATIONS_BY_MAJOR[18].semantic` gains one entry, `ui-html-page-div-refused`. +It records the narrowing `@objectstack/cli` takes on when its JSX page gate +reaches the SDUI component manifest that `@objectstack/console` ships: a project +with no `sdui.manifest.json` of its own has its `kind: 'html'` pages checked +against that manifest, which does not declare `div`, so `objectstack validate`, +`compile` and `lint` refuse a `div` there (`jsx-forbidden-tag`, +`jsx-unknown-component`). The entry prescribes `box` for a plain wrapper, names +the layout containers to reach for instead only when their layout is wanted, and +says how to prove the rewrite done. + +What moves for a consumer of this package: `MIGRATIONS_BY_MAJOR` carries the +entry, and `objectstack migrate meta` prints it for a range that reaches +protocol 18. Nothing else does. The protocol-18 step is not cut yet, so +`spec-changes.json` and the protocol upgrade guide, which project the steps up +to the current protocol major, are unchanged, and no schema accepts or refuses +anything it did not before. diff --git a/packages/spec/src/migrations/entries/semantic/18.ui-html-page-div-refused.ts b/packages/spec/src/migrations/entries/semantic/18.ui-html-page-div-refused.ts new file mode 100644 index 00000000000..63f8b8df74a --- /dev/null +++ b/packages/spec/src/migrations/entries/semantic/18.ui-html-page-div-refused.ts @@ -0,0 +1,56 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +import type { SemanticMigration } from '../../types.js'; + +// #20592 — the D3 record of the accept-set narrowing the CLI's JSX page gate +// takes on when its console-manifest fallback becomes reachable (#19922): a +// project with no `sdui.manifest.json` of its own has its `kind:'html'` pages +// checked against the manifest `@objectstack/console` ships, which does not +// declare `div`. The vocabulary is ruling A on #20112 (record 5852014527): an +// html page may author the intrinsic tags its renderer registers, the published +// manifest declares that set, and `div` stays deprecated in favour of `box` — +// the console's own html compile refuses it too since objectui#10808. No D2 +// conversion and no tombstone: the tag sits inside an authored JSX string, which +// no conversion rewrites and no schema key can tombstone, so this entry is the +// migration channel beside the changeset's FROM → TO table. +export const entry: SemanticMigration = { + id: 'ui-html-page-div-refused', + // No backticks and no pipes in `surface` — build-upgrade-guide.ts renders it + // inside a code span. + surface: + "kind:'html' page source (and its deprecated kind:'jsx' alias) in a project with no " + + 'sdui.manifest.json of its own — the div tag, and any other tag or prop the SDUI ' + + 'component manifest shipped in @objectstack/console does not declare', + replacement: + '`box` for a plain wrapper — the one drop-in swap: the same element, your `className` ' + + 'verbatim, the same children, and no layout of its own. Reach for `card`, `flex`, ' + + '`container`, `stack` or `grid` only where you want their layout. For any other tag or ' + + 'prop the command names, a component and prop the manifest declares; the file is ' + + '`dist/sdui.manifest.json` inside `@objectstack/console`.', + reason: + 'An html page\'s source is a JSX string, not a keyed document: `objectstack migrate meta` ' + + 'rewrites stored metadata by key and cannot rewrite a tag inside authored source, so the ' + + 'move is by hand, and which wrapper keeps a page\'s layout is the author\'s call. ' + + '`objectstack validate`, `objectstack compile` (which `dev` and `start` run first) and ' + + '`objectstack lint` check that source against an SDUI component manifest: the ' + + '`sdui.manifest.json` in the directory the command runs in, then the copy ' + + '`@objectstack/console` ships. The second lookup asked for a file the console package ' + + 'does not export, so it always failed, and a project without its own manifest had its ' + + 'html pages checked at parse level only — syntax and structure, never which components ' + + 'and props they use. It now reaches the shipped copy. That manifest declares the html ' + + 'tier\'s intrinsic tags but not `div`: the maintainer ruled (2026-09-27) that an html page ' + + 'may author the intrinsic tags its renderer registers and that the published manifest ' + + 'declares that set, while `div` stays deprecated in favour of `box`, and the console\'s ' + + 'own html-page compile refuses `div` the same way. A `div` in such a page, which used to ' + + 'pass unchecked, now fails the command with `jsx-forbidden-tag` and ' + + '`jsx-unknown-component`. A project that keeps its own `sdui.manifest.json` is checked ' + + 'against that file, as before.', + acceptanceCriteria: + '`objectstack validate` reports no `jsx-forbidden-tag`, `jsx-unknown-component` or ' + + '`jsx-unknown-prop` finding on any `kind:\'html\'` page and prints no ' + + '`sdui/jsx-parse-level-only` notice — that notice means the component check did not run, ' + + 'so a clean result beside it proves nothing; `objectstack compile` and `objectstack lint` ' + + 'agree. No html page source authors `div`, and in the console each rewritten page renders ' + + 'with no compile error. The platform\'s own reference is the showcase app\'s three html ' + + 'pages, which author their wrappers as `box` and pass with zero findings.', +}; diff --git a/packages/spec/src/migrations/registry.ts b/packages/spec/src/migrations/registry.ts index 8ff375ba697..ac898834c6b 100644 --- a/packages/spec/src/migrations/registry.ts +++ b/packages/spec/src/migrations/registry.ts @@ -17147,6 +17147,58 @@ const step18: MigrationStep = { + 'authoring-path save (zero such documents were measured to exist); on refusal the ' + 'author re-gates by record state or moves the gate to an app surface.', }, + // #20592 — the D3 record of the accept-set narrowing the CLI's JSX page gate + // takes on when its console-manifest fallback becomes reachable (#19922): a + // project with no `sdui.manifest.json` of its own has its `kind:'html'` pages + // checked against the manifest `@objectstack/console` ships, which does not + // declare `div`. The vocabulary is ruling A on #20112 (record 5852014527): an + // html page may author the intrinsic tags its renderer registers, the published + // manifest declares that set, and `div` stays deprecated in favour of `box` — + // the console's own html compile refuses it too since objectui#10808. No D2 + // conversion and no tombstone: the tag sits inside an authored JSX string, which + // no conversion rewrites and no schema key can tombstone, so this entry is the + // migration channel beside the changeset's FROM → TO table. + { + id: 'ui-html-page-div-refused', + // No backticks and no pipes in `surface` — build-upgrade-guide.ts renders it + // inside a code span. + surface: + "kind:'html' page source (and its deprecated kind:'jsx' alias) in a project with no " + + 'sdui.manifest.json of its own — the div tag, and any other tag or prop the SDUI ' + + 'component manifest shipped in @objectstack/console does not declare', + replacement: + '`box` for a plain wrapper — the one drop-in swap: the same element, your `className` ' + + 'verbatim, the same children, and no layout of its own. Reach for `card`, `flex`, ' + + '`container`, `stack` or `grid` only where you want their layout. For any other tag or ' + + 'prop the command names, a component and prop the manifest declares; the file is ' + + '`dist/sdui.manifest.json` inside `@objectstack/console`.', + reason: + 'An html page\'s source is a JSX string, not a keyed document: `objectstack migrate meta` ' + + 'rewrites stored metadata by key and cannot rewrite a tag inside authored source, so the ' + + 'move is by hand, and which wrapper keeps a page\'s layout is the author\'s call. ' + + '`objectstack validate`, `objectstack compile` (which `dev` and `start` run first) and ' + + '`objectstack lint` check that source against an SDUI component manifest: the ' + + '`sdui.manifest.json` in the directory the command runs in, then the copy ' + + '`@objectstack/console` ships. The second lookup asked for a file the console package ' + + 'does not export, so it always failed, and a project without its own manifest had its ' + + 'html pages checked at parse level only — syntax and structure, never which components ' + + 'and props they use. It now reaches the shipped copy. That manifest declares the html ' + + 'tier\'s intrinsic tags but not `div`: the maintainer ruled (2026-09-27) that an html page ' + + 'may author the intrinsic tags its renderer registers and that the published manifest ' + + 'declares that set, while `div` stays deprecated in favour of `box`, and the console\'s ' + + 'own html-page compile refuses `div` the same way. A `div` in such a page, which used to ' + + 'pass unchecked, now fails the command with `jsx-forbidden-tag` and ' + + '`jsx-unknown-component`. A project that keeps its own `sdui.manifest.json` is checked ' + + 'against that file, as before.', + acceptanceCriteria: + '`objectstack validate` reports no `jsx-forbidden-tag`, `jsx-unknown-component` or ' + + '`jsx-unknown-prop` finding on any `kind:\'html\'` page and prints no ' + + '`sdui/jsx-parse-level-only` notice — that notice means the component check did not run, ' + + 'so a clean result beside it proves nothing; `objectstack compile` and `objectstack lint` ' + + 'agree. No html page source authors `div`, and in the console each rewritten page renders ' + + 'with no compile error. The platform\'s own reference is the showcase app\'s three html ' + + 'pages, which author their wrappers as `box` and pass with zero findings.', + }, // The sibling axis of `ui-list-view-grouping-field-padded-refused` (#17360), // which scoped this one out by name. Same defect, same refusal, one difference // that changes the author's options: `kanban.groupByField` is REQUIRED, so a From 95ae699a5bb78a0cf6e11f687b08d63c459d484b Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 29 Sep 2026 06:54:09 +0000 Subject: [PATCH 2/2] docs(changeset): say migrate meta prints the entry by default Its default range runs to the chain terminus, protocol 18, so the entry reaches authors through migrate meta now; only the upgrade guide and spec-changes.json wait for the protocol major. Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1 Co-authored-by: Claude --- .changeset/20592-ui-html-page-div-refused.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.changeset/20592-ui-html-page-div-refused.md b/.changeset/20592-ui-html-page-div-refused.md index 04e67e23786..edf3e9d1b22 100644 --- a/.changeset/20592-ui-html-page-div-refused.md +++ b/.changeset/20592-ui-html-page-div-refused.md @@ -17,8 +17,8 @@ the layout containers to reach for instead only when their layout is wanted, and says how to prove the rewrite done. What moves for a consumer of this package: `MIGRATIONS_BY_MAJOR` carries the -entry, and `objectstack migrate meta` prints it for a range that reaches -protocol 18. Nothing else does. The protocol-18 step is not cut yet, so -`spec-changes.json` and the protocol upgrade guide, which project the steps up -to the current protocol major, are unchanged, and no schema accepts or refuses -anything it did not before. +entry, and `objectstack migrate meta` prints it, because its default range +already runs to protocol 18, the highest major with a step. Nothing else does. +The protocol-18 step is not cut yet, so `spec-changes.json` and the protocol +upgrade guide, which project the steps up to the current protocol major, are +unchanged, and no schema accepts or refuses anything it did not before.