Releases 0.4.3-0.4.7 uploaded zero source-map files to Sentry, leaving every
JS frame unsymbolicated (app:///index.android.bundle:1). Root-caused two
independent bugs:
1. No metro.config.js existed, so Metro never ran Sentry's debug-ID
injection. Without an embedded debug ID, sentry.gradle's upload task
falls back to matching source maps to events by release/dist string
alone (see has-sourcemap-debugid.js check in sentry.gradle) - and that
fallback was broken (see #2). Added metro.config.js wrapping Expo's
default config with getSentryExpoConfig from @sentry/react-native/metro,
the officially documented path for Expo + debug-ID symbolication.
The installed @sentry/react-native@6.14.0 could not actually bundle with
this enabled: its metro integration does a hard `require("metro/src/lib/
countLines")`, a deep path metro 0.83.x (bundled by Expo SDK 54) no
longer exposes via its package.json `exports` map, crashing every build.
Bumped to ~6.22.0 (package.json:18), which vendors countLines and adds
metro/private/* fallbacks for other deep metro imports. Verified via a
real `npx expo export:embed` run: bundle and source map now share a
matching `debugId`.
2. sentry.gradle's default release/dist for the upload is
`${applicationId}@${versionName}+${versionCode}` (computed from
android/app/build.gradle), which never matched what Sentry.init() reports
at runtime (`opencode-mobile@${app.json version}`, src/lib/sentry.ts:33-34).
Every source map was therefore filed under a release Sentry never
queries. Added a "Set Sentry release identifiers" step to build.yml,
publish-play-store.yml, and publish-fdroid.yml that exports
SENTRY_RELEASE/SENTRY_DIST from app.json's version before the Gradle
build step, forcing an exact match.
Also filled in organization/project on the `@sentry/react-native/expo`
plugin in app.json (previously a bare string, which only warned "Missing
config for organization, project" and relied on env-var fallback) so
android/sentry.properties is generated deterministically instead of by
accident/history.
Verified locally (no push - GitHub is down, consolidating to local main):
- npx expo export:embed (real Metro bundle) succeeds and embeds a matching
debugId in both index.android.bundle and its .map
- npm run typecheck: clean
- npm test: 81/81 passing
- Full ./gradlew Android build not verified: this machine has no
ANDROID_HOME/SDK and a JDK/Gradle-wrapper version mismatch unrelated to
this change; CI's Java 17 + Android SDK toolchain is unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NJKAQ6HAikWGQK7PGZ5Y4E
Installs are up 615% but 7-day retention is ~0% and we had no analytics SDK
to see where users drop off. Adds a thin PostHog wrapper (src/lib/analytics.ts)
that tracks app_opened, connection_form_submitted, connection_attempted,
connection_succeeded/failed (with a coarse error_class, e.g. the known 401
auth bug), message_sent, and response_received.
PostHog was chosen over Aptabase for its GMS-free JS-only RN SDK (fine for
the F-Droid/no-Firebase build), EU-hosted/self-host option, and generous
free tier. Analytics shares the exact same consent flag as Sentry
(telemetry.ts now gates both) so zero network calls happen without explicit
opt-in.
Requires a new EXPO_PUBLIC_POSTHOG_KEY CI secret (wired into build.yml,
publish-fdroid.yml, publish-play-store.yml, and documented in
publish-app-store.yml alongside the existing Sentry secrets).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NJKAQ6HAikWGQK7PGZ5Y4E
androguard 4.1.4 raises 'NoOverwriteDict object has no attribute append' in
parse_v2_v3_signature when fdroidserver extracts the signer cert — this broke the
self-hosted F-Droid publish from v0.4.2 on. 4.1.3 (which shipped v0.3.2–v0.4.1)
parses our re-signed v1+v2-only APK cleanly; verified locally with
fdroidserver.common.get_first_signer_certificate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The self-hosted F-Droid repo (https://dzianisv.github.io/opencode-mobile/fdroid/repo)
has been stuck at v0.4.1 because publish-fdroid crashed in androguard parsing the
CI APK's v2+v3 signature block pair ('NoOverwriteDict' object has no attribute
'append'). Force v1+v2-only signing: gradle flags for local builds, plus a
deterministic apksigner re-sign step in the workflow (expo prebuild regenerates
build.gradle, so the workflow step is the real guarantee). Bump to v0.4.3 /
versionCode 5 so a fresh tag re-runs the publish with the verified bug fixes
(#10 scope fixes, send-error fix) included.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reproduced locally against the v0.4.2 APK: androguard 4.0.x fails resource
parsing ('res1 must be zero!'), 4.1.0/4.1.1 fail signature parsing
('NoOverwriteDict' object has no attribute 'append'), and 4.1.4 parses both
cleanly. fdroidserver 2.4.4's own resolver pulls a buggy 4.1.x, so pin 4.1.4.
Pinning fdroidserver 2.4.4 hit androguard parse bugs on modern aapt2 APKs
(4.1+: NoOverwriteDict.append; 4.0.x: 'res1 must be zero!'). Upgrade to latest
fdroidserver which ships a compatible androguard.
fdroidserver 2.4.4 + androguard 4.1+ crashes in 'fdroid update' with
"'NoOverwriteDict' object has no attribute 'append'" while parsing the APK
v2/v3 signature. Pin androguard>=4.0,<4.1 to restore the self-hosted F-Droid
repo publish.