Skip to content

Add CI guardrails for the mobile discovery FFI contract (native compile + string-parity test) #333

Description

@momics

Summary

The Tauri plugin's mobile discovery commands cross a Rust ↔ Swift/Kotlin FFI boundary where command names are matched by string at runtime. CI today only cargo checks the Rust half of that boundary; the Swift and Kotlin handlers are never compiled or contract-checked. As a result, a rename or signature drift on the native side is a silent runtime failure (an unknown method-class bug) that only surfaces during manual on-device testing.

The genuinely un-automatable part is behavioral: real multicast mDNS over a LAN (advertise, browse, self-echo, resolution timing) needs a device on a real network. But the contract/wiring — do the renamed symbols still line up across Rust, Swift, and Kotlin — is deterministically testable without a device, and currently isn't tested at all.

Evidence

  • PR feat(discovery): standardize desktop mDNS on DNS-SD for iOS/Android interop #330 renamed the mobile command strings across crates/iroh-http-tauri/src/mobile_mdns.rs, the iOS IrohHttpPlugin.swift, and the Android IrohHttpPlugin.kt (commit 79433ef). Only the Rust side was verified via cargo check --target aarch64-apple-ios-sim; the Swift/Kotlin changes are flagged "device-untested" in the PR plan.
  • run_mobile_plugin("browse_peers_start", …) in Rust must match @objc func browse_peers_start (Swift) and @Command fun browse_peers_start (Kotlin). A mismatch compiles fine on each side independently but fails only at runtime, on-device.
  • Analogous failure already hit this cycle: a stale Deno .dylib produced IrohError: unknown method: advertisePeer after the dispatch keys were renamed — the same silent contract-drift class, just on a different adapter.

Impact

Mobile discovery command renames or additions can ship broken and only be caught during slow, easy-to-forget manual device verification. P2 — the workaround (on-device testing) exists but is manual and not enforced, so regressions can reach a release.

Remediation

  1. String-parity contract test (cheap, deterministic, no device). Enumerate the command strings the Rust plugin invokes via run_mobile_plugin("…") and assert that set equals the set of @objc handlers declared in Swift and @Command handlers declared in Kotlin (and vice-versa). A pure text/AST scan that runs in milliseconds and would have caught the feat(discovery): standardize desktop mDNS on DNS-SD for iOS/Android interop #330 rename with certainty.
  2. Native compile jobs in CI. Add xcodebuild/swift build for the iOS plugin sources and gradle assemble for the Android sources. This won't exercise the network but catches signature drift, missing symbols, and API misuse.
  3. (Optional) Rust-side unit tests for the record-mapping logic (service_record_from_mobile, TXT parsing) — no radio required.

Explicitly out of scope

Real multicast mDNS behavior (advertise/browse/self-echo/endpoint resolution) needs a device on a real LAN and stays a manual verification step. This issue only closes the gap on the contract, not the behavior.

Acceptance criteria

  1. A CI-run test fails if a Rust-invoked mobile command string has no matching Swift @objc handler and Kotlin @Command handler (and fails on orphaned handlers in the other direction).
  2. CI compiles the iOS Swift plugin sources and the Android Kotlin plugin sources (build-only, no device).
  3. The checks run as part of the standard CI pipeline (or a clearly-gated mobile job) so a native contract break blocks merge.
  4. Docs state which discovery aspects are covered by CI vs. which require manual on-device verification.

Context

Split out of #330 to keep that PR focused on getting the DNS-SD wire format and the peer-vs-generic API right. Refs #329, #330.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium priorityconnectivityPeer discovery and connectiondxDeveloper experienceenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions