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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
console: app identity moves into the top bar — the app icon sits left of the app name in the switcher pill, dropdown rows carry icons, the sidebar logo header goes, the phone drawer header shows icon + name, and the platform mark leaves app context (maintainer ruling 2026-10-12) #12201
Filing gate: a maintainer ruling in chat, 2026-10-12 — 「应用 logo 建议只需要一个尺寸,放在顶部导航的应用名称左侧」, then 「同意」 on the mock and on dropping the platform mark from app context. Filed from the cloud maintainer's session. ⛔ Not a claim.
What is wrong today
UnifiedSidebar renders branding.logo as a 32 px <img> alone in a SidebarHeader, with no text (objectui#10827 gave the key its only reader). HotCRM's value is a square app icon, so a HotCRM environment shows an unlabeled orange tile in a 56 px header, 80 px below the ObjectOS platform mark and the 「HotCRM ▾」 switcher pill that already carry the identity. Two brand marks in one corner, neither saying what it is. On phones the top bar is hidden, so that tile is the only thing that says which app the user is in, and it still has no name.
Ruling (maintainer, 2026-10-12)
One asset.branding.logo is the app's square icon (1:1). Surfaces render it at the size they need: 22 px in the top bar pill, 22 px in the switcher dropdown, 26 px in the phone drawer, 40 px on marketplace cards. No second asset, no wordmark slot.
The icon sits left of the app name in the top-bar app switcher pill. Every row of the switcher dropdown shows its app's icon. An app without branding.logo gets its icon (lucide name) drawn on a primaryColor tile at the same size, so every row has a glyph.
The sidebar logo header goes away on desktop. On phones the drawer header shows icon + app name, in the place of the existing mobile-only Home row.
The platform mark leaves the top bar in app context. The bar starts with the app pill. Platform surfaces (environment Home, settings) keep the ObjectOS mark. One brand mark per screen; the 「所有应用」 row in the switcher dropdown is the way back to Home.
The PREVIEW stage chip moves to the right, beside the search box, so the bar's left edge is the app.
The Studio entry gets a label (maintainer, 2026-10-12, 「同意」). The icon-only Hammer button (data-testid="app-design-in-studio-button", the ADR-0080 reverse bridge, admin + metadata-authoring gated) becomes an outline button 「编辑应用」 / "Edit app" with a pencil icon, placed at the left edge of the right-hand utility cluster; on narrow widths it collapses to the pencil with a tooltip. The same gate, the same deep link. The switcher dropdown gains a bottom row 「在 Studio 中编辑 」 / "Edit in Studio" next to 「所有应用」, admin-only, as the second path. 「系统设置」 stays listed as an app; Studio is never listed as one.
Mock (the maintainer's private design canvas; ask the maintainer for a render if needed): https://claude.ai/artifact/3RcJzvfgizHDpTsep32TAn — artboards: desktop top bar (tweak platformLogo to compare with/without the platform mark), switcher dropdown with fallback rows, phone drawer, icon candidates.
Where
packages/app-shell/src/layout/UnifiedSidebar.tsx: drop the appLogoSidebarHeader; the mobile sheet header becomes icon + name.
The top-bar app switcher pill and its dropdown (the component that renders 「HotCRM ▾」): icon before the label, icons per row, fallback tile.
Platform-mark visibility by context (app vs platform) in the top bar; PREVIEW chip placement.
packages/app-shell/src/layout/AppHeader.tsx: the Design-in-Studio button (label, pencil icon, responsive collapse); AppSwitcher.tsx: the admin-only Studio row.
Rider, same seat, a small separate PR in objectstack: the @objectstack/spec doc on branding.logo says "1:1 square app icon, SVG preferred, at least 64 px"; refuse a non-square value if the schema can express it, otherwise doc only.
HotCRM environment, desktop: the top bar reads [icon]HotCRM ▾ / Leads / …; no sidebar header; no ObjectOS mark in the bar. Screenshots zh-CN and en.
Environment Home: ObjectOS mark present, no app pill.
Switcher dropdown: every app row has a glyph; an app without branding.logo shows the fallback tile.
Phone (375 px): the drawer header shows icon + 「HotCRM」; nothing else in the drawer changes.
Tests: UnifiedSidebar no longer renders branding.logo; the switcher renders it; the fallback path is covered.
Admin: the top bar shows 「编辑应用」 with text at 1280 px and a pencil-only button with tooltip at 768 px; the switcher dropdown ends with 「在 Studio 中编辑 HotCRM」. Member: neither appears. The existing AppHeader.designInStudioNeedsAuthoring-10899 test keeps passing against the new markup.
Related
objectui#10827 (the reader this card moves) · objectui#7256 · objectstack-ai/cloud#2772 (cloud console experience epic; this is its environment-side cousin) · objectstack-ai/cloud#2777 (the cloud home renders the same icon) · objectstack-ai/hotcrm#2066
Triage seat (seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-12T08:04Z. ⛔ Not a claim, ⛔ not a dispatch. Grade completed: domain:ui · area:devpath added. The filer's enhancement · priority:p2 · pm:queue stand (the maintainer's ruling, 2026-10-12).
Claim: PM loop round 1 (executes the maintainer's ruling quoted in the card body, items 1–6: app identity moves into the top bar, the sidebar logo header goes, the phone drawer header shows icon + name, the platform mark leaves app context, the Studio entry gets a label)
Session: session_01G5TSaEwbEQsKMjhzTB4rEd
Account: os-warren
Branch: claude/issue-12201-app-identity-top-bar
Worktree: objectui-issue-12201
Domain: domain:ui
Seat: domain:ui#2
File surface, on objectui main9646e2e:
The sidebar:packages/app-shell/src/layout/UnifiedSidebar.tsx. The appLogoSidebarHeader (branding.logo, objectui#10827's reader) goes on desktop; on phones the sheet header shows icon + app name in place of the mobile-only Home row.
The switcher:packages/app-shell/src/layout/AppSwitcher.tsx, and whatever renders the 「HotCRM ▾」 pill (measured). Icon before the label, a glyph on every dropdown row, the icon-on-primaryColor fallback tile, and the admin-only bottom row 「在 Studio 中编辑 APP」 beside 「所有应用」.
The top bar:packages/app-shell/src/layout/AppHeader.tsx. The platform mark only in platform context, the PREVIEW chip beside the search box, and the Design-in-Studio button as the outline 「编辑应用」 / "Edit app" with a pencil, collapsing to the pencil with a tooltip on narrow widths. Same gate (isWorkspaceAdmin && canAuthorMetadata), same deep link.
Strings:packages/i18n/src/locales/*.ts, all ten packs.
Tests:packages/app-shell/src/layout/__tests__/. ConsoleLayout.appBrandingLogo-10827 moves its reader from the sidebar to the switcher; AppHeader.designInStudioNeedsAuthoring-10899 keeps passing against the new markup.
.changeset/12201-app-identity-top-bar.md (@object-ui/app-shell, @object-ui/i18n; ⛔ never major).
⛔ Not in this dispatch: the card's @objectstack/spec rider on branding.logo. New packages/spec work belongs to the spec seat, so this seat files it on objectstack. ⛔ No objectstack edit.
⛔ No change under packages/app-shell/src/environment/ or packages/app-shell/src/console/home/ (this round's other cards).
(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"
Clause-②: yes
Responsibility: n/a — not a defect card
Thread-read: 6120236629
Serial constraints cleared: read at 2026-10-12T08:57Z on objectui main9646e2e:
The three layout files: the last changes on main are ed12d48 (UnifiedSidebar.tsx, objectui#12165), 029bdaf (AppHeader.tsx) and 8732846 (AppSwitcher.tsx), all landed. No open PR touches them (7 open PRs read).
Locale packs: open PRs objectui#12203 (objectui#12187) and objectui#12209 also edit packages/i18n/src/locales/*.ts. That is ordinary concurrency, and the later lander merges.
Serial after this card: objectui#12198 (queued, p3) edits AppHeader.tsx (the 「页面」 crumb), so it waits for this card to land. This is recorded in the seat post's serial queue.
Rider routed · domain:ui seat 2 · session_01G5TSaEwbEQsKMjhzTB4rEd · 2026-10-12T09:04Z: the card's objectstack rider (the @objectstack/spec doc on branding.logo) is filed as objectstack-ai/objectstack#23000 for triage and the domain:spec seat. It is not part of this card's dispatch (claim 6121008577).
{
"issue": 12201,
"status": "done",
"branch": "claude/issue-12201-app-identity-top-bar",
"pr": "#12225",
"session": "session_01G5TSaEwbEQsKMjhzTB4rEd",
"premise_still_valid": true,
"summary": "Ruling items 1-6 implemented in packages/app-shell/src/layout. The app pill (AppSwitcher) draws branding.logo at 22 px left of the name, and every dropdown row draws its app's glyph: the logo, or the app's icon (via the existing getIcon) on a tile in that app's own hex primaryColor, published as CSS custom properties with a dark variant, or a neutral tile when no hex is declared. A new internal AppMark plus appTileColors does this; neither is exported. UnifiedSidebar drops the branding.logo SidebarHeader. On phones the drawer header shows the glyph (26 px) and the app name, with a trailing 「All apps」 link that keeps data-testid mobile-sidebar-home and useHomePath. In the app variant AppHeader no longer draws the platform mark or a separator before the pill, the PREVIEW chip moves beside the search box, and the Studio hammer becomes an outline pencil button 「Edit app」 (text from lg, pencil plus title tooltip below; same gate, same studioDesignPath, same test id). The pill's dropdown ends with 「All apps」 (the declared home) and an admin-only 「Edit APP in Studio」 row fed AppHeader's own studioDesignPath. Three i18n keys were added to all ten packs. AppHeader.tsx relay for objectui#12198: blocks were edited in place, with nothing extracted or renamed. The logo Link is wrapped in !isApp. The left PreviewBadge is gated !isApp, and an isApp PreviewBadge is inserted above the Group 1 Search block. The app-pill block lost its two leading PathSep spans and passes designInStudioPath. The Studio button moved from after InboxPopover to the first child of Group 2. Hammer became Pencil and the cn import was dropped. The breadcrumb code is untouched and in its old place: the extraSegments computation (its routeType page branch with console.breadcrumb.pages included) sits between studioDesignPath and the JSX, and the extraSegments.map render sits between the app-pill block and the mobile page-label block.",
"tests": "All at head c9ba7b8, after building app-shell's dependency closure (turbo run build --filter=@object-ui/app-shell^..., 28/28 successful). pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json; its include glob covers src/**/*.test.tsx, not counted with --listFiles): TYPECHECK_EXIT=0. pnpm exec vitest run packages/app-shell/src/layout/ plus homeAffordancesFollowDeclaration-7256, appSidebarRemoved-5817 and KeyboardShortcutsDialog.wiredOnly-11674: 'Test Files 64 passed (64)', 'Tests 462 passed (462)'. That covers the 3 new files (AppSwitcher.appIdentity-12201, AppHeader.appIdentity-12201, UnifiedSidebar.mobileAppHeader-12201), the rewritten ConsoleLayout.appBrandingLogo-10827 (reader assertion moved from the sidebar to the pill), and AppHeader.designInStudioNeedsAuthoring-10899, which is unchanged and green against the new markup. This is a declared narrowing; the rest of app-shell is left to CI. pnpm exec vitest run packages/i18n/: 'Test Files 83 passed (83)', 'Tests 1321 passed | 13 skipped'. pnpm --filter @object-ui/i18n type-check: exit 0. pnpm --filter @object-ui/app-shell lint && pnpm --filter @object-ui/i18n lint: lock VERDICT command-exit 0, '0 errors' in both; the new files have 0 warnings. Reverse check, run once with the fix committed: each source file was checked out at the BASE 9646e2e blob (disk hash equal to the BASE blob, anchor grep -c 0), the affected tests were run, then HEAD was restored (hash equal to the HEAD blob, git diff HEAD empty, trap restore on EXIT INT TERM). Results: UnifiedSidebar.tsx at BASE, 5 failed / 5 passed (the 4 drawer-header cases and sidebar-no-logo). AppSwitcher.tsx at BASE, 14 failed / 5 passed (every pill and row case; the appTileColors units and the unrelated controls stayed green). AppHeader.tsx at BASE, 6 failed / 6 passed (the 6 app-context cases; the platform controls, the member case and all 3 10899 cases stayed green). git status was empty after the run. NOT MEASURED: browser screenshots, reason: no ObjectStack backend can run here (the ../objectstack checkout has no node_modules or dist, and building one is a full install and build on a shared 4-core box). NOT MEASURED: check:eager-locale-catalogues, reason: PREREQUISITE NOT MET (needs a full console build for apps/console/dist/eager-closure.json). NOT MEASURED: check:readme-exports, reason: exit 1, but all 95 lines say 'type entry not on disk' for unbuilt packages, a prerequisite failure and not a finding.",
"mcp_calls": "0 — no MCP tool used",
"api_writes": "2 relay strokes, each a POST /repos/objectstack-ai/objectstack/dispatches from this seat: (1) pr_create, executed as POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/12225/assignees [os-warren]; (2) this os-dev-report comment, executed as POST /repos//issues/12201/comments. git push x3 (branch probe, two commits) is not a REST write. No label write, no PATCH.",
"open_questions": [
{
"question": "When the org context renders in an app (WorkspaceSwitcher for multi-org users, CurrentOrganizationIndicator on single-org walled deployments), it still sits left of the app pill, so the bar's left edge is the org name. The ruling places the pill first but does not place the org context. Should it move?",
"options": [
"A: keep it where it is. Zero further change; the common single-org environment shows neither control, so the bar starts with the pill.",
"B: move the org context to the right-hand cluster in app context only. It is a small AppHeader change, but the org context then sits in different places in app and platform contexts.",
"C: move it into the avatar menu everywhere. That is a larger change with its own design decision."
],
"recommendation": "A, until the maintainer's staging screenshots show a multi-org environment; it needs no new surface, and B or C is a design call the ruling did not make."
}
],
"out_of_scope_findings": [
"carrier: none · noted, not filed — appTileColors repeats @object-ui/layout AppShell's private dark-mode lightness floor (at least 65 %, saturation eased above 80 %); consolidating means exporting the AppShell hex helpers or moving them into @object-ui/core, outside this claim",
"carrier: none · noted, not filed — homeAffordancesFollowDeclaration-7256's AFFORDANCES source-scan table has no row for the switcher's new 「All apps」 entry; it is pinned behaviourally instead (AppSwitcher.appIdentity-12201 asserts the href is the declared home)",
"carrier: none · noted, not filed — content/docs/guide/console-architecture.md's layout diagram still lists the app switcher under the sidebar; it was stale at BASE already"
],
"gates": [
{
"command": "pnpm turbo run build --filter=@object-ui/app-shell^... --concurrency=2",
"exit": 0,
"verdict": "Tasks: 28 successful, 28 total; os-verify-lock: VERDICT command-exit 0"
},
{
"command": "pnpm --filter @object-ui/app-shell type-check",
"exit": 0,
"verdict": "TYPECHECK_EXIT=0 (head c9ba7b8)"
},
{
"command": "pnpm exec vitest run packages/app-shell/src/layout/ + 7256 + 5817 + 11674 pins",
"exit": 0,
"verdict": "Test Files 64 passed (64); Tests 462 passed (462)"
},
{
"command": "pnpm exec vitest run packages/i18n/",
"exit": 0,
"verdict": "Test Files 83 passed (83); Tests 1321 passed | 13 skipped"
},
{
"command": "pnpm --filter @object-ui/i18n type-check",
"exit": 0,
"verdict": "exit 0"
},
{
"command": "pnpm --filter @object-ui/app-shell lint && pnpm --filter @object-ui/i18n lint",
"exit": 0,
"verdict": "os-verify-lock: VERDICT command-exit 0; 0 errors"
},
{
"command": "pnpm check:i18n-keys",
"exit": 0,
"verdict": "Every in-scope call-site key resolves against the en pack (3358 keys) ..."
},
{
"command": "pnpm check:i18n-drift",
"exit": 0,
"verdict": "0 en value(s) changed (3 key(s) added, 0 removed)"
},
{
"command": "pnpm check:i18n-dead-keys",
"exit": 0,
"verdict": "report-only; none of the 3 new keys listed"
},
{
"command": "pnpm check:control-bytes",
"exit": 0,
"verdict": "check-control-bytes: OK (scanned 8461 tracked text file(s))"
},
{
"command": "pnpm check:new-line-citations",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"exit": 0,
"verdict": "No changeset declares a major bump."
},
{
"command": "node scripts/check-changeset-presence.mjs",
"exit": 0,
"verdict": "20 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)"
},
{
"command": "pnpm check:vi-mock-specifiers / vi-mock-inherit / vi-mock-override-shape",
"exit": 0,
"verdict": "OK x3"
},
{
"command": "pnpm check:test-path-roots / unreferenced-sources / phantom-deps / icon-record-names",
"exit": 0,
"verdict": "OK x4"
},
{
"command": "pnpm check:changeset-claims / pending-changeset-literals",
"exit": 0,
"verdict": "pass; one pending changeset (11806) names packages/app-shell/README.md, and its sign-up-table paragraph is untouched by this diff"
},
{
"command": "pnpm check:eager-locale-catalogues",
"exit": 2,
"verdict": "NOT MEASURED: PREREQUISITE NOT MET (no console build)"
},
{
"command": "pnpm check:readme-exports",
"exit": 1,
"verdict": "NOT MEASURED: 95/95 lines say 'type entry not on disk' (unbuilt packages)"
}
],
"line_budget": "n/a",
"deviations": [
"File surface addition: content/docs/guide/console-architecture.md, content/docs/guide/console.md and packages/app-shell/README.md describe exactly the UI this card moves (the sidebar logo header and the Design in Studio entry), and AGENTS.md rule 2 makes docs part of done. These edits are declared in the PR body. Nothing under app-shell/src/environment/ or app-shell/src/console/home/ was touched, and nothing in objectstack.",
"Interpretation, item 3: the phone drawer header keeps a trailing 「All apps」 icon link to the declared home beside the app's glyph and name, so a phone keeps its only way out of an app (the old Home row's job).",
"Interpretation, item 5: the PREVIEW chip moves right only in app context; on platform surfaces (Home, orgs, Studio front door) it stays beside the mark it belongs to.",
"Interpretation, item 6: 「left edge of the right-hand utility cluster」 is read as the first item of the bell/AI/help group, right after the search box; the label shows from lg (1024 px), and below that it is the pencil alone with a native title tooltip.",
"Measured, no change: Studio is never listed as an app because a stock boot registers no studio app (per the @objectstack/studio package header), so no client-side filter was added.",
"Browser screenshots were not captured (see tests); the PR body says so."
],
"files_changed": [
".changeset/12201-app-identity-top-bar.md",
"content/docs/guide/console-architecture.md",
"content/docs/guide/console.md",
"packages/app-shell/README.md",
"packages/app-shell/src/layout/AppHeader.tsx",
"packages/app-shell/src/layout/AppMark.tsx",
"packages/app-shell/src/layout/AppSwitcher.tsx",
"packages/app-shell/src/layout/UnifiedSidebar.tsx",
"packages/app-shell/src/layout/appTileColors.ts",
"packages/app-shell/src/layout/tests/AppHeader.appIdentity-12201.test.tsx",
"packages/app-shell/src/layout/tests/AppSwitcher.appIdentity-12201.test.tsx",
"packages/app-shell/src/layout/tests/AppSwitcher.publishState.test.tsx",
"packages/app-shell/src/layout/tests/ConsoleLayout.appBrandingLogo-10827.test.tsx",
"packages/app-shell/src/layout/tests/UnifiedSidebar.mobileAppHeader-12201.test.tsx",
"packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts"
],
"i18n_keys": {
"added": [
"topbar.editApp",
"layout.appSwitcher.allApps",
"layout.appSwitcher.editAppInStudio"
],
"removed": []
},
"public_surface": {
"@object-ui/app-shell": "AppSwitcher gains an optional prop designInStudioPath?: string | null (additive), and it now renders router Links, so it needs a Router context. AppHeader and UnifiedSidebar have no prop change and only the markup changes described above. AppMark and appTileColors are internal and not exported. No export was added or removed.",
"@object-ui/i18n": "3 keys added to all ten packs; none removed; no export change"
}
}
Reviewed against GitHub and the diff, not the report. Claim 6121008577; report 6122271226; contract review 6122684858 on the PR (CONTRACT_REVIEW_TIER, this head, PASS).
Shape: draft on main. The first line is Fixes #12201, and no other closing keyword is in the body. Clause-②: yes. 24 files, 1,261 changed lines; check-governed-merges --pr reads NOT governed.
Ruling items 1–6: each is checked against the diff in the contract review's ①.8. The seat's own read agrees: one asset at 22/22/26 px; the pill and every row draw a glyph; the sidebar header is gone; the platform mark is gone in app context; the PREVIEW chip is beside the search box; and 「Edit app」 plus the dropdown's Studio row share one gate and one target.
Surface amended at ACCEPT:content/docs/guide/console-architecture.md, content/docs/guide/console.md and packages/app-shell/README.md. They describe exactly the moved UI, and the PR body declares them. Each changed sentence was read against the diff.
Changeset (@object-ui/app-shell and @object-ui/i18nminor): matches what the diff publishes. One sentence is missing: AppSwitcher now needs a Router context. The PR body says so; the changeset does not. The contract review judged that gap non-blocking (①.2), and the seat accepts it.
Open question: where the org context sits in app context stays as it is (A). The ruling did not place it, and a single-org environment shows neither control. If a multi-org environment is in scope, this goes to the maintainer as its own question.
NOT MEASURED, declared: the browser screenshots (acceptance 1–4, 6). The maintainer's staging screenshots after the pin move are the visual check. CI on this head reads 40 success and 3 skipped.
Activity
objectstack-fleet commentedon Oct 12, 2026
Triage seat (seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T08:04Z. ⛔ Not a claim, ⛔ not a dispatch. Grade completed:domain:ui·area:devpathadded. The filer'senhancement·priority:p2·pm:queuestand (the maintainer's ruling, 2026-10-12).objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 1 (executes the maintainer's ruling quoted in the card body, items 1–6: app identity moves into the top bar, the sidebar logo header goes, the phone drawer header shows icon + name, the platform mark leaves app context, the Studio entry gets a label)
Session:
session_01G5TSaEwbEQsKMjhzTB4rEdAccount:
os-warrenBranch:
claude/issue-12201-app-identity-top-barWorktree:
objectui-issue-12201Domain:
domain:uiSeat:
domain:ui#2File surface, on objectui
main9646e2e:packages/app-shell/src/layout/UnifiedSidebar.tsx. TheappLogoSidebarHeader(branding.logo, objectui#10827's reader) goes on desktop; on phones the sheet header shows icon + app name in place of the mobile-only Home row.packages/app-shell/src/layout/AppSwitcher.tsx, and whatever renders the 「HotCRM ▾」 pill (measured). Icon before the label, a glyph on every dropdown row, theicon-on-primaryColorfallback tile, and the admin-only bottom row 「在 Studio 中编辑 APP」 beside 「所有应用」.packages/app-shell/src/layout/AppHeader.tsx. The platform mark only in platform context, the PREVIEW chip beside the search box, and the Design-in-Studio button as the outline 「编辑应用」 / "Edit app" with a pencil, collapsing to the pencil with a tooltip on narrow widths. Same gate (isWorkspaceAdmin && canAuthorMetadata), same deep link.packages/i18n/src/locales/*.ts, all ten packs.packages/app-shell/src/layout/__tests__/.ConsoleLayout.appBrandingLogo-10827moves its reader from the sidebar to the switcher;AppHeader.designInStudioNeedsAuthoring-10899keeps passing against the new markup..changeset/12201-app-identity-top-bar.md(@object-ui/app-shell,@object-ui/i18n; ⛔ nevermajor).@objectstack/specrider onbranding.logo. Newpackages/specwork belongs to the spec seat, so this seat files it on objectstack. ⛔ No objectstack edit.packages/app-shell/src/environment/orpackages/app-shell/src/console/home/(this round's other cards).Container & model:
M,mode:subagent,model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"Clause-②: yes
Responsibility:
n/a — not a defect cardThread-read: 6120236629
Serial constraints cleared: read at 2026-10-12T08:57Z on objectui
main9646e2e:mainareed12d48(UnifiedSidebar.tsx, objectui#12165),029bdaf(AppHeader.tsx) and8732846(AppSwitcher.tsx), all landed. No open PR touches them (7 open PRs read).packages/i18n/src/locales/*.ts. That is ordinary concurrency, and the later lander merges.everyoneaudience anchor, which the server refuses as a grant target; filter the audience anchors out of the grant picker #12200, console: changing or clearing the owner in a record's Edit form is silently dropped — the PATCH omits owner_id entirely (inline edit of the same field works) #12205, console: inline-editing a date-only field in record highlights saves the day before east of UTC — it sends local midnight as a UTC instant (the Edit form sends the plain date) #12206) declare no layout file. Epic objectui#7611's territory (Setup catalog pages, assignment pages, pickers) does not include them.AppHeader.tsx(the 「页面」 crumb), so it waits for this card to land. This is recorded in the seat post's serial queue.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Rider routed ·
domain:uiseat 2 ·session_01G5TSaEwbEQsKMjhzTB4rEd· 2026-10-12T09:04Z: the card's objectstack rider (the@objectstack/specdoc onbranding.logo) is filed as objectstack-ai/objectstack#23000 for triage and thedomain:specseat. It is not part of this card's dispatch (claim6121008577).Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{
"issue": 12201,
"status": "done",
"branch": "claude/issue-12201-app-identity-top-bar",
"pr": "#12225",
"session": "session_01G5TSaEwbEQsKMjhzTB4rEd",
"premise_still_valid": true,
"summary": "Ruling items 1-6 implemented in packages/app-shell/src/layout. The app pill (AppSwitcher) draws branding.logo at 22 px left of the name, and every dropdown row draws its app's glyph: the logo, or the app's icon (via the existing getIcon) on a tile in that app's own hex primaryColor, published as CSS custom properties with a dark variant, or a neutral tile when no hex is declared. A new internal AppMark plus appTileColors does this; neither is exported. UnifiedSidebar drops the branding.logo SidebarHeader. On phones the drawer header shows the glyph (26 px) and the app name, with a trailing 「All apps」 link that keeps data-testid mobile-sidebar-home and useHomePath. In the app variant AppHeader no longer draws the platform mark or a separator before the pill, the PREVIEW chip moves beside the search box, and the Studio hammer becomes an outline pencil button 「Edit app」 (text from lg, pencil plus title tooltip below; same gate, same studioDesignPath, same test id). The pill's dropdown ends with 「All apps」 (the declared home) and an admin-only 「Edit APP in Studio」 row fed AppHeader's own studioDesignPath. Three i18n keys were added to all ten packs. AppHeader.tsx relay for objectui#12198: blocks were edited in place, with nothing extracted or renamed. The logo Link is wrapped in !isApp. The left PreviewBadge is gated !isApp, and an isApp PreviewBadge is inserted above the Group 1 Search block. The app-pill block lost its two leading PathSep spans and passes designInStudioPath. The Studio button moved from after InboxPopover to the first child of Group 2. Hammer became Pencil and the cn import was dropped. The breadcrumb code is untouched and in its old place: the extraSegments computation (its routeType page branch with console.breadcrumb.pages included) sits between studioDesignPath and the JSX, and the extraSegments.map render sits between the app-pill block and the mobile page-label block.",
"tests": "All at head c9ba7b8, after building app-shell's dependency closure (turbo run build --filter=@object-ui/app-shell^..., 28/28 successful). pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json; its include glob covers src/**/*.test.tsx, not counted with --listFiles): TYPECHECK_EXIT=0. pnpm exec vitest run packages/app-shell/src/layout/ plus homeAffordancesFollowDeclaration-7256, appSidebarRemoved-5817 and KeyboardShortcutsDialog.wiredOnly-11674: 'Test Files 64 passed (64)', 'Tests 462 passed (462)'. That covers the 3 new files (AppSwitcher.appIdentity-12201, AppHeader.appIdentity-12201, UnifiedSidebar.mobileAppHeader-12201), the rewritten ConsoleLayout.appBrandingLogo-10827 (reader assertion moved from the sidebar to the pill), and AppHeader.designInStudioNeedsAuthoring-10899, which is unchanged and green against the new markup. This is a declared narrowing; the rest of app-shell is left to CI. pnpm exec vitest run packages/i18n/: 'Test Files 83 passed (83)', 'Tests 1321 passed | 13 skipped'. pnpm --filter @object-ui/i18n type-check: exit 0. pnpm --filter @object-ui/app-shell lint && pnpm --filter @object-ui/i18n lint: lock VERDICT command-exit 0, '0 errors' in both; the new files have 0 warnings. Reverse check, run once with the fix committed: each source file was checked out at the BASE 9646e2e blob (disk hash equal to the BASE blob, anchor grep -c 0), the affected tests were run, then HEAD was restored (hash equal to the HEAD blob, git diff HEAD empty, trap restore on EXIT INT TERM). Results: UnifiedSidebar.tsx at BASE, 5 failed / 5 passed (the 4 drawer-header cases and sidebar-no-logo). AppSwitcher.tsx at BASE, 14 failed / 5 passed (every pill and row case; the appTileColors units and the unrelated controls stayed green). AppHeader.tsx at BASE, 6 failed / 6 passed (the 6 app-context cases; the platform controls, the member case and all 3 10899 cases stayed green). git status was empty after the run. NOT MEASURED: browser screenshots, reason: no ObjectStack backend can run here (the ../objectstack checkout has no node_modules or dist, and building one is a full install and build on a shared 4-core box). NOT MEASURED: check:eager-locale-catalogues, reason: PREREQUISITE NOT MET (needs a full console build for apps/console/dist/eager-closure.json). NOT MEASURED: check:readme-exports, reason: exit 1, but all 95 lines say 'type entry not on disk' for unbuilt packages, a prerequisite failure and not a finding.",
"mcp_calls": "0 — no MCP tool used",
"api_writes": "2 relay strokes, each a POST /repos/objectstack-ai/objectstack/dispatches from this seat: (1) pr_create, executed as POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/12225/assignees [os-warren]; (2) this os-dev-report comment, executed as POST /repos//issues/12201/comments. git push x3 (branch probe, two commits) is not a REST write. No label write, no PATCH.",
"open_questions": [
{
"question": "When the org context renders in an app (WorkspaceSwitcher for multi-org users, CurrentOrganizationIndicator on single-org walled deployments), it still sits left of the app pill, so the bar's left edge is the org name. The ruling places the pill first but does not place the org context. Should it move?",
"options": [
"A: keep it where it is. Zero further change; the common single-org environment shows neither control, so the bar starts with the pill.",
"B: move the org context to the right-hand cluster in app context only. It is a small AppHeader change, but the org context then sits in different places in app and platform contexts.",
"C: move it into the avatar menu everywhere. That is a larger change with its own design decision."
],
"recommendation": "A, until the maintainer's staging screenshots show a multi-org environment; it needs no new surface, and B or C is a design call the ruling did not make."
}
],
"out_of_scope_findings": [
"carrier: none · noted, not filed — appTileColors repeats @object-ui/layout AppShell's private dark-mode lightness floor (at least 65 %, saturation eased above 80 %); consolidating means exporting the AppShell hex helpers or moving them into @object-ui/core, outside this claim",
"carrier: none · noted, not filed — homeAffordancesFollowDeclaration-7256's AFFORDANCES source-scan table has no row for the switcher's new 「All apps」 entry; it is pinned behaviourally instead (AppSwitcher.appIdentity-12201 asserts the href is the declared home)",
"carrier: none · noted, not filed — content/docs/guide/console-architecture.md's layout diagram still lists the app switcher under the sidebar; it was stale at BASE already"
],
"gates": [
{
"command": "pnpm turbo run build --filter=@object-ui/app-shell^... --concurrency=2",
"exit": 0,
"verdict": "Tasks: 28 successful, 28 total; os-verify-lock: VERDICT command-exit 0"
},
{
"command": "pnpm --filter @object-ui/app-shell type-check",
"exit": 0,
"verdict": "TYPECHECK_EXIT=0 (head c9ba7b8)"
},
{
"command": "pnpm exec vitest run packages/app-shell/src/layout/ + 7256 + 5817 + 11674 pins",
"exit": 0,
"verdict": "Test Files 64 passed (64); Tests 462 passed (462)"
},
{
"command": "pnpm exec vitest run packages/i18n/",
"exit": 0,
"verdict": "Test Files 83 passed (83); Tests 1321 passed | 13 skipped"
},
{
"command": "pnpm --filter @object-ui/i18n type-check",
"exit": 0,
"verdict": "exit 0"
},
{
"command": "pnpm --filter @object-ui/app-shell lint && pnpm --filter @object-ui/i18n lint",
"exit": 0,
"verdict": "os-verify-lock: VERDICT command-exit 0; 0 errors"
},
{
"command": "pnpm check:i18n-keys",
"exit": 0,
"verdict": "Every in-scope call-site key resolves against the en pack (3358 keys) ..."
},
{
"command": "pnpm check:i18n-drift",
"exit": 0,
"verdict": "0 en value(s) changed (3 key(s) added, 0 removed)"
},
{
"command": "pnpm check:i18n-dead-keys",
"exit": 0,
"verdict": "report-only; none of the 3 new keys listed"
},
{
"command": "pnpm check:control-bytes",
"exit": 0,
"verdict": "check-control-bytes: OK (scanned 8461 tracked text file(s))"
},
{
"command": "pnpm check:new-line-citations",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"exit": 0,
"verdict": "No changeset declares a
majorbump."},
{
"command": "node scripts/check-changeset-presence.mjs",
"exit": 0,
"verdict": "20 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)"
},
{
"command": "pnpm check:vi-mock-specifiers / vi-mock-inherit / vi-mock-override-shape",
"exit": 0,
"verdict": "OK x3"
},
{
"command": "pnpm check:test-path-roots / unreferenced-sources / phantom-deps / icon-record-names",
"exit": 0,
"verdict": "OK x4"
},
{
"command": "pnpm check:changeset-claims / pending-changeset-literals",
"exit": 0,
"verdict": "pass; one pending changeset (11806) names packages/app-shell/README.md, and its sign-up-table paragraph is untouched by this diff"
},
{
"command": "pnpm check:eager-locale-catalogues",
"exit": 2,
"verdict": "NOT MEASURED: PREREQUISITE NOT MET (no console build)"
},
{
"command": "pnpm check:readme-exports",
"exit": 1,
"verdict": "NOT MEASURED: 95/95 lines say 'type entry not on disk' (unbuilt packages)"
}
],
"line_budget": "n/a",
"deviations": [
"File surface addition: content/docs/guide/console-architecture.md, content/docs/guide/console.md and packages/app-shell/README.md describe exactly the UI this card moves (the sidebar logo header and the Design in Studio entry), and AGENTS.md rule 2 makes docs part of done. These edits are declared in the PR body. Nothing under app-shell/src/environment/ or app-shell/src/console/home/ was touched, and nothing in objectstack.",
"Interpretation, item 3: the phone drawer header keeps a trailing 「All apps」 icon link to the declared home beside the app's glyph and name, so a phone keeps its only way out of an app (the old Home row's job).",
"Interpretation, item 5: the PREVIEW chip moves right only in app context; on platform surfaces (Home, orgs, Studio front door) it stays beside the mark it belongs to.",
"Interpretation, item 6: 「left edge of the right-hand utility cluster」 is read as the first item of the bell/AI/help group, right after the search box; the label shows from lg (1024 px), and below that it is the pencil alone with a native title tooltip.",
"Measured, no change: Studio is never listed as an app because a stock boot registers no studio app (per the @objectstack/studio package header), so no client-side filter was added.",
"Browser screenshots were not captured (see tests); the PR body says so."
],
"files_changed": [
".changeset/12201-app-identity-top-bar.md",
"content/docs/guide/console-architecture.md",
"content/docs/guide/console.md",
"packages/app-shell/README.md",
"packages/app-shell/src/layout/AppHeader.tsx",
"packages/app-shell/src/layout/AppMark.tsx",
"packages/app-shell/src/layout/AppSwitcher.tsx",
"packages/app-shell/src/layout/UnifiedSidebar.tsx",
"packages/app-shell/src/layout/appTileColors.ts",
"packages/app-shell/src/layout/tests/AppHeader.appIdentity-12201.test.tsx",
"packages/app-shell/src/layout/tests/AppSwitcher.appIdentity-12201.test.tsx",
"packages/app-shell/src/layout/tests/AppSwitcher.publishState.test.tsx",
"packages/app-shell/src/layout/tests/ConsoleLayout.appBrandingLogo-10827.test.tsx",
"packages/app-shell/src/layout/tests/UnifiedSidebar.mobileAppHeader-12201.test.tsx",
"packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts"
],
"i18n_keys": {
"added": [
"topbar.editApp",
"layout.appSwitcher.allApps",
"layout.appSwitcher.editAppInStudio"
],
"removed": []
},
"public_surface": {
"@object-ui/app-shell": "AppSwitcher gains an optional prop designInStudioPath?: string | null (additive), and it now renders router Links, so it needs a Router context. AppHeader and UnifiedSidebar have no prop change and only the markup changes described above. AppMark and appTileColors are internal and not exported. No export was added or removed.",
"@object-ui/i18n": "3 keys added to all ten packs; none removed; no export change"
}
}
Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
ACCEPT: PR objectui#12225 (head
c9ba7b8) ·domain:uiseat 2 ·session_01G5TSaEwbEQsKMjhzTB4rEd· 2026-10-12T10:44ZReviewed against GitHub and the diff, not the report. Claim
6121008577; report6122271226; contract review6122684858on the PR (CONTRACT_REVIEW_TIER, this head, PASS).main. The first line isFixes #12201, and no other closing keyword is in the body.Clause-②: yes. 24 files, 1,261 changed lines;check-governed-merges --prreads NOT governed.content/docs/guide/console-architecture.md,content/docs/guide/console.mdandpackages/app-shell/README.md. They describe exactly the moved UI, and the PR body declares them. Each changed sentence was read against the diff.@object-ui/app-shelland@object-ui/i18nminor): matches what the diff publishes. One sentence is missing:AppSwitchernow needs a Router context. The PR body says so; the changeset does not. The contract review judged that gap non-blocking (①.2), and the seat accepts it.AppHeader.tsxblocks were edited in place; nothing was extracted or renamed. The breadcrumb code,extraSegmentswith itsrouteType === 'page'branch, is untouched and in its old place. The console breadcrumb on a page route adds a 「页面」/Pages crumb, a metadata-type word on a user page; and pin that a Cloud owner or member sees neither the Studio pencil nor the hammer (cloud#2777 item 4) #12198 starts from this card's merge.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Landed ·
domain:uiseat 2 ·session_01G5TSaEwbEQsKMjhzTB4rEd· 2026-10-12T11:05ZPR objectui#12225 merged through the merge queue as
38bb373onmain. Verified by content onorigin/main, not by sha:packages/app-shell/src/layout/AppMark.tsxis present.AppSwitcher.tsxcarries the 「All apps」 row (app-switcher-all-apps).UnifiedSidebar.tsxno longer draws theappLogoheader (0 hits).editApp(control:setUpProductionhits in the same file).pm:dispatchedis removed in this same act; the card was closed by the PR'sFixesline. Follow-ups:branding.logoas the app's one square icon (1:1, SVG preferred, at least 64 px), per the maintainer's ruling on objectui#12201 objectstack#23000 (triage, then thedomain:specseat);.objectui-shamove.Generated by Claude Code
feat(app-shell): app identity moves into the top bar (objectstack-ai#…