You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(cli,spec): i18n coverage gates view labels — the defineView() container is no longer skipped (#4123)
`i18n/missing-view` had ZERO producers. The `'view'` source exists in
`CoverageIssue`, the walker has code for it, and check-i18n-coverage's header
claims listViews is covered — but no view label in this repo had ever been
gated, and the ratchet reported green the whole time.
`collectExpectedEntries` recognized two view shapes; the compiled config is
neither:
1. Object-nested `listViews` — objects do not carry `listViews` once
compiled (0 across every example; only hand-authored platform objects
use that shape).
2. Top-level NAMED views — guarded by `if (!view?.name) continue`.
`defineView()` emits the aggregated View CONTAINER — `{ list, listViews,
formViews }` — which per spec (`view.zod.ts`) has no top-level `name`: it is
keyed implicitly by its target object at `list.data.object`, exactly as
objectql's `resolveMetadataItemName` resolves it. The guard therefore rejected
the spec's own container shape, i.e. every view every example declares.
Measured on the real compiled configs, same commit, before → after:
app-crm total 1402 → 1420 | view 0 → 18
app-showcase total 2210 → 2250 | view 0 → 40
app-todo total 1343 → 1349 | view 0 → 6
No other source moved; the totals rise by exactly the view counts.
The container walk emits under the same `objects.<object>._views.<view>.*`
convention the runtime resolver reads (`viewLabel` in @object-ui/i18n) and the
shipped platform bundles already carry (`sys_user._views.all_users.label`). An
unnamed default `list` resolves under `_views.list`, matching the console's
`primary.name || 'list'`. A named list view may retarget another object via its
own `data`, so its own object wins over the container's. `formViews` stays
uncovered on purpose: form views have no counterpart in that resolver
convention, so emitting keys for them would expect translations nothing reads.
`StrictObjectTranslation` gains the `_views` slot `ObjectTranslationDataSchema`
already permits — it is not derivable from the object type (views are declared
separately), so it is optional and loosely keyed rather than enumerated like
`fields`. Without it, `satisfies StrictObjectTranslation<…>` rejects the very
translations the gate now asks for (app-todo).
The 35 newly surfaced strings are TRANSLATED, not ratcheted — the precedent
from the object-less action: raising the baseline makes the gate green by
widening the debt it exists to prevent.
Verified the gate is genuinely live on view keys rather than green by accident:
deleting one view translation moves app-todo 120 → 121 and fails; restoring it
returns to OK. check-i18n-coverage: 665, none new. os lint 0 errors on all
three examples. spec 7022 tests, cli 877 tests, showcase 60, crm 20, todo 78.
tsc + eslint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
0 commit comments