Found while implementing objectui#7773 (the plugin-view / plugin-list half of the groupField cleanup). Filed unassigned and NOT touched there — packages/app-shell is outside that dispatch's two packages. Measured on origin/main a915064e.
What
packages/app-shell/src/views/ObjectView.tsx:2414 builds the view-level kanban config for the list-view it hands down, and writes the deprecated legacy alias rather than the spec-canonical key:
packages/app-shell/src/views/ObjectView.tsx:2409-2415
...(() => {
const lane =
viewDef.kanban?.groupByField ||
viewDef.kanban?.groupField ||
detectStatusField(objectDef as any) ||
undefined;
return lane ? { groupBy: lane, groupField: lane } : {};
})(),
It reads the canonical groupByField first (correct), then emits groupField — never groupByField.
Why this is not the same defect as objectui#7773, and not inert
This is the view-level config, where groupField is a live legacy alias of the spec's groupByField, not the retired node-level key. So the write works today. Two measured facts make it worth its own card anyway:
-
Its sibling already migrated, and left a note saying one key is enough.
packages/app-shell/src/views/InterfaceListPage.tsx:157, in defaultKanbanFromObject:
groupByField is the spec key. This used to emit the legacy groupField alongside it because ListView rendered off the alias only — that read-site now prefers the spec key, so one key is enough.
It returns { groupByField: field }. The ObjectView twin twelve hundred lines away was not carried along, so the same producer surface speaks two different vocabularies for the same concept depending on which entry point you came through.
-
The alias fold deliberately does not reach this bag, so the legacy spelling is what actually drives the lanes.
normalizeListViewSchema folds kanban.groupField into groupByField (packages/core/src/utils/normalize-list-view.ts:191), but only on the DECLARED path. Its own test pins the boundary as intentional — packages/core/src/utils/__tests__/normalize-list-view.test.ts:361 'does not reach into the legacy options.* twin'. ObjectView writes into options.kanban, so nothing folds it, and ListView.tsx:2495 resolves the lane as groupByField || groupField || detectStatusField(...) — landing on the alias because the canonical key was never written.
Net: a producer in this repo emits the deprecated spelling into the one bag where the migration machinery has been told not to look, and the alias read is load-bearing purely because of that.
Suggested shape
Emit groupByField (matching InterfaceListPage), leaving every alias READ untouched — ListView already prefers the canonical key, which is exactly the reason InterfaceListPage was able to drop the alias. Worth a pin so the two app-shell producers cannot fork again.
Boundary for whoever takes it
- ⛔ Do not touch any alias READ.
ListView.tsx :1536 / :1890 / :2165 / :2494 / :2495 and ObjectView.tsx (plugin-view) :1283 / :1313 / :1323 are the live view-level alias reads; stored metadata still authors the alias.
- ⛔ Do not touch
packages/plugin-list/README.md :126 / :186 — view-level config examples, still valid.
- ⚠️ The same expression also writes a view-level
groupBy, which is read only by the Kanban capability gate (ListView.tsx:1536 / :1890, v.groupByField, v.groupField, v.groupBy). objectui's KanbanConfig mirror declares only groupField and cardFields as local extensions on top of the spec config and is .passthrough(), so groupBy rides through undeclared at this level. I did NOT measure whether @objectstack/spec's own kanban config declares groupBy — check that before deciding whether the groupBy half is a second alias to fold or a legitimate key.
- ⛔ Not objectui#7773 (
plugin-view / plugin-list node-level write, in flight) and ⛔ not objectui#7772 (the page-block designer inspector). Both of those concern the RETIRED node-level key; this one is view-level and live.
Dedup
Searched before filing, with a positive control that fired in the same session (a query naming objectui#7773's defect returned objectui#7773 first). The query for this defect returned no card covering app-shell's ObjectView view-level alias emission. Closest neighbours, checked and not duplicates: objectui#2890 (the broad ListView legacy-vocabulary audit — this is one atomic producer site, the same relationship objectui#7773 has to it), objectui#7772 and objectui#7773 (node-level, retired key). ⚠️ Bounded reading: one targeted semantic search, not an exhaustive state=all sweep.
Filed by the dev of objectui#7773, session session_01YBWFb5YgMU5dw8p2VKj16S.
Found while implementing objectui#7773 (the
plugin-view/plugin-listhalf of thegroupFieldcleanup). Filed unassigned and NOT touched there —packages/app-shellis outside that dispatch's two packages. Measured onorigin/maina915064e.What
packages/app-shell/src/views/ObjectView.tsx:2414builds the view-level kanban config for thelist-viewit hands down, and writes the deprecated legacy alias rather than the spec-canonical key:It reads the canonical
groupByFieldfirst (correct), then emitsgroupField— nevergroupByField.Why this is not the same defect as objectui#7773, and not inert
This is the view-level config, where
groupFieldis a live legacy alias of the spec'sgroupByField, not the retired node-level key. So the write works today. Two measured facts make it worth its own card anyway:Its sibling already migrated, and left a note saying one key is enough.
packages/app-shell/src/views/InterfaceListPage.tsx:157, indefaultKanbanFromObject:It returns
{ groupByField: field }. TheObjectViewtwin twelve hundred lines away was not carried along, so the same producer surface speaks two different vocabularies for the same concept depending on which entry point you came through.The alias fold deliberately does not reach this bag, so the legacy spelling is what actually drives the lanes.
normalizeListViewSchemafoldskanban.groupFieldintogroupByField(packages/core/src/utils/normalize-list-view.ts:191), but only on the DECLARED path. Its own test pins the boundary as intentional —packages/core/src/utils/__tests__/normalize-list-view.test.ts:361'does not reach into the legacyoptions.*twin'.ObjectViewwrites intooptions.kanban, so nothing folds it, andListView.tsx:2495resolves the lane asgroupByField || groupField || detectStatusField(...)— landing on the alias because the canonical key was never written.Net: a producer in this repo emits the deprecated spelling into the one bag where the migration machinery has been told not to look, and the alias read is load-bearing purely because of that.
Suggested shape
Emit
groupByField(matchingInterfaceListPage), leaving every alias READ untouched —ListViewalready prefers the canonical key, which is exactly the reasonInterfaceListPagewas able to drop the alias. Worth a pin so the two app-shell producers cannot fork again.Boundary for whoever takes it
ListView.tsx:1536/:1890/:2165/:2494/:2495andObjectView.tsx(plugin-view):1283/:1313/:1323are the live view-level alias reads; stored metadata still authors the alias.packages/plugin-list/README.md:126/:186— view-level config examples, still valid.groupBy, which is read only by the Kanban capability gate (ListView.tsx:1536/:1890,v.groupByField, v.groupField, v.groupBy). objectui'sKanbanConfigmirror declares onlygroupFieldandcardFieldsas local extensions on top of the spec config and is.passthrough(), sogroupByrides through undeclared at this level. I did NOT measure whether@objectstack/spec's own kanban config declaresgroupBy— check that before deciding whether thegroupByhalf is a second alias to fold or a legitimate key.plugin-view/plugin-listnode-level write, in flight) and ⛔ not objectui#7772 (the page-block designer inspector). Both of those concern the RETIRED node-level key; this one is view-level and live.Dedup
Searched before filing, with a positive control that fired in the same session (a query naming objectui#7773's defect returned objectui#7773 first). The query for this defect returned no card covering⚠️ Bounded reading: one targeted semantic search, not an exhaustive
app-shell'sObjectViewview-level alias emission. Closest neighbours, checked and not duplicates: objectui#2890 (the broad ListView legacy-vocabulary audit — this is one atomic producer site, the same relationship objectui#7773 has to it), objectui#7772 and objectui#7773 (node-level, retired key).state=allsweep.Filed by the dev of objectui#7773, session
session_01YBWFb5YgMU5dw8p2VKj16S.