---
id: w1/m8/t006
title: "Test coverage — catalog validation, plan↔tier mapping, default-plan, 400 paths"
worker: worker1
status: done
estimate: 30m
depends_on: [w1/m8/t004]
---

## Objective

Pin the behaviors this milestone ships with tests that fail on regression — no tautological or snapshot-everything tests.

## Context

- Behaviors worth pinning: the catalog validation suite (t001 — malformed YAML/dup ids/dup renderPlans/bad quantities fail); `resourcesForTier` against the catalog incl. empty/unknown ⇒ best-effort; `normalizeTier` accepting exactly the catalog ids with empty ⇒ `free` preserved; plan⇄tier spelling round-trip (`pro_plus` ⇄ `pro-plus`); the plan verb row-first for store-managed apps (`SetAppTier` called, CR untouched until the projector runs) vs CR-patch for bare CRs; view omits `plan` for unknown/empty tier; unknown plan ⇄ 400 with valid names listed; authz guard on the new verb (`TestAuthzGuardsEveryVerb` should catch it for free — confirm).
- Existing patterns: operator controller tests (envtest), `lego/backend/internal/apps` + `store` table tests, `TestSurfaceParityAndWiring` for adapter parity.

## Steps

1. Fill any gaps t001–t004 left uncovered (each task carries its own first-line tests).
2. One adversarial case per boundary: catalog with a duplicated renderPlan, plan update with `plan: "gold"`, plan update on a bare-CR app with the store wired (must not touch the store).

## Files

- `lego/types/tiers_test.go`, `lego/operator/internal/controller/*_test.go`, `lego/backend/internal/{apps,store}/*_test.go`

## Acceptance criteria

- [ ] Each shipped behavior above has a test that fails if it regresses.
- [ ] `make test` + backend tests green.

## Out of scope

- e2e/kind suites (`make test-e2e`).
