---
id: w6/m12/t008
title: "Test coverage: guards, role gating, and the settings flow"
worker: worker6
status: todo
estimate: 40m
depends_on: [w6/m12/t006]
---

## Objective

Meaningful tests for what this milestone shipped: every downgrade guard (members, services, per-user cap, out-of-plan roles) as a distinct failure case, the upgrade happy path, plan-gated invite/change-role, and the dashboard dialog's guard-error rendering. Assert real behavior and failure modes — no tautological coverage.

## Context

- Backend precedents: `internal/workspaces/workspaces_test.go` (+ the real-infra `workspaces_e2e_test.go`), `internal/members/members_test.go`, `members_surface_parity_test.go` (three-surface fragment pattern).
- Dashboard precedent: workspace settings tests from w6/m3/m5 (guard-phrase gating tests).

## Steps

1. Backend: table-drive `ChangePlan` guards + no-op + authz denial; extend the surface-parity test to the new mutation.
2. Members: out-of-plan role rejection on invite and change-role, per plan.
3. Dashboard: dialog renders inline guard error; successful change updates the cache.

## Files

- `lego/backend/internal/workspaces/workspaces_test.go`
- `lego/backend/internal/members/members_test.go`
- dashboard workspace-settings feature `__tests__/`

## Acceptance criteria

- [ ] Each guard has a failing-case test that names its exact error; `go test ./...` + `yarn vitest run` green

## Out of scope

- Live-cluster e2e beyond the existing `workspaces_e2e_test.go` pattern
