Skip to content

feat(mobile): A2a — onboarding shell + PIN screens, F1 fix#27

Merged
temrjan merged 2 commits into
mainfrom
feat/rn-a2a-onboarding-shell-pin
Jul 3, 2026
Merged

feat(mobile): A2a — onboarding shell + PIN screens, F1 fix#27
temrjan merged 2 commits into
mainfrom
feat/rn-a2a-onboarding-shell-pin

Conversation

@temrjan

@temrjan temrjan commented Jul 3, 2026

Copy link
Copy Markdown
Member

Что это

Слайс A2a Этапа 2: онбординг-каркас (Welcome→KeepItSafe→CreatePin→ConfirmPin) + критический
security-фикс из аудита.

  • F1 (крит аудита): deviceWallet.createWallet() коммитил кошелёк на диск в тот же вызов, что
    генерировал мнемонику — до бэкапа и квиза. Расцеплено на generateMnemonic() (чистая, без I/O)
    • commitWallet(mnemonic) (атомарный коммит после подтверждённого бэкапа, в A2b). Regression-тест
      воспроизводит прежний баг.
  • 12-словная мнемоника (не 24) — ратифицировано на Гейте-1, зафиксировано spy-тестом на FFI-вызов.
  • onboardingStore — in-memory степ-машина; PIN коммитится до кошелька (уже предусмотрено
    A1c-контрактом reconcile()), мнемоника никогда не персистится.
  • PinKeypad — переиспользуемый компонент (пригодится в A3 для UnlockPin).
  • 4 экрана: Welcome — 1:1 порт готового флипбука; KeepItSafe/CreatePin/ConfirmPin — собраны по
    смыслу управляющей спеки (ратифицировано, closes carry-over build(deps-dev): bump react-test-renderer and @types/react-test-renderer #7).
  • RootNavigator's no_wallet теперь роутит на OnboardingNavigator.

Проверено

  • tsc / eslint / jest: 99/99, покрытие новых/изменённых модулей ≥83%
  • Мутационная верификация: F1-регресс, word-count spy, 2 PinKeypad-инварианта, onboardingStore
    match-check, setPin-failure ordering — все красные до фикса
  • Device-smoke PASS (Captain-witnessed): полный путь Welcome→KeepItSafe→CreatePin→ConfirmPin
    пройден на реальном устройстве без крашей
  • Гейт-1 (с дельта-фиксом: 12 слов, word-count-тест, pendingPin null) и Гейт-2 (fleet,
    4 находки: 2 минора зафиксены с red→green, 2 нита) — оба APPROVED

Побочные находки, зафиксены по ходу

  • KeepItSafe's Продолжить реагировал при неполном чек-листе (disabled-проп не блокирует прямой
    вызов onPress) — теперь onPress сам гейтится.
  • PinKeypad: same-tick double-tap (мультитач) мог дважды вызвать onComplete с разными строками
    (stale state closure). Первая попытка фикса (functional setState) исправила это, но завела новый
    баг — вызов onComplete (→ zustand.set()) изнутри state-updater'а триггерил React-предупреждение
    «update во время рендера другого компонента». Финальный фикс — синхронный ref-зеркало, обновляемое
    в обработчике нажатия, onComplete зовётся из него же, не из редьюсера состояния.

Спека: core/.claude/specs/2026-07-03-stage2-a2a-onboarding-shell-pin.md · Отчёт:
core/.claude/reports/2026-07-03-stage2-a2a-onboarding-shell-pin.md

temrjan added 2 commits July 3, 2026 11:03
…generate/commit)

- F1 (audit crit): deviceWallet.createWallet() committed the wallet in the
  same call that generated the mnemonic — abandoning onboarding before the
  backup quiz left a committed-but-unbacked-up, unrecoverable wallet.
  Split into generateMnemonic() (pure, no I/O) + commitWallet(mnemonic)
  (the atomic commit); regression test proves generation alone never
  touches storage
- 12-word mnemonic, not 24 (ratified Gate-1 A2a; matches the governing
  spec + the flipbook's ShowPhrase mock); spy-tested against the FFI call
  so a silent revert to 24 cannot pass jest with the word-count-agnostic
  bridge mock
- onboardingStore: in-memory-only step machine (welcome/keepItSafe/
  createPin/confirmPin/pinConfirmed) holding the mnemonic and pending PIN;
  PIN persists via pinSetupStore ahead of the wallet commit (the A1c
  reconcile() contract already anticipates this); pendingPin clears the
  moment it's hashed
- PinKeypad: shared dots+keypad component (CreatePin/ConfirmPin now, A3's
  UnlockPin later)
- Welcome screen ports the flipbook 1:1 (wordmark text, not the SVG logo —
  react-native-svg isn't a dependency yet, flagged rather than silently
  added); KeepItSafe/CreatePin/ConfirmPin built from the governing spec's
  language (no flipbook frames for these — ratified, closes carry-over #7)
- RootNavigator's no_wallet phase now renders OnboardingNavigator instead
  of a placeholder
- integration test caught a real bug: KeepItSafe's Continue button relied
  solely on the Pressable disabled prop, which a direct onPress call
  bypasses — onPress is now itself gated on all 3 acknowledgements
- 98 tests total (23 new/changed), 2 mutations verified red before green
…ore setPin-failure test

- MINOR #2: PinKeypad read/wrote a stale `digits` state closure on same-tick
  double-taps (multi-touch), letting onComplete fire twice with different
  strings. First fix attempt (functional setState update) traded this for a
  worse bug — calling onComplete (which drives a zustand set()) from inside
  a state updater fires during React's render phase ("Cannot update a
  component while rendering a different component"). Final fix: a
  digitsRef mirror read/written synchronously in the press() event handler
  (not during render), with onComplete called from press() itself. New
  double-tap test catches both the original bug and would catch the
  render-phase regression (backspace test also went red on the interim
  mutation, confirming ref/state sync matters)
- MINOR #1: onboardingStore.confirmPin's security-relevant ordering
  (persist PIN before advancing step) had no regression test; a future
  reorder would go green silently. New test mocks pinAuth.setPin to reject
  and asserts the step never advances and nothing persists — mutation
  (reordering set() before the await) turns it red
- NIT #3: stale createWallet.inFlightCreate reference in a pinAuth.ts
  docstring, now commitWallet.inFlightCommit
- NIT #4: dropped a cannot-fail 'starts at welcome' test (asserted only the
  beforeEach-forced initial state)
- all mutations verified red before green; 99/99 green, 0 lint errors
@temrjan temrjan merged commit 959fca1 into main Jul 3, 2026
@temrjan temrjan deleted the feat/rn-a2a-onboarding-shell-pin branch July 3, 2026 08:50
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