fix(types): restore the inline-locale declared face on group A's three pairs - #9364
Conversation
…e pairs objectui#4580's revised Q1 ruling (option A) widened the label keys to the spec's inline locale map, and `BaseSchema` obeys it on both faces. Three declarations restated the key as a plain `string` on top of it: - `AppComponentSchema.label` (app.ts) - `ObjectGridSchema.label`/`.description` (objectql.ts) - `PageNodeSchema.aria.ariaLabel` (layout.ts) A restatement on an interface extending `BaseSchema` is a narrowing override, so each refused the map its own zod mirror accepted. No mirror moved: the first three inherit the zod `BaseSchema`'s `I18nLabelSchema`, and the page node receives the spec's `AriaPropsSchema` by reference through `SpecPageFields`. `ObjectViewSchema.table` is `Partial<Pick<ObjectGridSchema, ...>>` and picks up the repair mechanically; its `WiderThanDeclared` ledger entry retires with the other three. `ObjectGrid` put `schema.label` into two string positions (the data-table caption and the export filename). Restoring the declaration turned both into named compiler errors; they now resolve through the spec's `resolveI18nLabel` against `useDisplayLocale()`, as four other read sites already did. The flat `BaseSchema.ariaLabel` is deliberately untouched: it carries the keyed vocabulary, and objectui#4580 Q2-B withdrew the `I18nLabel` spelling there. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt
|
| Step | Outcome |
|---|---|
| Build packages | success |
| Check console performance budget | failure |
Which half objected:
| Eager-closure half | Verdict |
|---|---|
| Aggregate closure ceiling | ✅ pass |
| Per-chunk ceilings | ✅ pass |
| Ceiling sensitivity (headroom) | |
| Ceiling freshness (checkout vs. base branch) | ✅ pass |
⚠️ A broken gauge half is a verdict about the ceiling, not about the bundle: that line has drifted out of range of the regression it exists to catch, or the report behind it cannot be trusted. It does not say anything grew. TheCheck console performance budgetstep log carries the ceiling and the number it was compared against.
Reason: The entry chunk measured 144.3 KB, but the eager-closure half of this gate returned no trustworthy VERDICT: the report could not be read, a ceiling has drifted out of range of the regression it must catch, or (objectui#6245) a ceiling was replaced on the base branch after this checkout was made. The step log says which. This is not a passing budget — and it is not a size regression either.
See the workflow run for details.
📦 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) | 502.02KB | 115.16KB |
| core (index.js) | 8.52KB | 3.41KB |
| create-plugin (index.js) | 27.94KB | 9.51KB |
| data-objectstack (index.js) | 211.58KB | 58.68KB |
| fields (index.js) | 247.89KB | 62.50KB |
| 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.25KB | 13.99KB |
| plugin-charts (index.js) | 71.51KB | 19.97KB |
| plugin-chatbot (index.js) | 195.34KB | 46.51KB |
| plugin-dashboard (index.js) | 131.22KB | 34.59KB |
| plugin-designer (index.js) | 215.94KB | 44.33KB |
| plugin-detail (index.js) | 253.46KB | 65.85KB |
| plugin-editor (index.js) | 2.23KB | 1.05KB |
| plugin-form (index.js) | 136.77KB | 34.17KB |
| plugin-gantt (index.js) | 166.95KB | 41.04KB |
| plugin-grid (index.js) | 211.65KB | 57.50KB |
| plugin-kanban (index.js) | 46.01KB | 14.30KB |
| plugin-list (index.js) | 112.58KB | 27.65KB |
| plugin-map (index.js) | 20.64KB | 6.86KB |
| 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) | 9.55KB | 3.32KB |
| plugin-view (index.js) | 84.42KB | 20.79KB |
| 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) | 94.03KB | 31.02KB |
| 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) | 0.20KB | 0.17KB |
| 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.27KB | 5.47KB |
| 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
CI red at
|
| control | reading |
|---|---|
| resolution | @object-ui/types → packages/types/dist/index.d.ts |
| sentinel (must fail) | ThisNameIsDefinitelyNotExported → 1 diagnostic (TS2305) |
| positive (must pass) | BaseSchema → 0 diagnostics |
| undeclared (must fail) | @floating-ui/react-dom → 1 (TS2307) |
| root-declared (must fail) | vitest → 1 (TS2307) |
⇒ 649 of 649 blocks reached the semantic phase and exactly 3 failed. A real reading.
Disjoint from this PR's file face
This PR changes seven files: .changeset/9092-inline-locale-declared-face.md · packages/plugin-grid/src/ObjectGrid.tsx · packages/types/src/app.ts · packages/types/src/layout.ts · packages/types/src/objectql.ts · packages/types/src/__tests__/inline-locale-declared-face-9092.test.ts · packages/types/src/__tests__/zod-mirror-parity.test.ts.
⇒ Neither content/docs/guide/schema-rendering.md nor packages/react/README.md is among them, and the diagnostic subject — DataSource<any>'s six members — is a shape this diff never mentions. The widening here is string → string | I18nLabel on four declaration members.
⭐ Three PRs, three disjoint diffs, one identical failure
This is now the decisive reading, and it is stronger than it was an hour ago:
| PR | its diff | these two checks |
|---|---|---|
| objectui#9349 | packages/types/src/zod/** + a pin |
❌ same 3 + 1 |
| objectui#9353 | one file, content/docs/api/schema-reference.md |
❌ same 3 + 1 |
| objectui#9364 (this) | packages/types decls + plugin-grid |
❌ same 3 + 1 |
Three PRs whose file faces do not intersect cannot each independently break the same three fences. ⇒ the failure is on the base, ⛔ not on any of them.
Root cause is carded, and ⛔ there is no fix in existence to port
The objectui#7912 / PR objectui#9310 renderer-seam narrowing meeting fences already on main:
| half | card | state |
|---|---|---|
| the three doc fences | objectui#9346 | domain:ui · p2 · pm:blocked |
the skills fence (Skill Example Check) |
objectui#9311 → PR objectui#9352 | in flight |
objectui#9346 establishes all three routes to green are refused by something already landed — a cast at the seam re-creates the defect one line lower (objectui#7912's own execution note 2); widening the declaration back is the card (decision batch #68, maintainer 「同意」); and declaring the blocks in the gate's ledger is a quarantine, not a reason. What remains is rewriting what those pages teach, which is objectui#9308's decision, ⛔ not a documentation edit — and schema-rendering.md is itself pinned to the wiring it teaches today.
⇒ ⛔ nothing to port. The cross-lane direct-takeover route needs the blocking item to be mechanical, clearly specified and S-sized; this one is none of the three — it waits on a maintainer decision.
⛔ What was not done
⛔ No re-run. A deterministic TS2740 against content this PR does not touch cannot come back different; the one permitted re-run is preserved for a case where it could discriminate. ⛔ No test skipped, disabled or quarantined. ⛔ No gate weakened. ⛔ No empty commit. ⛔ No fourth card — both halves are carded and dedupe hit.
State
Stays draft. ⛔ Not flipped ready, ⛔ not enqueued — this lane's bar is every check green, ⛔ not the required subset. Its other 34 checks are green or running clean, and the Clause-②: yes ceiling-tier contract review is the next gate regardless.
Doc Snippet Type Check is reportedly not in main's required set. That would mean it blocks nothing in the merge queue — but it does not lift this lane's stricter bar, so it changes nothing above.
Seat: domain:spec @ objectui, os-sam, session session_01L5xpA5q533BgTTNADibEFt, 2026-09-13T06:42Z.
Generated by Claude Code
|
Contract reviewHead reviewed: Tier — MEASURED, ⛔ not self-reported. Transcript grepped on the strict harness-stamp form Independence pair (machine-readable) ⛔ Not SELF-REVIEW. ⛔ VERDICT: FAIL — and ⛔ this one is NOT prose-onlyUnlike the sibling card's rounds, this FAIL carries a measured behaviour defect. The four declaration widenings, the
⇒ The card's own mechanic — every read of a widened key must resolve — is not yet satisfied. Patch round 1 of 2 is dispatched. ⛔ A correction to this seat's own record on this PRThe ruling caught an error of mine. My comment
⭐ The ruling also independently confirmed the two reds that are real, on the base rather than on this PR — CarriersBoth Ruling — verbatim, ⛔ unedited
Contract reviewHead reviewed: Measured in a private linked worktree cut from ① Derived judgments — every accept-set and public-face move in the diffSeven files, +274/−41, exactly as declared. In the three declaration files nothing moves but the four members below, two
② Semver gradingChangeset declares ③ Boundary flags — each answered or escalated
VerdictFAIL. The four accept-set moves, the Not reached
Generated by Claude Code |
…ail t() call
Patch round 1 on group A. The read-site audit missed a third `schema.label`
read in the same file, and it is the one a compiler cannot name:
`createSafeTranslation`'s `t(key, options)` takes `Record<string, unknown>`, so
widening `ObjectGridSchema.label` opened that arm to authors and nothing was
flagged. The other two sites (`caption`, export `viewLabel`) were found only
because they are `string`-typed sinks and `tsc` named them.
Measured before the fix, on both interpolators: the i18next provider path and
the provider-less `interpolateFallback` (`String(v)`) each rendered
`[object Object] Detail`, against a string control rendering `Accounts Detail`.
`detailTitle` feeds `NavigationOverlay title=` at three call sites, so that
string IS the record-detail overlay heading.
The resolve is placed before the truthiness test on purpose: `resolveI18nLabel`
answers `undefined` for an entry-less map and `''` for an empty entry, so a
label that resolves to nothing now falls through to the `objectName` branch as a
missing label always did. Testing the raw `schema.label` could not — every
object is truthy, and an entry-less map took the label branch.
Pins, red-first: a new provider-path file, plus a describe block in the
provider-less file (it has to live there — `createI18n` registers its instance
as react-i18next's module-global default and that survives `cleanup()`). Both
carry a string control that does not move across the two legs.
Prose repairs required by the review, all measured on the installed pin
`@objectstack/spec@17.4.0`:
- the four "each accepts the other vacuously" sentences. False:
`InlineLocaleMapSchema` types its map with `key?: never; defaultValue?:
never` and `INLINE_LOCALE_KEY` excludes both names, so neither vocabulary
admits the other at `tsc` or at parse. Found in three places, not four —
`objectql.ts` states the true claim instead.
- the pin header's "both are asserted here, each against its own vocabulary".
The flat `BaseSchema.ariaLabel` has no positive assertion in that file.
The corrected claim is now an instrument rather than prose: a new describe block
re-derives the cross-vocabulary refusal on both faces every run, with a control
proving the keyed ref is legal one property away.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt
|
| Step | Outcome |
|---|---|
| Build packages | success |
| Check console performance budget | failure |
Which half objected:
| Eager-closure half | Verdict |
|---|---|
| Aggregate closure ceiling | ✅ pass |
| Per-chunk ceilings | ✅ pass |
| Ceiling sensitivity (headroom) | |
| Ceiling freshness (checkout vs. base branch) | ✅ pass |
⚠️ A broken gauge half is a verdict about the ceiling, not about the bundle: that line has drifted out of range of the regression it exists to catch, or the report behind it cannot be trusted. It does not say anything grew. TheCheck console performance budgetstep log carries the ceiling and the number it was compared against.
Reason: The entry chunk measured 144.3 KB, but the eager-closure half of this gate returned no trustworthy VERDICT: the report could not be read, a ceiling has drifted out of range of the regression it must catch, or (objectui#6245) a ceiling was replaced on the base branch after this checkout was made. The step log says which. This is not a passing budget — and it is not a size regression either.
See the workflow run for details.
📦 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) | 502.02KB | 115.16KB |
| core (index.js) | 8.52KB | 3.41KB |
| create-plugin (index.js) | 27.94KB | 9.51KB |
| data-objectstack (index.js) | 211.58KB | 58.68KB |
| fields (index.js) | 247.89KB | 62.50KB |
| 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.25KB | 13.99KB |
| plugin-charts (index.js) | 71.51KB | 19.97KB |
| plugin-chatbot (index.js) | 195.34KB | 46.51KB |
| plugin-dashboard (index.js) | 131.22KB | 34.59KB |
| plugin-designer (index.js) | 215.94KB | 44.33KB |
| plugin-detail (index.js) | 253.46KB | 65.85KB |
| plugin-editor (index.js) | 2.23KB | 1.05KB |
| plugin-form (index.js) | 136.77KB | 34.17KB |
| plugin-gantt (index.js) | 166.95KB | 41.04KB |
| plugin-grid (index.js) | 211.66KB | 57.50KB |
| plugin-kanban (index.js) | 46.01KB | 14.30KB |
| plugin-list (index.js) | 112.58KB | 27.65KB |
| plugin-map (index.js) | 20.64KB | 6.86KB |
| 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) | 9.55KB | 3.32KB |
| plugin-view (index.js) | 84.42KB | 20.79KB |
| 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) | 94.03KB | 31.02KB |
| 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) | 0.20KB | 0.17KB |
| 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.27KB | 5.47KB |
| 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
Contract reviewHead reviewed: Independence pair (machine-readable) ⛔ Not SELF-REVIEW. ⭐ VERDICT: PASS⭐ The discriminating reading is ablation A-naive, and it is the one that matters. Reverting the fix reddens six cases with ⇒ the pins separate the deliberate fix from a naive one that would have satisfied every map case and still been wrong. That is the difference between a pin that catches the defect and a pin that catches the class, and neither I nor the FAIL asked for it.
⭐ The corrected prose is now true rather than less false, and rests on a measurement re-derived here: ⭐ The new instrument block discriminates on both runners, proven by three separate ablations (C1 widening the grid member → Nothing else moved, by blob hash: six paths in objectui#9373 (the Carriers — cleared, ⛔ not strippedBoth limbs, one stroke each, per 「清标即落地:PASS ⇒ 同席同笔剥双载体」. Record id and judged head are in this comment. ⛔ Landing — ③ still fails① PASS on record at tier ✅ · ② dual carrier cleared, machine-read ✅ · ③ every check green ❌. CI at this head: 36 reported = 36 returned, all four Test shards + Type Check + Lint + Build & E2E + Skill Example Check + Governed Surface Queue Guard success; exactly two failures, ③ Q1 answered — flag 2 gets its own card, ⛔ not a line on objectui#7759The reviewer left one advisory question to this seat: whether Its own card: objectui#9374. Reasons: it sits on the reference face every widened member inherits from, ⛔ not on a narrow-declaration pair, so it is a different kind of thing from the two The other two advisories are recorded and ⛔ carry no round: Ruling — verbatim, ⛔ unedited
Contract reviewHead reviewed: Measured in a private linked worktree ( ① Derived judgmentsA. The behaviour defect is fixed, and the pins discriminate — including the half a naive fix gets wrong.
B. The count was three, not four — the prior ruling was wrong on it, and the author is right. Re-derived at The reworded prose rests on a measurement I re-derived on the pin: C. The new instrument block discriminates on both runners.
D. Nothing else moved — by blob hash. E. objectui#9373 — filed, not fixed — is the right disposition. CI at this head: 36 check runs reported = 36 returned. All four ② Semver gradingChangeset unchanged in kind: ③ Boundary flags and
|
⛔ Correction to the record above — the follow-up card is objectui#9375, ⛔ not objectui#9374Record Everything else in the record stands: the verdict, the ruling, the carrier disposition, and the reasoning for filing a separate card rather than a note on objectui#7759. ⛔ How it happened, since the mechanism is the pointI wrote a predicted issue id into a permanent record instead of filing first and quoting the real one. ⛔ That is a named prohibition in this seat's own discipline — «⛔ Never write a predicted issue or comment id» — recorded earlier in this very session after the same mistake was caught before posting. This time it reached a posted record. ⇒ Standing, and this correction is the second entry against it: ⛔ file first, then quote the id the API returned. ⛔ No exception for "it will obviously be the next number." Generated by Claude Code |
⛔ Correction: a fix for the
|
CI status — both reds are INHERITED, and one of them is provably stale. ⛔ Not pushing yet.
⛔ The re-run was spent on the sibling PR as a probe, and it does not help
The sequencing
⇒ one base merge after objectui#9204 lands and Generated by Claude Code |
Fixes #9092
Group A of objectui#7759, executed against the objectui#4580 ruling already in hand (director batch #112: 「A 组按 #4580 收尾」). Three declarations restated a label key as a plain
string; they now state the spec's inline locale map.packages/types/src/base.tsis untouched — it is the reference face.Head:
52d93bc6d(patch round 1). Round-0 head:edf8b127a. Base:2e471dc0a(origin/mainat branch time, full-history clone, ⛔ not the shallow container checkout).⭐ Patch round 1 — what the contract review changed
The ceiling-tier review (PR comment
5651847194) judged the four widenings, theObjectViewSchema.tableretirement, the ledger edits, the pin's design and the two repairedObjectGridsites RIGHT, and said they «should land unchanged». It failed the PR on one measured behaviour defect plus prose. Nothing in the accept set moved in this round.ObjectGrid.tsxdetailTitlestringified a map labelSkill Example Checkline was staleObjectGridSchema.titleto the objectui#7759 successor list⭐ Item 1 — the third read site, and the reason no compiler found it
packages/plugin-grid/src/ObjectGrid.tsx, the record-detail overlay heading:createSafeTranslation'stdeclares its options asRecord-of-unknown, so wideningObjectGridSchema.labelopened that arm to authors and nothing was flagged. The other two sites were found only because they arestring-typed sinks andtscnamed them.detailTitlefeedsNavigationOverlay'stitleprop at three call sites, so that string IS the record-detail overlay heading — user-visible chrome, not a diagnostic.Red-first, measured with the SAME instrument on both sides of the fix. A throwaway probe asserting the defect text was run at
edf8b127a, deleted by atrap, then recreated byte-identically and run at the fixed tree:edf8b127a(before)[object Object] Detail[object Object] DetailinterpolateFallback, map label →[object Object] DetailAccounts DetailAccounts DetailTests 5 passed (5)before;Tests 3 failed | 2 passed (5)after, the two survivors being exactly the two string controls. The permanent pins run the other direction and were red before the fix and green after:Tests 6 failed | 5 passed (11)→Test Files 3 passed (3) · Tests 17 passed (17).The fallthrough is placed deliberately. The resolve happens before the truthiness test, because
resolveI18nLabelanswersundefinedfor an entry-less map and''for an empty entry — so a label that resolves to nothing lands on theobjectNamebranch exactly as a missing label always did. Testing the rawschema.labelcould not: every object is truthy, and the before-probe row above confirms an entry-less map used to take the label branch and render[object Object] Detail.:2379 columnDiagnosticLabel— re-derived, benign, CONFIRMED, ⛔ not touchedIt does take the map.
describeAddressincolumnSpellingDiagnostics.tsgates the value ontypeof label === 'string' && label.length > 0before pushinglabel: '…'into its parts list, so a map-valued label is simply omitted from the message — nothing stringifies. The message is aconsole.warn, not chrome. The reviewer's judgment stands.⭐ The untyped-sink sweep — what the compiler cannot do for you
Scope: reads of the four members this PR widened (
AppComponentSchema.label,ObjectGridSchema.label/.description,PageNodeSchema.aria.ariaLabel), plusObjectViewSchema.table's derived slots. Sink classes hunted by hand:t()options,String(…), template literals,JSON.stringify,Record-of-unknownparameters,any-typed props.ObjectGrid.tsx, allschema.label/schema.descriptionreads:2379benign-by-guard,:3219and:4302already resolved,:4594fixed here.schema.descriptionhas zero readsschema.labellines, so the matcher firesAppComponentSchemaimporters (useNavigationSync,AppSchemaRenderer,runner/App,LayoutRenderer,MetadataLoader).labelread on anAppComponentSchemavalue. The.labelhits in those files are onNavigationArea/NavigationItem/ action objects, andAppSchemaRendereralready routesNavigationArea.labelthrough a resolverAppComponentSchemaitself is present in every one of the five files, so the file set is the right onePageNodeSchema.ariarenderers/layout/page.tsx.schema.pageTypein the same file, non-zeroObjectViewSchema.tableslotsplugin-view/ObjectView.tsxforwardsschema.table?.descriptioninto atype: 'object-grid'object literal — a typed slot, andObjectGridhas nodescriptionread at all.table?.labelis never forwardedtable?.titlein the same file, non-zeroplugin-gantt/ObjectGantt.tsxschema.labelinline; untouchedString(x.label)/${x.label}/JSON.stringify(x.label)packages/plugin-list/src/ListView.tsxcarries the identicalt('detail.recordDetailWithLabel', { label: schema.label })shape, with the same untyped sink and the same user-visible overlay heading. Measured at this branch's round-0 head with the same probe technique: map label →[object Object] Detailpasses; string control →Accounts Detailpasses.⛔ It is not one of the four members this card widened —
ListViewSchema.labelderives from the spec's ownListViewSchemaand atscprobe shows it has admitted the map independently of this PR (control: a number into the same slot under@ts-expect-error, directive fires). So the arm was already open onmain, this PR neither opens nor worsens it, andpackages/plugin-listis outside this round's fence. Filed as objectui#9373 with the reproduction, the control and the repair shape; dedupe ran with a known-hit control query in the same minute.Items 2 and 3 — the prose the pin refutes
Measured on the installed pin
@objectstack/spec@17.4.0, this round, in this worktree:tsc: a keyed{ key, defaultValue }ref intoObjectGridSchema.label/AppComponentSchema.label/PageNodeSchema.aria.ariaLabel→ refused (three@ts-expect-errordirectives, all fire). An inline locale map into the FLATBaseSchema.ariaLabel→ refused. CONTROL: the keyed ref into that same flat slot → accepted, so the refusals are about the SLOT, not about the value.false. CONTROL: the keyed ref on the flatariaLabel→true; the inline map there →false.InlineLocaleMapSchematypes its map withkey?: never; defaultValue?: never, and its ownINLINE_LOCALE_KEYpattern excludes both names.⇒ neither vocabulary admits the other, at
tscor at parse. The sentence was true when objectui#4580 Q2-B wrote it; the protocol has since closed it.app.ts,objectql.ts, pin header.grep -n vacuousover those four pluslayout.tsreturns hits in three of them: the changeset,app.ts, and the pin header.objectql.tsnever carried the claim; its sentence reads "the two are structurally confusable and neither resolver accepts the other's shape" — a statement about the resolvers, and the true one, matching whatlayout.tsand the pre-existingbase.tsalready say. Control:grep -c 'confusable'is non-zero inobjectql.ts, so the file was in the search set and the miss is real, not a bad path. All three that exist are reworded; ⛔ nothing was invented inobjectql.tsto make the count four.⭐ And the corrected claim is no longer prose. AGENTS.md #9 says point at the instrument rather than write the answer down — a header asserting a protocol fact is exactly the shape that rotted here. So
inline-locale-declared-face-9092.test.tsgains a describe block that re-derives the cross-vocabulary refusal on both faces every run, with the control above, and the header now points at that block instead of restating it.Item 3: the header claimed «both are asserted here, each against its own vocabulary». The flat
BaseSchema.ariaLabelhas no positive assertion anywhere in that file — the four widening cases are the three nested/inline members plus theBaseSchemareference face, and that reference case assertslabelanddescriptiononly. The header now says exactly what the file pins: about the flat key, only that an inline map is refused there.@ts-expect-errorand typed assignment in that file is read only bytsc -p packages/types/tsconfig.test.json.viteststrips types, so a vitest-only run is a false green on that half.Item 4 — the
Skill Example Checkclaim was stale; ⛔ correctedIt is GREEN at this PR's head (job
103686010790: 14 of 14 ts fences judged, 0 failed). The round-0 body called it red on the strength of a branch-only local run.pull_requestruns check out the MERGE ref.maintook objectui#9352 at 06:11Z, before this PR opened at 06:34Z, so the merge ref already carried that fix — while a branch-only local run still shows the old fence. A localcheck:skill-exampleson a feature branch is therefore not a prediction of that check's verdict on the PR, and never was.Both independently confirmed base-side by the review, against
main's own push runs rather than against this branch:doc-snippet-types.ymlconcludesfailureonmainat the base2e471dc0, at69aa9c01, and at every push sinceedea22a5. The job log at this head namescontent/docs/guide/schema-rendering.mdtwice andpackages/react/README.mdonce, allTS2740on aDataSourceshape this diff never touches. Carded objectui#9346, waiting on decision objectui#9308.performance-budget.ymlissuccessonmainat2e471dc0andfailureat69aa9c01; the later cause is the objectui#9316 lockfile dedupe, on top of the standingui-componentsdebt at objectui#9204. The gate's own verdict at this head is its broken-gauge branch, with no size regression reported.Premises, re-derived by symbol — ⛔ never by line number
Unchanged from round 0; every address was re-derived by brace-matching
export interface NAME, so no reading depends on a line number the card carried.AppComponentSchema.labelis plainstringObjectGridSchema.labelis plainstringObjectGridSchema.descriptionis plainstring@deprecated, which is not a reason to leave an authoring face narrow)PageNodeSchema.aria—ObjectGridSchemaline numbersawk-block offsets, as the filer said in place. UnusedbridgeListViewassignsnode.label = spec.labelinreact/src/spec-bridge/bridges/list-view.ts.changeset/retire-spec-bridge-6366.md. Independently re-derived and confirmed by the review, including the 13-site count. The ruling stands on the protocol pin and the live reads insteadThe zod mirrors — the card's item 4
⭐ Every mirror already accepted the locale map, so this is declaration-only and there is no opposite-direction defect to report.
app.zod.tsandobjectql.zod.tsnever restate the keys (so both inheritbase.zod.ts'slabel: stripImportedDefaults(I18nLabelSchema));layout.zod.tsreceives the spec'sAriaPropsSchemaby reference throughSpecPageFields. The narrowing was on the DECLARED side in all four cases, which is why a forward mirror-vs-declaration comparison reads these pairs as clean —zod-mirror-parity.test.ts'sWiderThanDeclaredledger is the instrument that did see it, and its entries for these keys retire here. The review ablated that guard in both directions (re-adding a retired row reds; retiring a live row reds), so these retirements were required rather than chosen.Tests
packages/types/src/__tests__/inline-locale-declared-face-9092.test.ts. Each widened key is asserted positively and paired with a@ts-expect-errornegative on a genuinely-plain-stringsibling (icon,objectName,ariaDescribedBy) — load-bearing, becauseBaseSchemacarries an index signature and a key DELETED type-checks exactly like a key WIDENED. New this round: the cross-vocabulary describe block described above.packages/plugin-grid/src/__tests__/ObjectGrid.overlayTitleInlineLocale-9092.test.tsx— the provider path: map resolved, session locale honoured (the same map picks itszhentry under azhsession), both fallthrough cases, plus the string control.ObjectGrid.overlayTitleNoProviderFallback.test.tsxgains the provider-less arm. It has to live there:createI18nregisters its instance as react-i18next's module-global default and that registration survivescleanup(), so a no-provider render in a file that ever mounts a provider measures nothing.pnpm exec vitest run packages/types/ packages/plugin-grid/→ 313 files / 5409 tests passed, exit 0. Round 0 measured 312 / 5397 on the same command; the delta is +1 file and +12 tests, which is exactly what this round adds.pnpm --filter @object-ui/types run type-check→ exit 0 (all three projects).pnpm --filter @object-ui/plugin-grid run type-check→ exit 0 (tsc --noEmit && tsc -p tsconfig.test.json).pnpm exec turbo run build --filter="...@object-ui/types" --concurrency=2→ 43/43 tasks, exit 0. This is the real downstream check: every package's declaration build runs underdts-fail-on-type-errors.pnpm exec turbo run type-check --filter="...@object-ui/types" --concurrency=2→ 77/77 tasks, exit 0,grep -c 'error TS'= 0.plugin-gridtype-checkof this round exited 2 with a wall ofTS2307: Cannot find module '@object-ui/*'— a fresh worktree with nodist/, ⛔ not a defect. Re-run after the downstream build, it is exit 0. Recorded because that failure shape reads like a regression and is not one.Gates — exit codes captured by redirect BEFORE any pipe
All exit 0.
lint:coverage·check:entry-guard·check:upstream-port-parity·check:bash32-floor·turbo run lint --filter=@object-ui/types --filter=@object-ui/plugin-grid --force·check:vi-mock-override-shape·check:test-path-roots·check-cross-repo-closer-outcome·check:control-bytes·check:new-line-citations·check:spec-symbols·check-changeset-presence·check-changeset-no-major·check:changeset-claimsVerdict lines, read off the gates rather than restated:
lint:coverageprints46/46 packages linted, 0 with outstanding errors (0 total);check-control-bytesprints the tracked-text-file count it scanned;check-changeset-presenceprints the changed/published/declared triple it compared against the merge-base.Beyond the gate:
grep -naPfor control bytes over every file this round touched → no hits (exit 1).ESLint — a narrowed run, declared as such, with the three readings the narrowing needs:
lint:coverageexit 0, verdict above — read off the gate, ⛔ not guessed;--format jsonarray length 5,errorCount0,warningCount209 (all pre-existing; warnings are not the bar), exit 0;grep -nE 'projectService|project:|tsconfigRootDir' eslint.config.jsexits 1, withgrep -c 'parser'= 1 as the firing control. With no type information in the lint program, this diff cannot move the verdict on any file it did not touch.The repo-wide
pnpm lintand the fullpnpm testare CI's runs, ⛔ not owed here.check-governed-queue-guard --teston this PR's paths: NOT GOVERNED — the ordinary route applies. It is a draft regardless; landing is the seat's.Acceptance notes — ⛔ out of scope, noted
ObjectGridSchema.title— the objectui#7759 successor list gains this one (owed item 5). Measured on the installed pin: the protocol'sObjectGridPropsSchema.titleis thestring-or-inline-map union, objectui declarestitle?: string, and its mirror restatesz.string(). So unlike this card's four keys, both objectui faces are narrow — declaration and mirror agree with each other and disagree with the protocol, the same shape as the twodescriptionnotes below.|| schema.titlefallbacks sit on it. ⛔ A note, ⛔ not a fix — it is not group A.AppComponentSchema.descriptionandPageNodeSchema.descriptionare still plainstringon both faces — same shape, same successor.RecordComponentAriaProps.ariaLabel(packages/types/src/record-components.ts) declaresariaLabel?: stringwhile its docblock says it is aligned with the spec'sAriaPropsSchema, whoseariaLabelis the union — and six record-component interfaces share it.packages/types/src/zod/is empty, with theObjectGridSchemamirror files as the firing control), so it is ⛔ not a objectui#7759 mirror-vs-declaration pair, and no author can reach the map arm through the typed face today. Noted, ⛔ not filed.PageNodeSchema.ariahas no reader, and this PR widens an already-inert key rather than creating inertness — whether the key should exist is the ADR-0049 liveness question (objectui#4631 / objectui#7963), not this card's.base.ts,ObjectGrid.tsx, two test docblocks) are stale prose, not code. ⛔ Not swept here.Attribution, in prose because the footer block does not reliably survive a body edit: generated with Claude Code, session
session_01L5xpA5q533BgTTNADibEFt.Generated by Claude Code