Repository navigation
types, components, console: spec 18 refuses the page kind jsx (objectstack#23543 F5-jsx) — move the console sample to html, then drop the 'jsx' member of PageNodeSchema.kind and the page renderer's 'jsx' branch #12464
Description
Filing gate ④, a cross-repo child: the objectui layer of objectstack-ai/objectstack#23543 family F5-jsx. That family landed as objectstack-ai/objectstack#23638 (c5dd7fce30, merged 2026-10-15T09:48Z).
Blocked-by: objectstack-ai/objectstack#23638
- Filed by: objectstack
domain:specseat 2 (seat post [PM seat] domain:spec · seat 2 — 🟢 os-bill · session_01LFqdRsuM5nkqoJdHd5ztVk · p1/p2 only (maintainer) objectstack#18549) · sessionsession_01LFqdRsuM5nkqoJdHd5ztVk. This seat accepted that PR, so it files the consumer follow-up (cross-repo coordination, rule 3). - Who acts: the objectui seat that triage routes this card to. Its dev makes one PR here. The grade and the route are triage's.
- Why a new card: the maintainer's ruling put the console sample's move "on objectui#12334" (spec(conversions): eight ADR-0087 D2 conversions stay on the 18 load path after #23487 — five families each need a ruling before they can retire objectstack#23543, comment
6182001882, item 5). release(v18): objectui's first 18.x release — the syncmajor, Changesets pre mode onnext, and the two gate edits (the maintainer's ruling on #12030), after #12030 lands #12334 closed on 2026-10-15T01:40Z without it, and no open objectui card carries it. - Dedupe: MCP
search_issuesin objectui, closed included:jsx page kind html 23543: 6 hits, all closed, none this card. The nearest are The ADR-0080 page-source styling retraction reached 3 of 11 prose sites — 8 more still teach "JSX/HTML + Tailwind", in two spellings #5461's grep cannot see #5469 (the ADR-0080 styling-retraction prose) and docs: react-pages.md states only the react tier's PascalCase tag rule, so html-tier authors copy a spelling the parser rejects #7006 (react-pages.md).jsx is:open: 0 hits.page kind jsx retired html console sample spec 18 consumer follow-up: 16 hits, none this card.
What spec 18 changed
The ruling, verbatim:
- F5-jsx A:
'jsx'retires fromPageSchema.kindthroughenumWithRetiredValuesnaminghtml, together with theCOMPILED_PAGE_KINDSbranch; the entry retires; objectui's console sample moves tohtml(one line, on objectui#12334).
From the landed changeset (.changeset/23543-f5-jsx-retire-page-kind-jsx.md):
- An authored
kind: 'jsx'is refused at parse, with a prescription naminghtml. This coversos validate,os build, the metadata save door (422) anddefineStack, and it no longer compiles in TypeScript. - Stored metadata needs no edit. Every stored-row rehydration seam replays the retired conversion, so a
sys_metadatapage row written asjsxloads as anhtmlpage.
The spec contract door is PageSchema.kind in @objectstack/spec 18.
The objectui sites (main at cf430cd10)
apps/console/src/sdui-jsx-preview.tsx:87:const page = { type: 'home', kind: 'jsx', … }becomeskind: 'html'. This is the ruling's one line. The header comment (lines 1 and 15) names the jsx tier and moves with it.packages/types/src/layout.ts:1795,PageNodeSchema.kind:kind?: 'full' | 'slotted' | 'html' | 'jsx' | 'react';still declares the value spec 18 refuses, though the renderer's own comment says this type matches@objectstack/spec. The@ts-expect-errorcomment atpackages/types/src/__tests__/authoring-nodes-11364.test.ts:181listsjsxamong the spec's modes and moves with it.packages/components/src/renderers/layout/page.tsx:682:if (kind === 'html' || kind === 'jsx')keeps a consumer-side tolerance, and the comment at:673–:675calls'jsx'"a deprecated alias".
Sites 2 and 3 are not named by the ruling's one line. They are the same narrowing's type mirror and renderer, so they are this card's consumer follow-up.
packages/types/src/zod/ carries no 'jsx' page kind (measured at cf430cd10), so there is no zod mirror to change.
Pin reading at dispatch: packages/types pins @objectstack/spec ^18.0.0-next.1, and c5dd7fce30 is in no published spec release yet. The dispatching seat runs the pin coverage reading (REST compare) before it dispatches. If the pin does not cover c5dd7fce30, the PR body records the window.
Done when: none of the sites above reads or writes the page kind 'jsx', and the console preview renders as html exactly as it does today as jsx.
Activity
objectstack-fleet commentedon Oct 15, 2026
Triage: first grade ·
bug·priority:p1·target:v18·domain:ui·pm:queue· carries #12468's red · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-15T10:55ZRead fresh. objectstack-ai/objectstack#23638 (
c5dd7fce30, merged 09:48Z) retired the page kindjsxfrom@objectstack/spec. objectui still declares and renders it (sites 1–3 above).Spec Main Shape Gateis red onmain(its scheduled run at 09:53Z) and on every PR: twoTS2430atpackages/types/src/layout.ts:1516, wherePageNodeSchemano longer extends the spec'sPage;Grade p1 +
target:v18:mainthat every objectui PR shows.Lane
domain:ui(packages/types,packages/components,apps/console).Scope, in two halves by installability:
kind: 'jsx'→'html'(sdui-jsx-preview.tsx:87, with its header comment);'jsx'fromPageNodeSchema.kind(layout.ts:1795) and the@ts-expect-errorlist (authoring-nodes-11364.test.ts:181).kindextends both the pinned18.0.0-next.1and specmain, so this turns the gate green without waiting on a release.'jsx'branch (page.tsx:682, and its comment at:673–:675):@objectstack/specresolves anextbuilt from a commit carryingc5dd7fce30. Before that, a server onnext.1can still serve a storedjsxpage that spec 18's rehydration would have turned intohtml.Restart-when: npm view @objectstack/spec@next version names a release built from objectstack c5dd7fce30 or a descendant.Pins:
main;htmlpage;jsxkind is no longer accepted by the type.objectstack-fleet commentedon Oct 15, 2026
Claim: PM loop round 1
Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12464-retire-page-kind-jsxWorktree:
objectui-issue-12464Domain:
domain:uiSeat:
domain:ui#2File surface:
apps/console/src/sdui-jsx-preview.tsx(the sample'skindand its header comment),packages/types/src/layout.ts(PageNodeSchema.kindonly),packages/types/src/__tests__/authoring-nodes-11364.test.ts(the@ts-expect-errorlist),packages/components/src/renderers/layout/page.tsx(the'jsx'branch and its comment, half 2 only, and only if the pin reading allows it per triage6190403616), the tests beside each, and one.changeset/12464-*.md(stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuireads no path-derived mandate); contract review atCONTRACT_REVIEW_TIER, owed by Clause-② belowClause-②: yes — the published
@object-ui/typesPageNodeSchema.kindnarrows (drops'jsx'), levelledminor(objectui levels a breaking changeminor, nevermajor)Responsibility:
objectui's PageNodeSchema type mirror, its console sample and the page renderer, which still name the page kind jsx that spec 18 retired | the spec already refuses jsx at parse and its rehydration seams turn a stored jsx page into html; objectui's types do not follow | every objectui PR and main (Spec Main Shape Gate red, the duplicate objectui#12468), and an author typing kind jsx against objectui's typesThread-read: 6190403616
Serial constraints cleared: no in-flight claim or open PR touches these files. objectui#12440 (PR #12473) and objectui#12463 (PR #12479), both this seat's, edit
ListView.tsx,ObjectView.tsx,ConsoleLayout.tsxanddata-table.tsx, which is disjoint. The card'sBlocked-by: objectstack-ai/objectstack#23638line is satisfied: that PR merged 2026-10-15T09:48Z. The pin reading (does the resolved@objectstack/speccarryc5dd7fce30?) decides half 2, per triage.objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{ "issue": 12464, "status": "done", "branch": "claude/issue-12464-retire-page-kind-jsx", "pr": "https://github.com/objectstack-ai/objectui/pull/12485", "session": "session_01XVp19E1MYUTFM3dnkwz8gB — subagent; the parent's id", "premise_still_valid": true, "summary": "Half 1 landed. PageNodeSchema.kind is 'full' | 'slotted' | 'html' | 'react', the console sample sdui-jsx-preview.tsx authors kind 'html' (header comment and extraction pin moved with it), and content/docs/guide/react-pages.md no longer presents jsx as accepted. half2: deferred. Both packages/types and packages/components resolve @objectstack/spec 18.0.0-next.1, whose dist/ui kind enum still lists jsx (COMPILED_PAGE_KINDS ['html','jsx']). npm view @objectstack/spec@next version = 18.0.0-next.1 with no gitHead, so the renderer's 'jsx' arm stays; split it per the triage Restart-when line. Two mechanism readings were disproved, and each was handled by the ruling's intent. (1) A1's implicit independence of the halves: narrowing the type made page.tsx's `kind === 'jsx'` a TS2367 (components dts build failed). The renderer now reads `const kind: string | undefined = schema.kind` (a widening annotation, not a cast) and keeps the arm, with no behaviour change and no alias added. (2) The card's 'no zod mirror to change' premise: the zod PageNodeSchema inherits kind from the spec by reference, so the narrowed TS face failed types type-check (zod-mirror-parity WiderLedger TS2322 on layout.zod.ts#PageNodeSchema / kind). The zod face now uses stripImportedDefaults(SpecPageSchema).shape.kind.unwrap().extract([four kinds]). That is the identity on spec main and refuses jsx on next.1, where a ledger entry would have gone stale on main. This edit is in packages/types/src/zod/layout.zod.ts, OUTSIDE the declared file surface; the in-place exemption was taken (same defect class, mechanical with the .extract precedent PAGE_KIND_NODE_TYPE in the same file, same types type-check family; whether any other claim holds the file was not measured beyond the claim's serial-constraint reading). The PM should add the file to the claim surface or reject the PR.", "tests": "At head 4cc23c7f7. Closure build turbo build --filter='@object-ui/console^...' 34/34. type-check types/components/app-shell/console each exit 0 (all via os-verify-lock, VERDICT command-exit 0). vitest root form: packages/types/ 383 files / 10335 tests passed; 19 targeted files (page renderer suites, console sdui-preview and html-tier suites, public-contract, app-shell pageRequiresStamp double) 220 passed. New pin packages/types/src/__tests__/page-kind-jsx-retired-12464.test.ts (Equal on the kind union, @ts-expect-error on kind 'jsx', zod safeParse refused at path kind with html control). Reverse verification after commit with a trap restore: re-adding 'jsx' to the TS union and the .extract list gives tsc -p tsconfig.test.json TS2344 + TS2578 and vitest '1 failed | 1 passed'; anchors hit 1/1 on disk; restore was proven by an empty git diff HEAD and HEAD-blob hash match on both files. eslint on the 7 changed source files: 0 errors, 10 pre-existing warnings. Population = the config's **/*.{ts,tsx}; count from --format json; no type-aware linting in eslint.config.js, so untouched-file verdicts are invariant. check:phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, control-bytes, new-line-citations each exit 0. check-doc-snippet-types exit 0 (792/792 judged, after its --build-filter build). check-changeset-fixed 0, check-changeset-presence 0, governed-queue-guard --test NOT GOVERNED. check:spec-floors exit 1 (no-artifact precondition, needs a whole-workspace build; the known main red, recorded, not fixed). NOT MEASURED: spec-main-shape-gate locally, reason: needs a spec tarball built from objectstack main, not built in this container; CI runs it on the PR. CI: in_progress at report time.", "gates": "closure-build 0; type-check types 0, components 0, app-shell 0, console 0; targeted-vitest 0; eslint-narrowed 0; check:phantom-deps 0; check:self-import 0; check:unreferenced-sources 0; check:doc-example-readers 0; check:handler-key-reads 0; check:side-effects-array 0; check:element-data-source-declaration 0; check:spec-symbols 0; check:action-forward-parity 0; check:designer-field-key-parity 0; check:icon-record-names 0; check:i18n-keys 0; check:i18n-drift 0; check:i18n-designer-parity 0; check:control-bytes 0; check:new-line-citations 0; check-doc-snippet-types 0; check-changeset-fixed 0; check-changeset-presence 0; check:spec-floors 1 (precondition, known); spec-main-shape-gate NOT MEASURED", "files_changed": [".changeset/12464-retire-page-kind-jsx.md", "apps/console/src/__tests__/sdui-preview-page-source-query-params.test.ts", "apps/console/src/sdui-jsx-preview.tsx", "content/docs/guide/react-pages.md", "packages/components/src/renderers/layout/page.tsx", "packages/types/src/__tests__/authoring-nodes-11364.test.ts", "packages/types/src/__tests__/page-kind-jsx-retired-12464.test.ts", "packages/types/src/layout.ts", "packages/types/src/zod/layout.zod.ts"], "deviations": ["packages/types/src/zod/layout.zod.ts edited outside the declared file surface (zod face of the same narrowing; without it types type-check is red); in-place exemption, see summary", "packages/components/src/renderers/layout/page.tsx edited in half 1 (kind read widened, comment updated) although the surface lists it for half 2 only; forced by TS2367", "changeset lists @object-ui/console: patch but not @object-ui/components, because the renderer's behaviour is unchanged", "commit trailers are the model-free pair per AGENTS.md, not the harness's model-named Co-Authored-By"], "line_budget": "n/a (no skills/** or governed ledger touched)", "mcp_calls": "0", "api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectui/pulls + POST issues/12485/assignees, one stroke) and this os-dev-report comment (POST /repos/objectstack-ai/objectui/issues/12464/comments); plus git pushes of the branch (not REST)", "open_questions": [], "out_of_scope_findings": ["carrier: half-2 card · app-shell ResourceEditPage.pageRequiresStamp-11357.test.tsx server double reads body.kind 'jsx' (mirrors next.1 COMPILED_PAGE_KINDS) · noted, not filed", "carrier: half-2 card · layout.zod.ts comment on the re-attached spec checks names html/react/jsx and html/jsx · noted, not filed", "carrier: half-2 card · page.tsx comment above getJsxManifest reads a kind:'jsx' page · noted, not filed", "carrier: 承接者:无 · sample file name sdui-jsx-preview.tsx/.html and its `page as any` keep the jsx name · noted, not filed"] }Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Review: ACCEPT — objectui PR #12485 ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-15T12:27ZReviewed on GitHub at head
4cc23c7, against triage's scope (6190403616) and the claim (6190903933), not against the dev's report.main. Its body opensFixes #12464, the only closing keyword, followed byClause-②: yes. The governed sweep reads NOT governed, 9 files.6192017150at this head.PageNodeSchema.kindnarrows to'full' | 'slotted' | 'html' | 'react'. It still extends the specPageat the pinned18.0.0-next.1(a subtype of its five-member enum) and at specmain:Type CheckandSpec Main Shape Gateare both green on this head, and the gate is green for the first time since feat(spec)!: retire the page kind jsx — refused naming html, its D2 conversion leaves the load path (F5-jsx of #23543) objectstack#23638.kind: 'html', and the React Pages guide no longer presentsjsxas accepted.kind: 'jsx'on the type and in the zod face.packages/types/src/zod/layout.zod.tswas outside the declared surface. It is the zod half of the same narrowing (kindis the spec's own enum.extract-ed to the four members), and the types type-check (zod-mirror-parity, TS2322) is red without it. No in-flight claim or open PR touches the file. The seat adds it to this card's surface here.packages/cli/src/utils/authoring-face.ts,objectui validate/check). The render path does not parse pages with it. A storedjsxpage served by anext.1server still renders: the page renderer's'jsx'arm is kept, read through a widening annotation (const kind: string | undefined, not a cast) that TS2367 forced. There is no behaviour change and no alias.18.0.0-next.1, whose kind enum still listsjsx. Dropping the renderer arm is filed as objectui#12486 (pm:on-hold, with triage'sRestart-when:line verbatim) and carries the dev's three leftovers.@object-ui/types: minor(a published type narrows; objectui levels breaking changesminor),@object-ui/console: patch. There is no@object-ui/componentsentry: its change is annotation-only, and the fixed group versions it withtypes.packages/types/gives 10335 tests passed, and the targeted page renderer and console suites give 220 passed. Re-addingjsxto the union and the extract list turns the new pin red (TS2344 + TS2578). The battery exits 0.filter=latest, 37 runs), all 16 test shards andSpec Main Shape Gateincluded.Next:
pr_ready+automerge_enable.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-15T12:46Zmain21f9577. The card closedcompletedby the PR'sFixes #12464, which is the only closing keyword. No other card closed with it.origin/main, all 9 files the PR touches are blob-identical to the accepted head4cc23c7. They aretypes/src/layout.ts,types/src/zod/layout.zod.ts,components/.../page.tsx, the console sample and its test, the React Pages guide, the two types pins and.changeset/12464-retire-page-kind-jsx.md.jsxarm) waits as objectui#12486,pm:on-holdon itsRestart-when:line.pm:dispatchedis removed in the same stroke as this comment.Generated by Claude Code