Skip to content

docs(skills): the html-tier page example spells object-metric's aggregate in the object form - #21667

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-21627-pages-html-metric-aggregate
Oct 4, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-21627-pages-html-metric-aggregate

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #21627
Clause-②: no

Summary

skills/objectstack-ui/rules/pages.md:160, the object-metric line of the kind: 'html' example, read aggregate="count". The metric tile reads aggregate as an object: at the objectui pin ab187972 (.objectui-sha at eea82af67), packages/plugin-dashboard/src/ObjectMetricWidget.tsx computeOne (:452–:497) sends { field: aggregate.field, function: aggregate.function, groupBy, filter } to ds.aggregate and reads the answer back under aggregate.function === 'count' through r.count (its own comment: "the literal 'count' for a fieldless count"), so a count needs function: 'count' and no field. The string form hands both members over as undefined: 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, the analytics-inline-vs-dataset eval) and are untouched.

Positive control: the html tier's own compile, before and after

@objectstack/sdui-parser compile(source, manifest) over the example's source template literal, with the committed repo-root sdui.manifest.json (the manifest os build resolves through packages/cli/src/utils/sdui-manifest.ts; it declares object-metric's aggregate input as type: "object"):

  • before (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 carries aggregate: "count".
  • after (d5e95044e): ok=true, 0 diagnostics; the compiled node carries aggregate: {"function":"count"}.

The script and its raw output are in the dev report comment on #21627.

Readings

reading before (eea82af67) after (d5e95044e)
skills/objectstack-ui/rules/pages.md, whole file, lines 453 453
whole package, sum of every skills/**/SKILL.md (10 files), lines 4397 4397
scripts/check-skills-token-ratchet.mjs, pages.md 5676 / 5692 (headroom 16) 5679 / 5692 (headroom 13)

Bytes 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 d5e95044e

Derived with node scripts/pm/dispatch-gates.mjs --commands (no paths; change set from the merge base eea82af67): 23 commands. Every one run, exit captured before any pipe; --ran reconciliation 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/lint closure 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 (no client-react dist; nothing measured); after building the @objectstack/client-react closure 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 no os:check marker (the file's two markers sit at :64 and :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 Core shards, 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 by npx skills add from the repository, and no published package's files[] 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

  • The card cites the objectui pin 89cad75d557; .objectui-sha at eea82af67 is ab187972. The computeOne reading above is taken at ab187972 (:452–:497) and holds there. Noted, not filed.
  • The html tier's type-mismatch severity (a string handed to an object-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:125 spells 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.
  • The kind: 'html' example block is not an os:check-marked block (markers at pages.md:64 and :211 only), so check:skill-examples cannot see this line; the positive control above is the measurement that stands in for it.
  • No changeset: skills/** is outside every published package's files[] (measured over every tracked package.json); skip-changeset requested through scripts/pm/label-write.mjs.

Generated by Claude Code

…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>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d5e95044ef96ed0729344fe6b1a62a14c93eaa42
Local-runs: probe — node scripts/check-skills-token-ratchet.mjs run once in a detached read-only worktree at this head (and the same command once on origin/main for the baseline), so the token reading in ③ is this seat's own rather than the dev's; nothing built, nothing else run.

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 get_session). Review face: skills/**, governed rule text (Tier H). Readings taken at 2026-10-04T02:05Z.

① Derived judgments

  • Accept set: unchanged. One attribute value in one published skill example (skills/objectstack-ui/rules/pages.md +1/−1, :160); no schema, export, lint rule, error code or runtime behaviour moves. Clause-②: no holds.
  • The ruling's three lines, each read by this seat: aggregate={{"function":"count"}} in the html tier's own expression spelling, as the example's sibling attributes already use (gap={6}, style={{…}} on the context lines) — yes; no other line of pages.md changes — the diff is that one line, 453 → 453 lines; the html tier's type-mismatch severity is untouched — no file outside pages.md is in the diff.
  • The mechanism, re-read by this seat at the live pin: .objectui-sha on origin/main is ab187972; there, packages/plugin-dashboard/src/ObjectMetricWidget.tsx computeOne (:452–:497) sends aggregate.field / aggregate.function to ds.aggregate and, for function === 'count', sums r.count; the committed sdui.manifest.json declares object-metric's aggregate input as type: "object". The card's cited pin 89cad75d557 is not an object objectui's remote serves to this seat (git fetch origin 89cad75d557 finds no such ref); the reading holds at the live pin, so the card's citation is stale text, not a defect — as the dev's Acceptance note says.
  • Sibling surfaces spell the object form and are untouched: rules/dashboards.md:125 and evals/analytics-inline-vs-dataset.json:49, both read by this seat.
  • The before/after compile (one type-mismatch warning, then zero) is the dev's measurement, recorded in the report comment; this seat did not re-run it.

② Semver level

  • No released package publishes from this diff (skills/** is outside every published package's files[], per the dev's measurement over every tracked package.json); no changeset owed; skip-changeset is the correct declaration. No ADR-0087 disposition applies.

③ Boundary flags

  • Dev flags: open_questions empty. out_of_scope_findings[0] (class c candidate, the html tier's type-mismatch severity for a literal against an object-typed input, measured at the os build compile) is disposed on the ACCEPT. out_of_scope_findings[1] (the stale objectui pin in the card text): agreed, not a card.
  • Ratchet, read off the head tree by this seat against origin/main: pages.md 5676 → 5679 tokens (ceiling 5692, headroom 16 → 13); 453 → 453 lines; 22701 → 22716 bytes; no SKILL.md touched (the catalog sum on this tree is 4397 over 10 files). No ceiling moved.
  • Deviations read: the @objectstack/client-react closure built under the verify lock so check:skill-examples could measure (heavier than the dispatch lead; the gate reads no byte of this diff, as the dev showed by the marker positions :64 and :211); the gate runner's ledger reset and full re-run; the commit trailer per AGENTS.md. None a route change; mcp_calls 0; api_writes 3 as listed; report comment 5975567173 present and parses.
  • Check-runs on this head at this write: 19 success, 11 skipped, 3 in progress (Test Core 1/6, Lint & Repo Gates, Type Check · workspace) — the enqueue gate reads them at landing, not this record.

Implemented-by: claude/issue-21627-pages-html-metric-aggregate
Reviewed-by: session_01CB6W87z22K2yjUCDyVrJRk

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)— PR #21667(#21627)· skills seat 1 · 2026-10-04T02:06Z

改了什么: 对外发布的 UI 技能包 skills/objectstack-ui 里,rules/pages.md 的 kind: 'html' 页面示例中 object-metric 那一行的 aggregate 属性,由字符串 "count" 改为对象 {{"function":"count"}},用的是 html 层自己的表达式写法(同一示例的 gap={6}、style={{…}} 已在用)。全文件只动这一个属性值:453 → 453 行,token 棘轮 5676 → 5679(上限 5692 未动),整包 SKILL.md 未碰。

为什么改: 这一行是技能教给 AI 作者的「标准示例」。指标卡组件读的是对象(objectui 当前 pin ab187972 的 ObjectMetricWidget.tsx computeOne 取 aggregate.field / aggregate.function,计数走 r.count),字符串下两个成员都是 undefined;而 html 层编译对字符串只给一条 warning,os build 照样通过,页面上这块指标卡不显示数字。技能本身在教一种「构建通过、运行时静默空白」的写法。同一技能包里 dashboards.md:125 与 eval 用的都是对象形,只有这一行走偏。dev 实测:改前 html 层编译 1 条 type-mismatch 警告,改后 0 条。

风险与代价(含回滚): 纯技能文本,不碰 packages/**,无 changeset(skip-changeset);席内契约复核 PASS(本 PR 上一条评论);CI 此刻 19 绿、11 预期 skip、3 在跑。回滚 = revert 单个 commit d5e9504。已知残余:html 层对「字面字符串对上声明为 object 的输入」仍只给 warning 不给 error,卡与分诊都把它划在本卡范围外;席位已另立 finding 卡交分诊定级(见 #21627 上的 ACCEPT)。

席位意见: 建议批准。一行一值,席位逐项核过:diff 只有这一行;对象形与消费端、manifest 声明(aggregate 为 type: "object")一致;兄弟面已是对象形。卡正文引的 objectui pin 89cad75d557 在 objectui 远端取不到,是卡文过期引文,机制在现 pin 上成立,不影响本 PR。

你要做的(一个动作): 在 PR #21667 上给一次 APPROVED review;批准后由席位清标、ready、挂 auto-merge 入队。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants