# V2 Feature Flag Service

This runbook covers `TODOS.phase-72.72.12.1.4`, `TODOS.phase-72.72.12.1.5`, and
`TODOS.phase-72.72.12.1.11`: a live-ops feature flag service for games that can
enable new game modes, disable broken features, instantly disable features with
a kill switch, gradually roll out functionality without a client patch, and
integrate client SDK caching for startup checks, periodic refreshes, and offline
play.

The service package is `@v2/feature-flag-service` at
`apps/v2/feature-flag-service/`. Its contract is
`V2/ue/Content/V2/LiveOps/FeatureFlagService_V2_Contract.json` and the
validation gate is `V2/ue/Tools/check-v2-feature-flag-service.py`.

## Feature Flag Workflows

The initial service covers:

- enabling `game-mode.arena-royale.enabled` remotely for a new game mode
- force-disabling `combat.parry-v2.enabled` when a broken feature must be
  removed immediately
- activating a kill switch to instantly disable a shipped feature by forcing its
  state to `force-disabled`
- gradually rolling out `live-event.weekend-boss-rush.enabled` by percentage

Operators can enable a new game mode, disable a broken feature, instantly
disable a feature with a kill switch, or gradually roll out a feature without a
client patch. Use the rollout endpoint to gradually roll out functionality by
percentage.

Primary package API:

- `buildV2FeatureFlagServiceSurface`
- `evaluateV2FeatureFlag`
- `updateV2FeatureFlag`
- `buildV2FeatureFlagKillSwitchSurface`
- `buildV2FeatureFlagClientPayload`
- `buildV2FeatureFlagClientCache`
- `planV2FeatureFlagClientRefresh`
- `readV2FeatureFlagFromClientCache`

## Delivery Flow

1. Live ops publishes a feature flag snapshot with definitions, remote states,
   version ID, environment, timestamp, and TTL.
2. The service validates duplicate flag keys, unknown remote states, supported
   categories, rollout percentages from 0 to 100, ISO timestamps, and
   `clientPatchRequired: false`.
3. Clients or backend services fetch
   `GET /v2/live-ops/feature-flags/{environment}`.
4. Operators update a flag through
   `POST /v2/live-ops/feature-flags/{environment}/flags/{flagKey}`.
5. Operators change rollout percentage through
   `POST /v2/live-ops/feature-flags/{environment}/flags/{flagKey}/rollout`.
6. Operators activate the kill switch through
   `POST /v2/live-ops/feature-flags/{environment}/kill-switches/{flagKey}`.
7. Operators inspect active kill switches through
   `GET /v2/live-ops/feature-flags/{environment}/kill-switches/active`.

`evaluateV2FeatureFlag` uses a stable account hash bucket for gradual rollout.
`forceDisabled` always wins over enabled state and rollout percentage so broken
features can be disabled immediately without waiting for a client patch.

## Kill Switch

`buildV2FeatureFlagKillSwitchSurface` is the dedicated operator command for a
critical incident. It takes the current feature flag surface, target flag key,
incident ID, operator, activation time, severity, reason, and next version ID.
The result publishes a new version where the target is `force-disabled`, rollout
percentage is 0, and there is no client patch required.

The kill switch response includes incident audit metadata, the previous ETag,
the new ETag, the force-disabled client payload, and a forced client refresh
plan. The refresh plan invalidates the previous ETag, exposes a cache bust
token, and caps `maxClientStalenessSeconds` so clients can instantly disable the
feature across all refresh-capable clients without waiting for a binary patch.

## Client SDK Integration

The client SDK helpers support three runtime paths:

- startup checks: fetch flags on startup when online or fail closed when no
  cache exists offline
- periodic refresh: fetch again after `refreshAt` while keeping the previous
  cache usable during the request
- offline play: use cached flags until `offlineExpiresAt`, then fail closed to
  disabled defaults

`buildV2FeatureFlagClientCache` stores the fetched payload with refresh and
offline-expiry timestamps. `planV2FeatureFlagClientRefresh` returns
`fetch-startup`, `fetch-periodic`, `use-cache`, `use-offline-cache`, or
`fail-closed`. `readV2FeatureFlagFromClientCache` reads cached flag state, marks
when a network refresh is needed, and returns disabled defaults after the
offline cache expires.

## Release Gates

Required gates:

- `feature-flag-service-package`
- `feature-flag-service-remote-toggle`
- `feature-flag-service-emergency-disable`
- `feature-flag-service-gradual-rollout`
- `feature-flag-service-client-payload`
- `feature-flag-service-ci-wired`
- `feature-flag-client-sdk-startup-check`
- `feature-flag-client-sdk-periodic-refresh`
- `feature-flag-client-sdk-offline-cache`
- `feature-flag-client-sdk-fail-closed`
- `feature-flag-client-sdk-ci-wired`
- `feature-flag-kill-switch-command`
- `feature-flag-kill-switch-force-disabled`
- `feature-flag-kill-switch-client-refresh`
- `feature-flag-kill-switch-no-patch`
- `feature-flag-kill-switch-audit`
- `feature-flag-kill-switch-ci-wired`

## Verification

```bash
pnpm --filter @v2/feature-flag-service test
pnpm --filter @v2/feature-flag-service typecheck
python3 V2/ue/Tools/check-v2-feature-flag-service.py
python3 V2/ue/Tools/check-v2-feature-flag-client-sdk.py
python3 V2/ue/Tools/check-v2-feature-flag-kill-switch.py
python3 V2/ue/Tools/check-v2-ci-workflow.py
python3 V2/tools/validate-v2-docs.py
```
