Skip to content

Add native Bank and Location verification support - #60

Merged
arosasg merged 4 commits into
mainfrom
botinc/run-0aca012c
Oct 10, 2026
Merged

arosasg merged 4 commits into
mainfrom
botinc/run-0aca012c

Conversation

@botinc-agent

@botinc-agent botinc-agent Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Prepare the React Native wrapper for native Bank and Location verification through the existing entry points. Configure optional Location support, add English and Spanish iOS purpose strings in both examples, and preserve the native retryBlocked callback in JavaScript. Native builds retain the source checkout path through Turbo, and the iOS Location setting participates in the build cache key.

Native dependency: a single immutable source pin to the native SDK repository's integration branch (the branch name is in package.json), which stacks the open native Bank and Location pull requests at their 2026-10-08T07:49Z (Bank) and 07:59Z (Location) states. The pinned revision 88259c3b2ac57520ead46579ee7c1fb56686cdb1 equals that branch's head, re-verified in this pass by remote reference and by the integration pull request's head. The native Bank step, Location and Bank fallback pull requests have since received correction commits that are not part of the stack and therefore not in the pin; the precise list is below, for routing to the owning native packages. The pin moves to the released native version before the stacked push and package release. Released-binary CI checks compatibility only; those binaries do not provide the new steps.

Acceptance: NOT-READY. The consumed native revision still fails the visual gate against the frozen design boards. This wrapper renders none of those screens, and this revision's only source change is the Android bridge's diagnostic logging, which no screen shows, so it claims no visual fix; the corrections below are owned by the native SDK packages and the integration branch. Re-review of the unchanged pin cannot clear the visual gate. Once the integration branch carries the native head revisions below (plus the one item no native head carries yet, the Bank step-specific Spanish attribution string), this side moves the pin to the new integration head and re-runs the full visual matrix.

Missing from the consumed native revision

Behavioural list, measured at 390x844 against the frozen boards in light, dark and Spanish, each traced to the native revision that corrects it. None of the cited native revisions is an ancestor of the pinned revision; the stack predates them. Native Android Bank step head: 977a74266c81231eed7e99144741088579bc3d71. That same content is now also published as a single squashed commit off the native base at 7a22ab291c32def75ac49014945b79fb8937a976; both revisions have the byte-identical root tree bb0300745e0aa4969a99bd5a4af1e4b0cace36b9, so they are two open publications of one Android Bank step, not two variants. Stack exactly one of them, either is equivalent, and do not stack both. Native Android Bank fallbacks head: 2f1804c7db0cf98b00646ff084abee93ff2f26bc (a parallel branch off the native base, not stacked on the step head; it carries the same Bank visual corrections plus the fallback states). Native Android Location head: a3c2a152d31e772301b13e1967304981f82b9962. Native iOS Bank fallbacks head: da8154635d67cc4f6d50e67af91fbad2b5dd1023.

No iOS Location routing is required. The pinned revision's iOS Location surface is content-identical to the open iOS Location head a1a50a2c4e9fc253dd064e313da17f4a20676590: the diff over ios/sdk/didit-sdk/Sources/Features/Location, ios/sdk/Location, ios/sdk/didit-sdk/Sources/Core/Utils/GeolocationManager.swift, both Location test files and ios/sdk/tests/test_location_privacy.py is empty. The pin is therefore already current for iOS Location, and the routing action this list asks for is Android-only (Bank step, Bank fallbacks, Location) plus the iOS Bank fallbacks head. Every pixel-measured deviation below comes from the Android captures, because iOS cannot be compiled or captured in this Linux sandbox; the iOS items are stated from source, not from a render.

  1. Bank header and progress bar sit 16 px above the reference: the reference draws the progress bar at rows 34 to 37 from the top inset, the native screen at rows 18 to 21.
    • Corrected at the Bank head by 50853e1a146a2f64b1e503a84f8ff570d7743619: BankStepView.kt renders the shared header inside BankScreenContainer with Modifier.padding(horizontal = 4.dp).offset(y = 16.dp).
  2. Bank and Location footer button labels do not use the board's type style (17 sp, 20.74 sp line height, -0.84 sp tracking, medium weight). The native buttons render the generic button style with visibly narrower glyphs.
    • Corrected at the Bank head by 50853e1 (a textStyle parameter on PrimaryButton.kt and SecondaryButton.kt) and 977a742 (BankFooter supplies boardText(17.sp, 20.74.sp, (-0.84).sp, FontWeight.Medium) with a measured label height).
    • Corrected at the Location head by 7d977b10eb9021999ff4f16715739257db90f836 (buttonStyle() with the same board metrics in LocationStepView.kt, passed to the footer buttons).
  3. The footer attribution uses the generic "Secured by" string in the caption style at the secondary colour. The board uses a step-specific string at 12 sp and 18 sp line height in surface1 at 40 percent opacity. In Spanish the native screen reads "Desarrollado por" where the reference reads "Protegido por".
    • Location, string and style: corrected at the Location head by 7d977b1. PoweredByView gains text, textStyle and textColor parameters; the footer passes location_secured_by, a new string in every locale (Spanish "Protegido por"), at boardText(12.sp, 18.sp) in surface1 at 40 percent.
    • Bank, style only: corrected at the Bank head by 50853e1 (PoweredByView gains textStyle and textColor; the bank footer passes the board metrics).
    • Bank, Spanish string: not corrected at any current native head. At the Bank step head 977a742, at its squashed republication 7a22ab2 and at the Bank fallbacks head 2f1804c the footer still renders common_powered_by ("Desarrollado por" in Spanish) because their PoweredByView call passes styles but no step-specific text; re-verified at all three this pass, where PoweredByView.kt takes only modifier, textStyle and textColor and its Text reads stringResource(R.string.common_powered_by), and no secured_by string exists in the Android resources. Note also that the native heads extend PoweredByView.kt differently (Location adds text; Bank adds only textStyle and textColor), so re-stacking must join both signatures and add a Bank step-specific secured-by string. This is the single item on this list that no native head carries, so it is the only one that needs new native work rather than stacking.
  4. The bundled Inter font instances the board's metrics require are absent from the consumed revision, so board text styles fall back to the system font: different glyph widths and weights in both themes. The pinned revision has no android/sdk/src/main/res/font/ directory at all.
    • Corrected at the Bank head by 50853e1: res/font/bank_regular.ttf, bank_medium.ttf, bank_semibold.ttf, bank_bold.ttf plus res/raw/bank_font_license.txt, wired as BANK_FONT through boardText in BankComponents.kt.
    • Corrected at the Location head by 7d977b1: res/font/location_inter_regular.ttf, location_inter_medium.ttf, location_inter_semibold.ttf, wired as LOCATION_FONT through boardText in LocationStepView.kt.
  5. Bank lacks the close-match, micro-deposit amount entry and statement fallback states entirely; the consumed revision's Bank screens stop at the account, waiting and result states (its BankScreen enum has no close-match, micro-deposit, amounts or statement member).
    • Corrected at the Android Bank fallbacks head 2f1804c (a parallel branch off the native base, not stacked on the Bank step head): the BankScreen enum gains CLOSE_MATCH, MICRODEPOSIT, AMOUNTS and STATEMENT, with new BankFallback.kt, BankFallbackApi.kt, ui/BankFallbackScreens.kt, ui/BankInput.kt and ui/BankStatementScreen.kt plus screenshot coverage. The fallbacks are gated on the backend offering each method (onUnsupported on a 404), so the screens are built and render only when the backend enables them. This head also carries the same Bank visual corrections as the step head (bundled Inter fonts, BankScreenContainer with the 16 dp board offset, board button type style, PoweredByView style parameters), so for Android Bank it is effectively a superset of the step head 977a742.
    • Corrected at the iOS Bank fallbacks head da81546: BankFallbackAPI.swift, BankFallbackInputs.swift, Views/BankFallbackViews.swift and Views/BankStatementView.swift.
    • The note "the backend has neither yet, so only another bank is offered" lives in the Android Bank step head 977a742 (BankStepView.kt), which predates the fallbacks work; the fallbacks head 2f1804c supersedes it with the real screens. Whether the backend now offers close-match, micro-deposit and statement is a separate backend-contract question for the owning backend package; the native screens exist and only need stacking. Routing action: stack the Android and iOS Bank fallbacks heads (reconciling the Android fallbacks head with the Android Bank step head, since the fallbacks branch is a parallel superset), not confirm-or-close a scope gap.

Also at the Location head but not in the pin: b0e5be078a46ed3638a832581fdc21d9baf9af45 (AppLogo.kt measures logo contrast as displayed, composited over the page), aa319fd1b1a32f110aa5489130bbc279216f7001 (a StepRecovery session fence; not visual) and a3c2a152 (documentation only: README and CHANGELOG). The Android Bank step, Android Bank fallbacks and Location heads all regenerate their committed screenshot baselines to the corrected UI, so the pin's baselines still encode the pre-correction rendering.

Verification in this pass

Every exit status below was read from the owning command.

  • yarn lint, yarn typecheck: exit 0.
  • yarn test --maxWorkers=2: exit 0. Test Suites: 11 passed, 11 total; Tests: 92 passed, 92 total.
  • yarn prepare, git diff --check: exit 0; the working tree is clean and current main is already an ancestor.
  • Native source resolution for iOS and Android: exit 0 against a clean checkout at the pinned revision; the iOS Location subspec is present in the consumed podspec.
  • Native Android suites at the pin, through the native project's own Gradle wrapper with daemons disabled: exit 0, BUILD SUCCESSFUL in 6m 17s, 58 suites and 490 tests with 0 failures (Bank 170, Location 101), including the JVM screenshot tests. The 60 fresh Location captures reproduce the committed captures and the 63 Bank baselines compare clean.
  • Bare Android example, source-linked: yarn turbo run build:android exit 0, BUILD SUCCESSFUL in 7m 18s. Expo Android example: ./gradlew :app:assembleDebug exit 0, BUILD SUCCESSFUL in 12m 20s. Both merged manifests carry foreground fine and coarse location plus optional location hardware, with no background location permission. Every native artefact resolved from the local source repository; the built bundle contains 172 Bank and 108 Location classes.
  • Revision pass: yarn lint, yarn typecheck, yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests. The Android native build script now reports the intended missing-pin error instead of a type error when no source pin is configured, for example after the release moves to versioned binaries. Current main remains an ancestor, and the pinned revision still equals the native integration branch head, re-verified by remote reference.
  • This revision pass: yarn lint, yarn typecheck, yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests. Current main (9d50600) remains an ancestor; no base merge was needed. The pin was re-verified equal to the integration branch head and to the integration pull request's head by remote reference, and the native correction commits listed above were confirmed absent from it by ancestry check and by content (no res/font/ directory, no location_secured_by, parameterless PoweredByView() calls, no header offset in BankStepView.kt).
  • This revision pass, proof integrity: the six native captures were re-verified pixel-identical to the pin's own committed screenshot outputs (Location: the committed 390x844 captures; Bank: the committed 585x1266 baselines downsampled with Lanczos). The pixel matrix was recomputed from exactly the files published here: all six percentages reproduce to the third decimal (5.815, 6.337, 6.519, 6.690, 8.002, 7.482) and all six recomputed overlays are pixel-identical to the published diff images.
  • Pixel parity at 390x844 with the board's sample data, per-channel threshold 24: Bank consent 5.815% light, 6.337% dark, 6.519% Spanish; Location intro 6.690% light, 8.002% dark, 7.482% Spanish. The measured deviations are items 1 to 4 above; the remainder is glyph-level type rendering. The visual acceptance check exits 1: FAIL: NOT-READY. Passing screenshot regression tests do not establish parity.
  • Final handoff re-verification of this revision: yarn lint, yarn typecheck, yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests; the working tree is clean and current main (9d50600) remains an ancestor, so the code head is unchanged. The pin was re-verified equal to the native integration branch head and to the integration pull request's head by remote reference; the native Android Bank step head 977a74266c81231eed7e99144741088579bc3d71 is unchanged, the Location head advanced to a3c2a152d31e772301b13e1967304981f82b9962 (a documentation-only delta over the previously cited aa319fd1), and the Android Bank fallbacks head 2f1804c7db0cf98b00646ff084abee93ff2f26bc and iOS Bank fallbacks head da8154635d67cc4f6d50e67af91fbad2b5dd1023 all remain diverged from the pin (none is an ancestor); the pin still has no res/font/ directory and no location_secured_by string. All 22 embedded proof URLs were re-fetched: each returns HTTP 200 with PNG content byte-identical (sha256) to the local capture. The pixel matrix was recomputed from exactly the published files: all six percentages reproduce to the third decimal and all six published overlays are pixel-identical (max channel delta 0) to the recomputed overlays.
  • Bounded final revision pass (routing-list precision): re-read every cited native head by source. Corrected this list: the Location head is a3c2a152 (the extra commit over aa319fd1 is documentation only), and item 5 now traces the Bank fallback states to the Android fallbacks head 2f1804c and the iOS fallbacks head da81546, which implement them; the earlier "not corrected at any native head" claim was wrong and is withdrawn. Confirmed by source at each head: the fallbacks head carries CLOSE_MATCH/MICRODEPOSIT/AMOUNTS/STATEMENT plus the same Bank visual corrections, and no Android head carries a Bank step-specific Spanish attribution string. Reproduced the gate independently this pass: rendered all six boards fresh from the frozen canvas (renderer exit 0, owned server stopped and reaped), extracted the six native captures fresh from the pin by git archive (Bank 585x1266 downsampled to 390x844 with Lanczos, Location native 390x844), and ran the pixel diff in a fresh environment. My six renders are pixel-identical (max channel delta 0) to the published design references, my six pin captures are pixel-identical to the published native captures, and the diff reproduces all six percentages to three decimals (5.815, 6.337, 6.519, 6.690, 8.002, 7.482), 0 of 6 states identical. yarn lint, yarn typecheck, yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests. No wrapper source changed and the pin did not move, so the visual gate stays NOT-READY; this pass corrects the routing list the recorded decision makes the routing mechanism.
  • Review round 2 bounded pass (routing-list precision, no source change): re-verified the pin against the native remote by branch reference and by the integration pull request's head; both are still 88259c3b2ac57520ead46579ee7c1fb56686cdb1, committed 2026-10-08T08:25:12Z, so the integration branch has not moved and no compliant pin move exists. Re-verified by ancestry check that all six cited native heads remain diverged from the pin. Re-verified the pin's content by source: zero files under android/sdk/src/main/res/font/, no location_secured_by in the Android resources, HEADER_HEIGHT = 36.dp in BankComponents.kt, a parameterless PoweredByView() at BankComponents.kt:264, and a BankScreen enum that ends at RESULT with no close-match, micro-deposit, amounts or statement member. Two precision defects found and corrected in the list above. First, the Android Bank step content is now published twice, as 977a742 and as a single squashed commit 7a22ab291c32def75ac49014945b79fb8937a976; both have the identical root tree bb0300745e0aa4969a99bd5a4af1e4b0cace36b9, verified by tree comparison and by an empty diff between the two revisions, so the list now names both and says to stack exactly one. Second, the list cited no iOS Location head and so implied iOS Location might need routing; measured this pass, the pin's iOS Location surface is content-identical to the open iOS Location head a1a50a2c4e9fc253dd064e313da17f4a20676590 (empty diff over the Location sources, the Location privacy manifest, GeolocationManager.swift, both Location test files and test_location_privacy.py), so the list now states that the routing ask is Android-only plus the iOS Bank fallbacks head. Item 3's Bank Spanish attribution string was re-verified absent at all three Android Bank heads. All 22 embedded proof URLs were re-fetched: each returns HTTP 200 once GitHub's /raw/ redirect is followed, with a valid PNG body. yarn lint, yarn typecheck, yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests. Current main (9d50600) remains an ancestor and the working tree is clean, so the code head is unchanged. This pass did not re-run the pixel matrix: the pinned revision is byte-identical to the one the previous pass reproduced independently and the review round reproduced again, the boards are frozen, and the diff is deterministic over those two inputs, so a third run could only restate 5.815, 6.337, 6.519, 6.690, 8.002 and 7.482. No wrapper source changed and the pin did not move, so the visual gate stays NOT-READY; this pass narrows and corrects the routing list that the recorded decision makes the routing mechanism.
  • Privacy revision pass (this pass): yarn lint, yarn typecheck, yarn test --maxWorkers=2: exit 0; Test Suites: 12 passed, 12 total, Tests: 105 passed, 105 total, the new logging guard adding one suite and 13 tests. yarn prepare and git diff --check: exit 0. Current main (9d50600) remains an ancestor and the pin did not move, re-verified equal to the native integration branch head 88259c3b2ac57520ead46579ee7c1fb56686cdb1 by remote reference this pass. No JDK, Android SDK or Gradle exists in this Linux sandbox, so the module cannot be compiled here; two partial substitutes were run instead. The two new helpers and every call-site form they now receive, including the nullable throwable, the default parameter and both ::class.simpleName templates, were compiled with Kotlin 2.0.21, the version this module pins, against an android.util.Log stub carrying the real Android signatures and a BuildConfig stub: exit 0, no warnings. The whole module was then parsed by the same compiler: zero syntax errors, and its error profile is identical to main's apart from the absent React Native, native SDK and coroutines classpath. The full module compile against the pinned native source is still unverified here and lands with CI's Android compatibility job.

Diagnostic logging

The Android bridge logged data a release build must never log. android/src/main/java/com/sdkreactnative/SdkReactNativeModule.kt printed the first 8 characters of the session token together with the verification config, and the workflow entry point printed the workflow identifier, vendorData, metadata, contactDetails, expectedDetails and the config on one line, plus the parsed Configuration and, from the SDK error state, the native error message. All 16 call sites used plain Log.d and Log.e with no build-type check, and the library's release build type sets minifyEnabled false, so nothing stripped them: a release build wrote a credential prefix and personal data to logcat.

This revision removes the token and every personal-data field from those logs entirely and routes the remaining diagnostics through two private helpers gated on BuildConfig.DEBUG, so a release build emits nothing from this module.

Site Before After
startVerification entry token prefix and config startVerification: started
startVerificationWithWorkflow entry, 2 calls workflow identifier, vendorData, metadata, contactDetails, expectedDetails, config startVerificationWithWorkflow: started
parsed configuration, 2 calls the whole Configuration removed
result callbacks, 2 calls result class name unchanged text, now debug-only
SDK state observation the state, whose error case prints the native message state class name only
SDK error state the native error message SDK entered Error state
no-activity, timeout and 4 exception sites structural text plus the throwable unchanged text, now debug-only

The gate removes release-build crash diagnostics from this module. That is deliberate: loggingEnabled in the verification config stays the supported diagnostic channel and is documented in the README.

Guard: src/__tests__/android-logging-privacy.test.ts reads every Kotlin and Java file under android/src and every Swift and Objective-C file under ios, and fails when a log call interpolates a token, vendorData, metadata, contactDetails, expectedDetails, the config or configuration, a session identifier or the native error message, and when a call that reaches the platform logger directly sits outside a BuildConfig.DEBUG gate, or outside a #if DEBUG region in an Apple source. Six negative controls assert that the checker rejects the exact log this revision removed, rejects personal data placed behind the gate, rejects an ungated structural log and rejects a helper that reaches the logger without a gate, so the guard is not vacuous.

Reproduced before fixing: with the pre-revision module restored, the guard exits 1 and names all 16 offending call sites, among them line 49: logs token, line 83: logs vendorData, line 84: logs contactDetails, line 54: logs configuration and line 140: logs state.message. With the fix in place it passes.

Both example apps in this repository already default their session token fields to empty, so no demo credential ships in either.

Routing to the native packages, where source is read-only on this side: at the pinned revision 88259c3b, ios/example/verify-sdk/ContentView.swift:111 still defaults its demo sessionToken to a 12-character hard-coded value. It needs an obvious placeholder. The value is not reproduced here.

Visual proof

The images are hosted in this repository on the branch proof/bank-location-visual-matrix (commit 28df9e63153dfc040952feb6476b849534dd5f56); every embedded URL was verified to return HTTP 200 byte-identical to the local capture. Per state and theme: the design reference render of the end-user verification preview (phone 390x844, bare frame), the native Android screen compiled from the pinned native source revision, and the pixel-diff overlay (red = differing pixels, any channel over 24), plus 2x close-ups of the progress bar offset and the Spanish footer string. All captures use static sample data: no personal, provider, credential or token content. Bank native captures were produced at 1.5x density by the committed native screenshot tests and normalized to 390x844 with Lanczos; Location native captures are the committed native 390x844 screenshot-test captures at the pin. This revision changed no rendered surface, its only source change being the Android bridge's diagnostic logging, and did not move the pin, so the native captures remain both the before and the after state.

Bank consent, light

Bank consent, design reference, light
Bank consent, native at pin, light
Bank consent, pixel diff, light

Bank consent, dark

Bank consent, design reference, dark
Bank consent, native at pin, dark
Bank consent, pixel diff, dark

Bank consent, Spanish

Bank consent, design reference, Spanish
Bank consent, native at pin, Spanish
Bank consent, pixel diff, Spanish

Location intro, light

Location intro, design reference, light
Location intro, native at pin, light
Location intro, pixel diff, light

Location intro, dark

Location intro, design reference, dark
Location intro, native at pin, dark
Location intro, pixel diff, dark

Location intro, Spanish

Location intro, design reference, Spanish
Location intro, native at pin, Spanish
Location intro, pixel diff, Spanish

Measured deviations (close-ups, 2x)

Progress bar: the reference places it 16 px below the top inset; the native screen draws it at the top inset.

Bank progress bar, design reference, light
Bank progress bar, native at pin, light

Spanish footer attribution: the reference reads "Protegido por"; the native screen reads "Desarrollado por" in the caption style at the secondary colour.

Bank footer, design reference, Spanish
Bank footer, native at pin, Spanish

Still required on a Mac and on devices

Regenerate both CocoaPods lockfiles against the pinned source (neither Xcode nor CocoaPods exists in the Linux build sandbox; no checksum was fabricated), build both iOS examples, run the native-result bridge XCTests including retryBlocked against source and released binaries, and capture the real English and Spanish when-in-use and temporary precise-location prompts in both examples. Authenticated Bank return and cancellation, and physical-device Location flows (denial, approximate grant, Settings return, precise-location retry) remain unverified; the supervisor runs them locally at review.

Public metadata

Title and body describe the change in public terms only; the proof images are hosted in this public repository and every embedded link resolves to it. The final squash message must stay public-safe. Editing metadata cannot erase earlier disclosure.

…h (continuation of DID-5770)

Opened by a BotInc run. Delivery follows the workflow's review and merge policy.
@botinc-agent botinc-agent Bot changed the title DID-5907: [H10] React Native SDK: Bank and Location steps pass-through (continuation of DID-5770) Add native Bank and Location verification support Oct 8, 2026
…h (continuation of DID-5770)

Opened by a BotInc run. Delivery follows the workflow's review and merge policy.
…h (continuation of DID-5770)

Opened by a BotInc run. Delivery follows the workflow's review and merge policy.
…h (continuation of DID-5770)

Opened by a BotInc run. Delivery follows the workflow's review and merge policy.
@arosasg
arosasg merged commit 78ce13a into main Oct 10, 2026
5 checks passed
@arosasg
arosasg deleted the botinc/run-0aca012c branch October 10, 2026 07:49
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