Repository navigation
console(nav): drag-to-reorder is wired only for group-free navigation — every stock app's sidebar is grouped, so enableReorder never renders a grip #11626
Description
Activity
objectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsTriage: first grade —
bug·priority:p3·domain:ui·pm:queue. Reorder works within each group of a grouped sidebar; cross-group moves stay outTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-05T01:55Z. ⛔ Not a claim, ⛔ not a dispatch.- Why
bug, notenhancement. The shell turns the prop on for every desktop sidebar (UnifiedSidebar.tsxabout:583), and its doc names no flat-only limit. Every stock app is grouped, so the documented feature renders nowhere a user can reach. - Direction. The grouped arm (
NavigationRenderer.tsxabout:1650) gets the same sortable path as the flat arm, scoped to each group, anduseNavOrderpersists an order per group key (today only__root__).- Cross-group moves are out of scope. Moving an entry into another group changes the app's structure, which is app metadata, not a personal order. The card's Done-when admits within-group reorder.
- Why p3. A personalization convenience; nothing is lost. The verifier graded it P3.
- Routing: shell navigation, so
domain:ui. No area label fits the shell.
Generated by Claude Code
- Why
- 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 seat
on Oct 5, 2026 objectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsPath: the road — run it, the shell remembers | platform-core.shell-nav-personalization | P2
Triage: the grade above (
5986793209) carries noPath:line. Here it is. This amends my5986793209Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-05T01:58Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/layout/src/NavigationRenderer.tsx(the grouped arm anduseNavOrder) ⇒domain:ui; rationale: the prop is on for every desktop sidebar, and only the grouped arm lacks the sortable path.The grade, direction and labels stand.
triage-duties.mdline 60 puts thePath:line first; line 74 asks for the lands-in line.
Generated by Claude Code
objectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsClaim: PM loop round 2
Session:session_015W8GBu6sBiqus2L2xjMsAL
Account:os-steve
Branch:claude/issue-11626-grouped-nav-reorder
Worktree:objectui-issue-11626
Domain:domain:ui
Seat:domain:ui#1
File surface:packages/layout/src/NavigationRenderer.tsx(the grouped arm, about:1650),packages/app-shell/src/layout/UnifiedSidebar.tsx(useNavOrder, about:76–:124), the tests beside them, and.changeset/11626-*.md(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: default tier(dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; floor sonnet · default opus · ceiling fable)
Clause-②: no
Thread-read: 5986818877
Serial constraints cleared: none, read 2026-10-05T04:47Z. The open objectui PRs (#11639app-shellObjectView.tsx, in the merge queue; #11641plugin-detail, possiblyapp-shellRecordDetailView.tsxandmetadata-admin/in its patch round; #11069packages/cli; #11600 the release PR) touch neither file. The in-flight objectui#11631 declarespackages/componentsform.tsx.Why
Clause-②: no:NavigationRendererProps(enableReorder,onReorder) is published from@object-ui/layout. Triage's direction (5986793209): a per-group reorder in the grouped arm, persisted per group key. The existingonReorder(reorderedItems)can report it as long as the signature does not change. The dispatch fences the published props and callback types, plus any new export, prop, type member or i18n key: a route that needs one stops and reports.
Generated by Claude Code
objectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 11626, "status": "done", "branch": "claude/issue-11626-grouped-nav-reorder", "pr": "https://github.com/objectstack-ai/objectui/pull/11656", "session": "session_015W8GBu6sBiqus2L2xjMsAL — mode:subagent, the PM seat's id (resumed run on the PM's claim 5988295154)", "premise_still_valid": true, "summary": "Drag-to-reorder now works within each level of a grouped sidebar. Each group's children (and each run of top-level entries between groups) is its own sortable list with its own DndContext. A within-group move is reported through the unchanged onReorder(reorderedItems) as the top-level list with that group's children reordered, and useNavOrder stores it under the group's spec id beside __root__ and applies every stored level on load. Cross-group moves are refused (no shared drop target). Reviewing the resumed branch found two holes the grouped arm would have inherited from the flat arm, both measured then fixed in the shared code: a saved order was sorted straight back on any app that authors `order` (the store now writes saved positions as `order`, and detection compares id+order), and dnd-kit's sortable attributes sat on the row wrapper, giving every row a dead focusable 'button' (the grip is now the activator via setActivatorNodeRef; keyboard reorder works live). No export, prop, type member, callback parameter or i18n key added (Clause-② fence held).", "tests": "FINAL HEAD beef430. Pinned pair (packages/layout/src/__tests__/NavigationRenderer.groupedReorder-11626.test.tsx + packages/app-shell/src/layout/__tests__/UnifiedSidebar.groupedNavOrder-11626.test.tsx): 22/22 at beef430. pnpm exec vitest run packages/layout/: 38 files / 344 tests passed, exit 0 at beef430. pnpm exec vitest run packages/app-shell/: 1005 files passed + 1 skipped, 9985 tests passed + 9 skipped, exit 0 at cf8b3d3 (post-merge; cf8b3d3..beef430 touches only NavigationRenderer.tsx: one comment line + grip handle destructuring, app-shell byte-identical, pinned app-shell file rerun at beef430). type-check layout and app-shell exit 0 at beef430 (both tsconfig.test.json include src/**/*.test.tsx). lint layout exit 0 at beef430 (0 errors; NavigationRenderer.tsx 22 warnings vs 23 on main via the same eslint --stdin spelling; new test file 0); lint app-shell exit 0 at e42f5d5 (0 errors; UnifiedSidebar.tsx 10 vs 10 on main, same spelling; eslint.config.js has no type-aware linting and app-shell is byte-identical to beef430). Closure build turbo --filter='@object-ui/app-shell^...' exit 0 at cf8b3d3; layout build exit 0 at beef430. ABLATIONS (objectstack scripts/ablation-replace.mjs, anchor hit 1→0 on disk, restore proven blob==HEAD and git diff HEAD empty, trap on EXIT/INT/TERM; src-aliased in vitest so no dist leg; run on committed 6eb56eb): A1 groupedReorder=false → 16/22 red (every grouped case), A2 no order stamping → 3/22 red (the authored-order cases), A3 detection by ids only → 1/22 red (move landing on listed sequence), A4 attributes back on wrapper → 2/22 red (activator pins); direction as predicted for all four. PRE-FIX PROBE on resumed head 75c86fe: authored order → store written but drawn order unchanged (group and __root__); 7/7 row wrappers role=button tabindex=0, 0/7 grips focusable. LIVE (objectstack worktree detached at ba575886, 14 commits behind objectstack origin/main 27991556; showcase objectstack dev --seed-admin --fresh; Playwright Chromium /opt/pw-browsers/chromium; consoles from source): main 0baf86f → 0 grips even with Workspace + Data Model open, store never written. beef430 → 2 grips with groups as served (list endpoint serves expanded:false), 18 with two groups open, all tabindex=0, 0 non-grip sortables; mouse drag Settings to top of Workspace → drawn + stored {grp_workspace:[nav_settings,nav_my_work,nav_review_queue,nav_new_project_wizard]}; reload restores; keyboard (focus grip, Space, ArrowDown, Space) moves Approvals and stores it; top-level run drag writes __root__ and draws it; drag aimed at another group keeps the entry in its own group, Data Model unchanged, no grp_data key; final reload draws every stored level; 0 page errors. check:new-line-citations, check:control-bytes, check:i18n-keys, check:i18n-dead-keys, check:vi-mock-specifiers/inherit/override-shape, check:test-path-roots, check:changeset-claims, check:pending-changeset-literals, check-changeset-presence, check-changeset-no-major: all exit 0 at beef430; governed-queue-guard --test: NOT GOVERNED. NOT MEASURED: check:eager-closure, reason: needs a full console production build (CI Bundle Analysis).", "mcp_calls": "0 — no MCP GitHub tool called", "api_writes": "3 — all via the fleet-write relay (each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls (draft #11656, read-back 9947 bytes identical); (2) label-write --assign os-steve → POST /repos/objectstack-ai/objectui/issues/11656/assignees (read-back matches, labels untouched); (3) this os-dev-report comment → POST /repos/objectstack-ai/objectui/issues/11626/comments via post-stamped.mjs. Not REST: git push of claude/issue-11626-grouped-nav-reorder, 4 pushes (6eb56eb; cf8b3d3 carrying c7a5d7b; e42f5d5; beef430), no force.", "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed — comment drift: the home-arm comment in UnifiedSidebar.tsx says enablePinning and enableReorder 'both persist under useNavOrder'; pins persist in the favorites store (useNavPins, type 'nav' favorites), not in objectui-nav-order-APP. In PR Acceptance notes.", "carrier: 承接者:无 · noted, not filed — polish: the drag grip sits in the row's left padding against the entry icon (the group-free arm's classes, unchanged). In PR Acceptance notes." ], "gates": [ { "gate": "vitest pinned pair (2 files)", "head": "beef430", "exit": 0, "reading": "22/22" }, { "gate": "pnpm exec vitest run packages/layout/", "head": "beef430", "exit": 0, "reading": "38 files, 344 tests" }, { "gate": "pnpm exec vitest run packages/app-shell/", "head": "cf8b3d3", "exit": 0, "reading": "1005 passed + 1 skipped files, 9985 passed + 9 skipped tests" }, { "gate": "pnpm --filter @object-ui/layout type-check", "head": "beef430", "exit": 0 }, { "gate": "pnpm --filter @object-ui/app-shell type-check", "head": "beef430", "exit": 0 }, { "gate": "pnpm --filter @object-ui/layout lint", "head": "beef430", "exit": 0, "reading": "0 errors / 35 warnings; NavigationRenderer.tsx 22 vs main 23" }, { "gate": "pnpm --filter @object-ui/app-shell lint", "head": "e42f5d5", "exit": 0, "reading": "0 errors; UnifiedSidebar.tsx 10 vs main 10; app-shell byte-identical to beef430" }, { "gate": "turbo build --filter='@object-ui/app-shell^...' --concurrency=2", "head": "cf8b3d3", "exit": 0 }, { "gate": "pnpm --filter @object-ui/layout build", "head": "beef430", "exit": 0 }, { "gate": "check:new-line-citations, check:control-bytes, check:i18n-keys, check:i18n-dead-keys, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots, check:changeset-claims, check:pending-changeset-literals, check-changeset-presence, check-changeset-no-major", "head": "beef430", "exit": 0 }, { "gate": "check-governed-queue-guard.mjs --test (5 paths)", "head": "beef430", "exit": 0, "reading": "NOT GOVERNED" }, { "gate": "check:eager-closure", "head": "n/a", "exit": null, "reading": "NOT MEASURED: needs a full console production build; declared to CI" } ], "line_budget": "n/a — no skills/** or line-ratcheted ledger touched; diff vs origin/main 0baf86f: 5 files, +1000 / -69", "files_changed": [ ".changeset/11626-grouped-nav-reorder.md", "packages/app-shell/src/layout/UnifiedSidebar.tsx", "packages/app-shell/src/layout/__tests__/UnifiedSidebar.groupedNavOrder-11626.test.tsx", "packages/layout/src/NavigationRenderer.tsx", "packages/layout/src/__tests__/NavigationRenderer.groupedReorder-11626.test.tsx" ], "deviations": [ "RESUMPTION: resumed from head 75c86fe (6 commits beyond origin/main incl. one merge). None of the lost run's commits rewritten (no rebase/amend/force-push). Kept: the per-group sortable lists, the per-group-id store beside __root__, the cross-group refusal, the search switch-off, both test files (one assertion re-pointed: the gated-away case counted wrappers via aria-roledescription, which now sits on grips, so it counts the menu's direct-child wrappers instead). Added on top: 6eb56eb (authored-order stamping + id+order detection; grip as activator; 5 new pins), c7a5d7b (changeset rewritten for both fixes), cf8b3d3 (merge of origin/main at 0baf86f), e42f5d5 (a comment the activator change had made false), beef430 (grip destructures its handle: the first spelling added 3 refs-during-render lint warnings).", "ZONE 2 item 4 conflict, flagged not silently chosen: the dispatch says the flat arm's behaviour must not change for a group-free app. Its stored __root__ record is byte-identical (pinned), but the flat arm changes in two deliberate ways: (a) the grip, not the row wrapper, carries dnd-kit's role=button/tabIndex=0 (keyboard reorder now works; no dead tab stop); (b) on an app that authors `order`, a saved order is now drawn instead of being sorted back. Both are shipped flat-arm defects this change touches (it rewrote applyOrder and replicates the sortable row), which the standing os-dev contract says must be fixed; leaving (a) would have added one dead tab stop per entry on every stock app.", "ZONE 2 item 3 partly falsified: pinning does not share the nav-order store; pins live in the favorites store (useNavPins). The group key is the spec `id` (SnakeCaseIdentifierSchema ^[a-z][a-z0-9_]*$, so never __root__), not a translated label. Pinned and gated-away entries keep working (pinned test).", "Live backend ran from the lost run's objectstack worktree at ba575886, 14 commits behind objectstack origin/main 27991556 at run time, as the resume instructions allowed; it was then removed (clean, no --force). The 'before' leg used a temporary objectui worktree at 0baf86f (created, measured, removed clean) instead of mutating the dev worktree while gates were queued on it.", "Gate heads differ: app-shell suite measured at cf8b3d3 and app-shell lint at e42f5d5; invariance to beef430 stated in tests. lint-layout, tc-appshell and build-layout first hit the lock's queue timeout (exit 99, NOT MEASURED) and were re-run under the same slot until measured.", "Four git pushes of the branch (per-step commits), not one." ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsLanded: PR objectui#11656 →
mainb88937b, verified by contentdomain:uiexecution seat 1 @ objectui ·session_015W8GBu6sBiqus2L2xjMsAL(os-steve) · 2026-10-05T11:29Z.-
Merged through the merge queue as squash commit
b88937b(one parent,73b5d77), an ancestor oforigin/main. Its +/- lines are identical to the PR headbeef430diffed from its merge base: 5 files, +1000/−69. -
Content check against the first parent:
reading 73b5d77b88937bconst groupedReorderinlayoutNavigationRenderer.tsx0 1 setActivatorNodeRef(the grip as the drag activator)0 2 dragListeners(the old wrapper-attribute channel)7 0 UnifiedSidebar.groupedNavOrder-11626.test.tsxexistsno yes onReorder?: (reorderedItems: NavigationItem[]) => void(control: the published signature is unchanged)1 1 -
The card closed
completedthrough the PR'sFixesline. It was the only issue closed in that window.pm:dispatchedis removed in this stroke. -
Left as noted, not filed:
- The
UnifiedSidebar.tsxhome-arm comment places pins underuseNavOrder, but they live in the favorites store. - The grip sits in the row's left padding.
- The
Generated by Claude Code
-
- added a commit that references this issue
on Oct 7, 2026
QA-source: objectstack-ai/objectstack#21782 · platform-core.shell-nav-personalization · acceptance[2]
Clause A3 of
platform-core.shell-nav-personalizationfails in the ObjectStack 17.7 pre-release checklist run objectstack-ai/objectstack#21782 (framework subject316be321e, console pin2e818d0b51ec). An independent verifier (VF4, RUNNER rule 7; code at the pin) confirmed it: P3 (product gap). It predates the 17.6.0 console pin31971ff1e; no open duplicate was found. Owner: objectui.Reproduction
GET /api/v1/meta/app?id=showcase_app. The navigation carries groups (8), as do Setup and Account./_console/apps/showcase_app/showcase_taskand hover or try to drag any sidebar entry.objectui-nav-order-showcase_app).[aria-label="Drag to reorder"], no sortable, and the key is never written. Seen on two loads.Mechanism
NavigationRenderer.tsx:1590computeshasGroups.if (!hasGroups)arm (:1614-1631). The grouped arm (:1650ff.) renders plainNavigationItemRenderer.UnifiedSidebar.tsx:583passesenableReorder={!isMobile}unconditionally.useNavOrder(:76-110) persists only__root__.:224, "Enable drag-to-reorder for navigation items") states no flat-only limit.31971ff1e. No open duplicate.Done when
Reorder works on grouped navigation (within or across groups), or the maintainers rule flat-only and the prop doc and checklist clause say so.
Generated by Claude Code