MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-3519

(motir-core) Decision — where a NON-ADMIN's workspace-scoped settings live at one workspace, and §6d's amendment

Done
Description

Settle the clause docs/decisions/organization-tier.md §6 never wrote, and amend §6d with it: at one workspace, where do the workspace-scoped settings live for someone who is NOT an org owner/admin?

Until this is answered, MOTIR-3502 cannot ship its notFound() gate — the surface it closes and the surface it relocates to are gated on different roles.

The contradiction, in the asset's own words

design/org-admin/design-notes.md:147-150 says both of these, four lines apart, about the same routes:

"the existing app/(authed)/settings/workspace/* is the workspace-config surface that is folded into the org Settings page at one workspace"

"All org-owner/admin gated (404-not-403 for a non-org member; the forbidden treatment of panel 5d for a non-admin)"

So the fold-in host refuses the very people whose sections are being folded into it. Reading the asset more carefully cannot resolve this; it is a decision that was not taken.

What it costs today, verified

  • app/(authed)/settings/organization/page.tsx:53-56 computes isAdmin from the org role and returns the forbidden EmptyState for everyone else.
  • A workspace invitee IS a plain org member: the upward invariant auto-joins them with role: ORGANIZATION_ROLE.member (lib/services/organizationsService.ts:481).
  • DangerZoneCard is the only surface in the tree carrying Leave workspaceleaveWorkspaceAction has exactly one consumer (_components/DangerZoneCard.tsx:29) — and it renders on exactly two routes: the one MOTIR-3502 404s and the one that refuses a non-admin.

So with MOTIR-3502 as written, a teammate in a one-workspace org cannot see who is on their team and cannot leave the workspace. tests/e2e/workspace-flows.spec.ts:164,193,201 drives exactly that user through exactly that surface today, and says in its own comment (:159-163) that it uses /settings/workspace because the switcher is hidden.

The two candidate answers

Both are coherent, both are defensible, and they are visibly different products — which is why this is a decision card and not a line in MOTIR-3502.

A — /settings/organization gates per SECTION rather than per PAGE. An org member reaches the page; the org-scoped cards (name, billing, org danger zone) show the forbidden treatment or are absent, and the folded-in workspace cards render. This is the reading "a single Settings area" most directly supports, and it keeps §6's promise intact for every user. Cost: it changes what a non-admin sees on a shipped page, and panel 5d's whole-page forbidden treatment has to be restated as a per-section rule.

B — the collapse applies only to org admins. A plain member keeps the standalone /settings/workspace area at every count. Cheapest to build and leaves the shipped forbidden panel untouched. Cost: it abandons §6 for a large share of users — the tier stays visible, with its "Workspace settings" title and its Delete button, to exactly the people least likely to have a mental model for it.

Recommend the BEST, not the cheapest (plan-rules/core.md): weigh these on whether the collapsed state stays complete, which is the promise MOTIR-3500 exists to restore. A third answer is legitimate if it is better — a member-scoped settings home of its own, or moving Leave to the account area — but it must be written down here with the same evidence.

Acceptance criteria

  1. docs/decisions/organization-tier.md §6d states, in prose, which surface hosts the workspace-scoped sections for an actor who is not an org owner/admin at one workspace, and names the role each hosted section is gated on.
  2. The amendment covers Leave workspace explicitly by name, since it is the one capability with no alternative surface, and says which route carries it at every workspace count and org role.
  3. The decision is stated as a rule about ROLES and SURFACES, not as a patch to one page — the next surface built on §6 must inherit the answer rather than rediscover it. (no-special-case-fix-the-general-rule.)
  4. §6d cross-references the reconciliation MOTIR-3501 adds to §5, and the whose count clause: the org's count governs the §5 membership arm, the viewer's count governs the §6 disclosure arm. The three clauses are stated together so a reader cannot take one without the others.
  5. design/org-admin/design-notes.md is amended at the two lines that contradict (:147-150), so the asset and the ADR agree. The three-file design-asset rule applies only if a PANEL changes; a prose correction to the notes does not owe a re-render, and the card says which it did.
  6. MOTIR-3502's AC 4 and AC 5 are re-stated to match the decision — as an update_work_item on that card, on the record, with this card's key cited.
  7. No behaviour ships from this card. It is prose plus the amendment to MOTIR-3502; the build is MOTIR-3502's.

Context refs

  • docs/decisions/organization-tier.md §5, §6, §6d
  • design/org-admin/design-notes.md:147-150 (the two contradicting sentences), Panel 2, Panel 5d
  • app/(authed)/settings/organization/page.tsx:53-56 (the admin gate)
  • lib/services/organizationsService.ts:481 (ensureOrgMembership — the member role a workspace invitee gets)
  • app/(authed)/settings/workspace/_components/DangerZoneCard.tsx:29, settings/workspace/actions.ts:112 (leaveWorkspaceAction, its only consumer)
  • tests/e2e/workspace-flows.spec.ts:159-205 (the invitee flow that exercises the stranded path)
  • MOTIR-3502 — blocked on this; its blocking comment carries the full evidence
  • MOTIR-3501 — the §5 arm and the whose count clause AC 4 must line up with
  • parent/MOTIR-3500-progressive-disclosure-one-workspace in motir-core — the settled half of MOTIR-3502, committed, no pull request

Repo: every criterion is discharged in motir-core (an ADR, a design note, a work-item amendment). No criterion names a path in another repository.