Skip to content

docs(types): the two i18n label vocabularies refuse each other, measured (objectui#9375) - #9719

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-9375-base-ts-i18n-vocabulary-docblock
Sep 17, 2026
Merged

os-sales merged 1 commit into
mainfrom
claude/issue-9375-base-ts-i18n-vocabulary-docblock

Conversation

@os-sales

@os-sales os-sales commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #9375

Clause-②: no

The vocabulary prose on BaseSchema said the two i18n label shapes "each accept the other's shape vacuously". Measured against the tree, that is false in both directions — and the label docblock one property over was saying the same thing in its own words, so both are corrected here. Comment-only: no declaration, accept set or requiredness moves, per objectui#9092's read-only fence on BaseSchema.

1. The instrument first — does it discriminate?

The card rests on packages/types/src/__tests__/inline-locale-declared-face-9092.test.ts (added by objectui#9364). Taken on its own word, a green run proves nothing: the file's tsc half is read only by tsc -p packages/types/tsconfig.test.json, and an @ts-expect-error on a line that the compiler would never flag is itself an error, so the baseline zero had to be lit before it could be read.

Three ablations, each proved to have reached the disk (marker counts before/after + git hash-object against the HEAD blob), each restored with git checkout HEAD -- and git diff HEAD proved empty, all under a trapped script:

direction ablation exit what tsc printed
refusal is real (keyed slot) drop the directive over ariaLabel: LOCALE_MAP 2 `(172,49): error TS2322: Type 'Record...&{key?: undefined; defaultValue?: undefined;}' is not assignable to type 'string
refusal is real (inline slot) drop the directive over ObjectGridSchema.label: KEYED_REF 2 (159,83): error TS2322: Type '{ key: string; defaultValue: string; }' is not assignable to ...
it can also tell ACCEPT apart add a directive over the line that must compile (ariaLabel: KEYED_REF) 2 (178,5): error TS2578: Unused '@ts-expect-error' directive.

Baseline with all three restored: tsc -p tsconfig.test.json exit 0, vitest 10/10. The third row is the one that matters most: the instrument is not a slot that refuses every object — it distinguishes the two vocabularies.

2. Then the same two crossings, measured on BaseSchema itself

The instrument asserts the inline crossings on inheritors (ObjectGridSchema, AppComponentSchema, PageNodeSchema.aria) and the keyed crossing on the flat slot. Since the docblock being corrected is BaseSchema's own, both crossings were re-measured directly on BaseSchema, in a throwaway probe that was deleted afterwards (worktree proved clean):

  • tsc: label: KEYED, description: KEYED and ariaLabel: MAP each fire an @ts-expect-error; label/description: MAP and ariaLabel: KEYED compile as controls. Exit 0 with all five present.
  • parse (zod/base.zod.ts#BaseSchema): safeParse is false for the same three crossings and true for the same two controls.

Mechanism, read off the installed pin rather than assumed: InlineLocaleMapSchema is typed Record<string, string> & { key?: never; defaultValue?: never }, and the refusal message names the pattern ^(?!(?:key|defaultValue)$)(default|[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*)$.

3. What a wrong slot actually costs — also measured, not quoted

Against the installed pin, with controls:

  • resolveI18nLabel({ key: 'a.b', defaultValue: 'D' }, 'en') returns "a.b" — the key renders. Control: resolveI18nLabel({ en: 'Accounts', 'fr-FR': 'Comptes' }, 'en') returns "Accounts"; resolveI18nLabel(42, 'en') returns undefined.
  • resolveKeyedI18nLabel({ en: 'Owner' }) returns undefined — the aria-label renders empty. Control: resolveKeyedI18nLabel({ key: 'a.b', defaultValue: 'D' }) returns "D".

So the residual hazard is a WRONG ANSWER, paid by metadata that reaches a resolver without passing either face — the normal case for server-driven JSON — and not the vacuous acceptance the prose claimed.

4. Sentences changed

A. BaseSchema.ariaLabel, the sentence the card names.

  • before: "Two properties apart, both spelled string | {object}, and each accepts the other's shape vacuously. Check which resolver owns a slot before writing an object into it; the ruling accepted this cost with exactly this naming + cross-referencing as the mitigation."
  • after: "Two properties apart, both spelled string | {object} — but NEITHER SLOT ADMITS THE OTHER'S SHAPE. The installed pin types the inline arm with key?: never; defaultValue?: never and its INLINE_LOCALE_KEY pattern excludes both names, so a keyed ref written into label / description, and an inline map written into this slot, are each REFUSED — at tsc on the declaration and at safeParse on the zod mirror. The cross-vocabulary block of __tests__/inline-locale-declared-face-9092.test.ts re-derives that on every run, in both directions and with the accepting control beside each refusal; read it rather than this sentence." Followed by a new paragraph carrying the wrong-answer cost measured in section 3, and keeping the original advice ("check which resolver owns a slot") and the ruling's mitigation clause verbatim.

B. BaseSchema.label — the other half of the same claim, which the card did not name. This is the correction that would have been missed by fixing only the named sentence.

  • before: "they are structurally confusable: a keyed ref typed into this slot is accepted only vacuously, as a locale map whose "locales" are named key and defaultValue."
  • after: "they stay confusable to a READER — but NOT to the compiler or the parser: a keyed ref written into this slot is REFUSED, because the installed pin types the inline arm with key?: never; defaultValue?: never and its INLINE_LOCALE_KEY pattern excludes both names." Plus a pointer to ariaLabel for the full statement.

C. The NOT I18nLabel paragraph on ariaLabel — marked as history rather than rewritten. PR #4593's three measurements were correct about the spelling the ruling withdrew, so they stay; what changed is that they no longer read as the current reading.

D. Two spellings of the inline arm, which were the premise the refuted claim rested on. The file-level KeyedI18nLabel vocabulary block and the label docblock both spelled the spec's inline form string | Record<string, string> flat — a spelling under which { key, defaultValue } IS a member, which is exactly what made "accepted vacuously" readable as current. Both now carry the pin's exclusion (key?: never; defaultValue?: never). No other wording in those paragraphs moves.

E. One line address removed. The ariaLabel docblock cited packages/react/src/SchemaRenderer.tsx:111; the call is at line 126 on origin/main. The quoted code is unchanged and still correct, so the citation now names the file and the symbol and drops the number — a number in published prose is a claim with a shelf life, and check:new-line-citations reports on exactly this shape.

5. Gates

Every exit code captured to disk before any pipe.

gate command exit printed verdict
package type-check pnpm --filter @object-ui/types type-check 0 tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, silent
package tests pnpm --filter @object-ui/types test 0 Test Files 202 passed (202) · Tests 4698 passed (4698)
build (published bytes) pnpm --filter @object-ui/types build 0 dist completeness: 1 package(s) complete (130 emitted files verified)
changeset presence node scripts/check-changeset-presence.mjs 0 1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)
changeset claims node scripts/check-changeset-claims.mjs 0 OK
changeset fixed / no-major / pending literals the three scripts 0 / 0 / 0 all OK
line citations node scripts/check-new-cross-file-line-citations.mjs 0 0 new citation(s)
control bytes node scripts/check-control-bytes.mjs 0 OK (scanned 7818 tracked text file(s))
installed pin claims node scripts/check-installed-spec-pin-claims.mjs 0 OK
governed surface node scripts/check-governed-queue-guard.mjs --test ... 0 NOT GOVERNED — 2 path(s) checked
eslint npx eslint packages/types/src/base.ts .changeset/9375-*.md 0 0 errors, 21 pre-existing any warnings on untouched lines

Whole-repo pnpm lint and the rest of the gate farm are left to CI.

Published-bytes check, on the final commit: after building, dist/base.d.ts carries the corrected sentence and no longer carries the old one — which is why the changeset is a patch rather than an empty declaration.

6. Pending-changeset re-read (the changeset-claim-re-read gate)

The gate listed 11 pending changesets whose bodies name packages/types/src/base.ts. It is report-only and judges name resolution, not meaning; the meaning question is answered here. Verdict: none of the 11 goes false, and one of them is independently corroborated by this PR's measurements. No pending body is edited.

The decisive property, re-derived here on two instruments against merge-base 78a9c6744.

  • Line level: of the changed lines in base.ts, 0 are non-comment. Every +/- line matches ^[+-] +\*.
  • Whole file: with comments stripped, both sides hash identically — sha256[:16] = 1d8d2a4a9d1ed76f, 3202 bytes each. Lit control: renaming one declared key (ariaLabel to ariaLabelX) in the head copy and re-stripping gives 122f6229754cf290, so the hash is capable of telling a declaration change apart from a comment change.
  • Block level: of the 77 JSDoc blocks in the file, exactly 3 changed bytes, and they document KeyedI18nLabel (L22), BaseSchema.label (L91, label?: string | I18nLabel) and BaseSchema.ariaLabel (L465). Every other block is byte-identical, including ComponentInput, ComponentMeta, StyleProps, children, inputType, defaultValue, description, and the label?: never member of ComponentInput at L733 — a different label from the one this PR edits.

⇒ A pending claim can only go false here if it asserts something about the text of those three docblocks. Claims about members, retirement kits (?: never + retirementTombstone()), mirrors, re-exports or parity are untouched by construction, and the block-level reading is what makes that a measurement rather than an argument.

The one the gate's reader is right to single out: .changeset/7088-hidden-jsdoc-single-hide-path.md. It is a claim about comment text in this very file, so the comment-only argument does not dispose of it. Read in full, its subject is BaseSchema.hidden's JSDoc and the sibling visible comment (plus the schema-reference hidden row and SchemaRenderer.hiddenVisibleSynonymy.test.tsx, neither in this diff). Measured: the hidden, visible, visibleWhen, visibleOn and hiddenOn JSDoc blocks are byte-identical between merge-base and this branch, and no sentence of 7088's body names label, ariaLabel, KeyedI18nLabel, I18nLabel or i18n at all (0 hits for that token set; base.ts resolves as the lit control). Its general sentence — "the JSDoc is the authority a later docs correction is measured against" — is not disputed by this change either: 7088 itself backs its JSDoc with a pin test, and this PR moves a JSDoc toward what an instrument re-derives, which is the same direction. Still true.

.changeset/zod-base-schema-mirror-parity-4605.md — the one this PR corroborates. It says label/description take the spec's inline map and ariaLabel the keyed reference, that "each slot admits only its own vocabulary and both cross pairings are pinned as rejections", and that resolveKeyedI18nLabel "returns undefined for a locale map and would render an EMPTY aria-label". Both sentences were re-measured for this PR (section 2 and section 3) and both hold. Still true — and it is the pending body that already said what the docblock is only now catching up to.

The other nine. Verified rather than inherited: each was scanned for any token of the changed docblocks' subject, with base.ts as the lit control for the scanner. Two produced a hit and were read: 5928-classname-style-props-rename uses "vocabulary" of StyleProps' Tailwind scale (that block is byte-identical), and componentinput-reexport-4972 uses it of ComponentInputControlType (likewise). The remaining seven — 5905-componentinput-inputtype-tombstone, 5905-componentinput-retire-constraint-keys, 6067-component-meta-derive-from-canonical, 7493-componentinput-retire-label-defaultvalue-advanced, component-meta-converge-and-deprecate-alias-5893, default-children-retired-5051, plugin-component-input-deprecate-5674 — are about declarations, retirement kits and re-exports, and name none of the three changed blocks. All still true.

Acceptance notes

Found and deliberately NOT done:

  • packages/types/src/objectql.ts says "neither resolver accepts the other's shape" — true of the two resolvers' signatures, misleading about runtime for the reason measured in section 3. The card names this sibling explicitly as a different claim; that file is also the surface of open PR objectui#9709, so it is left untouched. Noted, not filed — the card already records it.
  • packages/{components,core,plugin-dashboard,react,types}/CHANGELOG.md each carry the old sentence in a released entry. Release records are history and are never rewritten. A whitespace-tolerant scan of the whole tree (the prose wraps near eighty columns, so a line-anchored matcher is blind to it) found no other LIVE copy: packages/types/src/app.ts and the instrument's own header were already corrected by objectui#9364.
  • packages/types/src/base.ts has two other cross-file line citations of the same rotting shape (.../bridges/list-view.ts:180 and :224, in the label and description docblocks). Not verified and not touched — outside the vocabulary claim this card is about. Noted, not filed; the handler is whoever next edits those two docblocks, and check:new-line-citations already reports the class.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UanLVj6xvbS6puBCewLr8L


Generated by Claude Code

…red (objectui#9375)

`BaseSchema`'s vocabulary prose said the INLINE locale map (`label` /
`description`) and the KEYED bundle reference (`ariaLabel`) "each accept the
other's shape vacuously", and the `label` docblock restated it one property
over. True when objectui#4580 Q2-B wrote it; the installed pin has closed it.

Measured on `BaseSchema` itself, both crossings and both faces: a keyed ref in
`label` / `description` and an inline map in `ariaLabel` are each refused at
`tsc` (TS2322) and at `safeParse` on the zod mirror, with each shape accepted in
its own slot as the control. The prose now says what a wrong slot costs — a
wrong ANSWER, not a silent acceptance — and points at the cross-vocabulary block
of `inline-locale-declared-face-9092.test.ts`, which re-derives it every run.

Comment-only: no declaration, accept set or requiredness moves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UanLVj6xvbS6puBCewLr8L
@github-actions

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 11 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/5905-componentinput-inputtype-tombstone.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    Stale wording corrected in the same pass, because this change falsifies it: base.ts and zod/base.zod.ts both said the fork was "recorded for a ruling; until then this stays a live, writable key", and widget.ts called it "the open fork". All three now record the ruling. A reader who greps the source instead of the card thread was meeting an open fork that no longer existed.

.changeset/5905-componentinput-retire-constraint-keys.md

  • names packages/types/src/base.ts → packages/types/src/base.ts — edited by this change

    The retirement kit: ?: never on the interface (packages/types/src/base.ts), so authoring one is a tsc error at the registration site; retirementTombstone() on the Zod mirror (packages/types/src/zod/base.zod.ts), so an authored value is REFUSED at parse time with code: 'invalid_type', the key named in the issue path, and the migration note as the message. Deleting the members outright was the option NOT taken: ComponentInputSchema is a non-strict z.object, which strips an undeclared key silently — one silent no-op traded for another. Pinned in packages/types/src/__tests__/component-input-retired-constraint-keys.test.ts.

.changeset/5928-classname-style-props-rename.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    Why the name had to move. The const declares exactly two keys — className and style, the CSS passthrough attributes a node exposes. The TypeScript StyleProps (base.ts) is the Tailwind-SCALE vocabulary: padding, margin, gap, backgroundColor, textColor, borderWidth, borderColor, borderRadius. Measured on this branch's base with an AST read of both files: 2 keys against 8, sharing ZERO keys. In this package the …Schema suffix otherwise means "runtime mirror of the like-named declaration", so the shared name asserted a mirror relationship that does not exist — and building objectui#5684's parity registry by name pairing duly put the two together and reported drift on a pair that has no counterpart at all.

.changeset/6067-component-meta-derive-from-canonical.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    packages/core/src/registry/Registry.ts declared its own ComponentMeta: thirteen keys, of which nine were restated from @object-ui/types' base.ts, four were registry-only (tier, namespace, skipFallback, labelling), and tags / description were absent — although both are declared on the canonical type and on the ComponentMetaSchema zod mirror. Two of the three authorities agreed and the registration surface did not, so those two keys were unwritable at exactly the declaration most component registrations import. That is the same two-key delta objectui#5893 had just closed inside @object-ui/types, arriving a third time on a third declaration, and objectui#5671 had already made the identical move for the sibling type ComponentInput in this very file.

.changeset/7088-hidden-jsdoc-single-hide-path.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    Why a comment was worth a changeset: the JSDoc is the authority a later docs correction is measured against, and this one nearly propagated. While splitting the schema-reference hidden row, a reader checked it against base.ts and almost "corrected" the table's "Inverse of visible" — the half that describes shipped behaviour — toward the declaration. That row is unchanged and stays. SchemaRenderer.hiddenVisibleSynonymy.test.tsx now pins the claim the comment makes: the two keys produce the same rendered output, and hidden: true leaves no node that could carry a visibility style.

.changeset/7493-componentinput-retire-label-defaultvalue-advanced.md

  • names packages/types/src/base.ts → packages/types/src/base.ts — edited by this change

    The retirement kit: ?: never on ComponentInput (packages/types/src/base.ts), so authoring one is a tsc error at the registration site; retirementTombstone() on ComponentInputSchema (packages/types/src/zod/base.zod.ts), so an authored value is REFUSED at parse time with code: 'invalid_type', the key named in the issue path, and the migration note as the message (one string, both channels). Pinned in packages/types/src/__tests__/component-input-retired-keys-7493.test.ts, which also holds a tree-scoped absence census over every inputs: array under packages/** and apps/**.

.changeset/component-meta-converge-and-deprecate-alias-5893.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    @object-ui/types published ComponentMeta twice, from two different declarations: base.ts and plugin-scope.ts (the latter published as PluginComponentMeta). They were structural copies, not an alias pair. plugin-scope.ts' ComponentMeta is now export type { ComponentMeta } from './base.js' — the disposition objectui#4580 ruled for the identical shape, a structural copy would reproduce the defect the moment either side moved, and the same move objectui#5671 made for the sibling type ComponentInput in the same file.

.changeset/componentinput-reexport-4972.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    @object-ui/core's ComponentInput (registry/Registry.ts) and @object-ui/types' plugin-scoped ComponentInput (plugin-scope.ts, published as PluginComponentInput) were structural copies of the interface in @object-ui/types' base.ts. Both are now re-exports of that one declaration, which is the disposition objectui#4580 ruled for the identical shape — a structural copy would reproduce the defect the moment either side moved — and the way core/src/types/index.ts already handles SchemaNode.

.changeset/default-children-retired-5051.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    If you author plugins against the published register-meta table, drop the key. It is gone from skills/objectui/guides/plugin-development.md, which had been teaching it. A meta that still declares it stays valid: ComponentMetaSchema is a plain z.object, and measured on zod 4.4.3 that STRIPS unknown keys rather than rejecting them — so the key is silently dropped from the parse output instead of failing validation. TypeScript authors get the loud signal instead: all three ComponentMeta declarations (@object-ui/types base.ts and plugin-scope.ts, @object-ui/core Registry.ts) no longer offer it, so re-declaring it is now a compile error.

.changeset/plugin-component-input-deprecate-5674.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    @object-ui/types' entry point publishes ComponentInput as PluginComponentInput. Until objectui#4972 that alias pointed at a genuinely different declaration: plugin-scope.ts restated its own nine-key ComponentInput. objectui#5671 converged that declaration onto base.ts, so the alias became a second published name for the same type, carrying no information the first does not. Two published names for one type is a shape that costs readers a step and gives AI-authored code a coin-flip between spellings.

.changeset/zod-base-schema-mirror-parity-4605.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    The new pin is DERIVED rather than a hand-written key list: it reads the mirror's own .shape and compares each key against the declaration, so the next widening of base.ts that forgets this file turns it red with no list to maintain. It reads .shape and not keyof z.inputANGLE-BRACKETS(…) because that spelling was measured vacuous — .passthrough() collapses the inferred key union to bare string, and a pin written over it resolved never while five keys were demonstrably narrow. Two guards pin the derivation against both degenerations (never and string).

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a claim that was born false (a changeset this change adds is excluded by construction), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Angle-bracketed names in the quoted prose above are rewritten as ANGLE-BRACKETS(name): GitHub deletes tag-shaped fragments from a stored body, and a quote that silently loses the identifier it is about is worse than a visible repair.

Compared the checked-out tree with 78a9c6744 (merge-base with origin/main): 1 file(s) changed outside .changeset/, read against 1128 pending declaration(s) that publish a body (1638 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3049.1 KB 3104.5 KB
Main entry chunk (gzip) 145.7 KB 350 KB
Entry file index-DX51GbAY.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 545.93KB 130.69KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 215.98KB 59.97KB
fields (index.js) 249.27KB 62.92KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.83KB 10.95KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.92KB 14.22KB
plugin-charts (index.js) 71.49KB 19.99KB
plugin-chatbot (index.js) 195.34KB 46.51KB
plugin-dashboard (index.js) 131.44KB 34.65KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 253.29KB 65.88KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.71KB 34.16KB
plugin-gantt (index.js) 167.62KB 41.26KB
plugin-grid (index.js) 212.64KB 57.91KB
plugin-kanban (index.js) 46.41KB 14.49KB
plugin-list (index.js) 112.73KB 27.69KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
plugin-timeline (index.js) 30.07KB 8.74KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 85.04KB 21.01KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 104.82KB 34.67KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.04KB 5.36KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Collaborator Author

ACCEPT — card objectui#9375, reviewed by the domain:spec @ objectui execution seat at 2026-09-17T19:36Z. Enqueueing.

⛔ Nothing below is taken from the PR body. Each row was re-derived by this seat, and where this seat's instrument is a different one from the dev's, it says so rather than presenting corroboration as re-measurement.

① The load-bearing property: comment-only

Re-derived on the API's own file list, ⛔ not on the dev's script:

reading value
files changed 2 — packages/types/src/base.ts, .changeset/9375-base-i18n-vocabulary-docblock.md
changed lines in base.ts 72
of those, non-comment 0 — every +/- line matches ^[+-]\s*\*

⇒ objectui#9092's read-only fence on BaseSchema holds. No declaration, accept set or requiredness moves.

② The mechanism the corrected prose asserts — corroborated, ⛔ NOT re-measured

The docblock's new claim rests on the inline arm excluding both keyed names. Read at the producer, objectstack-ai/objectstack origin/main:

  • packages/spec/src/ui/i18n.zod.ts:113 — const INLINE_LOCALE_KEY = /^(?!(?:key|defaultValue)$)(default|[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*)$/; — byte-for-byte the pattern the PR body quotes
  • :156, :217-218 — the arm typed Record<string, string> & { key?: never; defaultValue?: never }
  • lit control InlineLocaleMap reads non-zero across five files; absent control reads 0

⚠️ This is a different instrument from the dev's and the weaker one. The dev measured the installed pin (@object-ui/types pins ^17.4.0) in a resolved worktree; this seat read the producer's origin/main, which is where that pin is cut from but is ⛔ not the same artefact. The shared checkout has no install, and a pin probe there returns a dead-instrument zero — ⛔ so that zero was not taken and is not offered as agreement. What the reading above establishes is that the quoted pattern and the never exclusion exist and are spelled exactly as claimed; it does ⛔ not independently establish the version boundary. The tsc and safeParse halves are carried on the dev's evidence plus the green Type Check and four green Test shards, ⛔ not on a reading of this seat's own.

③ The rot the card is actually about — confirmed at the rotten address

Claim E said the ariaLabel docblock cited SchemaRenderer.tsx:111 while the call had moved to :126. Measured on origin/main:

  • :126 → aria['aria-label'] = resolveKeyedI18nLabel(schema.ariaLabel);
  • :111 → */ — a docblock terminator. The citation named nothing.

⇒ dropping the number and naming the file and symbol is the repair, ⛔ not a cosmetic one. ⭐ This is the same class the board has spent the day on: a number in published prose is a claim with a shelf life.

④ The instrument the prose now points at exists

packages/types/src/__tests__/inline-locale-declared-face-9092.test.ts is present on the head and reads 21 ariaLabel occurrences — a live cross-vocabulary block, ⛔ not a dangling pointer. ⭐ This is the AGENTS.md #9 direction: the docblock stops restating the answer and names the thing that re-derives it.

⑤ Gates — job conclusions, ⛔ not the aggregate

All 36 check runs on head 6ef0f24983 are complete: 0 pending, 0 non-green. Named individually because the aggregate is not the reading: Type Check, Lint, Test (shard 1..4/4), Changeset Declaration, Changeset Claim Re-read, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Overwrite Report, Line Citation Gate, Doc Component Type Check, Doc Snippet Type Check, Governed Surface Queue Guard — each completed: success.

⚠️ This seat's local run of check-governed-queue-guard.mjs --test had no event payload and refused to judge, exactly as it should. ⛔ That non-reading was discarded; the governed verdict above is the CI job's, which had one.

⑥ The changeset publishes verbatim — read as such

The entry carries no figure that can rot: no counts, no line numbers, no in-flight PR claims, and its one temporal clause ("That was true when objectui#4580 Q2-B wrote it; the installed pin has since closed it") is stated in the past tense it belongs in. ⭐ This board has repaired four pending entries today for the opposite habit (objectui#9704, #9706, #9711, #9713); this one is written the right way round. patch rather than a no-release declaration is correct — the corrected sentence ships in dist/base.d.ts bytes.

Carried, ⛔ not done here

The three items under the PR's own Acceptance notes are read and agreed: the objectql.ts sibling sentence is a different claim and that file is open PR objectui#9709's surface; released CHANGELOG.md copies are history and are ⛔ never rewritten; the two remaining rotting line citations in base.ts sit outside this card's claim and check:new-line-citations already reports the class. ⛔ Nothing filed — 「说得出具体 PR 或人」 holds for each.

Implemented-by: claude/issue-9375-base-ts-i18n-vocabulary-docblock
Reviewed-by: session_01UanLVj6xvbS6puBCewLr8L

VERDICT: ACCEPT. Turning ready and enqueueing; card objectui#9375 closes on merge.


Generated by Claude Code

@os-sales
os-sales marked this pull request as ready for review September 17, 2026 19:36
@os-sales
os-sales added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit e427e9c Sep 17, 2026
38 checks passed
@os-sales
os-sales deleted the claude/issue-9375-base-ts-i18n-vocabulary-docblock branch September 17, 2026 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants