# V2 One-Handed Control Schemes

This runbook covers `TODOS.phase-72.72.13.2.4`: full gameplay control schemes
for left-hand-only and right-hand-only controller use.

## Runtime Surface

One-handed controls extend the V2Input accessibility profile model:

- profile: `FV2OneHandedInputProfile`
- side enum: `EV2OneHandedInputSide`
- scheme row: `FV2OneHandedInputScheme`
- action mapping row: `FV2OneHandedInputActionMapping`
- resolved scheme: `FV2ResolvedOneHandedInputScheme`
- source library: `UV2InputBlueprintLibrary`
- config asset: `UV2InputConfigAsset`
- UI scheme: `FV2OneHandedControlSchemeSpec`
- persistence snapshot: `FV2PlayerSettingsSnapshot`
- save game: `UV2SaveGame`
- persistence subsystem: `UV2PersistenceSubsystem`
- contract:
  `V2/ue/Content/V2/Input/Accessibility/OneHandedControlSchemes_V2_Contract.json`
- focused checker: `V2/ue/Tools/check-v2-one-handed-control-schemes.py`

## Behavior

Profiles default to `Controls.OneHanded.Off`. Players can select
`Controls.OneHanded.Left` or `Controls.OneHanded.Right`; each enabled scheme
must map all 33 V2 gameplay actions with stable `OneHanded.Left.*` or
`OneHanded.Right.*` binding tokens scoped to a single controller hand surface.

The UI keeps the existing Controls row and pause-flow selector, but each visible
left/right choice now references the matching input scheme id and advertises
full gameplay coverage.

## Validation

The scheme table must include exactly the canonical off, left, and right ids.
The off scheme carries no remapped gameplay actions. Left and right schemes must
each cover every `EV2InputActionId`, including movement, attacks, defense,
grapple, team, presentation, environment, and ruleset-specific actions. Mapping
slots must match the action catalog and binding tokens must be single-hand
scoped and unique within the scheme.

## Persistence

`FV2PlayerSettingsSnapshot` stores `OneHandedInputProfile` with startup flags.
`UV2SaveGame::SaveOneHandedInputProfile` persists a validated profile per
player, `GetStartupOneHandedInputProfile` resolves it on startup, and
`MarkOneHandedInputAppliedOnStartup` records the before-gameplay apply time.
`ValidateSave` rejects profiles whose account id does not match the save header.

## Verification

Run these checks after changing one-handed control schemes:

```bash
python3 V2/ue/Tools/check-v2-one-handed-control-schemes.py
python3 V2/ue/Tools/check-v2-input-module.py
python3 V2/ue/Tools/check-v2-profile-save-game.py
python3 V2/ue/Tools/check-v2-persistence-module.py
python3 V2/ue/Tools/check-v2-accessibility-feature-set.py
python3 V2/ue/Tools/check-v2-ui-module.py
python3 V2/ue/Tools/check-v2-settings-ui.py
python3 V2/ue/Tools/check-v2-pause-practice-flow.py
python3 V2/ue/Tools/check-v2-ci-workflow.py
python3 V2/tools/validate-v2-docs.py
python3 -m py_compile V2/ue/Tools/check-v2-one-handed-control-schemes.py V2/ue/Tools/check-v2-ci-workflow.py
python3 -m json.tool V2/ue/Content/V2/Input/Accessibility/OneHandedControlSchemes_V2_Contract.json
```

Automation coverage:

- `V2.Input.Module`
- `V2.Persistence.Module`
- `V2.Persistence.ProfileSave.AssetContract`
- `V2.UI.Module`
- `V2.UI.PausePracticeFlow.AssetContract`

## Horde Gates

- `one-handed-input-source`
- `one-handed-full-gameplay-coverage`
- `one-handed-ui-selection`
- `one-handed-per-player-persistence`
- `one-handed-startup-apply`
- `one-handed-ci-wired`
