Skip to content

docs(spec): record the live read points of element:button.icon and object-metric.icon (#10053) - #10270

Merged
qq9340100 merged 1 commit into
mainfrom
claude/issue-10053-icon-read-point-describes
Aug 20, 2026
Merged

docs(spec): record the live read points of element:button.icon and object-metric.icon (#10053)#10270
qq9340100 merged 1 commit into
mainfrom
claude/issue-10053-icon-read-point-describes

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes#10053

A .describe() naming the objectui consumer plus an accept-pin for each of the last two icon slots in packages/spec/src/ui/component.zod.ts whose describes stated only the vocabulary — the #9881/#9972 read-point-describe patch, applied to the keys those two left behind.

Icon name (Lucide icon) and Icon name (Lucide) are sentences equally true of the page:headericon retired in #6946 — refused precisely because no render path reads it. Vocabulary does not separate a live key from a dead one; a read point does. That missing separation already cost a full dispatch cycle (#9397, closed premise-overtaken, re-deriving the accordion read point from scratch).

No key is widened, narrowed, retired or renamed. Both were already declared and already optional; Clause-②: no.

Read points, re-measured (not transcribed)

⚠️The pin moved. The card and the landed #9881/#9972 records cite .objectui-sha = 82a94170c; #10137 bumped it to 9a3daf8d37ad973a621e5edd276fe32467f90684. Everything below was measured at 9a3daf8d3, the pin this repo actually builds against, and the docblocks cite that. (82a94170c is not reachable in the shared objectui checkout — it is shallow — which is a second reason not to keep quoting it.)

ElementButtonPropsSchema.icon — anchors confirmed unchanged across the two pins:

  • packages/components/src/renderers/form/button.tsx:44-47toPascalCase(schema.icon) → a one-entry rename map (HomeHouse, :25-27) → icons[name] from lucide-react (imported :14).
  • :69 / :71 — drawn either side of the label per iconPosition (mr-2 h-4 w-4 left, ml-2 h-4 w-4 right), both suppressed while loading.

ObjectMetricPropsSchema.icon — the card's anchor was off, and re-measuring is what caught it:

  • plugin-dashboard/src/index.tsx:161 publishes it as a designer input (Icon (Lucide name)) on the registered object-metric block.
  • ObjectMetricWidget.tsx:142 destructures it and forwards it at :474 to MetricWidget — not MetricCard.
  • MetricWidget.tsx:312-321 resolves it via getLazyIcon(icon), guarded on typeof icon === 'string'; :373-382 draws it in the colorVariant-tinted square.
  • The card named MetricCard.tsx:82-83. That sibling does call getLazyIcon on line 83, but nothing on this key's path renders it (its heading key is title, this path's is label), and at the pin MetricCard is referenced only by its own tests and README. A line cited from it would have described a component this key never reaches. The metric docblock now carries that warning explicitly.

The LazyIcon note the card asked for

The button is the one authorable icon on this surface that does not go through LazyIcon, and the two paths are not interchangeable:

button (icons map)LazyIcon / getLazyIcon
normalisestoPascalCase, splitting on - onlyto kebab-case
validatesno — bare map lookupagainst Lucide's own name list
unknown nameundefinedrenders nothing, no diagnosticdegrades to the Database glyph

Source: components/src/lib/lazy-icon.tsx:66-92. So a spelling that draws an icon in a tab trigger can draw nothing on a button — previously discoverable only by reading two objectui files.

Also measured: the button renderer's registration publishes noicon input (button.tsx:82-98 lists label, variant, size, className), so the Studio block designer does not offer the key. Unpublished is not unread — the header icon is refused for the second, not the first, and the docblock exists to hold them apart.

Tests

Six accept-pins, matching the #9972 shape — per key: an accept carried through to the parsed output, an undeclared-sibling refusal so the accept is not vacuous, and an assertion that the .describe() still names its consumer.

✓ ElementButtonPropsSchema icon liveness (#10053) > accepts an icon on a button …
✓ ElementButtonPropsSchema icon liveness (#10053) > still refuses an undeclared sibling …
✓ ElementButtonPropsSchema icon liveness (#10053) > keeps a `.describe()` that names the consumer AND the non-LazyIcon path
✓ ObjectMetricPropsSchema icon liveness (#10053) > accepts an icon on the metric tile …
✓ ObjectMetricPropsSchema icon liveness (#10053) > still refuses an undeclared sibling …
✓ ObjectMetricPropsSchema icon liveness (#10053) > keeps a `.describe()` that names the consumer …
Tests 6 passed | 191 skipped (197)

Full spec suite: Test Files 415 passed (415) · Tests 11052 passed (11052).

Gates — all run at f928dae82, the final commit

node scripts/pm/dispatch-gates.mjs (no paths — derived from the real change set) named 24 path-matched families plus 5 convention-triggered by the edited test file. All green:

spec-typecheck · changeset-gate-self-tests · objectui-changeset · cross-package-test-inputs · doc-anchors · doc-formula-expressions · docs-audit-scope · docs-redirects · empty-state · liveness · merge-driver · published-readme-links · quick-reference-counts · role-word · slot-lookup · spec-parsed-alias · strictness-ledger · type-source-resolution · variant-docs · adr-0087-registration · changeset-no-major · empty-changeset · affected-docs · nul-bytes · query-options-erasure · type-check-coverage · engine-double-contract · where-matcher

pnpm --filter @objectstack/spec check:generated re-run at f928dae82: all 13 generated artifacts up to date. The only artifact this change made stale was content/docs/references/**, regenerated wholesale with pnpm --filter @objectstack/spec gen:docs — never hand-edited.

doc-formula-expressions was red on first run for a reason unrelated to this diff — a fresh worktree has no @objectstack/formuladist/. Green after pnpm --workspace-concurrency=2 --filter '@objectstack/lint^...' build.

One declared narrowing:check:type-check-debt --re-measure was not run locally — its ratchet half demands a full workspace turbo build, and the shared verify lock was contended throughout this run. What it would measure is covered from two sides that did run green at head: check:type-check-coverage (the structural half) and check:test-typecheck inside check:generated, plus pnpm --filter @objectstack/spec typecheck. The diff appends tests to a file already inside spec's tsc program, so no ledger count can move up. CI runs it on the required TypeScript Type Check job regardless.

Changeset

@objectstack/spec: patch — matching the precedent set by #9972's landed PR (.changeset/tabs-item-icon-liveness.md) and #9881's before it. Describe prose lands in content/docs/references/, so it is user-visible and not a skip-changeset case.


Generated by Claude Code

…`object-metric.icon` (#10053)
A `.describe()` naming the objectui consumer plus an accept-pin for each of the
last two icon slots in `component.zod.ts` whose describes stated only the
vocabulary — so a liveness sweep stops re-deriving a false retirement candidate
for keys that render.
Re-measured at the pin this repo builds against — `.objectui-sha` = 9a3daf8d3,
NOT the 82a94170c the #9881/#9972 records cite (the pin moved in #10137):
- `element:button.icon` — `renderers/form/button.tsx:44-47` resolves it, `:69` /
`:71` draw it either side of the label per `iconPosition`. This is the one
authorable icon on the surface that resolves through `lucide-react`'s `icons`
map rather than `LazyIcon`, and an unknown name renders nothing at all.
- `object-metric.icon` — `plugin-dashboard/src/index.tsx:161` publishes the
input, `ObjectMetricWidget.tsx:142`/`:474` forwards it to `MetricWidget`,
which resolves it at `MetricWidget.tsx:312-321` via `getLazyIcon`.
Nothing about what parses changes — both keys were already declared and optional.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016gcKVsiywU9CcS96S5t9qD
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ✅

What this run could not see
  • the SDK route bridge reached 45 of 221 client-bound route-ledger rows — the other 176 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run: node scripts/docs-audit/affected-docs.mjs --bridge-coverage

Coarse fallback — 115 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 67630c4521f931a3a62c63d20fb0a3240917a1dbpackageMentionDocs.

Which tree this was computed on

This run read content/docs from 0389515510913bcf9fe1ac645b0a5f8e6a07612f — the merge of head f928dae827989e773cea761ee6a86f8d32cc9801 into base 67630c4521f931a3a62c63d20fb0a3240917a1db, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 0389515510913bcf9fe1ac645b0a5f8e6a07612f && git checkout 0389515510913bcf9fe1ac645b0a5f8e6a07612f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 67630c4521f931a3a62c63d20fb0a3240917a1db f928dae827989e773cea761ee6a86f8d32cc9801 && git checkout -B drift-repro 67630c4521f931a3a62c63d20fb0a3240917a1db && git merge --no-ff f928dae827989e773cea761ee6a86f8d32cc9801
node scripts/docs-audit/affected-docs.mjs --json 67630c4521f931a3a62c63d20fb0a3240917a1db

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling protocol:ui labels Aug 20, 2026
@qq9340100
qq9340100 marked this pull request as ready for review August 20, 2026 17:06
@qq9340100
qq9340100 added this pull request to the merge queueAug 20, 2026
Merged via the queue into main with commit 5fa0d72Aug 20, 2026
38 of 40 checks passed
@qq9340100
qq9340100 deleted the claude/issue-10053-icon-read-point-describes branch August 20, 2026 17:46
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:uisize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] element:button.icon and object-metric.icon carry vocabulary-only describes — live readers measured, read point unrecorded

2 participants

@qq9340100@claude