Skip to content

Commit c352c0a

Browse files
committed
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 <noreply@anthropic.com>
1 parent 7a1faf1 commit c352c0a

3 files changed

Lines changed: 132 additions & 0 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
feat(spec): the protocol-18 migration step records the html-tier `div` refusal as the semantic entry `ui-html-page-div-refused` (#20592)
6+
7+
Clause-②: no
8+
9+
`MIGRATIONS_BY_MAJOR[18].semantic` gains one entry, `ui-html-page-div-refused`.
10+
It records the narrowing `@objectstack/cli` takes on when its JSX page gate
11+
reaches the SDUI component manifest that `@objectstack/console` ships: a project
12+
with no `sdui.manifest.json` of its own has its `kind: 'html'` pages checked
13+
against that manifest, which does not declare `div`, so `objectstack validate`,
14+
`compile` and `lint` refuse a `div` there (`jsx-forbidden-tag`,
15+
`jsx-unknown-component`). The entry prescribes `box` for a plain wrapper, names
16+
the layout containers to reach for instead only when their layout is wanted, and
17+
says how to prove the rewrite done.
18+
19+
What moves for a consumer of this package: `MIGRATIONS_BY_MAJOR` carries the
20+
entry, and `objectstack migrate meta` prints it for a range that reaches
21+
protocol 18. Nothing else does. The protocol-18 step is not cut yet, so
22+
`spec-changes.json` and the protocol upgrade guide, which project the steps up
23+
to the current protocol major, are unchanged, and no schema accepts or refuses
24+
anything it did not before.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
import type { SemanticMigration } from '../../types.js';
4+
5+
// #20592 — the D3 record of the accept-set narrowing the CLI's JSX page gate
6+
// takes on when its console-manifest fallback becomes reachable (#19922): a
7+
// project with no `sdui.manifest.json` of its own has its `kind:'html'` pages
8+
// checked against the manifest `@objectstack/console` ships, which does not
9+
// declare `div`. The vocabulary is ruling A on #20112 (record 5852014527): an
10+
// html page may author the intrinsic tags its renderer registers, the published
11+
// manifest declares that set, and `div` stays deprecated in favour of `box` —
12+
// the console's own html compile refuses it too since objectui#10808. No D2
13+
// conversion and no tombstone: the tag sits inside an authored JSX string, which
14+
// no conversion rewrites and no schema key can tombstone, so this entry is the
15+
// migration channel beside the changeset's FROM → TO table.
16+
export const entry: SemanticMigration = {
17+
id: 'ui-html-page-div-refused',
18+
// No backticks and no pipes in `surface` — build-upgrade-guide.ts renders it
19+
// inside a code span.
20+
surface:
21+
"kind:'html' page source (and its deprecated kind:'jsx' alias) in a project with no "
22+
+ 'sdui.manifest.json of its own — the div tag, and any other tag or prop the SDUI '
23+
+ 'component manifest shipped in @objectstack/console does not declare',
24+
replacement:
25+
'`box` for a plain wrapper — the one drop-in swap: the same element, your `className` '
26+
+ 'verbatim, the same children, and no layout of its own. Reach for `card`, `flex`, '
27+
+ '`container`, `stack` or `grid` only where you want their layout. For any other tag or '
28+
+ 'prop the command names, a component and prop the manifest declares; the file is '
29+
+ '`dist/sdui.manifest.json` inside `@objectstack/console`.',
30+
reason:
31+
'An html page\'s source is a JSX string, not a keyed document: `objectstack migrate meta` '
32+
+ 'rewrites stored metadata by key and cannot rewrite a tag inside authored source, so the '
33+
+ 'move is by hand, and which wrapper keeps a page\'s layout is the author\'s call. '
34+
+ '`objectstack validate`, `objectstack compile` (which `dev` and `start` run first) and '
35+
+ '`objectstack lint` check that source against an SDUI component manifest: the '
36+
+ '`sdui.manifest.json` in the directory the command runs in, then the copy '
37+
+ '`@objectstack/console` ships. The second lookup asked for a file the console package '
38+
+ 'does not export, so it always failed, and a project without its own manifest had its '
39+
+ 'html pages checked at parse level only — syntax and structure, never which components '
40+
+ 'and props they use. It now reaches the shipped copy. That manifest declares the html '
41+
+ 'tier\'s intrinsic tags but not `div`: the maintainer ruled (2026-09-27) that an html page '
42+
+ 'may author the intrinsic tags its renderer registers and that the published manifest '
43+
+ 'declares that set, while `div` stays deprecated in favour of `box`, and the console\'s '
44+
+ 'own html-page compile refuses `div` the same way. A `div` in such a page, which used to '
45+
+ 'pass unchecked, now fails the command with `jsx-forbidden-tag` and '
46+
+ '`jsx-unknown-component`. A project that keeps its own `sdui.manifest.json` is checked '
47+
+ 'against that file, as before.',
48+
acceptanceCriteria:
49+
'`objectstack validate` reports no `jsx-forbidden-tag`, `jsx-unknown-component` or '
50+
+ '`jsx-unknown-prop` finding on any `kind:\'html\'` page and prints no '
51+
+ '`sdui/jsx-parse-level-only` notice — that notice means the component check did not run, '
52+
+ 'so a clean result beside it proves nothing; `objectstack compile` and `objectstack lint` '
53+
+ 'agree. No html page source authors `div`, and in the console each rewritten page renders '
54+
+ 'with no compile error. The platform\'s own reference is the showcase app\'s three html '
55+
+ 'pages, which author their wrappers as `box` and pass with zero findings.',
56+
};

‎packages/spec/src/migrations/registry.ts‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17147,6 +17147,58 @@ const step18: MigrationStep = {
1714717147
+ 'authoring-path save (zero such documents were measured to exist); on refusal the '
1714817148
+ 'author re-gates by record state or moves the gate to an app surface.',
1714917149
},
17150+
// #20592 — the D3 record of the accept-set narrowing the CLI's JSX page gate
17151+
// takes on when its console-manifest fallback becomes reachable (#19922): a
17152+
// project with no `sdui.manifest.json` of its own has its `kind:'html'` pages
17153+
// checked against the manifest `@objectstack/console` ships, which does not
17154+
// declare `div`. The vocabulary is ruling A on #20112 (record 5852014527): an
17155+
// html page may author the intrinsic tags its renderer registers, the published
17156+
// manifest declares that set, and `div` stays deprecated in favour of `box` —
17157+
// the console's own html compile refuses it too since objectui#10808. No D2
17158+
// conversion and no tombstone: the tag sits inside an authored JSX string, which
17159+
// no conversion rewrites and no schema key can tombstone, so this entry is the
17160+
// migration channel beside the changeset's FROM → TO table.
17161+
{
17162+
id: 'ui-html-page-div-refused',
17163+
// No backticks and no pipes in `surface` — build-upgrade-guide.ts renders it
17164+
// inside a code span.
17165+
surface:
17166+
"kind:'html' page source (and its deprecated kind:'jsx' alias) in a project with no "
17167+
+ 'sdui.manifest.json of its own — the div tag, and any other tag or prop the SDUI '
17168+
+ 'component manifest shipped in @objectstack/console does not declare',
17169+
replacement:
17170+
'`box` for a plain wrapper — the one drop-in swap: the same element, your `className` '
17171+
+ 'verbatim, the same children, and no layout of its own. Reach for `card`, `flex`, '
17172+
+ '`container`, `stack` or `grid` only where you want their layout. For any other tag or '
17173+
+ 'prop the command names, a component and prop the manifest declares; the file is '
17174+
+ '`dist/sdui.manifest.json` inside `@objectstack/console`.',
17175+
reason:
17176+
'An html page\'s source is a JSX string, not a keyed document: `objectstack migrate meta` '
17177+
+ 'rewrites stored metadata by key and cannot rewrite a tag inside authored source, so the '
17178+
+ 'move is by hand, and which wrapper keeps a page\'s layout is the author\'s call. '
17179+
+ '`objectstack validate`, `objectstack compile` (which `dev` and `start` run first) and '
17180+
+ '`objectstack lint` check that source against an SDUI component manifest: the '
17181+
+ '`sdui.manifest.json` in the directory the command runs in, then the copy '
17182+
+ '`@objectstack/console` ships. The second lookup asked for a file the console package '
17183+
+ 'does not export, so it always failed, and a project without its own manifest had its '
17184+
+ 'html pages checked at parse level only — syntax and structure, never which components '
17185+
+ 'and props they use. It now reaches the shipped copy. That manifest declares the html '
17186+
+ 'tier\'s intrinsic tags but not `div`: the maintainer ruled (2026-09-27) that an html page '
17187+
+ 'may author the intrinsic tags its renderer registers and that the published manifest '
17188+
+ 'declares that set, while `div` stays deprecated in favour of `box`, and the console\'s '
17189+
+ 'own html-page compile refuses `div` the same way. A `div` in such a page, which used to '
17190+
+ 'pass unchecked, now fails the command with `jsx-forbidden-tag` and '
17191+
+ '`jsx-unknown-component`. A project that keeps its own `sdui.manifest.json` is checked '
17192+
+ 'against that file, as before.',
17193+
acceptanceCriteria:
17194+
'`objectstack validate` reports no `jsx-forbidden-tag`, `jsx-unknown-component` or '
17195+
+ '`jsx-unknown-prop` finding on any `kind:\'html\'` page and prints no '
17196+
+ '`sdui/jsx-parse-level-only` notice — that notice means the component check did not run, '
17197+
+ 'so a clean result beside it proves nothing; `objectstack compile` and `objectstack lint` '
17198+
+ 'agree. No html page source authors `div`, and in the console each rewritten page renders '
17199+
+ 'with no compile error. The platform\'s own reference is the showcase app\'s three html '
17200+
+ 'pages, which author their wrappers as `box` and pass with zero findings.',
17201+
},
1715017202
// The sibling axis of `ui-list-view-grouping-field-padded-refused` (#17360),
1715117203
// which scoped this one out by name. Same defect, same refusal, one difference
1715217204
// that changes the author's options: `kanban.groupByField` is REQUIRED, so a

0 commit comments

Comments
 (0)