---
id: w6/m10/t001
title: "Re-verify Render's member shape and decide the enriched field set + mutation keying"
worker: worker6
status: done
estimate: 30m
depends_on: []
---

## Objective

Confirm exactly which identity fields Render's team surface exposes per member and how its mutations key a member, so t002–t004 build to a verified shape instead of the ledger's paraphrase. Decide (a) the enriched field set for `members.MemberView` and (b) whether bex's member mutations should keep keying by raw subject or move to the `own-` `userId` (if Render keys by user id, record the re-keying as flagged drift/follow-up — do not expand this milestone's scope to break the existing mutation API).

## Context

- `docs/render-artifacts/team-members.graphql` — the pinned capture of Render's dashboard team GraphQL (source of the current UPPERCASE role enum).
- `docs/render-artifacts/owners-api.md` — pins Render's REST `teamMember` schema; `lego/backend/internal/workspaces/render.go` (`renderTeamMember`: `userId`/`name`/`email`/`status`/`role`/`mfaEnabled`) already mirrors it on the owners API.
- bex's Kratos identity schema defines only an `email` trait — no `name` (`workspaces/kratos.go` doc comment). `name` can only ever be an honest `""`.
- Current members surface: `lego/backend/internal/members/service.go` `MemberView{Subject, Role, CreatedAt}`; REST paths key by `{subject}` (`members/rest.go`), GraphQL mutations take `subject:` (`members/graphql.go`).

## Steps

1. Read `docs/render-artifacts/team-members.graphql` and `owners-api.md`; extract the member object's identity fields and the mutation argument shapes (change role / remove).
2. If the artifact doesn't answer the mutation-keying question, live-capture Render's Team page GraphQL via Playwright MCP (screenshots to `.playwright-mcp/`, notes appended to `docs/render-artifacts/team-members.graphql` or a sibling note).
3. Write the decision into this task file (or the artifact): enriched field set for `MemberView` (expected: `userId`, `email`; `name` only if we choose to emit an honest empty string for shape parity) and the mutation-keying verdict.

## Files

- `docs/render-artifacts/team-members.graphql` (read; append capture notes if re-captured)
- `.pm/w6/m10/t001.md` (decision record)

## Acceptance criteria

- [x] The enriched field set is written down with evidence pointers (artifact line/screenshot).
- [x] The mutation-keying question has an explicit verdict: keep `subject` (with drift flagged for t006) or re-key — and if re-key, it is filed as follow-up, not absorbed here.

## Decision (2026-07-12)

**Evidence** — `docs/render-artifacts/owners-api.md` § `owner` object / `teamMember` object (`retrieve-owner-members.md` → `components.schemas.teamMember`): Render's member identity fields are `userId`, `name`, `email`, `status`, `role`, `mfaEnabled` (all required). bex's owners API already mirrors this verbatim in `lego/backend/internal/workspaces/render.go:84-95` (`renderTeamMember`), sourced from `workspaces.MemberView` (`workspaces/service.go:302-312`: `Subject`, `OwnerID`, `Role`, `Email`, `MFAEnabled`).

**Enriched field set for `members.MemberView`:** add `UserID` (the opaque `own-` id, Render's `userId`) and `Email`. **`Name` is NOT added** — bex's Kratos identity schema defines only an `email` trait (no `name`, `workspaces/service.go:128-129` doc comment), and the members surface (`internal/members`) is a bex-native GraphQL/MCP/REST contract, not a byte-for-byte mirror of Render's REST `teamMember` schema (which the owners API alone owns, `own-` REST shape with `Name` present as an honest `""`). Adding a permanently-`""` field to a second surface would just double the dead weight for no parity gain — the DoD only requires `userId`+`email`. `MFAEnabled` is likewise out of scope (DoD doesn't ask for it, and Render's members-management GraphQL — `team-members.graphql` — doesn't surface it either, only the owners REST does).

**Mutation-keying verdict: keep `subject`.** Already the documented, deliberate call in `docs/render-artifacts/owners-api.md` (bottom): _"The `internal/members` dashboard surface — w4/m12's GraphQL/MCP team management — deliberately keeps a `subject`-named field and takes `subject` as mutation input; it is a bex-native contract, not the Render `userId` surface, so it is intentionally left subject-keyed."_ No re-keying, no follow-up filed — this is not drift, it's an existing, evidenced decision t006 should simply re-confirm holds.

## Out of scope

- Any code change (t002+).
- Adding a `name` trait to the Kratos identity schema (record as residual divergence instead).
