Skip to content

console(nav): the runtime sidebar must not offer drag-to-reorder — arranging navigation is Studio's job (maintainer ruling 2026-10-09; reverses objectui#11626) #12059

Closed

Description

@hotlong

Ruling

The maintainer, in chat on 2026-10-09 (session 64cb68a6-01c7-4dc6-acc6-ccb459c90ef2, looking at production demo.objectos.ai), verbatim:

右侧浏览器,左侧菜单在用户界面不应该显示拖动按钮,拖动设计是studio的工作。

The runtime (user-facing) sidebar must not offer drag-to-reorder. Arranging an app's navigation is authoring work, and authoring belongs to Studio. This reverses the direction of objectui#11626, which extended drag-to-reorder to every grouped sidebar to satisfy platform-core.shell-nav-personalization acceptance[2].

What users see today (production demo.objectos.ai, HotCRM, 2026-10-09)

  • Every sidebar entry has a permanently visible grip. The page holds 11 of them: <span role="button" aria-roledescription="sortable" aria-label="拖动以重新排序" aria-describedby="nav-reorder-top-nav_home" class="absolute left-0.5 … cursor-grab …">, computed opacity: 1, cursor: grab.
  • Source: packages/app-shell/src/layout/UnifiedSidebar.tsx ~:677 passes enableReorder={!isMobile} and onReorder={handleNavReorder} to NavigationRenderer (packages/layout/src/NavigationRenderer.tsx: the sortable rows ~:1180–1330, contextId nav-reorder-top-… / nav-reorder-group-…). The order persists per user in localStorage (objectui-nav-order-<app>).

Scope

  1. Runtime sidebar: no drag grip and no drag reorder on any viewport. UnifiedSidebar stops passing enableReorder / onReorder.
  2. Stored per-user orders stop applying: the sidebar renders the app's authored order. Any existing objectui-nav-order-* key is ignored and may be cleared, so a user who reordered before this change does not keep a private order that Studio cannot see or change.
  3. Studio keeps its own arranging. Navigation order is authored in Studio, the app/navigation designer, and every user sees that order. Check Studio's navigation editor still reorders, and if it has no reorder affordance, say so in the PR rather than adding one here.
  4. Unchanged, outside the ruling: sidebar collapse, nav pin/unpin, favorites and recents.
  5. Tests: pin that the runtime sidebar renders no aria-roledescription="sortable" grip, and that a stored objectui-nav-order-* value does not change the rendered order.

Related

  • The framework's conformance item platform-core.shell-nav-personalization still requires drag-reorder (step 3, acceptance[2]). Its amendment is filed on objectstack and linked below, so the next release checklist does not fail this change.
  • objectui#11626 is the card this reverses.

Activity

  1. hotlong commented on Oct 9, 2026

    @hotlong
    ContributorAuthor

    The framework checklist amendment is objectstack-ai/objectstack#22487 (retire platform-core.shell-nav-personalization's drag-reorder step and acceptance clause).

  2. hotlong commented on Oct 9, 2026

    @hotlong
    ContributorAuthor

    Scope addition: personal ordering moves to the Pinned section only (maintainer, 2026-10-09)

    The maintainer asked how mainstream products let users reorder a sidebar. They then ruled, verbatim: 「补到 12059 上,按置顶区来做」 and 「暂时不考虑编辑模式」.

    What this card delivers, on top of the removal above:

    1. The app's menu (the authored navigation) is never user-reorderable. Its order is Studio's, as already stated.
    2. The Pinned section is the only place a user orders things:
      • Users reorder pinned entries by dragging the entry itself. Nothing marks it at rest: no grip dots or any other persistent handle. The affordance is cursor: grab on a pinned row and an insertion line while dragging, which is the Notion / Slack / Linear / Teams pattern.
      • Keyboard: reachable without a visible handle. With a pinned row focused, dnd-kit's KeyboardSensor handles it (Space to pick up, arrow keys to move, Space to drop), with the sortable ARIA announcements. No extra buttons.
      • Persistence: the pinned order persists with the pins themselves, i.e. the same UserDataAdapter-backed favorites (nav:<navId>, useNavPins in packages/app-shell/src/hooks/useNavPins.ts), so it syncs across devices like the pins do. It does not live in localStorage.
      • Order rules: a newly pinned entry goes to the end, and unpinning removes it from the order.
    3. No edit mode for now: no 「编辑侧边栏」 entry, no hide/show toggles and no reset dialog. Leave that for a later card if it is ever asked for.
    4. Mobile: same as desktop for pinned rows, if the drag works with touch (press-and-hold activation). Otherwise mobile keeps the pinned order read-only.

    Tests to add:

    • the authored-menu rows render no sortable grip;
    • pinned rows reorder via the keyboard sensor, and the new order round-trips through the favorites store;
    • a stale objectui-nav-order-* key changes nothing.

    The framework checklist card objectstack-ai/objectstack#22487 should say the same thing: its replacement clause (if any) covers pinned-section ordering, not menu ordering.

  3. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    Triage: lane added, domain:ui. The maintainer's grade (priority:p2, pm:queue) and scope stand as written

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-09T13:54Z. ⛔ Not a claim, ⛔ not a dispatch.

    • Lane: packages/app-shell/src/layout/UnifiedSidebar.tsx and packages/layout/src/NavigationRenderer.tsx are in domain:ui. The card is the maintainer's ruling with the letter given, so it is execution. Both scopes ship as one card: the removal, and the Pinned-section ordering from 6081436048.
    • Ordering with the framework checklist: platform-checklist: retire the drag-reorder step and acceptance clause of platform-core.shell-nav-personalization — end users do not reorder the runtime sidebar (maintainer ruling 2026-10-09) objectstack#22487 rewrites platform-core.shell-nav-personalization. It must land no later than the objectstack console pin bump that carries this card's merge, or that release run fails the old clause.
      • Its new clause follows this card's final behaviour: no grip on the authored menu, and Pinned-section ordering that persists across reload.
      • The PR here names its merge commit, so the bump can cite it.
    • The opposite card: objectui#11626's direction is reversed by this ruling. Name it in the PR body, so the reversal is on record where its pins move.
  4. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 9, 2026
  5. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 3
    Session: session_01CGZy1BGCjdN5cXqL9cnvB8
    Account: os-support-ai
    Branch: claude/issue-12059-sidebar-no-reorder
    Worktree: objectui-issue-12059
    Domain: domain:ui
    Seat: domain:ui#3
    Authority: the maintainer filed this card directly (hotlong), with the ruling quoted in its body (「右侧浏览器,左侧菜单在用户界面不应该显示拖动按钮,拖动设计是studio的工作。」) and the scope addition 6081436048 (「补到 12059 上,按置顶区来做」, 「暂时不考虑编辑模式」). Triage added the lane in 6082337150. This is the seat's first claim under the maintainer's serial-dispatch instruction (one subagent at a time).
    File surface (line numbers on main 2a48bd40):

    • packages/app-shell/src/layout/UnifiedSidebar.tsx. Stop passing enableReorder / onReorder (about :677–:678), and remove handleNavReorder (about :549) and the objectui-nav-order-${appName} read and write (about :144), so a stored key changes nothing. Clearing a stale key is allowed, not required. Plus the Pinned section's ordering.
    • packages/layout/src/NavigationRenderer.tsx: the sortable rows (about :1180–:1330), only as the authored-menu removal and the handle-less pinned sort need.
    • packages/app-shell/src/hooks/useNavPins.ts: the pinned order persists with the pins, in the same UserDataAdapter-backed favorites (nav:<navId>), not localStorage. A new pin goes to the end, and an unpin leaves the order.
    • The component that renders the Pinned section, if it is not one of the files above. The dev names it before editing.
    • The tests beside these, the docs that describe sidebar drag-to-reorder (if any), and the changesets.

    Seat parameters, under existing rules:

    • Published props of NavigationRenderer: if, after the change, no in-repo caller passes enableReorder / onReorder, the menu-reorder props are zero-pull published surface. Retire them at once, under the zero-pull retire rule, with a breaking note. Any prop the handle-less pinned sort needs may be added. Name each removed or added prop in the PR.
    • Persistence: if the favorites store cannot hold an order without a server-side change (a new field on the stored record), ⛔ stop and report with measured options. That is an objectstack card, not this one.
    • Touch: press-and-hold activation if dnd-kit's touch sensor carries it. Otherwise the pinned order is read-only on mobile, as the card allows.
    • i18n: reuse existing keys. A key that becomes dead may be removed from all packs, with the i18n gates. A new key is a stop.

    ⛔ Not on it:

    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui over these paths: no path-derived mandate; default tier). The contract review runs at the ceiling, CONTRACT_REVIEW_TIER, because of the line below.
    Clause-②: yes
    Why Clause-②: yes: @object-ui/layout's published NavigationRenderer props change (the menu-reorder props retire if nothing passes them, and a pinned-sort prop may be added), and the runtime sidebar drops a shipped behaviour. Changesets: minor with a breaking note where a prop leaves; ⛔ never major.
    Responsibility: objectui app-shell's runtime sidebar and layout's NavigationRenderer: every sidebar entry shows a permanent drag grip and keeps a private per-user order in localStorage that Studio cannot see | the platform path: the app's authored navigation order (Studio), and the UserDataAdapter-backed pins for personal ordering | every console user, seen on production demo.objectos.ai (11 grips on one page)
    Thread-read: 6082337150
    Serial constraints cleared: none blocking.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 12059,
    "status": "done",
    "branch": "claude/issue-12059-sidebar-no-reorder",
    "pr": "#12066",
    "session": "session_01CGZy1BGCjdN5cXqL9cnvB8",
    "premise_still_valid": true,
    "summary": "The runtime sidebar draws no menu grip and keeps no personal menu order: UnifiedSidebar stops passing enableReorder/onReorder and useNavOrder is removed, so objectui-nav-order-APP is neither read nor written (a stale key is ignored, not cleared). NavigationRenderer retires enableReorder/onReorder and every menu sortable path (AppSchemaRenderer retires its pass-through copies too) and gains pinnedOrder/onPinnedReorder: the Pinned section is sortable by the row's own link (no grip, cursor-grab, insertion line; KeyboardSensor Space/arrows/Space, Escape cancels, Enter still follows the link), and the click a pointer drag ends with is swallowed (measured necessary in Chromium). The order persists as the order of the type nav favorites in the UserDataAdapter-backed favorites list (no server change: the ObjectStack adapter stores the whole list as one JSON value); a new pin joins the end, an unpin leaves the order, a reorder fills the named pins' own slots; useFavorites gains reorderNavPins and useNavPins gains reorderPins. console.nav.dragToReorder left all ten packs; the pending objectui#11626 changeset prose is corrected to say it was retired before release. Mobile: UnifiedSidebar keeps enablePinning={!isMobile}, so a phone draws no Pinned section and nothing needed a touch sensor. Studio's nav editor (AppNavCanvas) reorders with native HTML5 drag-and-drop over the root list; not edited.",
    "tests": "Final reading at 79d3688. pnpm exec vitest run packages/layout/ + the app-shell sidebar/pins/favorites suites (src/layout, src/context, src/hooks + every test naming UnifiedSidebar/useNavPins/FavoritesProvider/useFavorites, console included): 'Test Files 182 passed (182) / Tests 1512 passed (1512)'. pnpm exec vitest run packages/i18n/: 'Test Files 82 passed (82) / Tests 1316 passed | 13 skipped'. New: NavigationRenderer.pinnedOrder-12059 (11), UnifiedSidebar.pinnedOrder-12059 (4), FavoritesProvider.navPinOrder-12059 (4); retired the two 11626 pin files. Reverse verification, predictions written first, every restore proven by blob hash == HEAD and empty git diff HEAD (whole-file reverts by a trap script, anchor mutations through objectstack scripts/ablation-replace.mjs WRAP mode; tests resolve @object-ui/layout through the vitest alias to src, so no dist rebuild between mutate and run): RV1 4 source files to base → UnifiedSidebar test 4/4 failed as predicted; RV2 NavigationRenderer to base → 6 failed / 5 passed as predicted; RV2b layout type-check with base NavigationRenderer+AppSchemaRenderer → TS2578 on the four retired-prop @ts-expect-error lines; RV3 drop the click guard → 1 failed (first attempt refused by ablation-replace: replacement was a substring of the anchor, nothing ran; redone with a distinct marker); RV3b same in Chromium → a drag released on its own external link navigated away, restored → page stays, plain click navigates (control); RV4 default keyboard codes → 1 failed (Enter); RV5 no insertion line → 2 failed; RV6 nav pin prepended → 3 failed across two files; RV8 cap evicts first-in-order → 1 failed; RV9 keyboard drag not held in place → 1 failed. Chromium probe (temporary dev page, never committed, server stopped by PID): 0 grips, 0 aria-roledescription at rest; pinned link cursor grab, menu link pointer; keyboard drew one 2px line after the next row, live region read the move, Space dropped; pointer drag reordered with no navigation and no reload. Eager closure: HEAD 3,243,862 B gzip vs the same build over base sources 3,244,066 B (delta -204 B; ceiling 3,281,467 B).",
    "mcp_calls": "0 — no MCP GitHub tool called (ToolSearch loaded the SendMessage schema only; it was never called)",
    "api_writes": "3 — each one fleet-write relay stroke (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): pr_create → POST /repos/objectstack-ai/objectui/pulls (#12066, draft, body read back byte-identical, 14198 B); assign via label-write.mjs → POST /repos//issues/12066/assignees (os-support-ai; read-back MATCHES); this os-dev-report → POST /repos//issues/12059/comments. Plus git pushes of the branch (not REST writes): the empty-branch probe and seven commit pushes.",
    "open_questions": [
    {
    "question": "The claim's file surface does not list FavoritesProvider.tsx or AppSchemaRenderer.tsx, and its Clause-② rationale names only NavigationRenderer props. The work needed: useFavorites() gains reorderNavPins, useNavPins() gains reorderPins (public return members of @object-ui/app-shell), and AppSchemaRendererProps loses enableReorder/onReorder (its pass-through of the retired props). Amend the claim?",
    "options": [
    "A amend the claim text to name both files and the three surface changes; Clause-② stays yes, the changeset stays minor",
    "B rework so app-shell's public returns do not widen (e.g. a second, unexported context only for the reorder writer)"
    ],
    "recommendation": "A, because the claim's own persistence clause (the order persists with the pins in useNavPins / the favorites store) cannot be met without a write member, B would add an artificial second context only to dodge the enumeration, and AppSchemaRenderer's props become declared-but-unhonoured the moment NavigationRenderer's retire, which the startup-stage rule retires at once; the bump level and Clause-② verdict do not move"
    }
    ],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted in PR #12066 Acceptance notes, not filed — content/docs/guide/user-state-persistence.md says under Cross-device sync that a pin shows up on mobile, but UnifiedSidebar passes enablePinning={!isMobile} so a phone draws no Pinned section; the same guide's useFavorites() reference row omits refreshLabel (doc drift, no class a/b/c)",
    "carrier: 承接者:无 · noted in PR #12066 Acceptance notes, not filed — dnd-kit's default announcements read entry ids in English for the pinned sort (status quo of the retired menu sort); localizing needs new pack keys, which the claim forbids"
    ],
    "gates": [
    {
    "cmd": "pnpm --filter @object-ui/layout type-check && pnpm --filter @object-ui/app-shell type-check && pnpm --filter @object-ui/i18n type-check",
    "exit": 0,
    "verdict": "os-verify-lock VERDICT command-exit 0 (each script name echoed: layout, , app-shell, i18n)"
    },
    {
    "cmd": "pnpm exec vitest run packages/layout/ + app-shell touched suites --maxWorkers=2",
    "exit": 0,
    "verdict": "Test Files 182 passed (182); Tests 1512 passed (1512)"
    },
    {
    "cmd": "pnpm exec vitest run packages/i18n/ --maxWorkers=2",
    "exit": 0,
    "verdict": "Test Files 82 passed (82); Tests 1316 passed | 13 skipped (1329)"
    },
    {
    "cmd": "pnpm exec eslint (21 touched TS files)",
    "exit": 0,
    "verdict": "0 errors, 41 warnings, none on an added line"
    },
    {
    "cmd": "pnpm check:control-bytes",
    "exit": 0,
    "verdict": "check-control-bytes: OK"
    },
    {
    "cmd": "pnpm check:test-path-roots",
    "exit": 0,
    "verdict": "check-test-path-roots: OK"
    },
    {
    "cmd": "pnpm check:changeset-claims",
    "exit": 0,
    "verdict": "report-only; 1 pending changeset (11806) names packages/app-shell/README.md, read, still true"
    },
    {
    "cmd": "pnpm check:pending-changeset-literals",
    "exit": 0,
    "verdict": "No test source names a pending changeset."
    },
    {
    "cmd": "pnpm check:new-line-citations",
    "exit": 0,
    "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)"
    },
    {
    "cmd": "pnpm check:i18n-keys / i18n-drift / i18n-dead-keys / i18n-designer-parity",
    "exit": 0,
    "verdict": "all exit 0; dead-keys no longer lists console.nav.dragToReorder"
    },
    {
    "cmd": "pnpm check:readme-exports",
    "exit": 0,
    "verdict": "check-readme-exports: OK (582 self-imports judged, 0 fabricated, 0 unbuilt) — first run was PREREQUISITE NOT MET (cli, plugin-ai unbuilt), rerun after building them"
    },
    {
    "cmd": "pnpm check:eager-closure (console built at HEAD)",
    "exit": 0,
    "verdict": "Console eager closure is 3167.8 KB gzipped (budget 3204.6 KB, headroom 36.7 KB)"
    },
    {
    "cmd": "pnpm check:doc-fences / doc-types / doc-snippets / phantom-deps / unused-deps / eager-locale-catalogues / icon-record-names / unreferenced-sources / self-import",
    "exit": 0,
    "verdict": "all exit 0"
    },
    {
    "cmd": "node scripts/check-changeset-presence.mjs / check-changeset-no-major.mjs / check-changeset-overwrite.mjs / check-doc-links.mjs",
    "exit": 0,
    "verdict": "presence: 1 changeset added for 3 released packages; overwrite is report-only and reports the 11626 prose correction; doc-links valid"
    },
    {
    "cmd": "node scripts/check-governed-queue-guard.mjs --test DIFF",
    "exit": 0,
    "verdict": "NOT GOVERNED"
    },
    {
    "cmd": "CI on #12066 at 79d3688",
    "exit": null,
    "verdict": "in_progress — one read: 42 check runs, 19 success, 3 skipped, 20 in progress, 0 failed; not waited on"
    }
    ],
    "deviations": [
    "Opened the draft PR although the change carries surface beyond the claim's enumeration (FavoritesProvider.tsx and AppSchemaRenderer.tsx files; useFavorites().reorderNavPins, useNavPins().reorderPins, AppSchemaRendererProps' two retired props); the dispatch says stop and report before opening. Judged implied by the claim's persistence clause and by retiring NavigationRenderer's props; Clause-② (yes) and the minor bump do not move. Raised as an open question for the seat to amend the claim.",
    "Corrected the prose of another PR's pending changeset (.changeset/11626-grouped-nav-reorder.md; front matter untouched) because this change falsifies it in the same release window; check-changeset-claims prescribes the correction and check-changeset-overwrite reports it, report-only.",
    "Commit trailers use the model-free pair objectui AGENTS.md prescribes (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By; the PR body ends with the os-dev session-URL footer, not the reminder's form.",
    "Two temporary probe files lived in apps/console of the worktree during the Chromium check (never committed, deleted, vite server stopped by PID)."
    ],
    "files_changed": [
    ".changeset/11626-grouped-nav-reorder.md",
    ".changeset/12059-sidebar-no-reorder.md",
    "content/docs/guide/user-state-persistence.md",
    "packages/app-shell/README.md",
    "packages/app-shell/src/context/FavoritesProvider.tsx",
    "packages/app-shell/src/context/tests/FavoritesProvider.navPinOrder-12059.test.tsx",
    "packages/app-shell/src/hooks/useNavPins.ts",
    "packages/app-shell/src/layout/UnifiedSidebar.tsx",
    "packages/app-shell/src/layout/tests/UnifiedSidebar.groupedNavOrder-11626.test.tsx (deleted)",
    "packages/app-shell/src/layout/tests/UnifiedSidebar.pinnedOrder-12059.test.tsx",
    "packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts (10 files, one line each)",
    "packages/layout/src/AppSchemaRenderer.tsx",
    "packages/layout/src/NavigationRenderer.tsx",
    "packages/layout/src/tests/AppSchemaRenderer.mobileTabOrder-11395.test.tsx",
    "packages/layout/src/tests/AppSchemaRenderer.test.tsx",
    "packages/layout/src/tests/NavigationRenderer.groupedReorder-11626.test.tsx (deleted)",
    "packages/layout/src/tests/NavigationRenderer.listNesting-11690.test.tsx",
    "packages/layout/src/tests/NavigationRenderer.pinnedOrder-12059.test.tsx"
    ],
    "line_budget": "not applicable (no skills/** surface)"
    }


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    Claim amendment — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-09T15:49Z. It amends the claim 6082900231, on the dev's open question (report on this card, PR objectui#12066).

    Answer: A. The file surface and the Clause-② rationale gain:

    • packages/app-shell/src/context/FavoritesProvider.tsx: useFavorites() gains reorderNavPins. The claim's persistence clause ("the pinned order persists with the pins, in the same UserDataAdapter-backed favorites") needs a write member on the store useNavPins reads.
      • The order is the order of the nav favorites inside the one stored list, so there is no server change.
      • A reorder fills the named pins' own slots, a new pin joins the end, and an unpin leaves the order.
    • packages/app-shell/src/hooks/useNavPins.ts: useNavPins() gains reorderPins. The file was already on the surface; the member is named here.
    • packages/layout/src/AppSchemaRenderer.tsx: AppSchemaRendererProps loses its enableReorder / onReorder pass-through. These would be declared-but-unhonoured once NavigationRenderer retires them, and the claim's zero-pull retire parameter covers them.
    • .changeset/11626-grouped-nav-reorder.md: its prose now says that objectui#11626's grouped drag-to-reorder was retired before release; the front matter is unchanged. objectui#11626's behaviour never shipped, and this card removes it. A CHANGELOG that announced it, or announced it and then retracted it in the same release, would misstate what shipped. check-changeset-overwrite reports the edit (report-only), and no release declaration is lost.

    Clause-②: yes and the minor grades stand (@object-ui/layout, @object-ui/app-shell, @object-ui/i18n, the last for the retired console.nav.dragToReorder key). ⛔ Never major.

    On the order of steps: the dev opened the PR before this amendment, against the dispatch's stop-before-opening rule. The seat accepts it: both additions follow from clauses the claim already held, and nothing outside them moved. The deviation is recorded here.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    ACCEPT — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-09T16:13Z. PR objectui#12066, head 79d36886.

    • PR shape:

      • Draft against main, based on 2a48bd40. git merge-tree against main 2a48bd40 is clean.
      • First line Fixes #12059, the body's only closing keyword. Clause-②: yes at line start. objectui#11626 is named as the card this reverses.
      • The commits carry only the model-free trailer pair. Assignee os-support-ai, set with no refusal.
    • Scope: 27 files, +1,111/−1,194, on the claim 6082900231 as amended in 6084322873 (FavoritesProvider.tsx, AppSchemaRenderer.tsx, and objectui#11626's pending changeset prose). The governed-queue guard reads NOT GOVERNED.

    • What lands, against the maintainer's ruling and the scope addition 6081436048:

      • The authored menu: no grip and no reorder on any viewport. UnifiedSidebar passes neither prop, and useNavOrder is gone, so objectui-nav-order-APP is neither read nor written (a stale key is ignored).
      • Retired props: NavigationRenderer's enableReorder / onReorder and every menu sortable path, and AppSchemaRenderer's pass-through copies. No in-repo caller passed them after the change (zero-pull retire).
      • The Pinned section is sortable by the row's own link:
        • no grip at rest; cursor: grab and a 2px insertion line while dragging;
        • the keyboard sensor handles Space, the arrows and Space, and Escape cancels; Enter still follows the link;
        • the click that ends a pointer drag is swallowed, measured necessary in Chromium.
      • Persistence: the order of the nav favorites inside the one UserDataAdapter list, so it syncs across devices with no server change. A new pin joins the end, and an unpin leaves the order. useFavorites().reorderNavPins and useNavPins().reorderPins are the write members.
      • Mobile: unchanged. A phone draws no Pinned section (enablePinning={!isMobile}), which the card allows.
      • Studio's navigation editor (AppNavCanvas) reorders with native drag and drop over the root list. It was not edited.
      • i18n: console.nav.dragToReorder left all ten packs.
      • First-load bytes: −204 B gzip.
    • Contract review: 6084702137 on the PR, rendered at CONTRACT_REVIEW_TIER by an isolated, read-only reviewer on this head, reads PASS. The seat checked the record's lines:

      • Served-tier: CONTRACT_REVIEW_TIER;
      • Head-sha equal to the head;
      • Local-runs: none;
      • Implemented-by and Reviewed-by signed;
      • VERDICT: PASS;
      • no model name.

      It judged every surface change right against the claim and the amendment, and the three minor grades, each with a breaking note.

    • Gates:

      • layout plus the app-shell sidebar, pins and favorites suites: 182 files and 1,512 tests passed. i18n: 1,316 tests passed.
      • Three type-checks exit 0, and the four i18n gates exit 0.
      • check:readme-exports and check:eager-closure exit 0 (3,167.8 KB of 3,204.6 KB).
      • Reverse verification (RV1–RV9) went red as predicted, with every restore proven. A Chromium probe saw 0 grips at rest, a keyboard reorder with its live-region announcement, and a pointer drag with no navigation.
      • CI on 79d36886: 43 runs, 40 success, 3 skipped (the expected three), 0 failure.

    Findings, noted and not filed:

    • content/docs/guide/user-state-persistence.md (pre-existing): "Cross-device sync" says a pin shows up on mobile, but a phone draws no Pinned section, and the useFavorites() reference row omits refreshLabel.
    • Accessibility of the pinned sort: dnd-kit's default announcements read entry ids, in English, as the retired menu sort did. Localized, label-based announcements need new pack keys, which the claim forbids. A card is owed if a screen-reader reach is measured, with the announcement text quoted.
    • Touch at desktop width: the row-as-activator pointer sensor has no touch-action, so a pan cancels the drag and touch is effectively read-only there. The card allows this.

    Downstream: objectstack-ai/objectstack#22487, the checklist amendment, must land no later than the objectstack console pin bump that carries this merge. After landing, the seat names the merge commit there.

    Landing: ready + auto-merge through the queue, now. Its merge closes objectui#12059.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    Landed — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-09T16:33Z. PR objectui#12066 merged through the queue as 8a55f0ccdafa0b58e09f5d188641834f7da31521 at 2026-10-09T16:31Z; its Fixes #12059 closed this card.

    • The merge:
      • One parent, c7b30bd6, an ancestor of origin/main.
      • The landed tree equals git merge-tree of that parent and the accepted head 79d36886 (tree fb7d99d8 on both).
      • 27 files, +1,111/−1,194. The 25 files present are blob-equal to the accepted head's, and the two retired objectui#11626 test files are absent on both.
    • Content check, c7b30bd6 → 8a55f0cc:
      • In UnifiedSidebar.tsx, enableReorder= goes from 1 line to 0. objectui-nav-order survives only in a comment saying the key is not read, and localStorage appears 0 times.
      • FavoritesProvider.tsx carries reorderNavPins, and NavigationRenderer.tsx carries onPinnedReorder.
    • State: pm:dispatched is removed in this act; the card is closed completed. Contract review 6084702137 PASS; ACCEPT 6084726683.
    • Downstream: the merge commit is named on platform-checklist: retire the drag-reorder step and acceptance clause of platform-core.shell-nav-personalization — end users do not reorder the runtime sidebar (maintainer ruling 2026-10-09) objectstack#22487 in this act. That amendment must land no later than the objectstack console pin bump that carries 8a55f0cc.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions