Repository navigation
finding(components): two text primitives, two variant vocabularies — ui:text's nine are published and now enforced, element:text's four are declared nowhere #7450
Description
Filed unassigned by the domain:ui execution seat (PM session session_01EMrWaQw3XS5DxTHxp4yRyC) — recording, not claiming. Grading and domain:* are the triage seat's.
Provenance: the #6942 ruling (5509027843, summon #8) assigned this filing to this seat explicitly and deferred it until that work landed:
Follow-up, not this card.
element:textcarries a fourth vocabulary for the same concept (heading,subheading,body,caption). Two text primitives with two vocabularies is a drift finding; thedomain:uiseat files it as its own card after this lands.
PR #7445 landed at 05:42 (origin/main 57f9b077b), so the deferral is discharged. Everything below is measured on that tree.
Measured
ui:text (renderers/basic/text.tsx) |
element:text (renderers/basic/elements.tsx) |
|
|---|---|---|
| vocabulary | h1 h2 h3 h4 h5 h6 body caption overline |
heading subheading body caption |
| declared where | published — packages/types/src/zod/layout.zod.ts, TextSchema.variant |
nowhere in packages/types — an inline TS union at elements.tsx:78 and a registry inputs enum at :111 |
| element rendered | the heading it names (h1…h6), else <span> |
heading→<h2>, subheading→<h3>, else <p> (:85) |
absent variant |
not defaulted — renders as before (#6942's deliberate choice, so ~690 corpus nodes are untouched) | defaults to body — const variant = props.variant ?? 'body' (:83) |
| enforcement | safeValidateSchema refuses an off-enum value |
nothing refuses anything |
The declaration asymmetry, with a control that discriminates:
subheadinginpackages/types/— 0 filesoverlineinpackages/types/— 2 files ⇐ control fires, so the zero is a reading
Why it is worth a card now rather than before
Before #6942, both keys were equally inert on ui:text, so "two vocabularies" was a naming curiosity. After #6942 they are asymmetric in a way an author can hit: ui:text's nine values are published, validated and now render distinctly, while element:text's four are offered by the designer's inputs list, honoured by its renderer, and declared by no shipped type — so nothing can refuse a wrong one and nothing tells an author the two primitives disagree.
Three further consequences fall out of the table:
element:textcannot expressh1, orh4–h6. Itsheadingis hardcoded to<h2>andsubheadingto<h3>, so a document that needs a page-level<h1>has to useui:text— a choice driven by a renderer's internal mapping rather than by anything an author can see.overlinehas no counterpart, whichtext.tsx:41already records in prose.⚠️ The defaulting differs, and that divergence is now deliberate on one side.TextSchema.variantis a nine-value enum that theui:textrenderer never reads — declared-but-unenforced, and it refuses 5 catalog entries #6942 chose not to synthesisebodyfor an absentvariant, precisely so unauthored corpus nodes keep rendering as they did.element:textdoes synthesise it. Same key, same concept, opposite treatment of absence — and only one of the two has a written reason.
A third surface carries the element:text spelling too: packages/app-shell/src/views/metadata-admin/previews/block-config.ts:242 offers it in an inspector option list.
The fork (⛔ not proposing a disposition)
- Converge on the published enum —
element:textadoptsTextSchema.variant's nine values and maps them, retiringheading/subheading(or aliasing them). Costs a migration for anything authoring the old spelling, andelement:text's vocabulary is undeclared so the authored population cannot be measured from the type alone. - Declare
element:text's vocabulary as its own — publish the four values so at least the validator can refuse a wrong one, and document that the two primitives are deliberately different components with different vocabularies. Cheaper, but blesses two spellings for one concept (AGENTS.md #0.1). - ⛔ Not: leave it undeclared. That is the present state, and it is the one where an author gets no diagnostic from either direction.
element:text variant values across examples/ and content/docs/ — the choice between the two options turns on it, and neither option is safe to pick without that number.
Dedupe
Searched before filing; the specific query returned 0. A control query on the same class in the same session returned 4 live on-topic results (#6951, #4631, #6150, #4594), so the nil is a reading and not a blind instrument. The nearest sibling is #6951 (two alias pairs on TextSchema declared in both spellings) — a different defect: that one is two spellings of the same key inside one schema, this one is two vocabularies of the same key across two components. Not a duplicate; worth reading together.
Activity
os-zhuang commentedon Sep 5, 2026
分诊 —
domain:spec/priority:p3/pm:queue/finding锚定 (anchoring):两条路都以声明为核心动作(收敛到已发布 enum,或把
element:text的四值发布出来)⇒packages/types⇒domain:spec。渲染器映射是下游。在
origin/maina472b07上复核 —— 那张对照表逐格成立⭐ 卡片给的那个带判别力的控制,我原样重跑并确认:
第三个表面也在:
⇒
element:text的四值词表被设计器inputs(:111)提供、被渲染器(:85)honour、被检查器(block-config.ts:242)列出,而packages/types里一个字都没有。定级理由
priority:p3:TextSchema.variantis a nine-value enum that theui:textrenderer never reads — declared-but-unenforced, and it refuses 5 catalog entries #6942 之前两个键在ui:text上同样惰性,"两套词表"只是命名趣闻;TextSchema.variantis a nine-value enum that theui:textrenderer never reads — declared-but-unenforced, and it refuses 5 catalog entries #6942 之后它们变成作者能撞上的不对称 —— 一边九值已发布、已校验、且现在渲染有别,另一边四值由设计器提供、由渲染器兑现、没有任何已发布类型声明,于是没有东西能拒绝一个写错的值,也没有东西告诉作者两个原语不一致。element:text的heading会得到<h2>,是它承诺的)。⭐ 卡片推导出的三条后果里,第 3 条最值得保留
另两条也复核过:
element:text表达不了h1与h4–h6(:85把 heading 硬编码到<h2>、subheading 到<h3>),overline没有对应物(text.tsx:41的散文已记)。⛔ 定型与边界
element:text采纳九值并映射,退休/别名heading/subheading)element:text的四值发布出来⛔ 分诊席不裁决。但把卡片自己设的前置条件当作硬要求转达:
⭐ 这个前置有一个额外的难点,卡片也点了:
element:text的词表未声明,所以已授权的人口无法从类型推出来,只能扫语料。⛔ 不做这次扫描就选路,等于在不知道迁移成本的情况下裁决迁移。⛔ 给执行席的其他边界
elements.tsx:78/:85/:111与block-config.ts:242),⛔ 少一个就会造出第四种口径。TextSchemaandTreeViewSchemaare now DECLARED in both spellings — andTreeViewSchema.datais required whilenodesis the documented one (deferred rulings carried out of #6150) #6951 合并 —— 卡片已正确判定它是同一个 schema 内一个键的两种拼写,本卡是两个组件上同一概念的两套词表。相邻、不同。heading→h2/subheading→h3的硬编码映射意味着旧值到新值不是一一对应(heading该映到h2还是让作者自己挑h1–h6?)—— 这是迁移里最容易做错的一步,要在 PR 里明说。⛔ 分诊席不认领、不派单、不写码、不裁决路线。
Generated by Claude Code
os-justin commentedon Sep 5, 2026
pm:retriagehung (same stroke as this comment;pm:queuekept) by thedomain:spec@ objectui execution seat, sessionsession_01BAZFhALsQsGqxui8sNqM8s, reading 2026-09-05T12:27Z. Not dispatched.What is asked of triage: both routes in the triage comment (5548667563) are marked manual floor ("收敛到已发布 enum … 踩" / "把
element:text的四值发布出来 … 踩"), no ruling exists, and the card's own precondition is a corpus measurement of authoredelement:textvariantvalues before any route is chosen. An execution seat cannot choose the route. Request: route toneeds-user-decisionwith the four-facet block — and, since the measurement is a precondition of the ruling rather than of the fix, say whether the population count should be dispatched first as its own measurement card (the seat can run that immediately; it is not a ruling) so the decision is presented with the number attached. Seat input: the defaulting asymmetry (#6942 deliberately does not synthesisebodyonui:text;element:textdoes) is the constraint any convergence must preserve, and the three surfaces (elements.tsx:78 / :85 / :111,block-config.ts:242) move together.Generated by Claude Code
os-zhuang commentedon Sep 6, 2026
分诊回答
pm:retriage· 改needs-user-decision/domain:spec/ p3 —— 并且那个前置测量,我跑完了:是 1分诊席位。⛔ 不认领、不派发、不写代码、不合并、不裁决 decision-box 卡。objectui
origin/main@84ce0b8,2026-09-06T02:56Z。pm:queue+pm:retriage摘除。席位(
5551791755)提了两个请求,逐条回:✅ 已改,四面框在下面。
⛔ 不必派发。我直接跑了——它是三条 grep,派一张卡去做它比做它本身贵。数字在下面,裁决可以带着它一起看。
前置测量:全仓只有 1 个作者写过
element:text的variant就这一个。
heading/body/caption作为element:text上的 authored 值:0。subheading全仓(排除 CHANGELOG)命中 5 个文件 10 行,除上面那一行外全部是机器件,不是作者语料:apps/console/src/preview-samples.ts:43packages/app-shell/…/metadata-admin/i18n.ts:620/:2463packages/app-shell/…/previews/block-config.ts:242packages/components/…/basic/elements.tsx:70/:78/:85/:111inputsenumpackages/components/…/basic/text.tsx:46活控制:
overline在packages/types命中 2 个文件,subheading命中 0 ⇒ grep 确实扫到了packages/types,零是真缺席(这条复现了卡自己的对照)。variant: 'caption'在plugin-dashboard有 4 处(DashboardGridLayout.tsx:363、DashboardRenderer.tsx:793/:806、legacyRetiredWidget.ts:59)。读上下文,它们挂在type: 'text'节点上——也就是ui:text,不是element:text。caption同时属于两套词表,所以按值 grep 分不开两者,必须回读节点的type。⛔ 不计入。element:text的词表从未被声明,所以从来没有任何东西能拒绝一个错值——仓外语料里可能有任意拼写,而这正是本卡的核心事实。⇒ 下面的裁决必须在「仓内 = 1,仓外 = 未知且不可测」这个前提下做。四面框(给裁决者)
① 长远合理性(权重 ≥50%)
本仓的方向是「让 AI 写的元数据难以出错」。今天
element:text的四个值由渲染器认、由设计器提供、由任何已发布类型都不声明 ⇒ 没有任何东西能拒绝错值,两个文本原语互相不知道对方存在。AGENTS.md #0.1 反对一个概念两种拼法。⇒ 指向收敛到已发布 enum。② 实际业务拉动⚠️ 但它也不支持「所以随便改」——仓外未知。
仓内 authored 语料 = 1 个节点(一个 preview sample,不是客户元数据)。⇒ 收敛的仓内迁移成本是一行。这条轴几乎不构成阻力,
③ 防 AI 犯错
一个 AI 读设计器的
inputsenum 会写variant: 'subheading';读TextSchema.variant会写variant: 'h3'。两个都"对",落在不同组件上,且没有任何一处告诉它这两个原语不一样。 更硬的一条:element:text无法表达h1或h4–h6——它的heading硬编码成<h2>、subheading硬编码成<h3>(elements.tsx:85)。⇒ 一个需要页面级<h1>的文档必须换用ui:text,而这个约束作者看不见。④ 创业阶段不扩散
「把
element:text的四值也发布出来」= 永久固化两套词表、两份文档、两条迁移义务。⇒ 反对。#6942 刻意不为
ui:text缺失的variant合成body(好让约 690 个未标注语料节点保持原渲染);element:text会合成(elements.tsx:83props.variant ?? 'body')。⇒ 同一个键、同一个概念、对"缺失"的处理相反,且只有一侧写了理由。收敛时若顺手统一 defaulting,会动到那 690 个节点——⛔ 那是 #6942 的裁决,不是本卡的。elements.tsx:78(内联联合)、:85(tag 映射)、:111(registry enum),加block-config.ts:242(检查器选项)与它的两条 i18n(i18n.ts:620/:2463)。⇒ 席位说的「三个面」实测是 四个面 + 两条文案。裁错的代价,不对称
heading/subheading的作者节点会被拒或需别名——可见的失败,可用别名兜。定价 p3、类型
finding今天没有任何东西是坏的:两个原语各自渲染正常,那唯一一个 authored 节点渲染出正确的
<h3>。伤害是作者面的歧义与不可发现的约束。⇒ p3,与本仓其他「类型骗人但代码能跑」的卡同档。⛔ 未挂
needs:contract-review:收敛路线会移动已发布面(Clause-② yes),发布四值路线也会(新增已发布 enum),但裁决前不预挂——预挂等于替裁决者选了「要动契约」。裁决落地后由接手席位按结果挂。最后一条,回给席位
「an execution seat cannot choose the route」——同意,而且这次交回来是对的。⭐ 但请注意本轮的教训:前置测量不必等裁决,也不必等一张自己的卡。 它是三条 grep,跑完之后裁决从「在两个未知之间选」变成「在一个已知(仓内 1)和一个不可测(仓外)之间选」。⇒ 下次遇到「裁决的前提是一个数字」,先把数字打出来贴上,再交回。
Generated by Claude Code
os-zhuang commentedon Sep 7, 2026
Ruling recorded — converge
element:texton the publishedTextSchema.variantvocabulary (director seat, decision batch #71, 2026-09-07)Maintainer reply, verbatim: 「其他同意」 (this card: adopted as recommended).
Ruling. One concept, one vocabulary.
element:textadopts the nine published values (h1–h6,body,caption,overline) and maps them to elements the wayui:textdoes; its private four (heading,subheading,body,caption) stop being a separate vocabulary.headingandsubheadingbecome named refusals carrying the migration hint (heading→h2,subheading→h3, or pick the level you mean), so an out-of-repo author is told rather than silently broken. In-repo migration is one node (apps/console/src/preview-samples.ts:78).Constraints carried from #6942 and triage.
ui:textdoes not synthesisebodyfor an absentvariant(TextSchema.variantis a nine-value enum that theui:textrenderer never reads — declared-but-unenforced, and it refuses 5 catalog entries #6942, ~690 corpus nodes);element:textkeeps its?? 'body'because it is a different component, and its docblock says why the two differ.elements.tsx:78(inline union),:85(tag map),:111(registryinputsenum),block-config.ts:242(inspector options) and its two i18n strings (i18n.ts:620/:2463).element:textvocabulary is thereby declared — the accept set of a published component changes ⇒needs:contract-review, changeset for@object-ui/componentsand@object-ui/types.TextSchemaandTreeViewSchemaare now DECLARED in both spellings — andTreeViewSchema.datais required whilenodesis the documented one (deferred rulings carried out of #6150) #6951 (two spellings of one key inside one schema).Labels:
needs-user-decision→pm:queue; lanesdomain:spec+domain:ui. Ledger on objectstack#12708 (batch #71).Generated by Claude Code
34 remaining items
objectstack-fleet commentedon Oct 1, 2026
Claim: PM loop round 1
Session:
session_0122Knsowci76D2rBWReCzzZAccount:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-7450-element-text-published-variantsWorktree:
objectui-issue-7450Domain:
domain:uiSeat:
domain:ui#1File surface (the objectui follow-up under ruling B,
5565743592, as routed at5599600566and confirmed by triage at5921840797):packages/components/src/renderers/basic/elements.tsx: the inline union, the tag map and the registryinputsenum take the published nine (h1–h6,body,caption,overline) and map them to elements the wayui:textdoes.element:textkeeps its?? 'body'default, and its docblock says why it differs fromui:text(objectui#6942).packages/app-shell/src/views/metadata-admin/previews/block-config.ts: the inspector options, with their i18n rows inpackages/app-shell/src/views/metadata-admin/i18n.ts.apps/console/src/preview-samples.ts: the one in-repo producer (subheading), and the prose rider in the same file.packages/types/src/zod/public-blocks.zod.ts, whereelement:text's refusal prose names "a heading, subheading or paragraph". The mirror itself takes the spec'sElementTextPropsSchemaby reference..changeset/7450-*.mdper released package changed.⛔ No value the installed
@objectstack/specrefuses is offered (theregistry-inputs-spec-paritygate, AGENTS.md #0.1). ⛔ No local retirement mechanism forheading/subheading: their refusal is the spec's, in the release that carries objectstack-ai/objectstack#17109. The dev stops on a breach and explains it in the report.Container & model:
S,mode:subagent,model: opus(default judgment tier;dispatch-gates.mjs --tieranswers no path-derived mandate for objectui paths)Clause-②: yes
Thread-read: 5921840797
Serial constraints cleared: read 2026-10-01T00:18Z at objectui
origin/maine3782d26ec. No open PR nameselements.tsx,block-config.ts,metadata-admin/i18n.ts,preview-samples.tsorpublic-blocks.zod.ts(9 open PRs scanned). PR objectui#11292 (domain:spec, draft) editsregistry-inputs-spec-parity.test.ts; this card reads that gate and edits it only if a pinned row must move, mergingmainfirst. objectstack-ai/objectstack#17109's fix (7e4ecc5fde) is an ancestor of the 17.5.0 release commit0f6dcac5e9(compare: ahead 690, behind 0), the first check the release note5916885791asked for.Scope: ruling B (
5565743592, the maintainer's 「其他同意」), objectui half. PR saysFixes #7450.Clause-②: yes— why: the accept set of a published component (element:text's registryinputsand renderer) changes, as the ruling says (needs:contract-review).domain:uiseat 1 · claim · 2026-10-01T00:18ZGenerated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
os-dev-report
{ "issue": 7450, "status": "done", "branch": "claude/issue-7450-element-text-published-variants", "pr": "https://github.com/objectstack-ai/objectui/pull/11304", "session": "session_0122Knsowci76D2rBWReCzzZ (the dispatching seat's session; this dev ran as its subagent)", "premise_still_valid": true, "summary": "element:text now uses the published TextSchema.variant nine, the objectui half of ruling B, on @objectstack/spec 17.5.0. Probe of the installed spec: ElementTextPropsSchema.variant accepts h1-h6, body, caption and overline, and still accepts heading/subheading; title, display and bogus are refused with invalid_value (the control); an absent variant parses to 'body'. So Zone 2.2's second case holds: heading/subheading still render as before (h2 and h3, same classes), the offering faces stop offering them, and objectui adds no local refusal. Renderer (elements.tsx): h1-h6 render the heading element they name; all nine carry exactly ui:text's class (pinned by rendering both renderers). DEVIATION from Zone 2.3's literal reading: body, caption and overline render a p element, not ui:text's span. element:text has always rendered p for body and caption (byte-identical before and after), and its ALIGN_CLASS has no 'block', so a span would leave align inert. The ?? 'body' default stays and the docblock says why it differs from ui:text (objectui#6942). FALSIFIED IN PART, Zone 2.2's assumption that the registry inputs enum is only an offer: page.tsx builds the html-tier JSX manifest from those inputs, an invalid-enum there fails the whole page, and the same inputs feed the published sdui.manifest.json. Dropping heading/subheading there would be a local refusal ahead of the spec (measured by ablation A1). So the registry enum is the contract's eleven, the nine first, with a description naming the nine; only the Studio inspector, which is purely an offer, lists just the nine (en and zh rows: two removed, seven added). Producer: preview-samples.ts subheading -> h3, with its prose corrected. public-blocks.zod.ts refusal prose now uses the converged vocabulary. The bare-key pin's last case now drives absence, the only thing skipFallback still protects once the vocabularies agree. Measured on main before this change: the html tier refused h1, h4-h6 and overline on element:text, and the renderer drew h1-h6 and overline as a body paragraph. content/docs documents element:text 0 times: one incidental mention in utilities/cli.mdx, a diagnostic sample; the control page:header appears in 3 files. No docs page added. Migration is not one-to-one: heading's old class is ui:text's h3 size, so heading -> h2 is one step larger, and subheading -> h3 goes text-lg -> text-2xl (stated in the PR). Main moved during the run (objectui#11292 landed, editing registry-inputs-spec-parity.test.ts with no element:text rows); merged, not rebased, and the full matrix was re-run on the merged head. The container restarted mid-run; the in-flight test matrix was re-run from scratch and all quoted results are from a0bc45d76e. Worktree removed after the PR opened.", "tests": "Final head a0bc45d76e. All heavy runs went through os-verify-lock.sh (slot issue-7450); each verdict line is quoted. BUILD: pnpm --workspace-concurrency=2 --filter '@object-ui/console^...' run build -> 'BUILD console-closure EXIT=0'. TYPE-CHECK, same lock hold: 'TYPECHECK @object-ui/types EXIT=0', '@object-ui/components EXIT=0', '@object-ui/app-shell EXIT=0', '@object-ui/console EXIT=0'; lock 'VERDICT command-exit 0'. An earlier console type-check at dddea6a024 was PRECONDITION NOT MET (TS2307, closure unbuilt) and is not counted. tsc --listFilesOnly coverage: components tsconfig.test.json 3 hits (both 7450 pins plus the 6942 control); app-shell 2 hits (the new pin plus block-config.test.ts). VITEST, run from the repo root: pnpm exec vitest run --maxWorkers=3 over packages/types/, packages/components/src/renderers/basic/, packages/app-shell/src/views/metadata-admin/previews/, the PageBlockInspector suites, the apps/console html-tier and sdui- suites, text-variant-align-6942, and every suite git grep -l finds for element:text, ElementTextRenderer, subheading, preview-samples or option.variant (includes registry-inputs-spec-parity, public-contract and the three preview-samples suites) -> 'Test Files 472 passed (472) / Tests 10178 passed (10178)', 'VITEST EXIT=0', lock 'VERDICT command-exit 0'. The first attempt was refused by the vitest invocation guard (objectui#7814) for overlapping filters; fixed and re-run. REPO CHECKS at a0bc45d76e, all exit 0: check:control-bytes 'OK (scanned 9766 tracked text file(s))'; check:new-line-citations 'VERDICT ... 0 new citation(s)'; check-changeset-presence '8 source file(s) of 4 released package(s) changed, and this change declares 4 changeset(s)'; changeset:check 'No changeset declares a major bump'; check:i18n-keys 'Every in-scope call-site key resolves'; check:i18n-designer-parity 'Every en row has a zh row'; check:test-path-roots 'OK'. Report-only: check:changeset-claims names 8 pending changesets that cite touched files, each re-read and still true; check:component-surface-parity has no element:text row; check-governed-queue-guard --test 'NOT GOVERNED'. ESLINT, narrowed: eslint --no-inline-config --format json over the 8 changed TS/TSX files -> 8 files, 0 errors, 19 warnings, 0 ignored. All 19 are in elements.tsx and identical to the base blob linted via --stdin (12 no-explicit-any, 5 only-export-components, 1 set-state-in-effect, 1 exhaustive-deps). Invariance: eslint.config.js sets no parserOptions.project or projectService (not type-aware), and no rule under eslint-rules/ reads the filesystem, so this diff moves no untouched file's verdict; the repo-wide pnpm lint belongs to CI. ABLATIONS, from committed dddea6a024 (the elements.tsx blob is unchanged at a0bc45d76e), via objectstack scripts/ablation-replace.mjs wrapped in a trap. Every leg showed the anchor going x1 -> x0 and the blob changing, then a restore with blob 03740bf2 == HEAD blob and git diff HEAD empty. A1, drop heading/subheading from the registry enum: the new pin goes 3 failed / 47 passed (accept-set equality, html tier compiles heading, html tier compiles subheading) while registry-inputs-spec-parity stays 230/230 green. A1c, the control on the same path, widens the enum with 'title': the parity gate goes red ('element:text declares no arm the spec refuses outright'), proving it reads the mutated source. A2, h1 mapped to p: pin 1 failed ('h1 renders the heading element it names'). A3b, skipFallback set to false (the guard reads !meta?.skipFallback): bare-key pin 3 failed / 4 passed, including the rewritten absence case. The first A3 attempt was refused by the tool before any test ran (its replacement text already occurred, so the write could not be proven); it restored by blob equality and was re-run as A3b.", "mcp_calls": "0 — no MCP GitHub tool was called. Reads used unauthenticated REST GET via curl.", "api_writes": "3 REST writes, each relayed through scripts/pm (fleet-write dispatch -> objectstack-fleet[bot]): (1) pr_create, POST /repos/objectstack-ai/objectui/pulls (draft, PR #11304; relay run 36800864279 success); (2) label-write --assign os-warren, POST /repos/objectstack-ai/objectui/issues/11304/assignees (relay run 36800969368 success; the read-back matches, labels untouched); (3) this os-dev-report, POST /repos/objectstack-ai/objectui/issues/7450/comments via post-stamped.mjs. Plus git push (not REST), three pushes: the empty branch, dddea6a024, and the merge a0bc45d76e.", "gates": { "build_console_closure": "exit 0 @a0bc45d76e", "type_check": {"@object-ui/types": 0, "@object-ui/components": 0, "@object-ui/app-shell": 0, "@object-ui/console": 0}, "vitest_matrix": "472 files / 10178 tests passed, exit 0 @a0bc45d76e", "check:control-bytes": 0, "check:new-line-citations": 0, "check-changeset-presence": 0, "changeset:check": 0, "check:i18n-keys": 0, "check:i18n-designer-parity": 0, "check:test-path-roots": 0, "check:changeset-claims": "0 (report-only, 8 findings re-read, all still true)", "check:component-surface-parity": "0 (report-only, no element:text row)", "governed": "NOT GOVERNED", "eslint_narrowed": "8 files, 0 errors, 19 warnings (equal to base)", "pnpm check (CLI)": "NOT MEASURED: packages/cli dist not built; it validates JSON schema files through safeValidateSchema, whose element:text accept set is spec-derived and unchanged, and the diff touches no file it reads; CI runs it", "ci": "in_progress (not awaited, per contract)" }, "line_budget": "not applicable (no skills/** or governed file). Diff: 12 files, +478 / -29 (4 changesets, 3 test files, 5 source files).", "deviations": [ "Zone 2.2, measured and partly falsified: the registry inputs enum keeps heading/subheading (the contract's eleven, nine first) because it is the html tier's accept set and the published manifest's. Only the Studio inspector stops offering them. Literal reading: 'the registry inputs enum ... offer[s] the nine'.", "Zone 2.3: body/caption/overline render a p element (element:text's established block element, unchanged bytes for body/caption), not ui:text's span. The class matches ui:text's for all nine.", "File surface: packages/components/src/__tests__/text-bare-key-resolution-7450.test.tsx (an existing 7450 pin) was rewritten in its header and last case, because the convergence made its h1 case non-discriminating. text.tsx was NOT touched, under the order's 'do not change ui:text', although one of its docblock paragraphs is now stale (see the findings).", "Main moved (objectui#11292 landed); merged origin/main d79f525d9e (no rebase, no force) and re-ran build, type-checks and the full matrix on the merged head.", "The container restarted mid-run; the in-flight test matrix was re-run and all results quoted are from a0bc45d76e." ], "files_changed": [ ".changeset/7450-element-text-published-variants.md", ".changeset/7450-element-text-refusal-prose.md", ".changeset/7450-inspector-text-variant-options.md", ".changeset/7450-preview-sample-text-variant.md", "apps/console/src/preview-samples.ts", "packages/app-shell/src/views/metadata-admin/i18n.ts", "packages/app-shell/src/views/metadata-admin/previews/__tests__/element-text-variant-options-7450.test.ts", "packages/app-shell/src/views/metadata-admin/previews/block-config.ts", "packages/components/src/__tests__/text-bare-key-resolution-7450.test.tsx", "packages/components/src/renderers/basic/__tests__/element-text-published-variants-7450.test.tsx", "packages/components/src/renderers/basic/elements.tsx", "packages/types/src/zod/public-blocks.zod.ts" ], "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed: text.tsx's docblock paragraph 'The two vocabularies are NOT reconciled here and must not be: element:text publishes heading/subheading/body/caption ...' is stale after this PR. It was left untouched under the order's 'do not change ui:text'. A comment-only fix is suggested in PR #11304's Acceptance notes; the seat can approve it as a patch round.", "carrier: none · noted, not filed: the inspector shows a stored legacy heading/subheading through InspectorSelectField's generic 'not found' flag. A 'deprecated' flag would need per-field plumbing in BlockPropField (polish).", "carrier: none · noted, not filed: the preview sample's h3 now renders the same size as page:header's bare-title h1 (both text-2xl). The ui:text heading ladder and page:header's title size disagree (polish).", "carrier: none · noted, not filed: @object-ui/components declares @objectstack/spec ^17.0.0, while its offered enum matches 17.5.0's accept set. The validator @object-ui/types sets its floor at ^17.5.0, and check-spec-range-floors judges symbol presence only (objectui#9036). This is the behavioural-floor leg that card priced and left unjudged." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
os-dev-report
{ "issue": 7450, "round": "patch round 1", "status": "done", "branch": "claude/issue-7450-element-text-published-variants", "pr": "https://github.com/objectstack-ai/objectui/pull/11304", "head": "17d8023eb7 (parent a0bc45d76e; main NOT merged)", "session": "session_0122Knsowci76D2rBWReCzzZ (the dispatching seat's session; this dev ran as its subagent)", "premise_still_valid": true, "summary": "As the seat ruled, the stale ui:text docblock paragraph is now in scope. packages/components/src/renderers/basic/text.tsx: ONLY the paragraph that began 'The two vocabularies are NOT reconciled here and must not be' was rewritten. It now says three things. First, since objectui#7450 both primitives take ONE vocabulary, the published nine; element:text takes this map's nine (overline included) with this map's class for each, and this map is the vocabulary that does not move. Second, element:text still also accepts heading / subheading because the installed @objectstack/spec does; their retirement is a later spec release, through objectstack-ai/objectstack#17109's value-level mechanism, never this file. Third, the objectui#6942 defaulting asymmetry stays (pointing at the existing ABSENCE IS NOT body note). The same paragraph also clarifies that the adjacent paragraph ('The map is modelled on ElementTextRenderer ... Only overline has no counterpart there') records how this map was first built, not which way the dependency runs now; that adjacent paragraph's own text is untouched. Comment only: no code, class or export changed (every changed line is a docblock line). PR body not edited. Worktree recreated from the branch at a0bc45d76e and removed after the push.", "tests": "On the worktree whose only change was text.tsx (then committed unchanged as 17d8023eb7). pnpm check:control-bytes -> exit 0, 'OK (scanned 9766 tracked text file(s))'. node scripts/check-new-cross-file-line-citations.mjs --base d79f525d9e -> exit 0, 'VERDICT new-cross-file-line-citations: 0 new citation(s)'. node scripts/check-changeset-presence.mjs --base d79f525d9e -> exit 0, '9 source file(s) of 4 released package(s) changed, and this change declares 4 changeset(s)'. Both diff gates first ran without --base and were PRECONDITION NOT MET (exit 2 'no merge base between origin/main and HEAD', and exit 1 'Cannot resolve the commit to compare against'): the shared clone is now shallow (--is-shallow-repository true) and origin/main has moved to 1ccb5ba7de, which has no connected history. Those runs measured nothing and are not counted. The explicit base d79f525d9e is the main tip this branch merged; git merge-base --is-ancestor d79f525d9e HEAD -> exit 0, which proves itself; the control dddea6a024 -> exit 0. pnpm --filter @object-ui/components run type-check under os-verify-lock (slot issue-7450): attempt 1 exit 2 = PRECONDITION NOT MET (TS2307/TS2882, the fresh worktree had no built closure), so the script built pnpm --workspace-concurrency=2 --filter '@object-ui/components^...' run build (exit 0) and re-ran: 'TYPECHECK @object-ui/components EXIT=0'; lock 'VERDICT command-exit 0'. The vitest matrix was not re-run: comment-only change, not ordered.", "mcp_calls": "0", "api_writes": "1 REST write: this patch-round os-dev-report, POST /repos/objectstack-ai/objectui/issues/7450/comments via post-stamped.mjs (fleet relay). Plus 1 git push (17d8023eb7, not REST).", "gates": { "check:control-bytes": 0, "check:new-line-citations (--base d79f525d9e)": 0, "check-changeset-presence (--base d79f525d9e)": 0, "type-check @object-ui/components": 0, "ci": "in_progress (not awaited)" }, "deviations": [ "The two diff gates were run with an explicit --base d79f525d9e because the shared clone is shallow and origin/main has no merge base with HEAD; the default-base runs were PRECONDITION NOT MET and are not counted." ], "files_changed": ["packages/components/src/renderers/basic/text.tsx"], "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
os-dev-report
{ "issue": 7450, "round": "patch round 2", "status": "done", "branch": "claude/issue-7450-element-text-published-variants", "pr": "https://github.com/objectstack-ai/objectui/pull/11304", "head": "f6703b0c37 (parent 17d8023eb7; main NOT merged)", "session": "session_0122Knsowci76D2rBWReCzzZ (the dispatching seat's session; this dev ran as its subagent)", "premise_still_valid": true, "summary": "Contract review finding F1 is fixed, text only. In .changeset/7450-element-text-published-variants.md (@object-ui/components), the sentence 'the html tier refused `h1`, `h4`-`h6` and `overline`' now reads 'the html tier refused all seven of them (`h1`-`h6` and `overline`)'. The old registry enum carried no h2 or h3 either, so seven values were refused, as the new pin's header already said. On-disk check: the new phrase count went 0 to 1, the old phrase count went 1 to 0, and the committed blob carries the new phrase (count 1). The other three 7450 changesets do not carry the sentence: grep for 'refused' or 'h4' over .changeset/7450-*.md hit only this file and the types changeset's unrelated 'No accepted or refused value moves'. The PR body is not edited. The worktree was recreated from the branch at 17d8023eb7 and removed after the push.", "tests": "On the worktree whose only change was this changeset, committed unchanged as f6703b0c37. pnpm check:control-bytes: exit 0, 'OK (scanned 9766 tracked text file(s))'. node scripts/check-changeset-presence.mjs --base d79f525d9e: exit 0, '9 source file(s) of 4 released package(s) changed, and this change declares 4 changeset(s)'. pnpm changeset:check: exit 0, 'All workspace packages are in the changeset fixed group' / 'privatePackages declared' / 'No changeset declares a major bump'. pnpm check:changeset-claims: exit 0 (report-only), compared against d79f525d9 (merge-base with origin/main). Self-contradiction reading: 'Every package declared across those 4 body(ies) is either not negated...'. Went-false reading: 10 pending changesets name touched files, 2 more than round 0 because text.tsx is now touched (6150, 7735). All 10 were re-read; see the findings for 6150.", "mcp_calls": "0", "api_writes": "1 REST write: this patch-round os-dev-report, POST /repos/objectstack-ai/objectui/issues/7450/comments via post-stamped.mjs (fleet relay). Plus 1 git push (f6703b0c37, not REST).", "gates": { "check:control-bytes": 0, "check-changeset-presence (--base d79f525d9e)": 0, "changeset:check": 0, "check:changeset-claims": "0 (report-only; 10 findings re-read)", "ci": "in_progress (not awaited)" }, "deviations": [], "files_changed": [".changeset/7450-element-text-published-variants.md"], "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed (re-read owed by check:changeset-claims; went false BEFORE this branch). The pending .changeset/6150-undeclared-but-consumed-keys.md table says ui:text reads content at renderers/basic/text.tsx as `{schema.content || schema.value}`. At the branch's merge base d79f525d9e, text.tsx renders `{schema.content}` only: 0 `schema.value` reads, against 2 `schema.content` reads as the control. This branch's edit to text.tsx was comment-only and did not change it. The sentence will ship to the CHANGELOG as written. The seat decides whether a docs-only correction is wanted.", "noted: the other 9 flagged paragraphs (6310, 6726, 6783, 7125, 7735, 8278, 8279, 8344, 8632) still hold. 7735's text.variant row says 'text.tsx: none — a bare node, no typography class', which is still true." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
✅ ACCEPT: PR objectui#11304 at
f6703b0c3; ready and auto-merge follow this ACCEPTdomain:uiseat 1 ·session_0122Knsowci76D2rBWReCzzZ· 2026-10-01T02:00Z. Checked against the diff and the head's check-runs. Claim5922104823; dev reports5922856780, patch round 15922909345and patch round 25923066182.CONTRACT_REVIEW_TIER:5923048816on17d8023ebwas PASS. Its F1 was a changeset sentence that counted five refused values where seven were refused. Patch round 2 corrected that sentence only.5923142944is PASS on this head, which is the landing head. Round 1's judgments carry over.Implemented-by: claude/issue-7450-element-text-published-variants,Reviewed-by: session_0122Knsowci76D2rBWReCzzZ.5565743592), objectui's halfelement:texttakes the published nine (h1–h6,body,caption,overline).h1–h6render the heading they name, and all nine carry exactlyui:text's class.element:textkeeps its?? 'body'default, and its docblock says why it differs fromui:text(objectui#6942)@objectstack/spec17.5.0: the nine plusheading/subheading, defaultbody. So the registryinputsenum is the contract's eleven, nine first, because it is also the html tier's accept set and the publishedsdui.manifest.json's. Dropping the two would be a local refusal ahead of the spec, and ablation A1 measured exactly that. Only the Studio inspector, which is purely an offer, lists just the nine. No local retirement mechanism (the routing5599600566)heading/subheadingh2/h3). Their named refusal is the spec's later release, now carried by objectstack-ai/objectstack#21015 (filed here, with the objectui follow-up named)pelementbody/caption/overlinerenderelement:text's establishedp(byte-identical forbody/caption), notui:text'sspan:ALIGN_CLASShas noblock, so aspanwould leavealigninert. The migration's size change (headingone step larger,subheadingtext-lg→text-2xl) is disclosed in the PRpreview-samples.ts'ssubheading→h3with its prose corrected,public-blocks.zod.ts's refusal prose, the inspector's en / zh rows, andtext.tsx's docblock rewritten comment-only (AGENTS.md #2;ui:text's behaviour is untouched)@object-ui/componentsminor (the offered accept set widens);@object-ui/app-shell,@object-ui/typesand@object-ui/consolepatch.Clause-②: yes(the claim). The PR body's "five" refused values predates patch round 2: the changeset, which is the release text, now says sevenneeds:contract-reviewbelongs on both carriers.references/contract-review.mdnow says the marker is the PR's alone, and is hung only when no same-form PASS exists at ACCEPT. One does, so no marker is hungf6703b0c3: 43 runs, 40 success, 3 expected skips, 0 failuremainsinced79f525d9e, not touching this PR's 13 files. A test merge onto currentmain(1ccb5ba7de) is clean, and the merge queue re-tests the merged treecheck-governed-merges.mjs: not governed.Fixes #7450Out-of-scope findings:
heading/subheadingthrough its generic "not found" flag, and the preview sample'sh3is the same size aspage:header's bare-titleh1→ Acceptance notes (polish, no reach).@object-ui/componentsdeclares@objectstack/spec^17.0.0while its offered enum matches 17.5.0 → already carried by objectui#9036 (the behavioural-floor leg it priced), not a new card.6150-undeclared-but-consumed-keys.md(objectui#6150, closed) still saysui:textreads{schema.content || schema.value}. That went false at PR objectui#7761 (objectui#7016's retirement), andtext.tsxreadsschema.contentonly, before and after this PR. The pending6951-text-value-retired.mdstates the retirement in the same release. This PR'stext.tsxhunk is docblock-only → Acceptance notes: a text-only amendment to that changeset row, for the lane that owns it.domain:uiseat 1 · ACCEPT · 2026-10-01T02:00ZGenerated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
Landed: PR objectui#11304 merged as
caa0cd3927; closedcompleteddomain:uiseat 1 ·session_0122Knsowci76D2rBWReCzzZ· 2026-10-01T02:26Z.Fixes #7450) merged through the merge queue ascaa0cd3927, which is onorigin/main. The merge closed the card by itsFixeskeyword. The seat removes thepm:dispatchedstate label and the assignee in the same pass.origin/mainare blob-identical to the landing headf6703b0c3.5565743592):element:texttakes the published nine (h1–h6,body,caption,overline) withui:text's classes, and keeps its?? 'body'default. The Studio inspector offers the nine. The registryinputsenum follows the installed spec's accept set exactly (the nine plusheading/subheading), so no spec-valid document is refused locally. The one in-repo producer moved toh3. The records are5923048816and the delta5923142944(at-tier PASS on the landing head), and the ACCEPT is5923218642.heading/subheadingbecome named refusals through spec: there is no VALUE-level retirement mechanism —retiredKey()retires a key, and a ruled enum-member retirement has nothing to land on objectstack#17109's mechanism, is carried by spec(ui): release 2 of the objectui#7450 convergence —element:text.variant'sheading/subheadingbecome named refusals through the value-level retirement mechanism objectstack#21015. When that release is installable, objectui's registry enum drops the two values in a one-line follow-up that card names.h3/page:headertitle size parity; and the closed objectui#6150's pending changeset row that still saysui:textreadsschema.value.domain:uiseat 1 · landed · 2026-10-01T02:26ZGenerated by Claude Code
feat(components): element:text takes the published nine `variant` val…