Uh oh!
There was an error while loading. Please reload this page.
refactor(i18n): retire useObjectLabel().viewDescription() and its _views.VIEWNAME.description catalog key - #7451
Conversation
…iption` catalog key
`useObjectLabel().viewDescription()` resolved
`{ns}.objects.{objectName}._views.{viewName}.description` and had zero
production callers and zero in-repo bundle usage: an entry authored under that
key reached no screen. Per the maintainer ruling of 2026-09-02 (option B,
enforce-or-remove), the member and the convention are removed rather than wired
in — two vocabularies for one concept plus a precedence rule is the ambiguity,
not the fix.
A list view's description now has exactly one channel: the `I18nLabel` value
authored on the view entry, which `ObjectView` relays and `ListView` resolves
with `pickLocalized`.
`viewSuffixes` is untouched — `viewLabel` and `viewEmptyState` share it and keep
resolving; only the `'description'` tail is gone.
The three pin call sites are retargeted, not deleted. Each package now pins the
two survivors plus a case that AUTHORS the catalog `description`, proves that
node is live (its `label`/`emptyState` siblings resolve off it), and asserts the
description a consumer resolves is the authored value and a different string —
so a reintroduced catalog channel fails at either precedence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC`useObjectLabel-identity-5564.test.tsx` pins the hook's member set as an absolute count beside the with-instance / without-instance equality. Retiring `viewDescription` moves that absolute by exactly one; the equality assertion next to it is unaffected, which is the point — a member leaves both paths at once because there is only one path. Found by running the whole `@object-ui/i18n` suite rather than only the three retargeted call sites: the count is a fourth pin on the surface this card removes, in the same package, and a grep for the symbol does not reach it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
os-project-manager
commented
Sep 3, 2026
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
os-project-manager
commented
Sep 3, 2026
Contract review — VERDICT: PASSImplemented-by: objectui execution seat ( ① Derived judgments. Executes the #7219 ruling (5508044124, batch #6, 2026-09-02, option B — retire): the ② Semver / changeset. ③ Boundary flags. No governed path; no ledger-file collision. Landing. Carrier cleared, ready, auto-merge (SQUASH). All checks green on Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#7219
Retires
useObjectLabel().viewDescription()from@object-ui/i18ntogether with theNS.objects.OBJECTNAME._views.VIEWNAME.descriptioncatalog convention it resolved.This card reads as undecided and is not. Its body ends with "Possible dispositions"
under a heading saying the resolution is a decision — it was made. Authority:
comment 5508044124
(director seat, summon #8, decision batch #6, 2026-09-02, maintainer verbatim
「7205 B,其他同意」) — option B, retire. Option A (wire the catalog key in and state a
precedence rule) is explicitly not taken; neither is option C.
The premise, re-measured on this branch point
The card's core claim is zero production callers. Re-measured on
d6ceb8d29, not carriedover from the card:
git grep -n viewDescriptionover the whole treepackages/i18n/CHANGELOG.mdline, 12 unrelatedpreviewDescription, 3 inplugin-list/src/ListView.tsx(see below)useObjectLabel().viewDescription()git grep -l viewLabelThe three
ListView.tsxhits are NOT the hook member — they are the survivorpackages/plugin-list/src/ListView.tsx:3106declares a local variable of the samename, landed by #7199:
That is the authored
I18nLabelchannel — precisely what the ruling preserves ("theauthored value wins because it is the only reader"). It is untouched by this PR: no file
under
packages/plugin-list/is in the diff. The card's body claims every non-hook hit ispreviewDescription; that is stale, and a grep-driven cleanup would walk straight into it.What
viewSuffixesdoes — measured, not assumedviewSuffixesis kept unchanged. It is shared:viewLabelpasses it'label',viewEmptyStatepasses it'emptyState.title'/'emptyState.message', and only theretired member passed
'description'. The suffix construction is therefore not exclusiveto this member; the
'description'tail is what disappears, not the builder.Pins retargeted, not deleted
The ruling's surviving pins are that
viewLabelandviewEmptyStatestill resolve, andthat a
_views.VIEWNAME.descriptioncatalog entry is inert.An inert pin is the easy one to write vacuously — a test that only asserts the member is
gone is green on any tree where it never existed. Both new cases therefore author the
catalog
description, prove that bundle node is live and reachable (itslabel/emptyStatesiblings resolve off it — the control that fires), and then show that thedescription a consumer resolves is the authored value and a different string:
packages/i18n/src/__tests__/useObjectLabel-view.test.tsx— resolves the authored valuethrough the same
pickLocalizedcallListViewmakes.packages/app-shell/src/views/ObjectView.defaultViewIdentity.test.tsx— the authoredI18nLabelarrives on the view entry through the real pipeline(
expandViewContainer->mergeViewsIntoObjects) rather than being typed in at theassertion, while the served
ZH_PAYLOADstill carries the catalogdescription.Both also carry a
@ts-expect-erroron the removed member, so the return type ispinned too, not just the runtime object. That is a real check:
tsconfig.test.jsonin eachpackage compiles these files, proven with
tsc --listFiles(1 hit for each edited testfile, so neither is silently outside the program).
A fourth pin the grep does not reach
packages/i18n/src/__tests__/useObjectLabel-identity-5564.test.tsxasserts the hook'smember set as an absolute count, beside the with-instance / without-instance equality.
Removing a member moves that absolute by one (27 -> 26). It contains no occurrence of the
symbol, so it is invisible to a grep for
viewDescription; it was found by running thewhole
@object-ui/i18nsuite. The equality assertion next to the count is unaffected,which is the point — a member leaves both paths at once because there is only one path.
Reverse verification (ablation) — direction predicted before running
Mutation: put
viewDescriptionback on the hook — the pre-retirement / option-A world.Predicted 2 RED (the two inert pins) / 20 GREEN, including all six #7199 relay pins.
Both legs proved the mutation on disk before measuring anything (blob hash
0834ec2f->452ebac5, injected-markergrep -c0 -> 1), and proved the restore by state(
git hash-objectequal to the HEAD blob,git diff HEADempty, marker count back to 0) —never by an exit code. Both scripts used
trap ... EXIT INT TERMwith absolute paths.Tests 2 failed | 20 passed (22)— exactly as predicted, both failuresexpected [ 'objectLabel', …(26) ] to not include 'viewDescription', andObjectView.viewDescriptionRelay-7199.test.tsxfully green (the authored channel isuntouched by the mutation).
error TS2578: Unused '@ts-expect-error' directive.atuseObjectLabel-view.test.tsx(200,5)— the type pin fires as well.No rebuild was needed for either leg and none is silently missing:
vitest.config.mts:407aliases
@object-ui/i18ntopackages/i18n/src, and the i18n test imports../useObjectLabelrelatively, so both consumers read the mutated source. Nothing inthis ablation resolves through the package
exportstodist.Verification, all on head
18f24981cpnpm exec vitest run packages/i18nplus every repo test referencinguseObjectLabel—113 files / 1534 tests passed. That is the full
@object-ui/i18nsuite plus the 35app-shelland 20 other-package tests that touch the hook.turbo run type-check --filter=@object-ui/i18n --filter=@object-ui/app-shell— green,including each package's
tsc -p tsconfig.test.jsonleg.turbo run lint(repo-wide, theeslint .spelling) — 47/47 tasks, 0 errors.check-changeset-presence/-fixed/-no-major/-overwrite,check:control-bytes,check:i18n-keys,check:i18n-drift,check:vi-mock-specifiers,check:vi-mock-inherit,check:published-tsconfig-exclude— all report their own OKverdict line.
check:readme-exportsis NOT MEASURED here, not green and not red: it reads built./dist/index.d.tstype entries and saysrun pnpm build first. It needs a full repobuild, which is CI's run; no README and no package export is in this diff.
Landing
Changeset:
@object-ui/i18n, minor. Out-of-repo translation bundles that authored thecatalog key cannot be seen from this repo, so the changeset text is the notice, and it
says so.
Clause ② yes — this removes a member from a published package's hook return type. The PR
stays draft and waits on
needs:contract-reviewand the project director seat. Notenqueued, not self-reviewed, not auto-merged.
🤖 Generated with Claude Code
https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
Generated by Claude Code