Skip to content

fix(plugins): preserve Android component registration - #57

Merged
GenericJam merged 1 commit into
masterfrom
fix/preserve-android-component-registration
Aug 31, 2026
Merged

fix(plugins): preserve Android component registration#57
GenericJam merged 1 commit into
masterfrom
fix/preserve-android-component-registration

Conversation

@GenericJam

Copy link
Copy Markdown
Owner

Summary

  • restore the established ui_components.android.composable registry-key contract
  • require a separate android.factory opt-in for generated Kotlin registration
  • forward both props and the native event sender to opted-in factories
  • install generated factories before bridge registration so bridge-owned factories remain authoritative
  • reject malformed factory opt-ins during the native build and detect collisions across effective Android registry-key fallbacks

This 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.composable registry 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 excluded
  • mix format --check-formatted
  • mix credo --strict
  • mix compile --warnings-as-errors
  • mix erlfmt --check priv/android/crypto.erl
  • clean downstream Android assembleDebug with an eventful bridge-owned component plugin
  • generated downstream bootstrap contains the bridge handoff and no generated calls to legacy registry-key strings

The 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.

Keep legacy component keys bridge-owned by default. Add explicit event-capable factory generation without overriding bridge registrations.
@GenericJam

GenericJam commented Aug 31, 2026

Copy link
Copy Markdown
Owner Author

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.

@GenericJam
GenericJam merged commit f38851c into master Aug 31, 2026
3 checks passed
@GenericJam
GenericJam deleted the fix/preserve-android-component-registration branch August 31, 2026 18:52
GenericJam added a commit that referenced this pull request Sep 1, 2026
Keep legacy component keys bridge-owned by default. Add explicit event-capable factory generation without overriding bridge registrations.
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