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
console Home launcher ignores a permission set's tabPermissions: hidden — it reads /api/v1/meta/app while the hide is applied only in /api/v1/me/apps #26838
Filing gate: ① product defect, reproduced, landing site named.
Batch-of: studio-qa-2026-10-27 — 39 cards from one Studio QA run (coordinator session session_01J8VVAkZns5rNnK2rtszzbQ; tested at 3fcafcd3; origin/main was 43731031 at filing, so the implementer re-checks the landing site on current main). The run record is the qa-run issue filed with this batch.
Symptom
An app the member's set hides still appears as a tile on Home and opens; the app switcher (which reads /me/apps) hides it correctly.
Reproduction
Set tabPermissions: {showcase_app: "hidden"} on the member's set, publish.
As the member: GET /api/v1/me/apps → [setup, account] (correct); /_console/home shows the Showcase tile and opens it.
Toggle the setting back → tile behaviour follows only /meta/app, proving the cause. Not a data leak (object permissions still apply).
Expected
Every launcher surface reads the same filtered list (/me/apps).
Suspected landing site (the implementer verifies)
Console Home launcher data source (ui/apps/console / app-shell Home).
Filing facts
reach: Console UI + HTTP, measured by the Access QA card.
Business reason: Admins hide apps to simplify members' workspace; Home ignores it.
Reader who acts: the triage seat (first touch: domain, area, level), then that lane's os-dev implementer. QA suggestion only: domain:ui, area:access, p2.
p2: the console Home launcher reads /api/v1/meta/app, so a set's tabPermissions: hidden still shows the tile, while the switcher (/me/apps) hides it. Home reads /me/apps, so both surfaces have one source. Re-check the landing site on current main.
Dispatch order · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T00:43Z
You are the os-dev developer agent for exactly ONE card: #26838, 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/26838" -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 a third ui lane seat" (cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Uc2nCvWvLyYyaVYaUhakpJ) one message with your branch name and wait. Read-only measuring is fine meanwhile. Worktree objectstack-issue-26838 on that branch from a fresh origin/main (git checkout --detach the main checkout first, then git worktree add --no-track -B <branch> ../objectstack-issue-26838 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=26838 --file=F --json run ONCE with output captured to a file (no time-shaped stamp inside the fenced report JSON). ⛔ 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 #26838, 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 (merge origin/main first if it refuses as STALE TREE); node scripts/check-sdui-manifest.mjs is a gate on every ui card. Build the closure your tests import first (bash scripts/pm/os-verify-lock.sh -c "pnpm --workspace-concurrency=2 --filter '<pkg>^...' build"). Changeset in the root .changeset/ for each published package your diff changes (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 one message (PR, head sha, report gist); keep the thread open through review and drive CI to green. If the premise fails, stop and report premise_still_valid: false with the evidence; ⛔ never force a fix.
Ruling (cannot be re-ruled)
Triage 6450939210, verbatim: "Home reads /me/apps, so both surfaces have one source. Re-check the landing site on current main." Card Expected, verbatim: "Every launcher surface reads the same filtered list (/me/apps)." Card: "Not a data leak (object permissions still apply)." No maintainer ruling.
Home: ui/packages/app-shell/src/console/home/HomePage.tsx ≈L347 useMetadata(), ≈L417 filterActiveApps(apps) (utils/appRoute.ts ≈L142 checks only active/hidden), tiles to HomeAppsStrip ≈L776. useMetadata().apps = GET /api/v1/meta/app (providers/MetadataProvider.tsx ≈L133, ≈L1486).
Correction to the card: no file under ui/ reads /me/apps today (git log -S "me/apps" -- ui is empty), so the app switcher (layout/AppSwitcher.tsx ≈L68/86) very likely shows the hidden app too. Other readers of the same /meta/app list: console/AppContent.tsx ≈L316–340, views/app-launcher-renderer.tsx ≈L117, hooks/useNavMemberGates.ts ≈L117, hooks/sharedUserFeeds.ts ≈L1024. Measure which of these are launcher surfaces.
Server: GET /me/apps (packages/plugins/plugin-hono-server/src/current-user-endpoints.ts ≈L1026–1093) merges the sets' tabPermissions (most visible wins) and drops hidden apps. /auth/me/permissions also carries the merged tabPermissions.
PM suggested route (optional; measurement wins)
One shared filtered feed (/me/apps, as triage wrote) that Home and every launcher surface read, so they cannot disagree; when /me/apps is absent (no security plugin, 404), fall back to the /meta/app list rather than blanking Home. default_off is out of scope. A direct URL to a hidden app keeps opening (UI visibility, not access control; do not add a route guard). Tests: Home with /meta/app = [setup, account, showcase] and /me/apps = [setup, account] draws no showcase tile; the same for the switcher if you wire it; the 404 fallback shows all. Ablation: revert the filter; the Home test goes red.
Scope
File surface: ui/packages/app-shell/src/console/home/**, ui/packages/app-shell/src/utils/appRoute.ts or a new hook under ui/packages/app-shell/src/hooks/, ui/packages/app-shell/src/layout/AppSwitcher.tsx and views/app-launcher-renderer.tsx if they are launcher surfaces, tests beside them, root .changeset/. ⛔ No server change (if one is needed, stop and report). console/AppContent.tsx is a hot shared file: touch it only if a launcher surface lives there, and say so. Epic #26676 holds console/appObjectScope.ts: ⛔ do not edit it.
Tier
No path-derived mandate (dispatch-gates --tier, read 2026-10-28T00:43Z). TIER_DEFAULT, effort high (M). Clause-②: no, Metadata-protocol: none expected.
Claim: PM loop round 1
Session: session_01JQwxbXpF772qWJjojJvRXw
Account: os-warren
Branch: claude/project-thread-8n1lrs
Worktree: objectstack-issue-26838
Domain: domain:ui
Seat: domain:ui#2
File surface: ui/packages/app-shell/src/console/home/**, ui/packages/app-shell/src/utils/appRoute.ts or a new hook under ui/packages/app-shell/src/hooks/, ui/packages/app-shell/src/layout/AppSwitcher.tsx and ui/packages/app-shell/src/views/app-launcher-renderer.tsx if they are launcher surfaces, console/AppContent.tsx only for a launcher surface there, tests beside them, root .changeset/ (stop on breach; explain in the report)
Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the console launcher surfaces read /api/v1/meta/app, which does not apply tabPermissions | GET /me/apps already drops hidden apps server-side | every user whose permission set hides an app still sees its Home tile (UI visibility, not a data leak)
Thread-read: 6457561621
Premise: corrected 6457561621 (no ui/ file reads /me/apps today, so the switcher premise on the card is wrong; Home defect holds on origin/mainfd246c22)
Serial constraints cleared: epic #26676 holds console/appObjectScope.ts (not edited); no in-flight claim on console/home/**, appRoute.ts or AppSwitcher.tsx; AppContent.tsx is also on #26843's surface (seat 2, New-dialog form props), disjoint regions, second to land merges main.
Dispatch order: comment 6457561621. Card thread claude/project-thread-8n1lrs may start editing.
Claim 6457602008 (branch claude/project-thread-8n1lrs) widens its file surface by one file, at the card thread's request: ui/apps/console/src/AppContent.tsx, the ConsolePermissionsScope region only (mount LauncherAppsProvider inside MePermissionsProvider). Reason, as the dev measured it: the ui network-escape guard reds any test whose render reaches a relative fetch, so the /me/apps read is an explicitly composed provider, and ConsolePermissionsScope is the only common ancestor of /home and /apps/:appName. No other in-flight claim lists this file (#26843 edits the app-shell console/AppContent.tsx, a different file). Everything else in the claim stands.
{
"issue": 26838,
"status": "done",
"branch": "claude/project-thread-8n1lrs",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27021",
"head": "cbe8d370",
"base": "0b78a20b",
"session": "session_01JQwxbYwBbR8jCpWPE5Kosz",
"premise_still_valid": true,
"summary": "Home defect holds on origin/main; the card's switcher premise does not: no ui/ file read /me/apps, and AppSwitcher and the app:launcher block read /meta/app like Home (the dispatch's correction, confirmed). New hooks/useLauncherApps.tsx: LauncherAppsProvider reads GET /api/v1/me/apps once per user (again only when the active /meta/app name set gains a name the held answer was not asked about), and useLauncherApps(apps) returns filterActiveApps(apps) minus every asked-about app the answer did not list, keeping the /meta/app entries. No provider, 404 or a failed read narrows nothing (non-404 warns once; 404 not re-asked). Home's tiles and System Settings link, the AppSwitcher menu and the app:launcher block read it; Home's loading gate waits for the first read. Mounted once in ui/apps/console/src/AppContent.tsx ConsolePermissionsScope (surface amendment 6457698059). A provider, not a self-fetching hook, because the ui network-escape guard reds every test render that reaches a relative fetch and about 130 test files render these surfaces.",
"tests": "New: useLauncherApps-26838 (8), HomePage.launcherHiddenApps-26838 (4), AppSwitcher.launcherHiddenApps-26838 (3): 15/15 passed. Affected set (284 app-shell + console files naming the touched surfaces, plus console/home and layout test dirs): 2359 passed, exit 0, on 9f4f6f31 (the later origin/main merge touched none of these paths). type-check @object-ui/app-shell exit 0; type-check @object-ui/console exit 0 after the console closure build. Ablations via scripts/ablation-replace.mjs under the lock, anchor 1 -> 0, restored blob == HEAD, git diff HEAD empty: HomePage tiles from activeApps -> 2 failed / 2 passed; hook predicate return true -> 7 failed across the three files; AppSwitcher back to its inline filter -> 2 failed / 1 passed. No dist leg: tests import app-shell sources by relative path.",
"gates": "dispatch-gates --commands on cbe8d370 (origin/main merged): 34 derived, every one exit 0 (incl. node scripts/check-sdui-manifest.mjs and pnpm --dir ui exec vitest run scripts/); --ran: 34 derived, 34 run, 0 NOT-MEASURED, exit 0. Outside the derivation, exit 0: pnpm --dir ui run check:spec-symbols, check:new-line-citations, check:test-path-roots. CI check-runs on PR 27021: in_progress at report time.",
"line_budget": "11 files, +822 / -15 (837 changed lines, under the 3000 threshold); about 640 of the added lines are the three test files and the hook; no ratchet-governed file touched.",
"deviations": [
"File surface extended by the seat (amendment 6457698059) to ui/apps/console/src/AppContent.tsx, ConsolePermissionsScope region only; asked before editing it.",
"Changeset names @object-ui/console as well as @object-ui/app-shell: the console package is public and ships the app-shell code in its dist.",
"PR body: the platform attribution block sits on lines 1-2, so Fixes #26838 is line 3; .github/PULL_REQUEST_TEMPLATE.md headings folded into the os-dev section order (What changes / Tests / Acceptance notes / Verification / Human Minimum).",
"The session-context's MCP assignee/reviewer step skipped: the dispatch bans MCP; the relay set the assignee."
],
"files_changed": [
".changeset/26838-launcher-hidden-tabs.md",
"ui/apps/console/src/AppContent.tsx",
"ui/packages/app-shell/src/console/home/HomePage.tsx",
"ui/packages/app-shell/src/console/home/__tests__/HomePage.launcherHiddenApps-26838.test.tsx",
"ui/packages/app-shell/src/hooks/__tests__/useLauncherApps-26838.test.tsx",
"ui/packages/app-shell/src/hooks/index.ts",
"ui/packages/app-shell/src/hooks/useLauncherApps.tsx",
"ui/packages/app-shell/src/index.ts",
"ui/packages/app-shell/src/layout/AppSwitcher.tsx",
"ui/packages/app-shell/src/layout/__tests__/AppSwitcher.launcherHiddenApps-26838.test.tsx",
"ui/packages/app-shell/src/views/app-launcher-renderer.tsx"
],
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, assignee set by the relay); this report comment (POST /repos/objectstack-ai/objectstack/issues/26838/comments via post-stamped)",
"open_questions": [],
"out_of_scope_findings": [
"carrier: seat · noted, not filed — CommandPalette app lists (HomeLayout passes apps ?? []; the in-app palette likewise) still list a tabPermissions-hidden app; seat to decide whether it is a launcher surface",
"carrier: seat · noted, not filed — default-app landing in ui/packages/app-shell/src/console/AppContent.tsx (launcherApps there) filters active/hidden only, so /apps with no segment can land on a tab-hidden app",
"carrier: none · noted, not filed — GET /me/apps answers 200 with an empty apps list when its handler throws (outer catch in current-user-endpoints.ts), indistinguishable from every app hidden; read-only inference from source, not reproduced"
]
}
Claim 6457602008 (branch claude/project-thread-8n1lrs), after the seat's review of PR #27021 (REWORK, one patch round): the card's Expected — "Every launcher surface reads the same filtered list (/me/apps)." — also covers the two surfaces the PR's Acceptance notes leave open, so the file surface widens to: ui/packages/app-shell/src/console/home/HomeLayout.tsx (the apps it hands the command palette), ui/packages/app-shell/src/chrome/CommandPalette.tsx and its in-app caller if the palette's app list is assembled there, and ui/packages/app-shell/src/console/AppContent.tsx the launcherApps default-app landing region only (≈L340–375). #26843 (seat 2, claude/project-thread-58h2qh) edits the New-dialog form props in that same file, a disjoint region; second to land merges main. Everything else in the claim and amendment 6457698059 stands.
Landing held · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · 2026-10-28T03:01Z
PR #27021 (ACCEPT 6459467327, which supersedes REWORK 6458597628) is green on head 7b20f2d51d. Every check-run succeeded or was path-skipped, including the PR-body guards and Check Changeset that re-ran after the seat's body edit. mergeable_state is clean and the PR is not governed. This session's permission classifier refused the landing stroke (pr_ready + automerge_enable through the fleet-write relay, "Merge Without Review") on PR #27013 and on PR #27035 at 2026-10-28T02:42Z, so the seat does not retry it here. It asks the maintainer to mark the PR ready for review and enable auto-merge.
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: first grade —
priority:p2·domain:ui·area:access·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T18:57Z⛔ Not a claim, ⛔ not a dispatch.
/api/v1/meta/app, so a set'stabPermissions: hiddenstill shows the tile, while the switcher (/me/apps) hides it. Home reads/me/apps, so both surfaces have one source. Re-check the landing site on currentmain.Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
Dispatch order ·
domain:ui#2·session_01JQwxbXpF772qWJjojJvRXw· 2026-10-28T00:43ZYou are the os-dev developer agent for exactly ONE card: #26838, 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/26838" -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 a third ui lane seat" (cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Uc2nCvWvLyYyaVYaUhakpJ) one message with your branch name and wait. Read-only measuring is fine meanwhile. Worktreeobjectstack-issue-26838on that branch from a freshorigin/main(git checkout --detachthe main checkout first, thengit worktree add --no-track -B <branch> ../objectstack-issue-26838 origin/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=26838 --file=F --jsonrun ONCE with output captured to a file (no time-shaped stamp inside the fenced report JSON). ⛔ 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 #26838, 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(mergeorigin/mainfirst if it refuses as STALE TREE);node scripts/check-sdui-manifest.mjsis a gate on every ui card. Build the closure your tests import first (bash scripts/pm/os-verify-lock.sh -c "pnpm --workspace-concurrency=2 --filter '<pkg>^...' build"). Changeset in the root.changeset/for each published package your diff changes (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 one message (PR, head sha, report gist); keep the thread open through review and drive CI to green. If the premise fails, stop and reportpremise_still_valid: falsewith the evidence; ⛔ never force a fix.Ruling (cannot be re-ruled)
Triage 6450939210, verbatim: "Home reads
/me/apps, so both surfaces have one source. Re-check the landing site on currentmain." Card Expected, verbatim: "Every launcher surface reads the same filtered list (/me/apps)." Card: "Not a data leak (object permissions still apply)." No maintainer ruling.PM mechanism assumptions (measure; disproof welcome)
On
origin/mainfd246c22(read-only check):ui/packages/app-shell/src/console/home/HomePage.tsx≈L347useMetadata(), ≈L417filterActiveApps(apps)(utils/appRoute.ts≈L142 checks onlyactive/hidden), tiles toHomeAppsStrip≈L776.useMetadata().apps=GET /api/v1/meta/app(providers/MetadataProvider.tsx≈L133, ≈L1486).ui/reads/me/appstoday (git log -S "me/apps" -- uiis empty), so the app switcher (layout/AppSwitcher.tsx≈L68/86) very likely shows the hidden app too. Other readers of the same/meta/applist:console/AppContent.tsx≈L316–340,views/app-launcher-renderer.tsx≈L117,hooks/useNavMemberGates.ts≈L117,hooks/sharedUserFeeds.ts≈L1024. Measure which of these are launcher surfaces.GET /me/apps(packages/plugins/plugin-hono-server/src/current-user-endpoints.ts≈L1026–1093) merges the sets'tabPermissions(most visible wins) and dropshiddenapps./auth/me/permissionsalso carries the mergedtabPermissions.PM suggested route (optional; measurement wins)
One shared filtered feed (
/me/apps, as triage wrote) that Home and every launcher surface read, so they cannot disagree; when/me/appsis absent (no security plugin, 404), fall back to the/meta/applist rather than blanking Home.default_offis out of scope. A direct URL to a hidden app keeps opening (UI visibility, not access control; do not add a route guard). Tests: Home with/meta/app= [setup, account, showcase] and/me/apps= [setup, account] draws no showcase tile; the same for the switcher if you wire it; the 404 fallback shows all. Ablation: revert the filter; the Home test goes red.Scope
File surface:
ui/packages/app-shell/src/console/home/**,ui/packages/app-shell/src/utils/appRoute.tsor a new hook underui/packages/app-shell/src/hooks/,ui/packages/app-shell/src/layout/AppSwitcher.tsxandviews/app-launcher-renderer.tsxif they are launcher surfaces, tests beside them, root.changeset/. ⛔ No server change (if one is needed, stop and report).console/AppContent.tsxis a hot shared file: touch it only if a launcher surface lives there, and say so. Epic #26676 holdsconsole/appObjectScope.ts: ⛔ do not edit it.Tier
No path-derived mandate (
dispatch-gates --tier, read 2026-10-28T00:43Z).TIER_DEFAULT, efforthigh(M).Clause-②: no,Metadata-protocol: noneexpected.objectstack-fleet commentedon Oct 28, 2026
Claim: PM loop round 1
Session:
session_01JQwxbXpF772qWJjojJvRXwAccount:
os-warrenBranch:
claude/project-thread-8n1lrsWorktree:
objectstack-issue-26838Domain:
domain:uiSeat:
domain:ui#2File surface:
ui/packages/app-shell/src/console/home/**,ui/packages/app-shell/src/utils/appRoute.tsor a new hook underui/packages/app-shell/src/hooks/,ui/packages/app-shell/src/layout/AppSwitcher.tsxandui/packages/app-shell/src/views/app-launcher-renderer.tsxif they are launcher surfaces,console/AppContent.tsxonly for a launcher surface there, tests beside them, root.changeset/(stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
the console launcher surfaces read /api/v1/meta/app, which does not apply tabPermissions|GET /me/apps already drops hidden apps server-side|every user whose permission set hides an app still sees its Home tile (UI visibility, not a data leak)Thread-read: 6457561621
Premise: corrected 6457561621 (no
ui/file reads/me/appstoday, so the switcher premise on the card is wrong; Home defect holds onorigin/mainfd246c22)Serial constraints cleared: epic #26676 holds
console/appObjectScope.ts(not edited); no in-flight claim onconsole/home/**,appRoute.tsorAppSwitcher.tsx;AppContent.tsxis also on #26843's surface (seat 2, New-dialog form props), disjoint regions, second to land merges main.Dispatch order: comment 6457561621. Card thread
claude/project-thread-8n1lrsmay start editing.objectstack-fleet commentedon Oct 28, 2026
Claim amendment ·
domain:ui#2·session_01JQwxbXpF772qWJjojJvRXw· 2026-10-28T00:52ZClaim 6457602008 (branch
claude/project-thread-8n1lrs) widens its file surface by one file, at the card thread's request:ui/apps/console/src/AppContent.tsx, theConsolePermissionsScoperegion only (mountLauncherAppsProviderinsideMePermissionsProvider). Reason, as the dev measured it: the ui network-escape guard reds any test whose render reaches a relative fetch, so the/me/appsread is an explicitly composed provider, andConsolePermissionsScopeis the only common ancestor of/homeand/apps/:appName. No other in-flight claim lists this file (#26843 edits the app-shellconsole/AppContent.tsx, a different file). Everything else in the claim stands.objectstack-fleet commentedon Oct 28, 2026
os-dev-report
{ "issue": 26838, "status": "done", "branch": "claude/project-thread-8n1lrs", "pr": "https://github.com/objectstack-ai/objectstack/pull/27021", "head": "cbe8d370", "base": "0b78a20b", "session": "session_01JQwxbYwBbR8jCpWPE5Kosz", "premise_still_valid": true, "summary": "Home defect holds on origin/main; the card's switcher premise does not: no ui/ file read /me/apps, and AppSwitcher and the app:launcher block read /meta/app like Home (the dispatch's correction, confirmed). New hooks/useLauncherApps.tsx: LauncherAppsProvider reads GET /api/v1/me/apps once per user (again only when the active /meta/app name set gains a name the held answer was not asked about), and useLauncherApps(apps) returns filterActiveApps(apps) minus every asked-about app the answer did not list, keeping the /meta/app entries. No provider, 404 or a failed read narrows nothing (non-404 warns once; 404 not re-asked). Home's tiles and System Settings link, the AppSwitcher menu and the app:launcher block read it; Home's loading gate waits for the first read. Mounted once in ui/apps/console/src/AppContent.tsx ConsolePermissionsScope (surface amendment 6457698059). A provider, not a self-fetching hook, because the ui network-escape guard reds every test render that reaches a relative fetch and about 130 test files render these surfaces.", "tests": "New: useLauncherApps-26838 (8), HomePage.launcherHiddenApps-26838 (4), AppSwitcher.launcherHiddenApps-26838 (3): 15/15 passed. Affected set (284 app-shell + console files naming the touched surfaces, plus console/home and layout test dirs): 2359 passed, exit 0, on 9f4f6f31 (the later origin/main merge touched none of these paths). type-check @object-ui/app-shell exit 0; type-check @object-ui/console exit 0 after the console closure build. Ablations via scripts/ablation-replace.mjs under the lock, anchor 1 -> 0, restored blob == HEAD, git diff HEAD empty: HomePage tiles from activeApps -> 2 failed / 2 passed; hook predicate return true -> 7 failed across the three files; AppSwitcher back to its inline filter -> 2 failed / 1 passed. No dist leg: tests import app-shell sources by relative path.", "gates": "dispatch-gates --commands on cbe8d370 (origin/main merged): 34 derived, every one exit 0 (incl. node scripts/check-sdui-manifest.mjs and pnpm --dir ui exec vitest run scripts/); --ran: 34 derived, 34 run, 0 NOT-MEASURED, exit 0. Outside the derivation, exit 0: pnpm --dir ui run check:spec-symbols, check:new-line-citations, check:test-path-roots. CI check-runs on PR 27021: in_progress at report time.", "line_budget": "11 files, +822 / -15 (837 changed lines, under the 3000 threshold); about 640 of the added lines are the three test files and the hook; no ratchet-governed file touched.", "deviations": [ "File surface extended by the seat (amendment 6457698059) to ui/apps/console/src/AppContent.tsx, ConsolePermissionsScope region only; asked before editing it.", "Changeset names @object-ui/console as well as @object-ui/app-shell: the console package is public and ships the app-shell code in its dist.", "PR body: the platform attribution block sits on lines 1-2, so Fixes #26838 is line 3; .github/PULL_REQUEST_TEMPLATE.md headings folded into the os-dev section order (What changes / Tests / Acceptance notes / Verification / Human Minimum).", "The session-context's MCP assignee/reviewer step skipped: the dispatch bans MCP; the relay set the assignee." ], "files_changed": [ ".changeset/26838-launcher-hidden-tabs.md", "ui/apps/console/src/AppContent.tsx", "ui/packages/app-shell/src/console/home/HomePage.tsx", "ui/packages/app-shell/src/console/home/__tests__/HomePage.launcherHiddenApps-26838.test.tsx", "ui/packages/app-shell/src/hooks/__tests__/useLauncherApps-26838.test.tsx", "ui/packages/app-shell/src/hooks/index.ts", "ui/packages/app-shell/src/hooks/useLauncherApps.tsx", "ui/packages/app-shell/src/index.ts", "ui/packages/app-shell/src/layout/AppSwitcher.tsx", "ui/packages/app-shell/src/layout/__tests__/AppSwitcher.launcherHiddenApps-26838.test.tsx", "ui/packages/app-shell/src/views/app-launcher-renderer.tsx" ], "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, assignee set by the relay); this report comment (POST /repos/objectstack-ai/objectstack/issues/26838/comments via post-stamped)", "open_questions": [], "out_of_scope_findings": [ "carrier: seat · noted, not filed — CommandPalette app lists (HomeLayout passes apps ?? []; the in-app palette likewise) still list a tabPermissions-hidden app; seat to decide whether it is a launcher surface", "carrier: seat · noted, not filed — default-app landing in ui/packages/app-shell/src/console/AppContent.tsx (launcherApps there) filters active/hidden only, so /apps with no segment can land on a tab-hidden app", "carrier: none · noted, not filed — GET /me/apps answers 200 with an empty apps list when its handler throws (outer catch in current-user-endpoints.ts), indistinguishable from every app hidden; read-only inference from source, not reproduced" ] }objectstack-fleet commentedon Oct 28, 2026
Claim amendment ·
domain:ui#2·session_01JQwxbXpF772qWJjojJvRXw· 2026-10-28T01:57ZClaim 6457602008 (branch
claude/project-thread-8n1lrs), after the seat's review of PR #27021 (REWORK, one patch round): the card's Expected — "Every launcher surface reads the same filtered list (/me/apps)." — also covers the two surfaces the PR's Acceptance notes leave open, so the file surface widens to:ui/packages/app-shell/src/console/home/HomeLayout.tsx(theappsit hands the command palette),ui/packages/app-shell/src/chrome/CommandPalette.tsxand its in-app caller if the palette's app list is assembled there, andui/packages/app-shell/src/console/AppContent.tsxthelauncherAppsdefault-app landing region only (≈L340–375). #26843 (seat 2,claude/project-thread-58h2qh) edits the New-dialog form props in that same file, a disjoint region; second to land merges main. Everything else in the claim and amendment 6457698059 stands.objectstack-fleet commentedon Oct 28, 2026
Landing held ·
domain:ui#2·session_01JQwxbXpF772qWJjojJvRXw· 2026-10-28T03:01ZPR #27021 (ACCEPT 6459467327, which supersedes REWORK 6458597628) is green on head
7b20f2d51d. Every check-run succeeded or was path-skipped, including the PR-body guards and Check Changeset that re-ran after the seat's body edit.mergeable_stateis clean and the PR is not governed. This session's permission classifier refused the landing stroke (pr_ready+automerge_enablethrough the fleet-write relay, "Merge Without Review") on PR #27013 and on PR #27035 at 2026-10-28T02:42Z, so the seat does not retry it here. It asks the maintainer to mark the PR ready for review and enable auto-merge.