Skip to content

feat(mobile): add native app unlock state - #5719

Merged
iscekic merged 6 commits into
mobile-context-unlock-a61ffrom
mobile-context-unlock-a61f-s2
Sep 1, 2026
Merged

feat(mobile): add native app unlock state#5719
iscekic merged 6 commits into
mobile-context-unlock-a61ffrom
mobile-context-unlock-a61f-s2

Conversation

@iscekic

@iscekic iscekic commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

No new behavior — this change does not connect app unlocking to a setting or a lock screen.


AppUnlockProvider and useAppUnlock expose UnlockState, AppUnlockContextValue, and Outcome for device-local locking; setEnabled changes app-unlock-enabled only after authentication and durable storage.
Enabled cold starts and returns after at least five background minutes trigger locking; absent preferences keep older installations disabled.
nativeResultSchema validates native results; callers supply promptMessage, render protection, and use retry for failed preference reads or locked authentication.

Files
  • apps/mobile/src/lib/app-unlock-context.tsx — adds preference loading/error states, operation phases, and busy feedback. Setting changes authenticate both directions, wait for storage, and retain the prior preference after save failure. Requests run only while active and idle. Native capability checks permit biometrics and passcode fallback; outcomes distinguish setup requirements, cancellation, lockout, and other failures. Setup reasons distinguish missing hardware, unenrolled biometrics, unavailable authentication, and an absent passcode. Lazy imports contain missing-module errors, and success validation accepts nullable iOS fields. Invalid stored values become preference errors instead of disabling protection. Interval tracking excludes inactive-only and duplicate events, prevents concurrent or recursive prompts, and scopes completed attempts to their pending returns. Saving an enabled preference preserves a newer lock; saving disabled clears it. The hook requires its provider, prompt text follows updates, and unmounting removes event handling and stops state publication.

expo-local-authentication becomes a native dependency at ~57.0.2, with faceIDPermission describing app unlocking through Face ID.
The module and permission require a rebuilt native client; older clients return a failed authentication outcome instead of crashing.

Files
  • apps/mobile/app.config.ts — registers the authentication plugin with “Allow Kilo to use Face ID to unlock the app.”
  • apps/mobile/package.json — adds the expo-local-authentication dependency at ~57.0.2.

Tests: 2 files added — apps/mobile/src/lib/app-unlock-context.mounted.test.tsx (+285 lines) and apps/mobile/src/lib/app-unlock-context.test-helpers.tsx (+120 lines).
Generated: 1 lockfile updated — pnpm-lock.yaml (+13 lines).


Verification

Local end-to-end verification on an iOS simulator, 2026-09-01. Seven of eleven checks passed. Four have partial coverage.

This section covers the stack's three PRs together: #5715, #5719, and #5721.

No product bug was found. No product source changed. The worktree stayed clean.

Check Result Note
4. Removed membership shows "Organization unavailable" and survives a cold launch PASS Only an explicit Personal selection clears it.
5. Picker keeps Personal available with no memberships PASS Cancel stays available.
6. A transcript shows its own context as static text PASS A label tap opens no picker; the global context survives.
7. Preferences documents launch, background, setup, and passcode fallback PASS Help text covers all four.
9. A cold launch gates content behind authentication PASS The gate hides the draft, the open sheet, and the tab bar.
10. Five background minutes require authentication again PASS Real background time was 305 seconds.
11. A successful match restores the draft and the open sheet PASS Code stayed selected; the draft text survived.
1. Context switches on Home and Agents PARTIAL Quick Chat is owner-descoped and was unreachable.
2. A saved organization restores before Personal at startup PARTIAL Local restore finished before the first visible frame, so the loading state never appeared.
3. An organization-list failure shows an error and recovers on Retry PARTIAL Backend failure verified. A local SecureStore failure has no fault seam.
8. The unlock switch guards against taps during authentication PARTIAL Verified during native authentication. The local write phase completed too fast to test.

Test-harness limits, not defects

  • Account restoration and selection saving use SecureStore. A backend lock cannot delay or fail a local keychain operation, so failed-save retention has no runtime verdict.
  • No simulator passcode was set, so the passcode fallback path was not exercised. Check 7 covers its help text only.
  • This Xcode rejects simctl biometric. Native simulator enrollment, match, and failure notifications were used instead.
  • Accessibility checks read the simulator accessibility tree. VoiceOver speech itself was not tested.

Setup

  • Real worktree stack and Metro, branch mobile-context-unlock-a61f-s3, simulator iOS 26.5.
  • Normal browser sign-in. Faults came from bounded PostgreSQL transactions on named tables.
  • Screenshots captured with xcrun simctl io <udid> screenshot. Full report and images: /Users/igor/Projects/.scratch/local-e2e-context/.

@kilo-code-bot

kilo-code-bot Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (6 files)
  • apps/mobile/app.config.ts
  • apps/mobile/package.json
  • apps/mobile/src/lib/app-unlock-context.mounted.test.tsx
  • apps/mobile/src/lib/app-unlock-context.test-helpers.tsx
  • apps/mobile/src/lib/app-unlock-context.tsx
  • pnpm-lock.yaml
Previous Review Summary (commit 4320843)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 4320843)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (6 files)
  • apps/mobile/app.config.ts
  • apps/mobile/package.json
  • apps/mobile/src/lib/app-unlock-context.mounted.test.tsx
  • apps/mobile/src/lib/app-unlock-context.test-helpers.tsx
  • apps/mobile/src/lib/app-unlock-context.tsx
  • pnpm-lock.yaml

Reviewed by grok-4.6 · Input: 100.7K · Output: 5.2K · Cached: 78.7K

Review guidance: REVIEW.md from base branch mobile-context-unlock-a61f

@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 1, 2026
@iscekic
iscekic merged commit d8c580d into main Sep 1, 2026
28 of 48 checks passed
@iscekic
iscekic deleted the mobile-context-unlock-a61f-s2 branch September 1, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

human-ready The PR is ready for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants