Summary
In a single-member workspace, the owner has no way to see a pending proposal whose owner is a different principal. The proposals list personal-filters to owner === caller unless showAll is passed, showAll is gated to effectiveRole === 'owner' on the server, but Studio only renders the "Show All" toggle when the workspace has more than one member. So a sole owner is permanently locked to their own drafts, with no UI to reveal the rest.
Where
packages/server/src/routes/proposals.ts:186 sets viewerId = (showAll && viewer?.effectiveRole === 'owner') ? undefined : getUserId(context), so without showAll the list is filtered to the caller's own proposals.
packages/studio/src/pages/Proposals.tsx:207-208 renders the ShowAllToggle only when effectiveRole === 'owner' && status === 'pending' && multiMember, where multiMember = (members?.items.length ?? 0) > 1. A single-member workspace never shows the toggle, so showAll can never be sent.
Repro
- Open a single-member workspace as its owner.
- Have a pending proposal whose
owner is not the current user (e.g. authored by another principal).
- Proposals to Pending shows "No Pending Proposals", and there is no toggle to reveal it.
Observed concretely while reviewing: a pending proposal with owner: "local-user" was invisible to a session logged in as a different user id, with no affordance to show it.
Why it matters
The common path is fine (you run a skill, the proposal is owned by you, you see it). The gap bites when a pending proposal's owner is not the sole member, for example:
- a proposal authored under a synthetic or service principal,
- a proposal inherited from a member who has since left,
- any future flow that submits drafts under an id other than the interactive caller.
In those cases the sole owner cannot review or apply the proposal at all through Studio.
Suggested direction
Show the owner the "Show All" toggle regardless of member count (drop the multiMember condition), or default an owner's pending view to all-drafts. The server-side owner gate already protects the bypass, so relaxing the client condition is safe. The multiMember guard assumes "sole member implies sole submitter", which does not hold once ownership can diverge from the interactive caller.
🤖 Generated with Claude Code
Summary
In a single-member workspace, the owner has no way to see a pending proposal whose
owneris a different principal. The proposals list personal-filters toowner === callerunlessshowAllis passed,showAllis gated toeffectiveRole === 'owner'on the server, but Studio only renders the "Show All" toggle when the workspace has more than one member. So a sole owner is permanently locked to their own drafts, with no UI to reveal the rest.Where
packages/server/src/routes/proposals.ts:186setsviewerId = (showAll && viewer?.effectiveRole === 'owner') ? undefined : getUserId(context), so withoutshowAllthe list is filtered to the caller's own proposals.packages/studio/src/pages/Proposals.tsx:207-208renders theShowAllToggleonly wheneffectiveRole === 'owner' && status === 'pending' && multiMember, wheremultiMember = (members?.items.length ?? 0) > 1. A single-member workspace never shows the toggle, soshowAllcan never be sent.Repro
owneris not the current user (e.g. authored by another principal).Observed concretely while reviewing: a pending proposal with
owner: "local-user"was invisible to a session logged in as a different user id, with no affordance to show it.Why it matters
The common path is fine (you run a skill, the proposal is owned by you, you see it). The gap bites when a pending proposal's owner is not the sole member, for example:
In those cases the sole owner cannot review or apply the proposal at all through Studio.
Suggested direction
Show the owner the "Show All" toggle regardless of member count (drop the
multiMembercondition), or default an owner's pending view to all-drafts. The server-side owner gate already protects the bypass, so relaxing the client condition is safe. ThemultiMemberguard assumes "sole member implies sole submitter", which does not hold once ownership can diverge from the interactive caller.🤖 Generated with Claude Code