---
path: /studio/experimentation-feature-flags
surface: studio
domain: governance
auth: signed-in + studio entitlement
source: apps/oshun/web/src/app/studio/experimentation-feature-flags/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; body
  re-derived 2026-06-03 from current source (lane-console architecture).
  2026-07-03 addendum: real-dev-infra Playwright coverage added in
  apps/oshun/web/e2e/studio-experimentation-feature-flags.spec.ts. The spec
  verifies anonymous redirect, real admin catalog load, deterministic FNV-1a
  evaluation through the live BFF, exact browser POST body shape, quick actions,
  44px form/link hit targets, loading, service failure, malformed catalog,
  catalog-network failure, malformed JSON with zero POSTs, live BFF validation
  detail, evaluate-network failure, and non-admin unauthorized.'
---

# Studio · Experimentation and Feature Flags

## Purpose

Evaluate feature flags and assign experiments with the real deterministic
engine: the Flag Evaluation Lane runs FNV-1a per-(user, key) bucketing, rollout
plus targeting-rule flag evaluation, and sticky weighted experiment assignment.
It is a live admin console wired to `/v1/admin/studio/experimentation-flags`,
not an in-page simulation.

## Entry points

- **Direct URL / bookmark** — `/studio/experimentation-feature-flags` (signed-in
  and studio entitlement; admin scope required to evaluate)
- **Sibling Studio routes** — reached via the quick-action panel on
  performance-budgets, observability-operational-dashboards,
  metrics-analytics-instrumentation, and other operations pages

## Layout regions

`page.tsx` mounts `<ShellLayout active="studio">` and renders
`<StudioExperimentationFeatureFlagsWorkspace />` followed by a single `panel` of
quick-action links.

- **Shell**: `ShellLayout` chrome with the Studio tab active
- **Workspace heading**: `WorkspaceHeading` renders the page `<h1>` "Studio
  Experimentation & Feature Flags", followed by the
  `data-experimentation-feature-flags-summary` paragraph
- **Flag Evaluation Lane**: an `<h2>` `data-exp-lane-heading` ("Flag Evaluation
  Lane") section with the load states and, when ready, the evaluate form and
  result tables
- **Quick-actions panel** (`data-exp-quick-actions`): 5 sibling `quickAction`
  `Link`s — "Open Performance Budgets workspace", "Back to Observability and
  Operational Dashboards workspace", "Back to Metrics and Analytics
  Instrumentation workspace", "Back to Resilience and Error UX workspace", and
  "Back to Background Jobs and Progress UX workspace". No self-link and no Route
  Map panel.

## States

- [x] **Loading** — `data-exp-loading` ("Loading flag evaluator…")
- [x] **Unauthorized** — `data-exp-unauthorized` ("Access restricted.") on
      401/403
- [x] **Error** — `data-exp-error` on a failed catalog GET
- [x] **Ready / form** — `data-exp-enums` ("N rule ops · N flag reasons") plus
      the `data-exp-form` evaluate form seeded with `DEFAULT_PAYLOAD`
- [x] **Result** — `data-exp-result` with the `data-exp-headline`
      (`data-exp-on-count` / `data-exp-off-count`), the `data-exp-flags` table
      of `data-exp-flag-row` rows (`data-flag-key`, `data-on`, `data-reason`,
      `data-exp-flag-bucket`, `data-exp-flag-reason`), and the optional
      `data-exp-experiments` list (`data-exp-experiment-row`, `data-variant`)
- [x] **Evaluate error** — `data-exp-evaluate-error` for invalid JSON or a
      non-200 response
- [x] **Offline** — catalog GET fails closed to the error panel; the evaluate
      POST surfaces the generic error when the network is unreachable
- [x] **Gated** — admin scope denied → `data-exp-unauthorized`; the route itself
      is proxy-gated to signed-in + studio
- [ ] **Standalone PWA** — renders within the shell; no URL-bar dependency

## Interactions

- [x] **Evaluation (JSON)** — `textarea` `data-exp-payload`,
      `aria-label="evaluation json"`, seeded with `DEFAULT_PAYLOAD` (the user
      context, flag definitions with rollout + targeting rules, and experiment
      definitions)
- [x] **Evaluate flags** — `button` `data-exp-submit` (`type="submit"`); POSTs
      the parsed payload to `/v1/admin/studio/experimentation-flags/evaluate`,
      setting `data-exp-result` on a 200 with a valid `result`, or
      `data-exp-evaluate-error` otherwise
- [x] **Quick-action links** — each `quickAction` `Link` navigates to its
      sibling Studio route (see Layout regions for the 5 targets)

## E2E coverage

- `apps/oshun/web/e2e/studio-experimentation-feature-flags.spec.ts` runs against
  the real Next shell and local BFF.
- The happy path plants an admin session, lets the browser
  `GET /v1/admin/studio/experimentation-flags` and
  `POST /v1/admin/studio/experimentation-flags/evaluate` reach the live BFF, and
  captures the bearer headers plus exact parsed POST body before fallback.
- It proves the deterministic engine results for the default payload: 2 on / 3
  off, `new-checkout` bucket `48.14` → `in_rollout`, `dark-mode` →
  `out_of_rollout`, `beta-gate` → `rule_excluded`, `legacy` → `flag_disabled`,
  and `homepage-cta` sticky assignment to `variant-a` at bucket `76.12`.
- It covers anonymous redirect, non-admin 403, loading, 503, malformed catalog,
  aborted catalog GET, malformed JSON with zero evaluate POSTs, real BFF
  mis-summed experiment-weight validation detail, evaluate POST network failure,
  quick-action hrefs, and 44px minimum hit targets for the textarea, submit
  button, and five quick-action links.

## Data & contracts

- **Reads**: `GET /v1/admin/studio/experimentation-flags` on mount — returns the
  catalog (`ruleOps[]`, `flagReasons[]`)
- **Writes**: `POST /v1/admin/studio/experimentation-flags/evaluate` — returns
  `{ onCount, offCount, flags[{ key, bucket, on, reason }], experiments[{ key, assignedVariant, bucket }] }`
- **Realtime**: none
- **Caching**: client `fetch` with `cache: 'no-store'`; `buildBffAuthHeaders()`
  attaches the bearer token; SSR shell only
- **Auth/role check**: admin-scoped fail-closed — `admin:*` or `admin:studio`,
  401/403 under the studio workspace gate

## Cross-references

- Parent: [`../studio-overview.md`](../studio-overview.md)
- Siblings:
  [`studio-launch-readiness-governance.md`](./studio-launch-readiness-governance.md),
  [`../operations/studio-metrics-analytics-instrumentation.md`](../operations/studio-metrics-analytics-instrumentation.md),
  [`../operations/studio-performance-budgets.md`](../operations/studio-performance-budgets.md)
- Component source:
  `apps/oshun/web/src/components/studio/StudioExperimentationFeatureFlagsWorkspace.tsx`
  behind `/v1/admin/studio/experimentation-flags`

## Open questions / known gaps

- [ ] Confirm whether the page will gain a breadcrumb/Route Map panel like other
      Studio surfaces, or keep the flat quick-action panel
- [ ] Document the live flag/experiment registry the lane should evaluate
      against once it moves off a pasted JSON payload
- [ ] Add a dedicated installed-PWA/standalone display-mode check for this
      route; the current coverage verifies shell rendering but not installed
      standalone launch behavior.
