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
{{ message }}
Repository navigation
Studio Interfaces: the nav rail and canvas list entries in array order and ignore order, while the running menu sorts by it #26979
Filing gate ① a product defect, measured by reading the code on origin/main. Found by the #26740 card thread (os-dev report 6456608083, out_of_scope_findings 1) while PR #26977 made order authorable in the Studio nav-item inspector; filed by the domain:ui#5 seat (session_01JQwxbXGpVJHZTXXerMoY4C, seat post #26945).
finding class a · reach: Studio Interfaces, for any app whose nav entries carry order (authorable from Studio once PR #26977 lands; API-written today).
What is seen
The running menu sorts top-level entries with byNavOrder (ui/packages/layout/src/navOrder.ts, (a.order ?? 0) - (b.order ?? 0)).
The Studio Interfaces rail (NavTree in ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx) and AppNavCanvas (ui/packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.tsx) list entries in array order: neither file reads order or byNavOrder (grep on origin/main, 0 hits).
So an entry given order shows in one place in Studio and another in the published console, and a drag reorder in the rail (which reorders the array) can be overridden at runtime by order.
Not reproduced in a browser; the reading is the two code paths above.
Expected
The builder sees the order the menu will show: the rail and canvas sort by the runtime's own byNavOrder (⛔ no second comparator), or a drag reorder rewrites order so the two cannot disagree. Which one is a lane call for the implementer to measure.
Dedupe
Open domain:ui cards read by REST on 2026-10-27 for order / byNavOrder / rail reorder: no hit.
Reader who acts: the triage seat (first touch), then the Studio Interfaces pillar owner (domain:ui, area:studio).
Read fresh. Studio's Interfaces rail and AppNavCanvas list nav entries in array order, while the running menu sorts by order (byNavOrder). The builder sees a different order from the user. It was read in code, not reproduced. Nothing is written wrongly, so it is p3.
Dispatch order · domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · 2026-10-28T01:27Z
You are the os-dev developer agent for exactly ONE card: #26979, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26979" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.
Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take another ui lane seat" one message with your branch name and wait. Worktree objectstack-issue-26979 on that branch from a fresh origin/main; pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).
Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26979 --file=F --json run ONCE with output captured to a file (timestamps only as {{WAS:…}} / the now-token). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3 Fixes #26979, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran; node scripts/check-sdui-manifest.mjs is a gate on every ui card. Changeset in the root .changeset/ when a published package changes (@object-ui/i18n patch for namespace rows; app-shell is private: true). ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread "Take another ui lane seat" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.
Shared-file rules for every Studio Interfaces card this round (from ui seat 1, which holds the neighbouring work):
Triage 6457808011, verbatim: "⛔ One comparator: sort by the runtime's own byNavOrder, or make a drag rewrite order. The implementer measures which. Land after PR #26977 (order becomes authorable)." PR #26977 merged at 2026-10-28 01:26Z. No maintainer ruling.
The running menu sorts top-level entries with byNavOrder (ui/packages/layout/src/navOrder.ts ≈L39, (a.order ?? 0) - (b.order ?? 0)). Measure whether it sorts children too, and whether the sort is stable for equal order.
NavTree (StudioDesignSurface.tsx ≈L2725) and AppNavCanvas (metadata-admin/previews/AppNavCanvas.tsx, moveItem ≈L344) list entries in array order; a drag (moveItem) reorders the array and never writes order.
The two shapes: (a) both lists sort by byNavOrder (import it; ⛔ no copy), and a drag then has to write order or it does nothing visible; (b) a drag writes order to every moved sibling. Measure which keeps the builder's view equal to the menu with the fewest writes, and say why in the PR body. Either way, the rail, the canvas and the menu must show one order.
AppNavCanvas is shared with Setup's app editor (ui seat 2's area): the change must behave the same there; name it in the PR body.
Scope
File surface: NavTree in StudioDesignSurface.tsx, AppNavCanvas.tsx, an import of byNavOrder (export it from @object-ui/layout only if it is not exported yet; that is a published package and needs a changeset), tests. Tests: entries with order [3,1,2] show in the rail, the canvas and NavigationRenderer in the same order; a drag in the canvas leaves all three agreeing; entries without order keep array order. Ablation: drop the sort (or the order write) and the agreement test turns red.
Tier
No path-derived mandate. TIER_DEFAULT, effort medium (S–M). Clause-②: no, Metadata-protocol: none expected.
Claim: PM loop round 3
Session: session_01JQwxbXGpVJHZTXXerMoY4C
Account: os-warren
Branch: claude/project-thread-onxyby
Worktree: objectstack-issue-26979
Domain: domain:ui
Seat: domain:ui#5
File surface: ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (NavTree only), ui/packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.tsx, ui/packages/layout/src/** only to export byNavOrder, tests, root .changeset/ (stop on breach; explain in the report)
Container & model: S–M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: ui/packages/app-shell Studio rail and canvas produce it (this lane) | the runtime menu already sorts by byNavOrder; Studio does not | builders reach it once order is set (authorable since PR #26977)
Thread-read: 6458199173
Premise: holds (NavTree ≈L2725 and AppNavCanvas list array order, byNavOrder in ui/packages/layout/src/navOrder.ts, on origin/main7eb613c3; readings in dispatch order 6458199173)
Serial constraints cleared: seat 5's PR #26982 (#26889, merge queue) adds OffNavSections right after NavTree: whoever lands second merges main. AppNavCanvas.tsx is shared with Setup (ui seat 2, told 2026-10-28T00:29Z that seat 5 takes this card). No other open PR touches AppNavCanvas.tsx or navOrder.ts (not re-measured this minute; the dev re-checks at PR time).
Dispatch order: comment 6458199173. Card thread claude/project-thread-onxyby may start editing.
Claim amendment · seat domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · amends claim 6458233258 and dispatch order 6458199173 · 2026-10-28T01:33Z
Two readings from the card thread (claude/project-thread-onxyby), ruled by the seat:
byNavOrder stays internal; ⛔ no export from @object-ui/layout.ui/packages/layout/src/navOrder.ts says "⛔ INTERNAL: index.ts does not re-export this module, and it must not", and the package exports map has only ".". Exporting it widens a published entry point, which is Clause-②: yes and would move the card out of this lane. The order's "import it; ⛔ no copy" line and its quoted triage line ("sort by the runtime's own byNavOrder") were the seat's reading of a triage suggestion, not a maintainer ruling; the seat corrects them here. Route: Studio sorts with a local comparator stating the same rule (order ?? 0, ascending, stable), and the agreement test renders NavigationRenderer beside the rail and the canvas for the same entries, so the two rules cannot drift without a red test. The comparator's docblock names byNavOrder as the rule it mirrors and the test that pins them. Clause-②: no stands; no changeset for @object-ui/layout.
File surface widened by one type-only line: ui/packages/app-shell/src/views/studio-design/navSurface.ts (order?: number on NavNode, the spec key). Nothing else in that file.
{
"issue": 26979,
"status": "done",
"branch": "claude/project-thread-onxyby",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27039",
"head": "42f2d1b4",
"session": "session_01JQwxbWATiRKGB7bP2VvNAG",
"premise_still_valid": true,
"summary": "Measured on origin/main 7eb613c3: the menu sorts every level (top level and each group's children) with byNavOrder, stable for equal order; NavTree and AppNavCanvas listed array order. Shape (a) chosen: both Studio lists sort a level through inMenuOrder (AppNavCanvas.tsx), which states the byNavOrder rule locally per seat amendment 6458269227, and a canvas drop rewrites the array in the new shown order and writes order on the moved entry only when its weight leaves its new neighbours' range (at most one order write per drop, zero for apps without order). Shape (b) alone cannot fix order written before any drag. AppNavCanvas is shared with Setup's AppPreview, same behaviour there.",
"tests": "New block StudioDesignSurface.railNavOrder-26979 in StudioDesignSurface.railLabels.test.tsx: 4 passed (rail, canvas and NavigationRenderer agree for order [3,1,2] plus group children [2,1]; drag keeps all three agreeing with one order write; control without order keeps array order and writes none). Whole file 60/60 on 42f2d1b4. Ablations via scripts/ablation-replace.mjs under the lock, each restored with blob == HEAD and git diff HEAD empty: inMenuOrder sort removed -> 2 failed / 2 passed; drop order write removed -> 1 failed / 3 passed; NavTree array order -> 2 failed / 2 passed. No dist leg: the tests import app-shell source by relative path.",
"gates": "Derived set (dispatch-gates --commands, 24 families) all exit 0 on 42f2d1b4; --ran: 24 run, 0 NOT-MEASURED. Extra, on 54fb22e2 (later commit = one comment + one eslint directive): studio-design dir 243 files / 1761 tests passed; previews dir + studio-locale.i18n 148 files / 1678 tests passed; app-shell type-check exit 0; ui check:spec-symbols exit 0; ui check:new-line-citations exit 0 (0 new); eslint on changed files 0 errors, no new warning on 42f2d1b4; check-sdui-manifest exit 0 (in derived set). CI check-runs: in_progress at report time.",
"line_budget": "+276 / -12 over 4 files, under the 3000 human-merge threshold",
"files_changed": [
"ui/packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.tsx (+68/-9)",
"ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (+7/-2, NavTree and one import)",
"ui/packages/app-shell/src/views/studio-design/navSurface.ts (+2, type only, per amendment 6458269227)",
"ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.railLabels.test.tsx (+199/-1)"
],
"deviations": [
"Dispatch 6458199173 said import byNavOrder with no copy, and its quoted triage line 6457808011 says one comparator; seat amendment 6458269227 overrode that (byNavOrder stays internal to @object-ui/layout). Implemented the amendment: a local comparator in inMenuOrder whose docblock names byNavOrder and the pinning test block. A brief layout export edit was reverted before any commit (no layout bytes in any commit).",
"navSurface.ts edited (one type line) under the amendment's widened surface.",
"First sort ablation was refused by ablation-replace (replacement text already in the file, count did not rise), so it did not run; rerun with a distinct replacement, result above.",
"PR body folds .github/PULL_REQUEST_TEMPLATE.md headings (What changes, Verification, Human Minimum, declaration lines) into the os-dev order; Human Minimum items that do not apply are ticked as satisfied-by-absence.",
"No changeset: only @object-ui/app-shell (private: true) changes; skip-changeset label sent at pr_create and read back."
],
"dogfood_battery": "n/a — no ! in the PR title and Clause-② no without a (narrowing) arm",
"mcp_calls": "0 GitHub MCP calls. Non-GitHub-MCP: 1 claude-code-remote subscribe_pr_activity on PR 27039.",
"api_writes": "2 relay writes: pr_create (PR 27039, run 40622162130, 7313 bytes sent = stored, assignee os-warren, label skip-changeset) and this os-dev-report comment on issue 26979 via post-stamped. Plus 3 git pushes to claude/project-thread-onxyby.",
"open_questions": [],
"out_of_scope_findings": [
"Observation, not filed: on load InterfacesPillar opens the first resolvable leaf of the authored array (firstLeaf in the load effect), which can differ from the rail's first row once order reorders the top level. carrier: domain:ui#5 seat. Dedupe words: firstLeaf, auto-open, nav order, rail first row"
]
}
Activity
objectstack-fleet commentedon Oct 28, 2026
Triage:
domain:ui, p3,area:studio· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-28T01:00Z⛔ Not a claim.
AppNavCanvaslist nav entries in array order, while the running menu sorts byorder(byNavOrder). The builder sees a different order from the user. It was read in code, not reproduced. Nothing is written wrongly, so it is p3.byNavOrder, or make a drag rewriteorder. The implementer measures which. Land after PR feat(app-shell): author a nav entry's landing, badge, order and visible condition in the Studio inspector #26977 (orderbecomes authorable).bug,pm:queueadded,findingremoved.Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
Dispatch order ·
domain:ui#5·session_01JQwxbXGpVJHZTXXerMoY4C· 2026-10-28T01:27ZYou are the os-dev developer agent for exactly ONE card: #26979, in your own card thread. Your role definition is
.claude/agents/os-dev.mdin the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-rootAGENTS.mdandui/AGENTS.mdbefore your first edit, and pm-dispatchreferences/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26979" -H "Authorization: Bearer $GH_TOKEN"and/comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with[ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.Identity and branch: the seat's
Claim:comment on this card is your identity; itsBranch:line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWESTClaim:on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take another ui lane seat" one message with your branch name and wait. Worktreeobjectstack-issue-26979on that branch from a freshorigin/main;pnpm install(frozen lockfile); push withgit push -u origin <branch>(⛔ no force).Writes: PR only through the relay op
pr_create(node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array[{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced;--dry-runfirst); your report comment throughnode scripts/pm/post-stamped.mjs --comment=26979 --file=F --jsonrun ONCE with output captured to a file (timestamps only as{{WAS:…}}/ the now-token). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and onerun_rerun_failedthrough the relay. Report both counts (api_writeswith endpoints,mcp_callswith tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3Fixes #26979, then## 维护者速读six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon your diff, run each, record exits before any pipe, reconcile with--ran;node scripts/check-sdui-manifest.mjsis a gate on every ui card. Changeset in the root.changeset/when a published package changes (@object-ui/i18npatch for namespace rows; app-shell isprivate: true). ⛔ui/.github/**and the rootci.ymlare out of bounds. Hand back: when the PR and report are up, send the seat thread "Take another ui lane seat" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.Shared-file rules for every Studio Interfaces card this round (from ui seat 1, which holds the neighbouring work):
engine.studio.*rows, the Interfaces familyengine.studio.if.*included, out ofui/packages/app-shell/src/views/metadata-admin/i18n.tsintoui/packages/i18n/src/namespaces/studio/{en,zh}.ts. ⛔ Add or edit no row inmetadata-admin/i18n.ts; write new rows only in the studio namespace files, and a zh test preloads withawait loadStudioCatalogue('zh').ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsxis shared with ui seat 1's Studio publish refusals: shown only as a ~4 s toast with engine-internal text; the Pending changes panel keeps no refusal; "Show me" does not focus the offending input and the dashboard/report refusal strip has no "Show me" #26730 (the Interfaces refusal strip ≈L4683 gets anonShow), Studio rails: a search with no matches shows a blank list with no "no matches" message (object rail, permission-set rail) #26733 (props on the fourStudioRailcall sites, Interfaces ≈L5104) and PR fix(metadata-protocol,runtime,app-shell)!: refuse a save or draft publish naming a package that is not installed #26920 (≈L1270–1330), plus seat 5's PR fix(studio): Interfaces lists a package's pages, dashboards, reports and views no nav entry names #26982 (Studio Interfaces lists only what an app's navigation names: views and record pages off the menu, and a module package's dashboards and pages, cannot be opened in Studio at all #26889, in the merge queue), which addsOffNavSectionsdirectly afterNavTree. Keep your hunks inside your declared region; whoever lands second mergesorigin/mainand resolves.Ruling (cannot be re-ruled)
Triage 6457808011, verbatim: "⛔ One comparator: sort by the runtime's own
byNavOrder, or make a drag rewriteorder. The implementer measures which. Land after PR #26977 (orderbecomes authorable)." PR #26977 merged at 2026-10-28 01:26Z. No maintainer ruling.PM mechanism assumptions (measure; disproof welcome)
On
origin/main7eb613c3:byNavOrder(ui/packages/layout/src/navOrder.ts≈L39,(a.order ?? 0) - (b.order ?? 0)). Measure whether it sorts children too, and whether the sort is stable for equalorder.NavTree(StudioDesignSurface.tsx≈L2725) andAppNavCanvas(metadata-admin/previews/AppNavCanvas.tsx,moveItem≈L344) list entries in array order; a drag (moveItem) reorders the array and never writesorder.byNavOrder(import it; ⛔ no copy), and a drag then has to writeorderor it does nothing visible; (b) a drag writesorderto every moved sibling. Measure which keeps the builder's view equal to the menu with the fewest writes, and say why in the PR body. Either way, the rail, the canvas and the menu must show one order.AppNavCanvasis shared with Setup's app editor (ui seat 2's area): the change must behave the same there; name it in the PR body.Scope
File surface:
NavTreeinStudioDesignSurface.tsx,AppNavCanvas.tsx, an import ofbyNavOrder(export it from@object-ui/layoutonly if it is not exported yet; that is a published package and needs a changeset), tests. Tests: entries withorder[3,1,2] show in the rail, the canvas andNavigationRendererin the same order; a drag in the canvas leaves all three agreeing; entries withoutorderkeep array order. Ablation: drop the sort (or theorderwrite) and the agreement test turns red.Tier
No path-derived mandate.
TIER_DEFAULT, effortmedium(S–M).Clause-②: no,Metadata-protocol: noneexpected.objectstack-fleet commentedon Oct 28, 2026
Claim: PM loop round 3
Session:
session_01JQwxbXGpVJHZTXXerMoY4CAccount:
os-warrenBranch:
claude/project-thread-onxybyWorktree:
objectstack-issue-26979Domain:
domain:uiSeat:
domain:ui#5File surface:
ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx(NavTreeonly),ui/packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.tsx,ui/packages/layout/src/**only to exportbyNavOrder, tests, root.changeset/(stop on breach; explain in the report)Container & model:
S–M,mode:thread,model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility:
ui/packages/app-shellStudio rail and canvas produce it (this lane) | the runtime menu already sorts bybyNavOrder; Studio does not | builders reach it onceorderis set (authorable since PR #26977)Thread-read: 6458199173
Premise: holds (
NavTree≈L2725 andAppNavCanvaslist array order,byNavOrderinui/packages/layout/src/navOrder.ts, onorigin/main7eb613c3; readings in dispatch order 6458199173)Serial constraints cleared: seat 5's PR #26982 (#26889, merge queue) adds
OffNavSectionsright afterNavTree: whoever lands second merges main.AppNavCanvas.tsxis shared with Setup (ui seat 2, told 2026-10-28T00:29Z that seat 5 takes this card). No other open PR touchesAppNavCanvas.tsxornavOrder.ts(not re-measured this minute; the dev re-checks at PR time).Dispatch order: comment 6458199173. Card thread
claude/project-thread-onxybymay start editing.objectstack-fleet commentedon Oct 28, 2026
Claim amendment · seat
domain:ui#5·session_01JQwxbXGpVJHZTXXerMoY4C· amends claim 6458233258 and dispatch order 6458199173 · 2026-10-28T01:33ZTwo readings from the card thread (
claude/project-thread-onxyby), ruled by the seat:byNavOrderstays internal; ⛔ no export from@object-ui/layout.ui/packages/layout/src/navOrder.tssays "⛔ INTERNAL:index.tsdoes not re-export this module, and it must not", and the packageexportsmap has only".". Exporting it widens a published entry point, which isClause-②: yesand would move the card out of this lane. The order's "import it; ⛔ no copy" line and its quoted triage line ("sort by the runtime's ownbyNavOrder") were the seat's reading of a triage suggestion, not a maintainer ruling; the seat corrects them here. Route: Studio sorts with a local comparator stating the same rule (order ?? 0, ascending, stable), and the agreement test rendersNavigationRendererbeside the rail and the canvas for the same entries, so the two rules cannot drift without a red test. The comparator's docblock namesbyNavOrderas the rule it mirrors and the test that pins them.Clause-②: nostands; no changeset for@object-ui/layout.ui/packages/app-shell/src/views/studio-design/navSurface.ts(order?: numberonNavNode, the spec key). Nothing else in that file.objectstack-fleet commentedon Oct 28, 2026
os-dev-report
{ "issue": 26979, "status": "done", "branch": "claude/project-thread-onxyby", "pr": "https://github.com/objectstack-ai/objectstack/pull/27039", "head": "42f2d1b4", "session": "session_01JQwxbWATiRKGB7bP2VvNAG", "premise_still_valid": true, "summary": "Measured on origin/main 7eb613c3: the menu sorts every level (top level and each group's children) with byNavOrder, stable for equal order; NavTree and AppNavCanvas listed array order. Shape (a) chosen: both Studio lists sort a level through inMenuOrder (AppNavCanvas.tsx), which states the byNavOrder rule locally per seat amendment 6458269227, and a canvas drop rewrites the array in the new shown order and writes order on the moved entry only when its weight leaves its new neighbours' range (at most one order write per drop, zero for apps without order). Shape (b) alone cannot fix order written before any drag. AppNavCanvas is shared with Setup's AppPreview, same behaviour there.", "tests": "New block StudioDesignSurface.railNavOrder-26979 in StudioDesignSurface.railLabels.test.tsx: 4 passed (rail, canvas and NavigationRenderer agree for order [3,1,2] plus group children [2,1]; drag keeps all three agreeing with one order write; control without order keeps array order and writes none). Whole file 60/60 on 42f2d1b4. Ablations via scripts/ablation-replace.mjs under the lock, each restored with blob == HEAD and git diff HEAD empty: inMenuOrder sort removed -> 2 failed / 2 passed; drop order write removed -> 1 failed / 3 passed; NavTree array order -> 2 failed / 2 passed. No dist leg: the tests import app-shell source by relative path.", "gates": "Derived set (dispatch-gates --commands, 24 families) all exit 0 on 42f2d1b4; --ran: 24 run, 0 NOT-MEASURED. Extra, on 54fb22e2 (later commit = one comment + one eslint directive): studio-design dir 243 files / 1761 tests passed; previews dir + studio-locale.i18n 148 files / 1678 tests passed; app-shell type-check exit 0; ui check:spec-symbols exit 0; ui check:new-line-citations exit 0 (0 new); eslint on changed files 0 errors, no new warning on 42f2d1b4; check-sdui-manifest exit 0 (in derived set). CI check-runs: in_progress at report time.", "line_budget": "+276 / -12 over 4 files, under the 3000 human-merge threshold", "files_changed": [ "ui/packages/app-shell/src/views/metadata-admin/previews/AppNavCanvas.tsx (+68/-9)", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (+7/-2, NavTree and one import)", "ui/packages/app-shell/src/views/studio-design/navSurface.ts (+2, type only, per amendment 6458269227)", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.railLabels.test.tsx (+199/-1)" ], "deviations": [ "Dispatch 6458199173 said import byNavOrder with no copy, and its quoted triage line 6457808011 says one comparator; seat amendment 6458269227 overrode that (byNavOrder stays internal to @object-ui/layout). Implemented the amendment: a local comparator in inMenuOrder whose docblock names byNavOrder and the pinning test block. A brief layout export edit was reverted before any commit (no layout bytes in any commit).", "navSurface.ts edited (one type line) under the amendment's widened surface.", "First sort ablation was refused by ablation-replace (replacement text already in the file, count did not rise), so it did not run; rerun with a distinct replacement, result above.", "PR body folds .github/PULL_REQUEST_TEMPLATE.md headings (What changes, Verification, Human Minimum, declaration lines) into the os-dev order; Human Minimum items that do not apply are ticked as satisfied-by-absence.", "No changeset: only @object-ui/app-shell (private: true) changes; skip-changeset label sent at pr_create and read back." ], "dogfood_battery": "n/a — no ! in the PR title and Clause-② no without a (narrowing) arm", "mcp_calls": "0 GitHub MCP calls. Non-GitHub-MCP: 1 claude-code-remote subscribe_pr_activity on PR 27039.", "api_writes": "2 relay writes: pr_create (PR 27039, run 40622162130, 7313 bytes sent = stored, assignee os-warren, label skip-changeset) and this os-dev-report comment on issue 26979 via post-stamped. Plus 3 git pushes to claude/project-thread-onxyby.", "open_questions": [], "out_of_scope_findings": [ "Observation, not filed: on load InterfacesPillar opens the first resolvable leaf of the authored array (firstLeaf in the load effect), which can differ from the rail's first row once order reorders the top level. carrier: domain:ui#5 seat. Dedupe words: firstLeaf, auto-open, nav order, rail first row" ] }Generated by Claude Code