Skip to content

fix(mobile): show the no-organization state for deep links without memberships - #8563

Merged
iscekic merged 2 commits into
mainfrom
drain/no-org-deep-link
Oct 23, 2026
Merged

iscekic merged 2 commits into
mainfrom
drain/no-org-deep-link

Conversation

@iscekic

@iscekic iscekic commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Change

OrganizationBoundary decided its settled states in an order that let an explicit deep-link org id outrank an empty membership list. An account with no memberships that opened a shared organization link therefore fell into Access denied with only Back to profile — no way to reach create/join, and no mention that the account simply has no organization.

apps/mobile/src/components/organization/organization-boundary.tsx now branches on the membership list first: zero memberships always renders the no-organization state, whose action opens the web organizations page with Back to profile as the exit. Access denied keeps exactly the case it describes — an override absent from a non-empty member list, where the account does have organizations but not that one. The stale-selection fallback is unchanged.

  • No new copy keys and no locale changes: the state reuses organization.boundary.noOrganization, noOrganizationDescription, openWebOrganizations, backToProfile.
  • Pending invitations are not surfaced here. Mobile exposes no self-facing invitation query (organizations.list returns memberships and inherited children; invitations appear only inside organizations.members.list for a member of that org), and the work item rules out a new backend API. The state points at the web organizations page, which owns join/accept.
  • Doc comment and the inline branch list updated to match the new precedence.

Tests

apps/mobile/src/components/organization/organization-boundary.mounted.test.tsx

  • New: a deep-link override with zero memberships renders the no-organization state, its website action opens the organizations page, and neither Access denied nor Select an organization appears.
  • Changed: the access-denied case now uses a non-empty member list, which is the case that copy is for.

Failing-before/passing-after was checked by planting origin/main's boundary module over the changed one and running the suite: the new deep-link case failed with expected [ 'Access denied', … ] to include 'No organization'; with the fix all 10 cases in the file pass, and the hub-screen mounted suite passes too (17 tests across both files). tsc --noEmit and oxlint on the app are clean.

End-to-end evidence (Android emulator, local dev stack)

Test account with zero memberships, signed in on the emulator; the deep link /organizations/<org-id>/overview maps to the hub route.

  1. Before (module from main, full bundle reloaded): the route rendered Access denied / You do not have access to this organization. / Back to profile.
  2. After: the same route renders No organization, the explanation, Open organizations on web and Back to profile.
  3. Tapping Open organizations on web opens the web organizations page for that account: breadcrumb Organizations with You're not part of any organizations yet. The tab's share sheet confirmed the target URL http://localhost:3000/organizations.
  4. Access denied still applies when the account does have memberships: covered by the mounted test above.

Screenshots are attached in a comment on this pull request.

Proxy answers

The owner's proxy gave these answers in the owner's place.

  1. Question: Zero-membership deep links should reuse the existing no-organization copy, or get a deep-link-specific description?
    Answer: Reuse existing copy
    Confidence: 0.75 · Precedent: Speed and least work: "do the least amount of work possible, with no drop in quality"; the brief asks for the same no-organization EmptyState
  2. Question: Pending invitations: is it confirmed out of scope for mobile to surface them here?
    Answer: Out of scope
    Confidence: 0.80 · Precedent: Trust the code over documents: "only trust code"; the brief makes invitations conditional on an existing mobile query and forbids a new backend API
  3. Question: Access-denied precedence after the fix: should a deep link absent from a NON-empty membership list stay access-denied?
    Answer: Keep access-denied
    Confidence: 0.90 · Precedent: Follows the work item directly: keep access-denied only for a deep-link override absent from a non-empty membership list
  4. Question: Android E2E scope for this fix?
    Answer: Deep link + web action
    Confidence: 0.90 · Precedent: Proof and verification: "when doing e2e verify taps doing the expected thing"; the brief requires confirming that the website action opens the page
  5. Question: The kilobot review failed for infrastructure reasons (environment preparation timeout) and no review ran on this head. How should I request a re-review?
    Answer: Push an empty commit
    Confidence: 0.82 · Precedent: Never accept blocked as an end state: a work item must converge; blocked is not an acceptable end state

…mberships

An account with no memberships that opened a shared organization link
carrying an explicit org id landed in access-denied with only a Back to
profile action. The settled-branch order gave an absent deep-link
override precedence over the empty membership list, so the
no-organization state, which offers the web organizations page where
create and join live, was skipped.

The boundary now decides the no-organization state first, from the
membership list alone. Access denied keeps its own case: an override
absent from a non-empty member list, where the account does have
organizations but not that one.

Regression tests cover the deep-link zero-membership case and pin the
access-denied case to a non-empty member list. Verified on the Android
emulator with a test account that has no memberships: the deep link
renders the no-organization state and its action opens the web
organizations page.
@iscekic iscekic added drain Work item from the findings drain explorer:android Finding surfaced by the Android explorer labels Oct 22, 2026
@iscekic

iscekic commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

bot: End-to-end evidence from the Android emulator against the local dev stack, with a test account that has no organization memberships. The deep-linked organization route was opened twice: once with the boundary module from main, once with this branch.

Observed:

  1. On main, the route rendered "Access denied", "You do not have access to this organization.", and only "Back to profile".
  2. With this branch, the same route renders "No organization" with the explanation, "Open organizations on web", and "Back to profile".
  3. Tapping "Open organizations on web" opens the web organizations page for the same account: breadcrumb "Organizations" and "You're not part of any organizations yet". The opened tab's share sheet reported the target URL ending in /organizations.

Access denied for an organization the account is not a member of, while having other memberships, is covered by the mounted test in the changed file.

Organization route on main: access denied with only Back to profile

Same route with this branch: no-organization state with website action

After tapping the website action: web organizations page for the same account

The previous Kilo Code Review check ended with an environment
preparation timeout before any review ran, so no verdict was recorded
for this head. This empty commit re-requests the review without
changing the tree.
@kilo-code-bot

kilo-code-bot Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The boundary now decides the no-organization state from the membership list alone, and the changed branch is consistent with useOrgBoundary's returned values, with regression tests covering both zero-membership deep links and the retained non-empty access-denied case.

Assumptions: [INFERENCE] I did not run the test suite or typecheck (read-only review); verification relies on reading organization-boundary.tsx, useOrgBoundary/useOrganizationsList, and the mounted tests.

Files Reviewed (2 files)
  • apps/mobile/src/components/organization/organization-boundary.tsx
  • apps/mobile/src/components/organization/organization-boundary.mounted.test.tsx

Reviewed by deepseek-flash-latest · Input: 65.6K · Output: 6.3K · Cached: 735.1K

Review guidance: REVIEW.md from base branch main

@iscekic iscekic added the merge:human Substantive functional risk requires human review. label Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

drain Work item from the findings drain explorer:android Finding surfaced by the Android explorer merge:blocked:judge-unavailable Risk assessment unavailable merge:bot Bot-owned review; merge when ready once readiness passes and a review approves.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants