docs(skills): the html-tier page example spells object-metric's aggregate in the object form - #21667
Conversation
…gate in the object form
The `kind: 'html'` example in skills/objectstack-ui/rules/pages.md wrote
`aggregate="count"`, a string the html tier only warns on (`type-mismatch`)
and the metric tile cannot read: ObjectMetricWidget's computeOne reads
`aggregate.field` / `aggregate.function`. The line now reads
`aggregate={{"function":"count"}}`, the html tier's own expression spelling
the example's sibling attributes already use.
Claude-Session: https://claude.ai/code/session_01CB6W87z22K2yjUCDyVrJRk
Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Read-only shape otherwise: the diff against the merge base eea82af, card #21627 with every comment, the objectui tree at the live pin, the committed manifest, and this head's check-runs. Reviewed by the dispatch seat in seat (served tier equals the constant's value, read from ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
维护者速读(终稿)— PR #21667(#21627)· skills seat 1 · 2026-10-04T02:06Z改了什么: 对外发布的 UI 技能包 为什么改: 这一行是技能教给 AI 作者的「标准示例」。指标卡组件读的是对象(objectui 当前 pin 风险与代价(含回滚): 纯技能文本,不碰 席位意见: 建议批准。一行一值,席位逐项核过:diff 只有这一行;对象形与消费端、manifest 声明( 你要做的(一个动作): 在 PR #21667 上给一次 APPROVED review;批准后由席位清标、ready、挂 auto-merge 入队。 |
Fixes #21627
Clause-②: no
Summary
skills/objectstack-ui/rules/pages.md:160, theobject-metricline of thekind: 'html'example, readaggregate="count". The metric tile readsaggregateas an object: at the objectui pinab187972(.objectui-shaateea82af67),packages/plugin-dashboard/src/ObjectMetricWidget.tsxcomputeOne(:452–:497) sends{ field: aggregate.field, function: aggregate.function, groupBy, filter }tods.aggregateand reads the answer back underaggregate.function === 'count'throughr.count(its own comment: "the literal'count'for a fieldless count"), so a count needsfunction: 'count'and nofield. The string form hands both members over asundefined: the build passes with a warning and the tile draws no number.The line now reads
aggregate={{"function":"count"}}, the html tier's own expression spelling the example's sibling attributes already use (style={{"maxWidth":…}},gap={6}). One attribute value changed; no other byte of the file, no other file. The sibling surfaces already spell the object form (rules/dashboards.md:125, theanalytics-inline-vs-dataseteval) and are untouched.Positive control: the html tier's own compile, before and after
@objectstack/sdui-parsercompile(source, manifest)over the example'ssourcetemplate literal, with the committed repo-rootsdui.manifest.json(the manifestos buildresolves throughpackages/cli/src/utils/sdui-manifest.ts; it declaresobject-metric'saggregateinput astype: "object"):eea82af67):ok=true, 1 diagnostic:[warning] type-mismatch: object-metric prop "aggregate" expected an object(the tag is spelled bare here; the diagnostic prints it in angle brackets); the compiled node carriesaggregate: "count".d5e95044e):ok=true, 0 diagnostics; the compiled node carriesaggregate: {"function":"count"}.The script and its raw output are in the dev report comment on #21627.
Readings
eea82af67)d5e95044e)skills/objectstack-ui/rules/pages.md, whole file, linesskills/**/SKILL.md(10 files), linesscripts/check-skills-token-ratchet.mjs,pages.mdBytes 22701 → 22716 (+15). Net lines 0. No ceiling moved. Token count reported because the sibling gate (
check-skills-token-ratchet) defines one; there is no second token gate on this file.Gates run locally at
d5e95044eDerived with
node scripts/pm/dispatch-gates.mjs --commands(no paths; change set from the merge baseeea82af67): 23 commands. Every one run, exit captured before any pipe;--ranreconciliation attached in the report.node scripts/check-ci-filter-parity.mjs: exit 0, "OK: all 193 declared cross-package glob(s) … are covered".node scripts/check-closing-keyword-parity.mjs: exit 0;--self-test: exit 0, "40 assertions, 5 mutations … each driven to red".node scripts/check-comment-mask-corpus.mjs: exit 0, "8127 files, 0 disagree, 0 unparseable".node scripts/check-doc-route-spelling.mjs --advisory: exit 0, "population clean";--self-test: exit 0.node scripts/check-skills-token-ratchet.mjs: exit 0, "54 authored bundle file(s) within their ceilings";--self-test: exit 0, "65 cases pass".pnpm --filter @objectstack/lint run check:doc-formula-expressions(after building the@objectstack/lintclosure under the verify lock, VERDICT command-exit 0): exit 0.pnpm check:agent-test-spelling·check:corpus-claim-drift·check:cross-package-test-inputs·check:doc-authoring("53 published skill files clean") ·check:driver-memory-census·check:gitlink-declared·check:nul-bytes("scanned 10035 text file(s) … no raw ASCII control bytes") ·check:pm-governed-merges·check:refd-timer-probe·check:role-word·check:skill-compatibility("10 SKILL.md file(s) reconciled") ·check:skill-frame-sync·check:skill-identifier-liveness("457 citation(s) over 53 published file(s)") ·check:watch-hint-literal: all exit 0.Dispatch-named leads outside the derived list:
pnpm --filter @objectstack/spec run check:skill-docs: exit 0, "Skill docs in sync".pnpm --filter @objectstack/spec run check:skill-examples: first run exit 3,PREREQUISITE NOT MET(noclient-reactdist; nothing measured); after building the@objectstack/client-reactclosure under the verify lock (VERDICT command-exit 0, 210s held), exit 0: "260 prose examples type-check across 3 surface(s)". The edited html example block carries noos:checkmarker (the file's two markers sit at:64and:211), so this gate reads no byte of the diff; it is run because the dispatch named it.NOT MEASURED locally, CI's own: the
Test Coreshards, the four type-check lanes, the 11 whole-tree families, the 55 artifact-roster families and the 15 changeset-derived families (this PR carries no changeset:skills/**is shipped bynpx skills addfrom the repository, and no published package'sfiles[]lists it; measured, see the report).维护者速读(草稿)
改了什么
对外发布的 UI 技能包
skills/objectstack-ui里,rules/pages.md的kind: 'html'页面示例中object-metric那一行的aggregate属性,由字符串"count"改为对象{{"function":"count"}}。全文件只动这一个属性值:行数 453 → 453,整包 SKILL.md 行数 4397 → 4397,token 棘轮 5676 → 5679(上限 5692 未动)。为什么改
这一行是技能包教给 AI 作者的「标准示例」。原来的字符串写法
os build只给一条 warning(构建照样通过),而指标卡组件读的是对象(aggregate.field/aggregate.function),字符串下两个成员都是 undefined,页面上这块指标卡不显示数字 —— 技能本身在教一种「构建通过、运行时静默空白」的写法。同一技能包里dashboards.md与 eval 用的都是对象形,只有这一行走偏。实测:改前 html 层编译 1 条type-mismatch警告,改后 0 条。风险与代价(含回滚)
纯文本改动,不碰代码、schema 或任何其它文件;发布面是
skills/**(经npx skills add进客户项目),不走 npm,无 changeset。回滚即git revert本 PR 的单个 commit。已知残余:html 层对字符串形仍只给 warning 而非 error,卡与分诊裁决都把它划在本卡范围外,本 PR 不碰。席位意见
(留空,席位定稿)
你要做的
本 PR 触及
skills/**(Tier H),需要你的一次 APPROVED review;之后由席位落地。你不需要手改任何东西。Acceptance notes
89cad75d557;.objectui-shaateea82af67isab187972. ThecomputeOnereading above is taken atab187972(:452–:497) and holds there. Noted, not filed.type-mismatchseverity (a string handed to anobject-typed input is a warning, not an error) is out of scope by the card's own words and the triage ruling; noted, not filed.rules/dashboards.md:125spells the react tier's object form as a JSX object literal (single quotes); this html-tier line spells JSON, as its sibling attributes do. Both are the object form; neither changes.kind: 'html'example block is not anos:check-marked block (markers atpages.md:64and:211only), socheck:skill-examplescannot see this line; the positive control above is the measurement that stands in for it.skills/**is outside every published package'sfiles[](measured over every trackedpackage.json);skip-changesetrequested throughscripts/pm/label-write.mjs.Generated by Claude Code