Repository navigation
console: grid grouping and dashboard category axes/legends order a select field's values alphabetically, not in the field's declared option order #11809
Description
Activity
- addedbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatarea:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, search
on Oct 7, 2026 objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsPath: ② the capabilities an end user meets in the app — grouped lists and charts | 缺项 | P2
Triage: first grade,
bug·priority:p2·domain:ui·area:records·pm:queue. Direction as the body proposesTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-07T17:11Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in the grid's grouping (
packages/plugin-grid) and the chart category and legend order (plugin-charts/plugin-dashboard) ⇒domain:ui; rationale: a Studio or console surface in objectui. Filed from the browser QA pass of 2026-10-07 (objectstack879bd38c, objectui179f6fe9); paths re-read on objectuimain9990f9e122.- Why p2: every grouped list and chart on a select field shows its values in label order, not in the declared order (measured on three surfaces). Kanban and the dashboard filter already use the declared order. It runs, but wrong.
- Direction:
- for a select dimension, order groups, categories and legend entries by the option index from the field metadata
- empty and unknown values last
- label order only where no option order exists
- Pins: Group by Status and Tasks by Status read Backlog → To Do → In Progress → In Review → Done; Kanban stays as it is (control).
Clause-②: no. Patch changeset in objectui.
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsClaim: PM loop round 3
Session:session_01CGZy1BGCjdN5cXqL9cnvB8
Account:os-support-ai
Branch:claude/issue-11809-select-option-order
Worktree:objectui-issue-11809
Domain:domain:ui
Seat:domain:ui#3
File surface (on9990f9e):packages/plugin-grid/src/useGroupedData.ts(compareGroups:228, the group sort:444,keyOrder:502);- the chart category and legend order:
packages/plugin-charts/src/AdvancedChartImpl.tsx(:2231–:2236) andpackages/plugin-dashboard/src/DatasetWidget.tsx(:1622,:1641). The dev measures which path draws the showcase Tasks by Status and Priority Mix widgets and names it; - the tests beside them;
- one
.changeset/11809-*.mdcovering each changed package.
Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)
Clause-②: no
Responsibility:objectui plugin-grid / plugin-charts / plugin-dashboard: grouped rows, chart categories and legends for a select dimension are sorted by label, not by the field's declared option order | the platform path exists: the field metadata declares options in order, and Kanban and the dashboard filter already read that order | every end user who groups a list or reads a dashboard chart by a select field; measured by the filer on three surfaces in the showcase console
Thread-read: 6042918298
Serial constraints cleared:noneblocking. The two otherarea:recordscards in flight have disjoint surfaces: this seat's objectui#11775 (plugin-viewObjectView.tsx, PR objectui#11821 in the merge queue), and seat 1's objectui#11777 (plugin-formfield-group sections and two designer files). No open objectui PR touches the files above (read 2026-10-07T18:25Z; open: #11826, #11825, #11821, #11600, #11069).Why
Clause-②: no: an ordering fix inside three plugins. If the fix needs a published export, prop or type member, for example a new option-order input on a chart component, the dev reports it before opening the PR, and the seat amends this line.
Generated by Claude Code
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11809,
"status": "blocked",
"branch": "claude/issue-11809-select-option-order",
"pr": null,
"session": "session_01CGZy1BGCjdN5cXqL9cnvB8",
"premise_still_valid": true,
"summary": "Implemented, verified and pushed. The branch head is 72c7ae8: the fix, the pins, the changeset, and a merge of origin/main at 2b30d39. GRID: in plugin-grid useGroupedData.ts, both group sorts (server header rows and client buckets) now go through compareGroupEntries. A grouping field with options orders its groups by declared option index; desc reverses that order; undeclared values come next, by label; the empty group comes last, in both directions. A field without options keeps label order. A multi-value key ranks as the tuple of its members' indexes. ObjectGrid.tsx builds the per-field ranks from the object field's options with core's buildCategoryOrder and buildCategoryRank (the funnel's reader; no new reader of the option list). It calls the package-internal useGroupedDataInOptionOrder. The published useGroupedData keeps its signature, and index.tsx and the exports map are unchanged, so Clause-② stays no. CHARTS, measured: Tasks by Status (bar_status) and Priority Mix (donut_priority) are dataset widgets. DashboardGridLayout and DashboardRenderer route them to DatasetWidget, which renders them through ChartRenderer and AdvancedChartImpl. Their order is the dataset's GROUP BY order: the stored values sorted alphabetically give exactly the orders the card reports. AdvancedChartImpl's only sort is the funnel's. The two DatasetWidget sorts the claim cites are the flat TABLE's. So DatasetWidget now charts a reordered copy of the rows: declared options first, undeclared values next in dataset order, the empty bucket last. A pivoted second select dimension's series follow the same order. chartRows keeps its drill index alignment. An explicit options.sortBy is left as answered. AdvancedChartImpl is unchanged; widening its published categoryOrder prop would also override plugin-report's explicit order. Kanban (control): untouched, and it imports no changed module. BLOCKED on one step only the PM can take. packages/plugin-grid/src/ObjectGrid.tsx is outside the claim's File surface line, and the grid half needs it, because the hook receives no field metadata (dispatch Zone 2 point 1 anticipated this). The claim says stop on breach and report before opening the PR, so no PR was opened. PM: amend the claim's File surface with that file, then open the draft PR from the branch. The body is ready at /tmp/claude-0/-home-user/613acf53-7e5b-52cd-a1e4-8670521d3bcb/scratchpad/issue-11809/11809-pr-body.md: first line Fixes #11809, then a line Clause-② colon no, session-URL footer. Then set the PR assignee to os-support-ai. Two existing pins beside the changed files relied on the old order and are restated: gridGroupingMembers-8071 and DatasetWidget.optionLabelI18n.",
"tests": "Run from the worktree root under os-verify-lock (slot issue-11809-dev). (1) New pins: groupSelectOptionOrder-11809 (9 tests: real ObjectGrid on server-grouped and client-grouped paths, status, priority, desc, undeclared legacy and empty last, multi-value tuple; CONTROLs for a text field and for the published hook keeping label order) and DatasetWidget.selectOptionOrder-11809 (7 tests: bar by status, donut by priority, server-resolved labels, pivoted series, drill on a moved bar opens status todo; CONTROLs for explicit sortBy and a field with no options). On 72c7ae8, those two plus the two restated pins plus 3 app-shell DatasetWidget hosts (DatasetPreview.dimensionLabels-8187, DatasetPreview, DashboardView.autoRefresh-11062): Test Files 7 passed (7), Tests 52 passed (52), RERUN_EXIT=0. (2) Whole packages, on 352bde9: vitest run packages/plugin-grid/ gave Test Files 1 failed, 187 passed (188), Tests 1 failed, 1735 passed. vitest run packages/plugin-dashboard/ gave Test Files 1 failed, 173 passed (174), Tests 1 failed, 1732 passed, 6 skipped. Each red was an existing pin tied to the old order (gridGroupingMembers-8071 expected Closed Lost before Closed Won; optionLabelI18n's drill clicked categories()[0], which was orion). Both are restated and pass in (1). Since 352bde9 neither package changed except those two test files: git diff --quiet over both packages with the two files excluded exits 0. (3) Ablation on de2b75e, fix committed first; useGroupedData.ts, ObjectGrid.tsx and DatasetWidget.tsx are byte-identical to 72c7ae8 (git diff --quiet exit 0). Each mutation went through objectstack scripts/ablation-replace.mjs. Grid: compareGroupEntries forced to label order (anchor 1 to 0, blob 4090a29e845e to bcbe64195a4f). Result: Tests 6 failed, 3 passed (9); the 3 that passed are the three CONTROLs. Chart: category rank and series rank both nulled (blob c97b49629905 to 1f48df1aa8b0 to 33506f6b4ede). Result: Tests 5 failed, 2 passed (7); the 2 that passed are the two CONTROLs. Restores: blob equals HEAD (4090a29e845e, c97b49629905) and git diff HEAD is empty, from both the tool and a separate hash check. Direction observed: turns red, as predicted. (4) pnpm --filter @object-ui/plugin-grid type-check exit 0 and pnpm --filter @object-ui/plugin-dashboard type-check exit 0 on 72c7ae8. Before that, turbo run build over both packages' dependency closures gave Tasks 14 successful, 14 total. tsc --listFilesOnly on each tsconfig.test.json lists the new pin file. The dashboard type-check was red once on 7727a89 (TS7006, untyped find callback in the restated optionLabelI18n pin), was fixed in 0a3d8e9, and is green on 72c7ae8. NOT MEASURED: the live showcase console in a browser.",
"mcp_calls": "0",
"api_writes": "1 — this os-dev-report comment, POST /repos//issues/11809/comments through the fleet-write relay (post-stamped.mjs). git push is not counted. No pr_create and no label-write: no PR was opened (file-surface stop).",
"open_questions": [
{
"question": "File surface: may packages/plugin-grid/src/ObjectGrid.tsx be added to the claim, so the draft PR can be opened from the pushed branch?",
"options": [
"A — amend the claim's File surface with ObjectGrid.tsx and open the draft PR from the prepared body (the grid half needs it: ObjectGrid is the only caller holding the object definition)",
"B — open a chart-only PR (Part of #11809) and re-dispatch the grid half after the amendment"
],
"recommendation": "A. Business need: the card's first named surface is the grid (Group by Status), and it cannot be ordered without ObjectGrid passing the option order in. Long-term soundness: one PR, one comparator reading core's buildCategoryOrder. AI-error resistance: no published-surface change, so nothing new for an author to misdeclare. Scope: no new capability. B splits one ruling across two landings for no gain."
},
{
"question": "Chart precedence: should an explicit widget options.sortBy keep the dataset's order over a select dimension's declared option order? This PR keeps it (only the funnel's existing rule lets the declared order win over sortBy).",
"options": [
"A — explicit sortBy wins (this PR): declared option order is the DEFAULT order only",
"B — declared option order always wins on a select dimension, sortBy ignored for ordering on charts"
],
"recommendation": "A. Business need: a top-N-by-count chart (sortBy a measure, desc) is a real authoring pattern the widget lowers into the query. Long-term soundness: an author's explicit key outranks an implicit default. AI-error resistance: B would make a declared sortBy silently inert on charts, which is a declared key the runtime does not honour. Scope: A adds nothing."
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted in the PR body's Acceptance notes, not filed (no public door measured in this run, so no reach: line). Same defect class, family close-out card if the seat has one: plugin-report DatasetReportRenderer charts the dataset rows in answered order unless the report declares an order (it passes categoryOrder to AdvancedChartImpl, which applies it to funnels only), and plugin-charts ObjectChart (view:chart / object-chart aggregate path) passes no declared order at all. Dedupe words: report chart category order picklist · object chart group by select order · chart category declared option order",
"carrier: 承接者:无 · noted, not filed. The dataset TABLE and PIVOT keep the dataset's row order by design (objectui#5827, objectui#4263), so the showcase pivot Tasks by Status x Priority still lists rows in GROUP BY order. The card names grouped lists, category axes and legends, not tables."
],
"gates": [
{
"command": "pnpm exec vitest run (7 files: 2 new pins, 2 restated pins, 3 app-shell DatasetWidget hosts) --maxWorkers=2 @72c7ae8",
"exit": 0,
"verdict": "Test Files 7 passed (7) · Tests 52 passed (52)"
},
{
"command": "pnpm exec vitest run packages/plugin-grid/ --maxWorkers=2 @352bde9",
"exit": 1,
"verdict": "Test Files 1 failed | 187 passed (188) · Tests 1 failed | 1735 passed (1736) — the red is gridGroupingMembers-8071, restated after this run; green in the 72c7ae8 rerun"
},
{
"command": "pnpm exec vitest run packages/plugin-dashboard/ --maxWorkers=2 @352bde9",
"exit": 1,
"verdict": "Test Files 1 failed | 173 passed (174) · Tests 1 failed | 1732 passed | 6 skipped (1739) — the red is DatasetWidget.optionLabelI18n drill boundary, restated after this run; green in the 72c7ae8 rerun"
},
{
"command": "ablation grid (ablation-replace, compareGroupEntries label order) @de2b75e",
"exit": 1,
"verdict": "Tests 6 failed | 3 passed (9); restored blob == HEAD 4090a29e845e, git diff HEAD empty"
},
{
"command": "ablation chart (ablation-replace x2, category and series rank nulled) @de2b75e",
"exit": 1,
"verdict": "Tests 5 failed | 2 passed (7); restored blob == HEAD c97b49629905, git diff HEAD empty"
},
{
"command": "pnpm exec turbo run build --filter=@object-ui/plugin-grid^... --filter=@object-ui/plugin-dashboard^... --concurrency=2",
"exit": 0,
"verdict": "Tasks: 14 successful, 14 total"
},
{
"command": "pnpm --filter @object-ui/plugin-grid type-check @72c7ae8",
"exit": 0,
"verdict": "tsc --noEmit && tsc -p tsconfig.test.json, no output; lock VERDICT command-exit 0"
},
{
"command": "pnpm --filter @object-ui/plugin-dashboard type-check @72c7ae8",
"exit": 0,
"verdict": "tsc --noEmit && tsc -p tsconfig.test.json, no output; lock VERDICT command-exit 0 (was 2 on 7727a89: TS7006 in the restated pin, fixed in 0a3d8e9)"
},
{
"command": "pnpm exec eslint (7 touched ts/tsx files)",
"exit": 0,
"verdict": "0 errors, 254 warnings (pre-existing no-explicit-any in the touched sources and the two restated pins); the two new test files carry 0 warnings"
},
{
"command": "pnpm check:control-bytes @72c7ae8",
"exit": 0,
"verdict": "check-control-bytes: OK (scanned 7790 tracked text file(s); skipped 85 binary)"
},
{
"command": "pnpm check:test-path-roots @72c7ae8",
"exit": 0,
"verdict": "check-test-path-roots: OK"
},
{
"command": "pnpm check:changeset-claims @72c7ae8",
"exit": 0,
"verdict": "No pending changeset names a file this change touches."
},
{
"command": "pnpm check:pending-changeset-literals @72c7ae8",
"exit": 0,
"verdict": "No test source names a pending changeset."
},
{
"command": "pnpm check:new-line-citations @72c7ae8",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0"
},
{
"command": "pnpm check:vi-mock-specifiers / check:vi-mock-inherit / check:vi-mock-override-shape @72c7ae8",
"exit": 0,
"verdict": "OK x3"
},
{
"command": "pnpm check:phantom-deps / check:self-import @72c7ae8",
"exit": 0,
"verdict": "Every in-scope import is declared by the package that publishes it. · No package names itself inside its own src/."
},
{
"command": "node scripts/check-changeset-presence.mjs @72c7ae8",
"exit": 0,
"verdict": "7 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s): .changeset/11809-select-option-order.md."
},
{
"command": "i18n gates, check:readme-exports",
"exit": null,
"verdict": "NOT RUN: no locale pack changed, no package entry export changed"
}
],
"deviations": [
"File-surface breach: packages/plugin-grid/src/ObjectGrid.tsx is not on the claim's File surface line. The claim says stop on breach and report before opening the PR, so the PR is not opened and status is blocked. All work is pushed.",
"Restated two existing pins beside the changed files (gridGroupingMembers-8071, DatasetWidget.optionLabelI18n), counted as the tests beside them. 8071's file header, which documented order as label order, was restated too.",
"AdvancedChartImpl.tsx is on the claim's surface and is not changed: measurement put the fix in DatasetWidget.",
"Merged origin/main 2b30d39 (plugin-view and app-shell only), per the dispatch's merge-never-rebase term. The tests after the merge cover the delta; the whole-package suites ran before it, at 352bde9.",
"Lock queue: two calls were not served (exit 99 after 540s, holder pid 31886, a sibling's full app-shell vitest, alive at about 216 percent CPU). Later calls went through a background driver that re-took the same slot, waited on with foreground tail --pid. No run was skipped."
],
"files_changed": [
".changeset/11809-select-option-order.md",
"packages/plugin-grid/src/useGroupedData.ts",
"packages/plugin-grid/src/ObjectGrid.tsx",
"packages/plugin-grid/src/tests/groupSelectOptionOrder-11809.test.tsx",
"packages/plugin-grid/src/tests/gridGroupingMembers-8071.test.tsx",
"packages/plugin-dashboard/src/DatasetWidget.tsx",
"packages/plugin-dashboard/src/tests/DatasetWidget.selectOptionOrder-11809.test.tsx",
"packages/plugin-dashboard/src/tests/DatasetWidget.optionLabelI18n.test.tsx"
],
"line_budget": "not applicable (no skills/** surface)"
}
Generated by Claude Code
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsClaim amendment —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-07T19:45Z. It amends claim6044202981after the dev's file-surface stop (report6045476328). The claim stands otherwise.- File surface, added:
packages/plugin-grid/src/ObjectGrid.tsx.- Measured by the dev:
useGroupedDatareceives no field metadata, andObjectGridis the only caller holding the object definition. So the grid half needsObjectGridto pass the declared option order in, from@object-ui/core's existingbuildCategoryOrder/buildCategoryRank, through the package-internaluseGroupedDataInOptionOrder. - The published
useGroupedDatakeeps its signature, andindex.tsxand theexportsmap are unchanged. - Zone 2 item 1 of the dispatch anticipated exactly this.
- Measured by the dev:
- File surface, unused:
packages/plugin-charts/src/AdvancedChartImpl.tsxstays unchanged. The showcase Tasks by Status and Priority Mix widgets are dataset widgets, ordered by the dataset'sGROUP BYorder, so the fix belongs inDatasetWidget.tsx. Its only sort is the funnel's. Clause-②: nostands: no published export, prop or type member changes.- The dev's two open questions, answered (neither is a product fork; both stay inside triage's ruling
6042918298):- Amend the surface and open one PR: A.
- An explicit widget
options.sortBykeeps its order over the declared option order: A. The ruling replaces the default label order; it does not override an order the author declared. Under B, a declaredsortBywould be silently inert on charts.
Generated by Claude Code
- File surface, added:
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsACCEPT —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-07T20:19Z. PR objectui#11830, head72c7ae8.-
PR shape: draft against
main(2b30d39merged in). First lineFixes #11809, no other closing keyword.Clause-②: noat line start. -
The PR was opened by the seat. The dev stopped before opening it, on a file-surface breach (
ObjectGrid.tsx), as the claim says to. The seat amended the claim (6045546046) and opened the dev's prepared body unchanged. -
Scope: 8 files, +796/−31, on the amended surface:
useGroupedData.tsandObjectGrid.tsxinplugin-grid;DatasetWidget.tsxinplugin-dashboard;- two new pin files, and two existing pins beside them restated to the declared order;
- one changeset for both packages.
AdvancedChartImpl.tsxis unchanged, by measurement. Neither package'sindex.tsx,exportsmap orpackage.jsonchanges. No governed path. -
Diff read (the seat's own):
ObjectGridbuilds each grouping field's rank from the object field'soptions, through@object-ui/core's existingbuildCategoryOrder/buildCategoryRank(the reader the funnel already uses). It is memoised on the order string, not on the per-renderschema.grouping, and passed to the package-internaluseGroupedDataInOptionOrder. The publisheduseGroupedDatakeeps its signature and its label order, and a control pins that.- Grid: declared options first;
descreverses that; undeclared values by label after them; the empty group last, in both directions. DatasetWidgetcharts a reordered copy of the rows (declared, then undeclared in dataset order, then empty), and a pivoted second select dimension's series follow the same order. The drill index stays aligned, and a pin clicks a moved bar.
- Grid: declared options first;
-
Ruling honoured (triage
6042918298):- option index for a select dimension, on groups, categories and legends;
- empty and unknown values last;
- label order where no option order exists.
The ruling's pins are covered: grid Group by Status and chart Tasks by Status read Backlog → To Do → In Progress → In Review → Done. Kanban is untouched (control): it imports no changed module.
-
Open questions, both answered A in the amendment:
- one PR with
ObjectGrid.tsxadded; - an explicit widget
options.sortBykeeps the author's order.
- one PR with
-
Changeset sentences checked against the head:
- the alphabetical-before readings;
- the grid bullet (declared,
desc, undeclared by label, empty last, both grouping paths); - the dataset-charts bullet, including "An explicit
options.sortBy… is left as the dataset returned it" and "Tables and pivot tables keep the dataset's row order"; - "Nothing is added to either package's entry".
patchon both packages. -
Reverse verification (dev report
6045476328):- Grid ablation (
compareGroupEntriesforced to label order) turned 6 of 9 red; the 3 controls stayed green. - Chart ablation (category and series rank nulled) turned 5 of 7 red; the 2 controls stayed green.
- Each ablation was restored with the blob equal to HEAD.
- Whole-package runs at
352bde9each showed exactly one red: an existing pin that encoded the old order, which was restated. Both are green on72c7ae8. - Commit trailers on the branch are the model-free pair only.
- Grid ablation (
-
Gates: CI on
72c7ae8(head_shaequals the PR head): 43 runs, 40 success, 3 skipped (Test (coverage), its shard template,dependabot), 0 failure.LintandType Checkare success. Mergeable stateclean. -
Contract review: not required (
Clause-②: no; no entry, export or type change in either package).
Findings:
plugin-report'sDatasetReportRendererandplugin-charts'ObjectChartaggregate path chart a select dimension in the dataset's order. These are the same defect class on other surfaces, but no public door was measured, so there is no reach →Acceptance notes- Dataset tables and pivots keep
GROUP BYorder by design (objectui#5827, objectui#4263) →dropped — by design, not this card
Landing: ready + auto-merge through the queue, now.
Generated by Claude Code
-
objectstack-fleet commented
on Oct 7, 2026 ContributorAuthorMore actionsLanded —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-07T20:46Z. PR objectui#11830 merged through the queue as8aebc6fat 2026-10-07T20:37Z.- The merge:
- One parent,
d53fd02, an ancestor oforigin/main. - The landed tree equals
git merge-treeof that parent and the accepted head72c7ae8(treed55955c4on both). - 8 files, +796/−31.
- One parent,
- Content check,
d53fd02→8aebc6f:- files in
plugin-grid/srcnaminguseGroupedDataInOptionOrder: 0 → 3; buildCategoryRankinplugin-dashboard/src/DatasetWidget.tsx: 0 → 4;- control:
plugin-grid's publishedexport { useGroupedData }is 1 on both sides.
- files in
- Closures: the PR's only closing keyword was
Fixes #11809. It is the only issue closed since 20:00Z.pm:dispatchedis removed.
Generated by Claude Code
- The merge:
- added a commit that references this issue
on Oct 9, 2026
Filing gate ① — product defect with a named location and a reproduction. reach: showcase Tasks list → Group → Status, and the Delivery Operations dashboard, in the end-user console.
Who acts on it: objectui triage → the console / records owner. ⛔ Not a claim. Found in a manual browser QA pass of the end-user console on 2026-10-07; filed one card per finding on the maintainer's word: 「你发现的问题全部提交 issue,然后继续测试前端」, and on the one-card-per-finding question 「覆盖规则,逐条立卡」.
What happens
showcase_task.statusdeclares Backlog → To Do → In Progress → In Review → Done, andpriorityLow → Medium → High → Urgent. Several surfaces drop that order and sort by label:The same app gets it right elsewhere: the Kanban board's columns and the dashboard's own Task Status filter both list the values in declared order.
Expected
Groups, category axes and legends for a select/picklist dimension follow the field's option order (empty/unknown values last).
Suggested direction (triage to rule)
Sort grouped rows and chart categories by the option index from the field metadata when the dimension is a select, falling back to label order only for free text.
Environment
objectstack
879bd38c·examples/app-showcasebooted withobjectstack dev --ui --seed-adminon an isolated port and SQLite file · objectui179f6fe9(HEAD; the framework pin.objectui-shaisa58626c8) served by the console's Vite dev server, perf numbers from avite buildof the same commit · Chromium 141 at 1440×900 · signed in as the seeded platform adminadmin@objectos.aiunless stated.Duplicate check
Dedupe words: group by select option order alphabetical · chart category axis order picklist · legend order declared options
Filed by Claude Code (session
session_01D76mrPJrSSdaKRxR2rvrMG) from that QA pass.Generated by Claude Code