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 入队。

@os-zhuang
os-zhuang marked this pull request as ready for review October 4, 2026 02:40
@os-zhuang
os-zhuang enabled auto-merge October 4, 2026 02:41
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 4, 2026
Merged via the queue into main with commit 8ad9694 Oct 4, 2026
44 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-21627-pages-html-metric-aggregate branch October 4, 2026 03:16
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
… error, not a warning (objectstack-ai#21678)

Fixes objectstack-ai#21671
Clause-②: no (narrowing)

## What changed

The html-tier compiler (`@objectstack/sdui-parser` `compile`) now grades
every `type-mismatch` as `error`, not only the ones whose input declares
an `enum` arm. `aggregate="count"` on an `object-metric` (repo-root
`sdui.manifest.json` declares `aggregate` as `type: "object"`) now fails
the compile, so `os build` fails on it. Before, it compiled `ok` with
one warning, the build stayed green, and the tile drew no number. The
diagnostic code and message are unchanged. No new code and no new gate.

## The mechanism, measured

The brief assumed that literals and expressions both reach `checkType`,
and that a signal would have to be passed in to tell them apart.
Measured on `93a54b87e7`, that is not how it works:

- `validateTree` (`packages/sdui-parser/src/validate.ts`) sends a value
that `isExpr` matches (the parser's deferred `$expr` marker) to
`inert-expression`, which is a `warning`. It calls `checkType` only in
the `else` branch. So **every value that reaches `checkType` is already
a literal**: a quoted attribute (a string), a bare attribute (`true`),
or a braced value that `interpretBrace` materialized in full.
- `interpretBrace` is all-or-nothing. Probed: `["a", foo]`, `{"a": foo}`
and `{a: 1, b: x.y}` each become ONE `$expr` marker; `[1,2]` and
`{function: "count"}` materialize in full. So a container never reaches
the type check with an expression inside it.

So the expression case is already separate before `checkType` runs, and
no new signal is needed. The change is the severity, plus a restated
header that names the second certain fact (a literal's coarse type) next
to the enum's closed list. A braced expression still gets the
`inert-expression` warning, and a test pins that.

**`checkMemberTypes` follows the same rule** (the brief left this to
measurement). Its members come from a container that was materialized in
full, so each member is a literal too, and a member that no declared arm
accepts is just as certain a mismatch. Its header already said "Severity
mirrors `checkType`'s rule", and that stays true. `member-type-mismatch`
is now `error`.

**Unchanged on purpose:** the single-arm `invalid-enum` diagnostic is
byte-identical, severity included (the existing pin in
`union-arm-type-mismatch.test.ts` passes untouched).

## Census (first step): every stored html page source, compiled against
the committed `sdui.manifest.json`

It was run with `compile` from `@objectstack/sdui-parser` (source), not
with grep. The page modules were imported and each `kind: 'html'`
export's `source` was compiled (`capability-map.page.ts` interpolates,
so a regex would have read a different string). Every fenced block in
`skills/**/*.md` and `content/docs/ui/*.mdx` that has a lowercase tag
was compiled too. A positive control (`aggregate="count"`) was compiled
in the same run.

| source | literal handed to a non-string input | verdict |
|---|---|---|
| `examples/app-showcase/src/ui/pages/command-center-jsx.page.ts`
(`CommandCenterJsxPage`) | none (0 diagnostics) | clean, nothing to fix
|
| `examples/app-showcase/src/ui/pages/capability-map.page.ts`
(`CapabilityMapPage`) | none (0 diagnostics) | clean, nothing to fix |
| `examples/app-showcase/src/ui/pages/start-here.page.ts`
(`StartHerePage`) | none (0 diagnostics) | clean, nothing to fix |
| `skills/objectstack-ui/rules/pages.md:154` block (its line 160 is the
`object-metric` example) | none: line 160 reads
`aggregate={{"function":"count"}}`, so PR objectstack-ai#21667's fix is confirmed on
`origin/main` | clean, nothing to fix |
| hotcrm | no `kind: 'html'` page in this repo (both
`packages/metadata/src/__fixtures__/hotcrm-*.artifact.json` have 0) |
not applicable |
| other fenced blocks in `skills/**` and `content/docs/ui/**` |
React-tier or non-page code (each fails at `no-root` or `forbidden-tag`,
which shows they are not html-tier sources) | not applicable |
| control: `aggregate="count"` | before: `ok=true`, `[warning]
type-mismatch`; after: `ok=false`, `[error] type-mismatch` | the census
can see the case |

There are zero writers to fix, so no example or skill file changes in
this PR.

## Pins
(`packages/sdui-parser/src/__tests__/literal-type-mismatch-error.test.ts`)

The inputs are copied verbatim from the tracked `sdui.manifest.json` and
written inline, so the test reads nothing outside its package.

- `aggregate="count"`: exactly one `{ severity: 'error', code:
'type-mismatch', message: 'object-metric prop "aggregate" expected an
object' }` (the real message has the tag in angle brackets), and `ok ===
false`.
- `aggregate={{"function":"count"}}`: zero diagnostics, `ok === true`.
- A string literal on a `number` (`object-kanban` `limit`), a `boolean`
(`invert`) and an `array` (`filter`) input: each gives one `error`
`type-mismatch`, and `ok === false`.
- An expression handed to an object input (`aggregate={count}`), and a
container that holds an expression: each gives exactly one `warning`
`inert-expression`, no `type-mismatch`, and `ok === true`.

Three existing pins described the old rule, and they were updated: the
non-enum union case and the single string-arm case in
`union-arm-type-mismatch.test.ts`, and the member severity in
`member-type-mismatch.test.ts`. Their codes and messages are unchanged.
Only severity, `ok`, and the wording that called these "byte-identical"
were edited.

## `os build` probe (the html-tier path through
`packages/cli/src/utils/sdui-manifest.ts`)

A scratch project with one `kind: 'html'` page, the committed
`sdui.manifest.json` copied beside its config, and the CLI run from
source (`bin/run-dev.js build`):

| page source | before (severity reverted, rebuilt) | after (this PR) |
|---|---|---|
| `aggregate="count"` | exit 0, a warning that the `aggregate` prop
expected an object, `Build complete` | **exit 1**, `Author-time rules
failed (1 issue)`, a failure that the `aggregate` prop expected an
object |
| `aggregate={{"function":"count"}}` | not run | exit 0, `Build
complete` |

The before leg is a one-off ablation run from the committed fix. It used
`scripts/ablation-replace.mjs` (anchor hit, 1 marker on disk), then
`pnpm --filter @objectstack/sdui-parser build`, then
`ablation-dist-preflight.mjs` (marker present in `dist/`, exit 0). After
the probe it was restored with `git checkout HEAD --`: `git diff HEAD`
was empty and the blob matched HEAD (`86cc5784`). The package was
rebuilt, the `--absent` preflight passed for both readings, and the
probe was re-run with exit 1. No permanent test file was left behind.

## Tests run (at `79df1db84f`)

- `pnpm --filter @objectstack/sdui-parser test`: 14 files, 225 tests
passed. `typecheck`: exit 0.
- Downstream consumers, after rebuilding `sdui-parser` (`dist` checked:
0 copies of the old ternary left). `pnpm --filter @objectstack/lint exec
vitest run`: 119 files, 5627 tests passed. `pnpm --filter
@objectstack/metadata-protocol exec vitest run`: 209 files passed and 3
skipped, 3463 tests passed. CLI unit tier, limited to the 4 files that
compile html pages (`src/utils/sdui-manifest.test.ts`,
`test/validate-build-gate-parity.test.ts`,
`test/platform-page-i18n-parity.test.ts`,
`test/i18n-section-coverage.test.ts`): 129 tests passed. The rest of the
CLI unit tier and its integration tier are left to CI.
- `node scripts/pm/dispatch-gates.mjs --commands` gave 63 derived
commands. 61 exited 0, including `check:sdui-lockstep`,
`check:nul-bytes`, `check:cross-package-test-inputs`,
`check-adr-0087-registration` and `check-changeset-no-major`. **NOT
MEASURED: `check:dual-build-cjs-loads`**: `PREREQUISITE NOT MET`,
because `embedder-openai` and `service-cluster-redis` have no `dist/`
(packages this diff does not touch). **NOT MEASURED:
`check:type-check-debt`**: it is a whole-tree tsc ratchet and hit the
240s local timeout. CI runs both.
- eslint was run on only the 4 changed `.ts` files, with
`--no-inline-config --format json`: 4 files, 0 errors, 0 warnings. The
repo config has no `parserOptions.project` (type-aware linting is off),
so this diff cannot change the lint result of any file it does not
touch. CI runs the full `pnpm lint`.

## Changeset

`.changeset/21671-html-literal-type-mismatch-error.md`:
`@objectstack/sdui-parser` `minor`. **Clause-② conflict for the seat to
resolve:** the claim states `Clause-②: no`, and this body carries that
line verbatim. The changeset declares `Clause-②: no (narrowing)`,
because a page that used to compile (and save, where the host has a
component manifest) is now refused. Earlier PRs treated a new refusal at
an authoring door as an accept-set narrowing (`21459`, `20827`). The
changeset therefore carries the `**BREAKING**` header, a `minor` bump
under the launch-window convention, and an ADR-0087 `not-required
(no-migration-prescription)` disposition: no key, declaration or stored
shape moves. `check-adr-0087-registration` and
`check-changeset-no-major` both pass, whether the body line has the arm
or not (both were simulated locally).

## objectui lockstep (declared, not acted on)

objectui has its own copy of this validator,
`packages/sdui-parser/src/validate.ts`, at the `.objectui-sha` pin
`ab187972`. It still has the old ternary in both `checkMemberTypes`
(`:418`) and `checkType` (`:465`). After this PR the two copies agree on
codes, messages and the accepted grammar, and differ only in
**severity**. `check:sdui-lockstep` compares grammar, codes and the
containment predicate, not severity, so it passes. This repo's copy is
the stricter one (save gate and `os build`). The dangerous direction, a
page that saves clean and then renders inert, cannot come from this
difference. The lockstep header in `validate.ts` now records this lead.
The port belongs to objectui's lane, and this PR does not write to
objectui.

## Acceptance notes

- The new severity covers every literal mismatch, including a number
literal handed to a string input (`label={42}`). That was the narrower
reading in the triage title ("a string literal against a declared
non-string input"). The claim and the brief specify the general rule ("a
literal whose coarse type no declared arm accepts"), and the measurement
shows that every value at this point is a literal, so the general rule
is the one implemented. The census found no writers of either form in
the repo.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01VDtqoecgES7ScQYGbFVDRv)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
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