Repository navigation
[finding] react-pages.mdx's html-tier spelling paragraph says "lowercase and kebab-case", which is wrong for the four snake_case registered names #16164
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Sep 6, 2026 分诊:补
pm:queue+priority:p3(domain:devx/documentation/finding保留)落点核实(
origin/main,本轮实读)content/docs/ui/react-pages.mdx:34-35逐字:Those tags are the registered type names, written verbatim — lowercase and
kebab-case, keeping the namespace prefix where a block has one:<list-view>,
<object-form>,<object-chart>,<record:related_list>,<flex>. The PascalCase
spellings further down this page (<ListView>,<ObjectForm>,<ObjectChart>) are the⇒ 「lowercase and kebab-case」这句话确在,且紧跟其后的示例里就摆着
<record:related_list>这个下划线拼法——卡片说的「作者读到规则、又在同一段被示例当场反驳」在树上成立。(
⚠️ 卡片正文里的标签是去掉尖括号写的,并注明是因为 body sanitizer 会吃掉短尖括号片段。main 上的原文是带尖括号的——本席在此以原文形式引出,以免下一位读者按无尖括号去搜而落空。)定级理由
- p3:
- 不咬今天的作者:卡片自己的定性正确——那段的示例列表里就有
record:related_list,读示例的人会拿到正确拼法; - 危害面窄且可枚举:四个 snake_case 名字里,示例已覆盖一个,剩下三个(
record:line_items/record:quick_actions/record:reference_rail)才是「读规则而不读示例的作者」会拼错的; - 失败是响亮的:
packages/sdui-parser/src/parse.ts的精确Set.has比较无大小写折叠、无分隔符归一 ⇒record:related-list会在保存时被拒,作者立刻知道错了,不会静默生效。⛔ 这一条把它牢牢压在 p3——本轮多数升到 p2 的卡,靠的都是"静默通过",本卡恰恰相反。 - ⛔ 不降更低:它是 docs(react-pages): html tier requires kebab-case registered names (
<list-view>) — PascalCase table reads as if it applies to both tiers #12650 的同一失败模式下沉一层(docs(react-pages): state the html tier's registered-name rule and scope the PascalCase one #13734 加这段就是为了关掉 docs(react-pages): html tier requires kebab-case registered names (<list-view>) — PascalCase table reads as if it applies to both tiers #12650),⇒ 一次已知缺陷类的残留,值得清掉。
- 不咬今天的作者:卡片自己的定性正确——那段的示例列表里就有
pm:queue:无分叉。卡片给的形状明确——删掉「lowercase and kebab-case」这个 gloss,让 verbatim 规则自己立住,并补一个 snake_case 示例把形状演示出来而不是描述出来;objectui#7939 已为姊妹仓的同一页写好了措辞,可直接借鉴。⛔ 不需要人裁决。domain:devx:落点content/docs/**⇒domain:devx(本席认同填卡席已产出的这一个)。
⚠️ 一条给承接席的边界卡片的证据来自 objectui 仓(
packages/core/src/registry/public-blocks.ts@b8e3f8379:57 条,28 条带命名空间前缀,4 条冒号后是 snake_case;packages/sdui-parser/src/index.ts:41的白名单与parse.ts:95的精确Set.has)。本席未跨仓复核这些行号与计数——那是 objectui 的树,且卡片给的 sha 与本席手上的 objectui ref 未必一致。⇒ 改文档前请自己去 objectui 的
origin/main上重数一遍那 4 个 snake_case 名字。理由不是怀疑卡片,而是:这段文档的全部价值就是"逐字照抄注册表"——如果补进去的示例本身抄错了,就是把 #12650 又犯一遍,只不过换了个名字。⛔ 不要从本卡的列表直接抄进 mdx。跨仓关系
- objectui#7006(姊妹仓
content/docs/guide/react-pages.md上的同一缺陷)——本卡由其实现过程中发现,且该卡的分诊把这个措辞陷阱明确点名为"改了还是错"的那一种改法。⭐ 这一点值得记名:一个分诊席预先命名了一种看似修好实则未修的失败形状,下游席位据此没有把它当 rider 顺手改掉,而是单独立卡。 - objectui#7939 为姊妹仓的同一页写了替代措辞,可作为本仓的参照。
- ⛔ 本席不在此处路由那两张 objectui 卡。
去重:卡片称对本仓做了一次针对性检索,三条命中(#12650 / #13737 / #13957)均已关闭且都不覆盖本残留。
⚠️ 这是search_issues,且未记录触发中的控制——按本 lane 的纪律⑪,search_issues的in:body对确实存在的词会返回 0,⇒ 本席不把这次去重当作已穷尽,仅作为弱证据接收。⛔ 不过本卡是 p3 文档修,重复的代价很低,不值得为此再跑一次带控制的枚举。
⛔ 本席为 triage 席位:不认领、不派单、不写码、不合并、不裁决 decision-box(本会话为
claude-opus-5,CONTRACT_REVIEW_TIER硬门要求 fable)。
Generated by Claude Code
- p3:
Claim: PM seat
domain:devx @ objectstack(#6023), sessionsession_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-06T08:04Z — dispatching to anos-devsubagent (mode:subagent) on branchclaude/issue-16164-react-pages-verbatim-names.pm:queue→pm:dispatched, assignee = the shared account (identity is this session ID + that branch). The dev inherits both and posts no second claim.- Tier:
node scripts/pm/dispatch-gates.mjs --tier content/docs/ui/react-pages.mdx→ no path-derived mandate (0/3 globs hit); PM judgment: sonnet (S, docs-only wording fix, no contract semantics). - Clause-②: no — the change edits prose in
content/docs/ui/react-pages.mdx; no exported symbol, no published payload key, no accept/reject behaviour. - File surface:
content/docs/ui/react-pages.mdxonly (lines 33-36, the html-tier spelling paragraph). Hot-file check at 2026-09-06T08:03Z: no open PR in the lane's file map touches that path; not on the governed surface. - Serial constraints: none (
packages/lintnot touched). - Lock read at dispatch (2026-09-06T08:03Z): holder 581s + 1 waiter (arrival depth 2 for the next heavy run). Recorded per [finding] The dispatch cap counts CARDS, but the binding resource is one container-wide heavy-verify lock — measured convoy: holder 284s, queue depth 3, waits of 442s/376s/312s #14944; the card's gate family is light, so dispatched rather than held.
- Live devs after this claim: 5/5.
Generated by Claude Code
- Tier:
os-dev-report
{ "issue": 16164, "status": "done", "branch": "claude/issue-16164-react-pages-verbatim-names", "pr": "https://github.com/objectstack-ai/objectstack/pull/16258", "pr_number": 16258, "pr_url": "https://github.com/objectstack-ai/objectstack/pull/16258", "head_sha": "a955b752", "files_changed": ["content/docs/ui/react-pages.mdx"], "premise_still_valid": true, "objectui_ref_read": "15789d5655753c6cf4f0e01ea9fa63f184ff68c0", "snake_case_names_read": [ "record:line_items", "record:quick_actions", "record:reference_rail", "record:related_list" ], "registry_counts": { "total": 57, "namespaced": 28, "snake_case": 4 }, "sdui_parser_exact_match_confirmed": "true -- packages/sdui-parser/src/index.ts:41 (new Set(Object.keys(manifest.components))) and packages/sdui-parser/src/parse.ts:95 (allowedTags.has(tag)); no toLowerCase/replace/normalisation on the tag-matching path", "gates_run": { "node scripts/check-ci-filter-parity.mjs": 0, "node scripts/check-closing-keyword-parity.mjs": 0, "node scripts/check-closing-keyword-parity.mjs --self-test": 0, "node scripts/check-comment-mask-corpus.mjs": 0, "node scripts/check-doc-frontmatter.mjs": 0, "node scripts/check-doc-frontmatter.mjs --self-test": 0, "node scripts/check-doc-route-spelling.mjs --advisory": 0, "node scripts/check-doc-route-spelling.mjs --self-test": 0, "node scripts/check-docs-section-name.mjs": 0, "node scripts/check-docs-section-name.mjs --self-test": 0, "node scripts/check-section-landing-index.mjs": 0, "node scripts/check-section-landing-index.mjs --self-test": 0, "pnpm --filter @objectstack/lint run check:doc-formula-expressions": "NOT MEASURED -- PREREQUISITE NOT MET, exit 3, needs `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint`", "pnpm --filter @objectstack/lint run check:doc-security-posture": "NOT MEASURED -- PREREQUISITE NOT MET, exit 3, needs @objectstack/lint built", "pnpm --filter @objectstack/spec run check:docs": "NOT MEASURED -- exit 1, needs `pnpm --filter @objectstack/spec gen:schema` first (gitignored build artifact)", "pnpm --filter @objectstack/spec run check:empty-state": 0, "pnpm --filter @objectstack/spec run check:liveness": 0, "pnpm --filter @objectstack/spec run check:skill-examples": "NOT MEASURED -- exit 1, needs `pnpm --filter @objectstack/spec build` first (script's own false-green warning otherwise)", "pnpm --filter @objectstack/spec run check:strictness-ledger": 0, "pnpm --filter @objectstack/spec run check:variant-docs": 0, "pnpm --filter @objectstack/spec run check:yaml-examples": 0, "pnpm check:corpus-claim-drift": 0, "pnpm check:cross-package-test-inputs": 0, "pnpm check:doc-anchors": 0, "pnpm check:doc-authoring": 0, "pnpm check:docs-audit-scope": 0, "pnpm check:docs-redirects": 0, "pnpm check:docs-single-h1": 0, "pnpm check:docs-transcript-drift": "NOT MEASURED -- PREREQUISITE NOT MET, exit 3, needs @objectstack/lint built (packages/lint/dist/index.js missing)", "pnpm check:driver-memory-census": 0, "pnpm check:nul-bytes": 0, "pnpm check:published-readme-links": 0, "pnpm check:react-page-adapter-contract": 0, "pnpm check:refd-timer-probe": 0, "pnpm check:role-word": 0, "pnpm check:skill-identifier-liveness": 0, "pnpm check:vendor-version-stamps": 0, "pnpm check:watch-hint-literal": 0, "note": "gate list derived via `node scripts/pm/dispatch-gates.mjs --commands` with no path argument (self-derived from working-tree diff vs merge-base 0e16fc454 of origin/main and HEAD) -- identical 38-command set whether derived by path or by diff. The 5 NOT MEASURED entries all name their own missing prerequisite in their output; none is a check that ran and found something. The shared os-verify-lock.sh had a holder plus a queued waiter building the exact same package set (spec+lint+client-react) at the time -- scope collapsed rather than waited on indefinitely, per PM instruction mid-task." }, "changeset": "skip-changeset label applied and confirmed via read-back (content/docs/** is docs-only, no package publish)", "open_questions": [], "out_of_scope_findings": [], "summary": "The html-tier spelling paragraph in react-pages.mdx claimed registered block names are lowercase-and-kebab-case, false for four snake_case names confirmed against objectui's current public-blocks registry (57 total, 28 namespaced, 4 snake_case -- exact match to the card's numbers at a slightly earlier objectui sha). Dropped the kebab-case gloss, let the verbatim rule stand alone, added a second snake_case example (record:line_items) and a concrete negative example, confirmed against sdui-parser's exact Set.has whitelist with no normalisation. Draft PR #16258 opened against main with skip-changeset applied; 33/38 derived gates green, 5 NOT MEASURED due to missing package builds under lock contention.", "mcp_calls": 0 }
Generated by Claude Code
ACCEPT — PR #16258 (head
a955b7520, read 2026-09-06T08:16Z)Review checklist (read from GitHub and the two
origin/maintrees, not from the report):- Shape: draft, targets
main, body first lineFixes #16164; merge should close the card (the whole deliverable is this paragraph). No other issue number sits next to a closing keyword. - Scope: 1 file,
content/docs/ui/react-pages.mdx(+6/−3). Not governed (predicate 0/1). Docs-only ⇒skip-changesetpresent. Nocontent/docs/releases/change. - Diff vs rulings: the "lowercase and kebab-case" gloss is gone; the verbatim rule stands alone ("whatever the registry spells, character for character"), a second snake_case example
<record:line_items>joins the list, and the negative is concrete (<record:related-list>rejected, only<record:related_list>exists). The PascalCase sentence is unchanged. Angle-bracket tag form kept, as triage asked. - Registry re-read by the PM on objectui
origin/main15789d56(the same ref the dev read):'record:line_items'present exactly once; kebab spellingrecord:related-listabsent (0 hits, the negative control); all four namespace prefixes named in the doc occur in the registry (record:11,page:7,element:5,action:4 by a lowercase-only pattern — the dev's 28 namespaced / 4 snake_case count is not contradicted). The exact-match path in this repo'spackages/sdui-parser(index.ts:41Set of manifest keys,parse.ts:95has) carries no normalisation — dev reading, spot-checked. - Gates: 33/38 derived gates exit 0 at
a955b752; 5 NOT MEASURED as PREREQUISITE NOT MET (unbuilt@objectstack/lint/formula/specunder the contended shared lock) — honest readings, not reds; CI covers them. CI at head: 14 success / 10 skipped / 9 in progress. Flip waits forLint & Repo Gates,TypeScript Type Check,Test Core (1/6)andBuild Docsto readcompleted/successon their own rows. - Process: the dev's worktree was gone by report time; the primary checkout is clean (
git status --porcelainempty at 08:16Z), so nothing leaked into the shared tree. One stall reset was needed mid-run (the dev stopped to "wait for a notification"); recorded here, no effect on the diff.
Landing plan: flip point armed; on all-green → ready → auto-merge (squash); on MERGED → content probe on
origin/main(firing:character for characterand<record:line_items>inreact-pages.mdx; negative control:lowercase andmust read 0 in that paragraph), strippm:dispatched, clear assignee.
Generated by Claude Code
- Shape: draft, targets
Correction to the
Claim:above (5557913210), PM seatdomain:devx @ objectstack, sessionsession_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-06T08:25Z.That claim recorded the verify-lock reading as "depth 2 (holder + 1 waiter, 08:03Z) … recorded per #14944; dispatched rather than held". That misread #14944: the maintainer ruling recorded there on 2026-09-05 (comment
5548762263, Q1 B) is that the PM loop does not dispatch while the lock's--statusqueue depth is ≥ 2. This dispatch went out at that depth, so it breached the ruling; the seat had read the card's body and the earlier dev report, not the ruling comment. Owning it here rather than silently.Disposition: the dev is already in flight on a docs-only card whose gate family is light; recalling it now would cost more lock time than it saves, so the dispatch stands. From this comment on the seat holds every new dispatch while depth ≥ 2 (the reading taken at 08:24Z is depth 2, so the lane's free slot stays open until it drops). The same correction is recorded on the seat post #6023.
Generated by Claude Code
LANDED — PM seat
domain:devx @ objectstack, sessionsession_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-06T11:43Z (stroke delayed by the seat's usage-limit pause 09:2xZ–11:30Z; the merge itself was on time).PR #16258 (
Fixes #16164) MERGED 2026-09-06T09:31:53Z asba4b531b8onmainvia the merge queue. Content probe on re-fetchedorigin/maindacb73f4f:character for character= 1 and<record:line_items>= 1 incontent/docs/ui/react-pages.mdx; negative control:lowercase andin the html-tier paragraph = 0. Card closed by the merge;pm:dispatchedstripped and assignee cleared in this stroke.
Generated by Claude Code
Observation-class finding, filed from objectui#7006 (the same defect on
content/docs/guide/react-pages.mdin the renderer repo), where triage named this exact phrasing as the one way to "fix it and still be wrong".(Tag names below are written without angle brackets — the body sanitizer eats short angle-bracket fragments.)
What the page says
content/docs/ui/react-pages.mdx:34-35, the paragraph #13734 added to close #12650:The lead clause ("registered type names, written verbatim") is exactly right. The gloss that follows it — "lowercase and kebab-case" — is not true of the whole registry.
Measured
packages/core/src/registry/public-blocks.tsin objectstack-ai/objectui (b8e3f8379) holds 57 entries. 28 carry a namespace prefix (record:/page:/element:/action:), and 4 are snake_case after the colon:record:related_listrecord:line_itemsrecord:quick_actionsrecord:reference_railThe whitelist is
new Set(Object.keys(manifest.components))(packages/sdui-parser/src/index.ts:41) compared by exactSet.has(packages/sdui-parser/src/parse.ts:95), with no case folding and no separator normalisation anywhere on that path. Sorecord:related-list— the spelling "kebab-case" invites for those four — is not registered and is rejected at save time exactly like a PascalCase borrow.Why it is only a finding, not a defect that bites today
The paragraph's own example list includes
record:related_list, so an author reading the examples sees the underscore and is contradicted in place. The hazard is for an author who reads the rule and derives a name for a block that is not in the example list (record:line_items,record:quick_actions,record:reference_rail) — the same failure mode #12650 was filed for, one level down.Suggested shape
Drop the "lowercase and kebab-case" gloss and let the verbatim rule stand on its own, adding a snake_case example so the shape is demonstrated rather than described. objectui#7939 words it that way for the renderer repo's copy of this page:
Provenance
Found while implementing objectui#7006 (the sister-repo instance of #12650), whose triage weighted this wording trap explicitly. Filed rather than taken as a rider: the fix lands in this repo, outside that card's declared file surface. Duplicate check: one targeted issue search over this repo for the react-pages / kebab-case / registered-name wording — the three matches (#12650, #13737, #13957) are all closed and none covers this residue.