Greptile review: `com.chaquo.python.PyObject) -> onEvent` also ends a two-arg
signature, so a stripped PyEventCallback could have passed on a surviving
PyTwoArgCallback line. Anchor the open paren to require a single-PyObject
param list. Backstopped by the class-level BRIDGE_CLASSES check; verified the
anchored pattern still matches the real synthetic single-arg SAM impl
(3 matches in the noSentryPythonBackendRelease mapping).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
assert_bridges_kept.py guarded only the original 5 bridges, so it would not
have caught the very regression it sits beside — the 2-arg PyTwoArgCallback
.onEvent that R8 mangled in release. Add PyTwoArgCallback and
StampGeneratorCallback to the class checks, assert StampGeneratorCallback
.generate survives, and generalize the SAM check to both the 1-arg and 2-arg
onEvent shapes. Comments/messages updated @Keep -> @ReflectivelyKept.
Verified against the noSentryPythonBackendRelease R8 mapping: passes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the instrumented R8 gate with a mapping.txt assertion — the
canonical, deterministic way to verify keep rules:
- scripts/assert_bridges_kept.py parses R8's mapping.txt and fails if any
bridge class was renamed/stripped, any host-bridge method Python calls was
renamed (asserted per class), or the PyEventCallback.onEvent SAM was
renamed.
- proguard-verification job now just builds
:app:assembleNoSentryPythonBackendRelease and runs the script — no emulator,
no testBuildType flip, no androidTest-against-minified compile conflict.
Why the pivot: the instrumented test only did Class.forName/getDeclaredMethods
(a name check, not behavior), so it paid the emulator+minified-build cost for
something mapping.txt already states authoritatively. It also forced the whole
androidTest suite to compile against the minified variant, which broke on the
debug-only Compose UI tests (TestHostActivity). Checking R8's own rename table
is simpler, faster, flake-free, and is exactly what caught the PyEventCallback
regression.
Removes the releaseMinified build type, testBuildType, test-proguard-rules.pro,
and PythonKotlinBridgeR8Test. Keeps the @Keep annotations (the fix) and the
src/androidTestDebug move. Verified locally: assembleNoSentryPythonBackendRelease
-> script passes against the real mapping.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scripts/verify-on-device.sh:
- JAVA_HOME: honour caller's env; otherwise auto-detect Android
Studio's bundled JBR at common locations (Mac /Applications,
$HOME/android-studio, /opt/android-studio).
- Drop hardcoded device-IP fallbacks. Now reads optional
COLUMBA_PHONE_IPS (space-separated) when no device is discovered
via `adb devices`. Unset -> no auto-fallback; just instruct the
user to adb connect manually.
- Comments refreshed to reflect the env-driven shape.
- Delete scripts/verify_proguard_bridge.py — Chaquopy-era script that
hardcodes KotlinReticulumBridge (just deleted) and exits immediately
because the python/ directory it looks for no longer exists. Not
wired into any CI workflow.
- Remove the stale KotlinReticulumBridge detekt-baseline entry.
Done via a deterministic sed+git-mv script rather than Android Studio's
package refactor, which silently dropped 169 files on the previous
attempt. Script does:
1. Substitute "com.lxmf.messenger" and "com/lxmf/messenger" in every
tracked text file (Kotlin, AIDL, XML, Gradle, ProGuard, CI, etc.).
2. git mv every file under the 15 "com/lxmf/messenger/" source trees
(across app/data/reticulum/detekt-rules/screenshot-tests/micron, in
main/test/androidTest/debug sourceSets) to its "network/columba/app/"
counterpart.
3. Delete emptied parent directories.
Verified: assembleNoSentryDebug, all unit tests (app/data/reticulum/
micron), and detekt on app/reticulum/data all pass.
R8 obfuscated PacketRouter.onInboundPacket() and onInboundSignal()
because they are only called from Python (Chaquopy reflection), not
from Kotlin. LXST-kt now ships consumer-rules.pro to keep all core/
classes. Also update verify_proguard_bridge.py to scan LXST-kt source
in addition to reticulum/.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace individual -keep rules for each bridge class with a single
generic pattern that matches any class ending in "Bridge":
-keep class com.lxmf.messenger.**.*Bridge { *; }
This fixes a bug where CallBridge was not being preserved by R8,
causing incoming voice calls to fail with:
"'h' object has no attribute 'onIncomingCall'"
The verification script is also updated to:
- Dynamically discover *Bridge classes from Kotlin source
- Use generic patterns to find bridge method calls in Python
- No longer requires manual updates when adding new bridges
Convention: Any Kotlin class callable from Python should be named
with a "Bridge" suffix (e.g., FooBridge) to be automatically preserved.
Fixes voice call bug on release builds where R8 obfuscation broke
the Python→Kotlin bridge communication.
Co-Authored-By: claude-flow <ruv@ruv.net>
Test Infrastructure (Phases 2-3):
- Add DatabaseTest base class for in-memory Room database testing
- Add integration tests for message data flow and conversation creation
- Add smoke test for basic app functionality
- Create screenshot-tests module with Paparazzi setup
- Enable build cache in CI for faster builds
- Add preinstrumentedJars to Robolectric config for faster startup
- Fix NetworkCardTest to include new required parameters
- Add verify-on-device.sh script for device testing
Architecture Improvements (Phase 4):
- Extract AttachmentViewModel from MessagingViewModel
- Image selection, compression with presets, file attachments
- Save/share received media functionality
- Extract LocationSharingViewModel from MessagingViewModel
- Peer-specific sharing state computation
- Start/stop sharing operations
These changes reduce MessagingViewModel's responsibilities and create
reusable ViewModels that follow single responsibility principle.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded method list in CI with Python script that:
- Extracts all bridge method calls from Python source code
- Verifies those methods exist in the release APK's DEX files
- Detects 31 methods automatically vs 4 hardcoded previously
This ensures CI verification stays in sync with actual Python→Kotlin
bridge usage without manual maintenance.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for displaying the Columba constellation logo on RNode's
OLED display when connected. The logo is sent via KISS protocol using
the external framebuffer commands (CMD_FB_EXT, CMD_FB_WRITE).
Changes:
- Add conversion script to render icon to 64x64 monochrome bitmap
- Add columba_logo.py with 512-byte framebuffer data
- Add framebuffer methods to ColumbaRNodeInterface
- Auto-display logo after successful RNode connection
- Enable by default via enable_framebuffer config option
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>