(motir-core) Hide the workspace-settings SURFACE at one workspace — fold Name / Members / Danger into org settings and 404 the area
The surface arm of MOTIR-3500 — ship §6d's settings collapse, which the header half of progressive disclosure shipped without.
docs/decisions/organization-tier.md §6: "At one workspace the workspace-settings surface is hidden … the single Settings home folds in the workspace-config sections." ShellTierNav.tsx:103 gates the switcher at >= 2 and nothing else is gated, so at count 1 a surface titled "Workspace settings" — carrying Name, Members and a Delete workspace danger zone — is reachable from four entry points, one of which renders only in the collapsed state.
⚠️ RE-SCOPED TWICE. Read this before building.
2026-08-25 — the fold-in TARGET refuses a non-admin. /settings/organization returned the forbidden EmptyState to anyone who is not an org owner/admin (page.tsx:53-56), and a workspace invitee is a plain org member. So ACs 4+5 as first written left a teammate with no team roster and no route to Leave the workspace — its only surface (DangerZoneCard) renders on exactly the two routes the collapse closes to them.
2026-08-26 — MOTIR-3519 settled it: the settings home gates PER SECTION, not per page. Option A of the two candidates. ADR §6d and design/org-admin/design-notes.md now both carry the rule; this card's ACs 4, 5 and 9 are its build.
The general form the decision states, which this card must implement rather than special-case: relocating a surface preserves its GATE. A hidden tier changes what the product NAMES, never what a user may DO. Concretely — and note that rename and delete are membership-gated, not admin-gated (workspacesService.renameWorkspace / deleteWorkspace assert membership only), so hosting these for a plain member widens nothing:
section on /settings/organization | who sees it |
|---|---|
| org-scoped (org name, billing, org danger zone) | org owner/admin only — a plain org member gets panel 5d's forbidden treatment for those sections |
| the folded-in workspace sections (Name, Members, Danger zone) | any member of that workspace |
| nothing at all | a non-member of the org — 404, never 403 |
Already built — committed on parent/MOTIR-3500-progressive-disclosure-one-workspace, no pull request
Resume from that branch, not from origin/main. tsc clean, 42 assertions green. Settled and unaffected by the decision:
lib/workspaces/tierDisclosure.ts(+ its.serverhalf) — the reveal predicate, computed ONCE for the shell, the entry points and the route's own gate, replacing the lone>= 2literal inShellTierNav. Split because two readers are'use client'.- ⚠️ The predicate is the VIEWER's workspaces in the active org, not the ORG's — what has always shipped, and correct for a disclosure rule. This is the OPPOSITE of what MOTIR-3501's §5 arm reads. ADR §5/§6 now say so explicitly. Do not unify them.
- The four entry points, two of them RE-POINTED rather than removed: the rail's no-project settings door and ⌘K's "Go to settings" target
/settings/organization, since AC 1 asks that no markup name the workspace area and with no active project that rail row is the only settings door there is. Only the UserMenu row — literally labelled "Workspace settings" — is absent. WorkspaceConfigCard→WorkspaceFoldInSection: a MOUNT of the same three cards.- The
revalidatePathfan-out — the cards render on two routes now. - The
en/zhpair, two dead keys dropped.
Still to build: the per-section gate (AC 4), the notFound() (AC 5), and the E2E re-point (AC 9).
Acceptance criteria
- Rendering the shell for an org with ONE workspace produces no markup naming the
/settings/workspaceAREA inUserMenu,AppCommandPaletteorSidebarNav's settings door — asserted grep-shaped on the exact href, so the workspace-SCOPED sub-routes are not caught by it. A re-pointed door satisfies this; the door need not vanish. ✅ built /settings/organizationat ONE workspace renders the workspace Name, Members and Delete-workspace cards in its stack, and the old "Open workspace settings" button is gone. ✅ built- Saving the workspace name from the folded-in card shows the new value on that same page without a manual reload (the
revalidatePathfan-out). ✅ built - [Set by MOTIR-3519]
/settings/organizationgates per section: a plain orgmemberreaches the page and sees the folded-in workspace sections for a workspace they belong to, while the org-scoped cards show panel 5d's forbidden treatment. An org owner/admin sees both. A non-member of the org still gets 404, never 403. - [Set by MOTIR-3519] At the collapsed count
/settings/workspaceanswers 404 for every actor — asserted on a production build, the status being the assertion — and every capability it carried has a route: the folded-in danger zone renders Leave workspace for a plain member of that workspace, asserted by name. /settings/workspace/github,/settings/workspace/gitlaband/settings/workspace/jobsanswer 200 at every workspace count and org role, unchanged.- At TWO workspaces every entry point renders and
/settings/workspaceis unchanged frommain. - No new
loading.tsxis added anywhere aboveapp/(authed)/settings/workspace, andtests/navigation/loading-boundary-guard.test.tsstays green. - Every consumer of the changed contracts is updated in the same PR.
tests/components/UserMenu-platform-door.test.tsxandSidebarNav-settings-door.test.tsxare already repaired on the branch;tests/e2e/workspace-flows.spec.ts:159-205is the one that matters — it reads the active workspace's name at/settings/workspacebecause the switcher is hidden (its own comment says so) and then has the invitee Leave there. Re-point it at the folded-in section; it is the end-to-end proof of AC 5's second half.
Context refs
docs/decisions/organization-tier.md§6 + §6d (the per-section rule, the Leave table, the whose count clause)design/org-admin/design-notes.md— the amended Where it lives block;design/workspaces/settings.pnglib/workspaces/tierDisclosure.ts+.server.ts— the shared predicateapp/(authed)/settings/organization/page.tsx(:53-56, the whole-page gate AC 4 replaces),_components/WorkspaceFoldInSection.tsxapp/(authed)/_components/{UserMenu,AppCommandPalette,SidebarNav,ShellTierNav,TopNav}.tsx,layout.tsxapp/(authed)/settings/workspace/page.tsx,actions.ts,_components/{NameCard,MembersCard,DangerZoneCard}.tsxlib/services/workspacesService.ts—renameWorkspace/deleteWorkspaceassert membership, not admintests/e2e/workspace-flows.spec.ts:159-205,tests/e2e/org-admin.spec.ts:269,304,378,tests/e2e/shell-a11y.spec.ts:65CLAUDE.md§ Aloading.tsxmay NOT sit above a route that decides existence
Repo: every criterion is discharged in motir-core.
Sizing: re-estimated 5 → 8 pts / 85 → 120 min by MOTIR-3519, which added the per-section gate. Still under the 13-point split signal, and it is NOT split: the doors, the rooms and the host's gate are one state — landing them separately leaves an interval where the doors are hidden and the rooms are unreachable, which is strictly worse than today.