@@ -175,19 +175,24 @@ export interface SkillMemberEntry {
175175}
176176
177177/**
178- * The canonical member roster for a skill: every CURRENT workspace member
179- * mapped through {@link resolveSkillRole}, so the list always matches what
180- * enforcement grants. Workspace admins surface as derived admins, explicit
181- * active rows as their role, revoked rows as removed (deny) entries, and —
182- * while the skill is workspace-shared — remaining members as implicit members.
183- * Explicit rows for users no longer in the workspace are ignored, exactly as
184- * enforcement ignores them.
178+ * The canonical member roster for a skill, scoped to what the viewer may see:
179+ * every CURRENT workspace member mapped through {@link resolveSkillRole}, so
180+ * the list always matches what enforcement grants. Workspace admins surface as
181+ * derived admins, explicit active rows as their role, and — while the skill is
182+ * workspace-shared — remaining members as implicit members. Revoked rows are
183+ * deliberate per-skill deny markers and exist to be restored, so they are
184+ * included only for skill-admin viewers; other members never learn who was
185+ * denied. Explicit rows for users no longer in the workspace are ignored,
186+ * exactly as enforcement ignores them.
185187 */
186- export async function listSkillMembers ( skillRow : {
187- id : string
188- workspaceId : string
189- workspaceShared : boolean
190- } ) : Promise < SkillMemberEntry [ ] > {
188+ export async function listSkillMembers (
189+ skillRow : {
190+ id : string
191+ workspaceId : string
192+ workspaceShared : boolean
193+ } ,
194+ viewer : { role : SkillMemberRole }
195+ ) : Promise < SkillMemberEntry [ ] > {
191196 const [ explicitRows , workspaceMembers ] = await Promise . all ( [
192197 db
193198 . select ( {
@@ -215,7 +220,10 @@ export async function listSkillMembers(skillRow: {
215220 workspaceAccess : { hasAccess : true , canAdmin } ,
216221 } )
217222
218- if ( role === null && row ?. status !== 'revoked' ) continue
223+ if ( role === null ) {
224+ // Entries only a deny marker would produce are admin-only data.
225+ if ( row ?. status !== 'revoked' || viewer . role !== 'admin' ) continue
226+ }
219227
220228 entries . push ( {
221229 id : row ?. id ?? `${ canAdmin ? 'workspace-admin' : 'workspace' } -${ wsMember . userId } ` ,
0 commit comments