Uh oh!
There was an error while loading. Please reload this page.
docs(spec): record the live read points of element:button.icon and object-metric.icon (#10053) - #10270
Conversation
…`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
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ✅ What this run could not see
Coarse fallback — 115 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # 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 |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#10053
A
.describe()naming the objectui consumer plus an accept-pin for each of the last twoiconslots inpackages/spec/src/ui/component.zod.tswhose describes stated only the vocabulary — the #9881/#9972 read-point-describe patch, applied to the keys those two left behind.Icon name (Lucide icon)andIcon name (Lucide)are sentences equally true of thepage:headericonretired 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)
.objectui-sha=82a94170c; #10137 bumped it to9a3daf8d37ad973a621e5edd276fe32467f90684. Everything below was measured at9a3daf8d3, the pin this repo actually builds against, and the docblocks cite that. (82a94170cis 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-47—toPascalCase(schema.icon)→ a one-entry rename map (Home→House,:25-27) →icons[name]fromlucide-react(imported:14).:69/:71— drawn either side of the label periconPosition(mr-2 h-4 w-4left,ml-2 h-4 w-4right), both suppressed whileloading.ObjectMetricPropsSchema.icon— the card's anchor was off, and re-measuring is what caught it:plugin-dashboard/src/index.tsx:161publishes it as a designer input (Icon (Lucide name)) on the registeredobject-metricblock.ObjectMetricWidget.tsx:142destructures it and forwards it at:474toMetricWidget— notMetricCard.MetricWidget.tsx:312-321resolves it viagetLazyIcon(icon), guarded ontypeof icon === 'string';:373-382draws it in thecolorVariant-tinted square.MetricCard.tsx:82-83. That sibling does callgetLazyIconon line 83, but nothing on this key's path renders it (its heading key istitle, this path's islabel), and at the pinMetricCardis 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
LazyIconnote the card asked forThe button is the one authorable icon on this surface that does not go through
LazyIcon, and the two paths are not interchangeable:iconsmap)LazyIcon/getLazyIcontoPascalCase, splitting on-onlyundefined→ renders nothing, no diagnosticDatabaseglyphSource:
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 no
iconinput (button.tsx:82-98listslabel,variant,size,className), so the Studio block designer does not offer the key. Unpublished is not unread — the headericonis 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.Full spec suite:
Test Files 415 passed (415) · Tests 11052 passed (11052).Gates — all run at
f928dae82, the final commitnode 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-matcherpnpm --filter @objectstack/spec check:generatedre-run atf928dae82: all 13 generated artifacts up to date. The only artifact this change made stale wascontent/docs/references/**, regenerated wholesale withpnpm --filter @objectstack/spec gen:docs— never hand-edited.doc-formula-expressionswas red on first run for a reason unrelated to this diff — a fresh worktree has no@objectstack/formuladist/. Green afterpnpm --workspace-concurrency=2 --filter '@objectstack/lint^...' build.One declared narrowing:
check:type-check-debt --re-measurewas not run locally — its ratchet half demands a full workspaceturbo 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) andcheck:test-typecheckinsidecheck:generated, pluspnpm --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 requiredTypeScript Type Checkjob 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 incontent/docs/references/, so it is user-visible and not askip-changesetcase.Generated by Claude Code