fix(plugins): preserve Android component registration - #57
Conversation
Keep legacy component keys bridge-owned by default. Add explicit event-capable factory generation without overriding bridge registrations.
|
Adversarially reviewed against the app-fbm acceptance matrix, with the real downstream consumers as the proof. Approve — merging and releasing as 0.6.32. All six criteria pass with evidence: (1) legacy manifests (a real downstream mob_plugin.exs, 18 components, no factory keys) generate ZERO registrations — emitted bootstrap greps clean of the downstream UI library_* and registerUiComponents, bridge-only, behaviorally identical to 0.6.30; (2) opt-in factories emit register(key) { props, send -> Factory(props, send) } — typechecked by Gradle against a real composable and proven eventful on the physical Moto (generated-factory button tap → assigns transition); (3) generated registrations precede bridge register()/handOff and the registry is last-write-wins map-put, so the bridge stays authoritative — verified in both the downstream host and the 0.4.30 template; (4) malformed opt-ins fail the native build pre-Gradle with the manifest location (exercised factory: 42 and no-registry-key); the silently-ignored non-binary bug from pre-commit review is genuinely fixed (Map.has_key? gating); (5) precedence fixed — composable always wins, pinned by test, no remaining fallback-shadowing path found; (6) the bead's downstream proof: clean downstream Android assembleDebug (the exact build 0.6.31 broke), APK on the physical Moto, physical tap and type round-trips through bridge-owned eventful components. Gates: 2182 tests, format/credo-strict/warnings-as-errors/erlfmt clean, packed-artifact regression passes. Diff fully on-topic, one commit atop the 0.6.31 bump. Two follow-ups, neither gating (both pre-existing surfaces): cross_validate collision detection runs only in mix mob.plugins and doesn't exit non-zero — duplicate opted-in keys would last-write-win silently at runtime; filing an issue to fail loudly. And binary-but-invalid identifiers ('', '1Bad') pass classify and only fail at Kotlin compile — the regex lives in mob.validate_plugin; worth unifying someday. Release note will carry the explicit deprecation: skip 0.6.31, upgrade 0.6.30 → 0.6.32, and 'android.factory is inert on ≤ 0.6.30' for the skew case. |
Keep legacy component keys bridge-owned by default. Add explicit event-capable factory generation without overriding bridge registrations.
Summary
ui_components.android.composableregistry-key contractandroid.factoryopt-in for generated Kotlin registrationpropsand the native event sender to opted-in factoriesThis is the corrective change intended for the 0.6.32 patch release. Versioning remains in the repository's post-merge release step.
Why
0.6.31 began treating the existing
android.composableregistry key as a callable Kotlin symbol. That broke plugins which register factories from their bridge, and the generated replacement discarded the native event sender. Depending on the plugin, the result was either a Kotlin compile failure or eventless native components.Verification
mise exec zig@0.17.0-dev.269+ebff43698 -- mix test— 2,182 passed, 10 excludedmix format --check-formattedmix credo --strictmix compile --warnings-as-errorsmix erlfmt --check priv/android/crypto.erlassembleDebugwith an eventful bridge-owned component pluginThe strict security scan reports the same six machine-cache bundled-runtime drift findings present before this change; dependency and source-code layers are clean.
Review
Fresh adversarial review found two issues before commit: registry-key precedence still favored the new fallback, and non-binary explicit factories could be silently ignored. Both were fixed and covered by regression tests before the branch was committed.