# Owners API parity drift — from w6/m2/t006

Field-level diff of the shipped `/v1/owners` REST + MCP surface against the pinned schema (`docs/render-artifacts/owners-api.md`) found three intentional divergences, each already commented at its source:

1. **`own-` user ids + caller-only resolution.** _Partly addressed by `w6/m7` (2026-07-11)._ bex now **mints** stable opaque `own-<xid>` ids per identity (`id.Owner`, persisted subject⇄own-id in `owner_ids`) and reports them as the members `userId` — no more raw Kratos subject leaking there. Two adjacent Render behaviors remain **deliberate non-goals** (recorded, not built): (a) owner `type` stays `"team"` — bex mints only `tea-` team workspaces, has no personal-account/user-owner entity, so `type: "user"` is never emitted; (b) `GET /v1/owners/{own-id}` resolves the **caller's** default workspace only — resolving a PEER's own- id is not a real Render workflow (a key only reaches its own workspaces) and has **no consumer**, so it stays caller-scoped via `core.Base.Tenant` (`lego/backend/internal/workspaces/service.go`, `ownIDPrefix`/`defaultWorkspace`). See `docs/render-artifacts/owners-api.md`.
2. ~~**No cursor pagination.**~~ **RESOLVED 2026-07-11.** `GET /v1/owners` now honors Render's `cursor`/`limit` params (default 20, min 1, max 100) via a shared `core.Page`/`core.PageParams` helper (`internal/core/pagination.go`), sliced by each owner's workspace-id cursor; paging past the end returns an empty array (the client's stop signal). Applied to `GET /v1/services` too (cursor = service name) so the whole REST list surface is consistent — the divergence was never owners-only. Covered by `internal/core/pagination_test.go` + `TestOwnersREST_Pagination`.
3. ~~**`databaseName`'s `ownerId` filter is a documented no-op today.**~~ **RESOLVED by `w6/m4` (`af1f9b3`, 2026-07-10).** The managed-Postgres create path now stamps `core.LabelTenant` (+ `core.LabelWorkspace`) on the `Database` CR (`internal/postgres/service.go` create path), `ListPostgres(ctx, ownerID)` authorizes `can_view` on the workspace and filters by that label — no longer an empty no-op — and `PostgresView.OwnerID` reads the label back. Covered by `internal/postgres/ownerid_test.go`. KeyValue got the same treatment in the same milestone.

None of these are silent — each is commented at its source and reflected in `docs/render-artifacts/owners-api.md`. No REST/GraphQL/MCP mutation exists under `/v1/owners` (verified: `internal/workspaces/rest.go` registers GET only).

**Triage outcome (closed 2026-07-11).** All three items are now resolved or reduced to documented non-goals. Items 2 (pagination) and 3 (datastore `ownerId` filter) are **implemented**. Item 1's real gap — leaking raw Kratos subjects as member `userId`s — is closed by `w6/m7` (bex now mints opaque `own-` ids). Its two residuals (owner `type: user`, peer `own-` resolution) are **structural non-goals** for bex's all-teams model, recorded at source + in `docs/render-artifacts/owners-api.md` — not deferred work. No pending action.

Source: w6/m2/t006 parity pass, 2026-07-09.
