* fix(mobile): recover pairing save when the Android keystore alias is unusable
Orca Mobile could reach a state where pairing succeeded but the host could
never be saved, with every attempt failing identically:
Could not encrypt the value for key 'orca.host-token.host-...'
under keychain 'key_v1'. Caused by: unknown
expo-secure-store derives ONE Android keystore alias from the keychain
service (`<service>:unauthenticated`) and shares it across every host token,
so a single unusable alias rejects all writes. Its built-in self-heal only
covers KeyPermanentlyInvalidatedException, and a null-message
GeneralSecurityException takes the unrecoverable branch instead — leaving
onboarding permanently blocked, which a reinstall does not clear.
Route host-token persistence through a keychain generation that rotates to a
fresh service (and therefore a fresh alias) only after a write has already
failed. Generation 0 keeps expo's default service so tokens written by
earlier builds stay readable, reads walk back through retired services, and
deletes clear every generation so a rotation cannot strand a live credential.
Refs #6600
* fix(mobile): record a keychain rotation before storing the token under it
Greptile flagged that a token could be stored under a generation the
generation record never captured. `commitGeneration` swallowed the
AsyncStorage failure and cached the new generation in memory, so the write
succeeded for the rest of the session — but the next launch re-read the old
record, and because reads only walk back from the recorded generation they
never probed the newer service. The host silently vanished and the user had
to re-pair, which is the same class of loss this change set out to fix.
Record the rotation first and let a storage failure propagate, so a token is
never written under a generation reads won't reach. Advancing the record
before the write is safe because reads walk back through every older service;
the worst case is one spent generation and one extra probe per miss.
* fix(mobile): harden pairing keychain recovery
* fix(mobile): harden pairing keychain recovery state
* fix(mobile): fail closed on unreadable pairing credentials