Skip to content

chore(mobile): RN onboarding Slice-0 — bump core submodule to off-thread FFI + real ubrn regen + remove PoL + PIN/keychain compat#22

Merged
temrjan merged 1 commit into
mainfrom
feat/rn-onboarding-slice0
Jul 1, 2026
Merged

chore(mobile): RN onboarding Slice-0 — bump core submodule to off-thread FFI + real ubrn regen + remove PoL + PIN/keychain compat#22
temrjan merged 1 commit into
mainfrom
feat/rn-onboarding-slice0

Conversation

@temrjan

@temrjan temrjan commented Jul 1, 2026

Copy link
Copy Markdown
Member

First slice of the RN onboarding/unlock epic (spec: core/.claude/specs/2026-07-01-stage2-rn-onboarding-unlock.md, Gate-1 APPROVED WITH NITS). No UI yet — this is the foundation: get the current async FFI into the app and de-risk the PIN/keychain dependencies.

What

  • Bump vendor/core submodule 2e97b53 (D1) → bc70f07 (off-thread, core #82). The RN bridge now regenerates against the current async FfiWalletimportKeystore/importMnemonicPromise<FfiWalletLike>, sign*Promise<ArrayBuffer>, exportKeystore. Shape A is now confirmed on a real (non-throwaway) regen.
  • Remove the D1 proof-of-life block from App.tsx (its sync importMnemonic call no longer compiles against the async FFI) → dark placeholder shell (colorScheme.set('dark') kept). Render-smoke test updated accordingly.
  • Dependency compat check (spec В1): add react-native-keychain@10, react-native-argon2@4, react-native-get-random-values@2. All three link under RN 0.85 new-arch; libargon2jni/libargon2native + the regen bridge .so package into the APK. react-native-argon2 needed a jcenter()mavenCentral() patch (dead repo) — recorded in patches/ + patches/README.md.

Verification

  • Mechanical gates green: typecheck / lint / jest (1/1) + gradlew assembleDebug BUILD SUCCESSFUL + .so present in APK.
  • condition-1 intact (submodule closure adds only futures-channel/futures-core, no tokio).
  • On-device boot witnessed: dark "Rustok" placeholder renders (no redbox), bridge + native modules load.

Notes / follow-ups

  • react-native-argon2 is a legacy old-arch bridge module; it builds under new-arch interop, but its runtime interop is exercised on-device at the PIN slice. The spec keeps a fallback (PIN-Argon2id in the Rust FFI). The next epic slice (B — crypto-storage de-risk) does not touch argon2/PIN.
  • No secret/auth/crypto surface in this slice (deps added but not wired to any secret flow).

…ubrn regen, remove PoL, add PIN/keychain deps

- Bump vendor/core submodule 2e97b53 (D1) -> bc70f07 (off-thread, PR #82): the RN
  bridge now regenerates against the current async FfiWallet (exportKeystore /
  importKeystore / importMnemonic / sign_* -> Promise). Shape A finalized on a real
  regen (no longer a throwaway).
- Remove the D1 proof-of-life block from App.tsx (its sync importMnemonic call no
  longer compiles against the async FFI); replace with a dark placeholder shell and
  update the render-smoke test.
- Onboarding-spec compat check (В1): add react-native-keychain@10, react-native-argon2@4,
  react-native-get-random-values@2 and build the APK. All three link under RN 0.85
  new-arch; libargon2jni / libargon2native + the regen bridge .so package into the APK.
  react-native-argon2 needed a jcenter()->mavenCentral() patch (dead repo); it is a
  legacy old-arch bridge module, so its runtime new-arch interop is verified on-device
  at the PIN slice (fallback: PIN-Argon2id in the Rust FFI).

condition-1 intact (submodule closure adds only futures-channel/futures-core, no tokio).
JS gates green: typecheck / lint / jest.
@temrjan temrjan merged commit 8f21496 into main Jul 1, 2026
@temrjan temrjan deleted the feat/rn-onboarding-slice0 branch July 1, 2026 08:17
temrjan added a commit that referenced this pull request Jul 8, 2026
## Что и зачем (A4 · Этап 2, последний A-слайс)

Восстановление кошелька записанной 12-словной BIP-39-фразой: **Welcome →
ImportPhrase → CreatePin → ConfirmPin → commit → unlocked**. Активирует
инертную кнопку «Импортировать фразу». **Закрывает go-live-блокер #21**
(KPI-recovery — после потери устройства/ключа фраза снова ведёт к
кошельку).

Второй из двух PR арки; core-часть (`validate_mnemonic`) уже на main
(rustok-org/core#85), сабмодуль бампнут на неё.

## Ключевое
- **Валидность решает ТОЛЬКО Rust FFI** (`validateMnemonic`, без KDF,
честный тег `InvalidInput`). JS-словарь — лишь подсказка (полоса
автодополнения + подчёркивание), не гейт.
- **Экран ввода = самая чувствительная поверхность:** фраза живёт только
в JS-памяти, стирается на success/cancel/back; анти-утечка-пропсы на
всех 12 полях (`visible-password` глушит Gboard-подсказки); ноль чтений
клипборда/сети/логов/persist.
- **Paste** — только OS-нативный: пробел-в-конце фиксирует слово;
multi-word раскладывается по полям; >12 слов → ошибка целиком (без
обрезки).
- **Полоса автодополнения** под 3 замками: локальный словарь / без кэша
/ только явный tap.
- **Таксономия ошибок коммита:** exists / ffi / storage — три различимых
сообщения + Retry.

## Гейты
- `npm run typecheck` → чисто
- `npm run lint` → 0 ошибок (изменённые файлы 0/0)
- `npm test` → **196 passed / 196** (+46 новых; покрытие
phraseInput+onboardingStore 100%, ImportPhrase 95.8%, ConfirmPin 85.7%)
- Red→green доказан мутациями (prefix-guard, lowercase,
таксономия-collapse, invalid-дискриминация, overflow index-blind,
словарь-корозия)
- **Device-smoke 8/8 при Капитане** (round-trip #21:
создать→wipe→импорт→адрес совпал; Gboard-подсказки отсутствуют)

Гейт-1 и Гейт-2 (fleet 5 линз + security ЧИСТО) — оба APPROVED; МИНОРы
вшиты. Mobile CI = workflow_dispatch (заглушён, #3/#16) → мерж по
локальному зелёному, build-android остаётся #16.

**Вне скоупа (записано):** #22 (ru→en sweep существующих экранов), #19
(FLAG_SECURE для ImportPhrase), #23 (вход без биометрии).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant