Task 13.3: default NDK symbol upload on for React Native - #38
Conversation
Every RN app ships Hermes and libreactnative.so it did not write, so the generated root bugsee.properties sets plugin.ndk.enabled beside the unprefixed app_token. The wrapper already exposes bugsee-android-ndk as an api dependency, so the example app does not declare it again. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Deep code review — Task 13.3 NDK symbol upload default
Reviewed 907fcec against plugin 4.0.7 (
bugsee/bugsee-android-gradle-plugin:BugseePlugin.registerNativeUploadTask,NativeUploadTask,BugseeNdkExtension,CoreSdkAutoLoad) and AGP'sndk.debugSymbolLeveldefault. Diff is three files; the example already appliescom.bugsee.android.gradleon:appand the wrapper alreadyapisbugsee-android-ndk:7.3.0.
plugin.ndk.enabled=trueis the correct properties key. It is not sufficient to make NDK symbol upload actually happen for this app.Findings
P1 High —
examples/bare/scripts/write-credentials.mjs:81
The flag registersuploadBugsee{Variant}Native, which only zips AGP'snative_debug_metadata/native-debug-symbolsoutput. AGP defaultsdebugSymbolLevelto'none'; this example never sets it, so extract is empty and the task warns and skips. Hermes /libreactnative.sofrom Maven are also pre-stripped (RN #38568), so evenSYMBOL_TABLE/FULLwould not upload those two libraries the commit cites.P2 Medium — same file, generated properties
BUGSEE_ENDPOINTis written tocredentials.jsononly. Plugin uploads default tohttps://api.bugsee.com. The documented apidev flow therefore cannot attach symbols to the environment the SDK reports into.P2 Medium —
write-credentials.mjs:17
The new comment says the flag “only enables upload.” Plugin 4.0.7 auto-addscom.bugsee:bugsee-android-ndk:[7.2.0,8.0.0)on the app because the wrapper pin is transitive, not a direct:appdependency.1. Overall risk: Medium
Runtime native-crash detection was already on via the wrapper. This change is unlikely to fail CI:
NativeUploadTaskwarns and returns on missing symbols / bad token (CLI substantive failures do not throw). The 13.3 product goal — symbolicated RN native stacks — is not met.2. Merge recommendation: Request changes
Do not mark 13.3 complete until a build of this example actually produces extract output (or the gap is documented and the checkbox stays open).
3. Most important issues to fix
- Set
ndk.debugSymbolLevelon the variants you intend to symbolicate (run-android.shisassembleDebug). Treat Hermes/libreactnative.sosymbolication as unsolved until there is an unstripped artifact source.- Write
plugin.endpointfromBUGSEE_ENDPOINTwhen it is set.- Stop claiming the flag is upload-only; pin NDK on
:appor accept the dynamic auto-add explicitly.4. Positive observations
- Unprefixed
app_token=at the root Gradle project is the right token key;plugin.appTokenis correctly avoided.- The new unit test pins the exact properties lines and that the token is not printed.
- Wrapper
apiofbugsee-android-ndkis the right place for detection; this PR correctly does not redeclare it on the example module (the plugin may still auto-add it — see P2).Did not run the new Jest file here (Yarn 4 / corepack not enabled in this environment). Did not wait for the in-progress
androidCI job; plugin upload paths are warn-and-skip, so a red assemble would be a surprise rather than the expected outcome of this diff.Sent by Cursor Automation: Bugsee code review
AGP's debugSymbolLevel defaults to none, so the plugin's native upload skips. SYMBOL_TABLE lets AGP emit symbols for code this app builds; pre-stripped Hermes and libreactnative.so stay unsymbolicated. A set endpoint is written as plugin.endpoint, and :app declares bugsee-android-ndk at the native-versions pin so the plugin does not substitute its version range. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Deep code review — Task 13.3 NDK symbol upload (877cefa)
Re-reviewed 877cefa against plugin 4.0.7 (
NativeUploadTask,BugseePlugin.registerNativeUploadTask,autoAddModule,SymbolUploader,CliUploader) and the example's placeholder-token policy (endpoint.ts,.github/workflows/ci.yml). Prior threads reconciled below.Prior findings
Prior Verdict Why P1 AGP debugSymbolLeveldefaultnonepartially_addressed Debug and release now set SYMBOL_TABLE. Extract runs; locally built JNI (bugsee-e2e-native) can upload. Maven Hermes /libreactnative.soremain pre-stripped (RN #38568); the new comments say so.P2 plugin.endpointnot writtenfully_addressed Non-empty BUGSEE_ENDPOINTbecomesplugin.endpointwith no/v2; empty is omitted. Tests cover both.P2 NDK auto-add [7.2.0,8.0.0)fully_addressed :appdeclarescom.bugsee:bugsee-android-ndk:${nativeVersions.android.sdk}directly, soautoAddModuleskips. Comment no longer says the flag is upload-only.New finding
- P2 Medium —
examples/bare/scripts/write-credentials.mjs:82
Unconditionalplugin.ndk.enabled=trueplusSYMBOL_TABLEmeansuploadBugseeDebugNativenow has extract output. CIassembleDebuguses the placeholder token and the plugin default endpoint, so every android job downloadsbugsee-cliand POSTs to production. Runtime already blocks that (isPlaceholderToken→DEAD_ENDPOINT).1. Overall risk: Medium
The three knobs from the last review are in the right place for a real Android token: unprefixed
app_token,plugin.endpoint, pinned NDK,SYMBOL_TABLE. The remaining issue is that the same path now fires in CI / placeholder builds, which this repo deliberately keeps off the real server.Hermes /
libreactnative.sosymbolication is still an RN-ecosystem gap, not a missing Gradle switch. That residual is documented next todebugSymbolLeveland is not re-raised as blocking.2. Merge recommendation: Request changes
Gate
plugin.ndk.enabled=trueon a non-placeholder Android token. Do not treat 13.3 as done until placeholderassembleDebugstops contactingapi.bugsee.com.3. Most important issues to fix
- Write
plugin.ndk.enabled=trueonly whenBUGSEE_TOKEN_ANDROIDis non-empty and not the placeholder UUID (same rule asisPlaceholderToken). Omit it for CI / local placeholder credentials.- Keep
debugSymbolLeveland the:apppin; those are the correct product defaults for a real token.4. Positive observations
SYMBOL_TABLEon both debug and release is the right AGP fix;run-android.shisassembleDebug, so debug-only would have been wrong.- Direct
:appNDK pin atnative-versions.json'sandroid.sdkmatches how the wrapper avoids the plugin's dynamic range.plugin.endpointis written only when set, without a/v2suffix, which matchesSymbolUploader's$endpoint/apps/...URL shape and the README'shttps://apidev.bugsee.com.- Credentials tests pin
app_token=,plugin.ndk.enabled=true, noplugin.appToken, and that neither token nor endpoint is printed.Did not run
yarn jest scripts/__tests__/write-credentials.test.tshere (node_moduleswas not installed). Did not wait for in-progress android CI; plugin upload failures usually warn-and-return, so a red assemble would more likely be a Kotlin-path timeout than a bad-token CLI exit.Sent by Cursor Automation: Bugsee code review
assembleDebug runs the native upload once symbols exist, and CI's placeholder token would otherwise hit the plugin's default host. Write plugin.ndk.enabled only for a non-empty Android token that isPlaceholderToken does not match. Co-authored-by: Cursor <cursoragent@cursor.com>
write-credentials.mjs runs under plain node, which rejects a .ts import. Copy isPlaceholderToken's regex into the script so a CI placeholder still leaves NDK upload off. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Deep code review — Task 13.3 NDK symbol upload (3c1fe1e)
Re-reviewed 3c1fe1e against plugin 4.0.7 (
NativeUploadTask,BugseePlugin.registerNativeUploadTask,autoAddModule/withDependencies,BugseeNdkExtension.enableddefaultfalse,UploaderStrategy.CLI). Checked callers (run-android.shassembleDebug, CIandroidjob,endpoint.tsplaceholder rule) and ranwrite-credentials.mjsfor fake token, CI UUID, placeholder+endpoint,/v2endpoint, and iOS-only. Prior threads reconciled below.Prior findings
Prior Verdict Why P1 AGP debugSymbolLeveldefaultnonepartially_addressed Debug and release set SYMBOL_TABLE. Extract can run; locally built JNI (bugsee-e2e-native) can upload. Maven Hermes /libreactnative.soremain pre-stripped (RN #38568); the comments next to the level say so.P2 plugin.endpointnot writtenfully_addressed Non-empty BUGSEE_ENDPOINTbecomesplugin.endpointwith no/v2appended; empty is omitted. Tests cover both.P2 NDK auto-add [7.2.0,8.0.0)fully_addressed :appdeclarescom.bugsee:bugsee-android-ndk:${nativeVersions.android.sdk}directly. PluginautoAddModuleruns inwithDependencies(after the dependencies block) and skips a direct dep.P2 unconditional plugin.ndk.enabled=truefully_addressed Flag is written only when BUGSEE_TOKEN_ANDROIDis non-empty andisPlaceholderTokenis false. CI UUID00000000-0000-4000-8000-000000000000omits the key, so the plugin defaultfalsestands anduploadBugseeDebugNativeis not registered.fake-android-tokenstill writes it. The regex inwrite-credentials.mjsis identical toendpoint.ts.New findings
None that meet the P0–P3 bar. Placeholder
assembleDebugno longer registers the native upload task, so CI does not downloadbugsee-clior POST toapi.bugsee.comon this path. Mapping upload remains registered but skips when there is nomapping.txt(debug does not minify). Build-info stays release-and-non-debuggable only.Hermes /
libreactnative.sosymbolication is still an RN-ecosystem gap, not a missing Gradle switch. That residual is documented next todebugSymbolLeveland is not re-raised as blocking.1. Overall risk: Low
The four knobs a real Android token needs are in the right place: unprefixed
app_token,plugin.endpointwhen set, pinned NDK on:app,SYMBOL_TABLEon debug and release. The CI placeholder path leaves NDK upload off.2. Merge recommendation: Safe once CI is green
13.3 as an example-app Gradle default is complete. Do not treat Hermes /
libreactnative.sodashboard stacks as proven; that waits on an unstripped artifact source (or 13.5 for JS).3. Most important issues to fix
None remaining on this head.
4. Positive observations
- Gating the flag on
isPlaceholderTokenmatches runtime (endpoint.ts→DEAD_ENDPOINT) instead of inventing a second rule.- Copying the regex into plain JavaScript is the right constraint:
write-credentials.mjsruns under node, which cannot importendpoint.ts. The two copies are byte-identical.- Direct
:appNDK pin atnative-versions.json'sandroid.sdkis the same coordinate the wrapper uses, so plugin auto-add does not introduce a 7.x range.plugin.endpointis omitted when unset, which keeps production tokens on the plugin defaulthttps://api.bugsee.com.Ran
write-credentials.mjsdirectly for the cases above (node_modules/ Jest were not installed here). Did not wait for in-progress CI37058633966; with NDK upload unregistered, a redassembleDebugwould come from the existing compile path, not from this flag.Sent by Cursor Automation: Bugsee code review
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Deep code review — Task 13.3 NDK symbol upload (7dd4dc7)
Re-reviewed 7dd4dc7 (merge of origin/main into 3c1fe1e) against plugin 4.0.7 (NativeUploadTask, BugseePlugin.registerNativeUploadTask, autoAddModule / withDependencies, BugseeNdkExtension.enabled default false, MappingUploadTask, UploaderStrategy.CLI). Callers checked: run-android.sh assembleDebug, CI android job, endpoint.ts placeholder rule. 13.3 production files are identical to 3c1fe1e; the merge only brought Task 9.7. Prior threads reconciled below.
Prior findings
| Prior | Verdict | Why |
|---|---|---|
P1 AGP debugSymbolLevel default none |
partially_addressed | Debug and release set SYMBOL_TABLE. Extract can run; locally built JNI (bugsee-e2e-native) can upload. Maven Hermes / libreactnative.so remain pre-stripped (RN #38568); the comments next to the level say so. |
P2 plugin.endpoint not written |
fully_addressed | Non-empty BUGSEE_ENDPOINT becomes plugin.endpoint with no /v2 appended; empty is omitted. Tests cover both. Plugin ApiEndpoint.buildsUrl also strips a trailing /v2 if one is supplied. |
P2 NDK auto-add [7.2.0,8.0.0) |
fully_addressed | :app declares com.bugsee:bugsee-android-ndk:${nativeVersions.android.sdk} directly. Plugin autoAddModule scans declared dependencies and skips that GAV. |
P2 unconditional plugin.ndk.enabled=true |
fully_addressed | Flag is written only when BUGSEE_TOKEN_ANDROID is non-empty and isPlaceholderToken is false. CI UUID 00000000-0000-4000-8000-000000000000 omits the key, so the plugin default false stands and uploadBugseeDebugNative is not registered. fake-android-token still writes it. The regex in write-credentials.mjs is byte-identical to endpoint.ts. |
New findings
None that meet the P0–P3 bar. Placeholder assembleDebug does not register the native upload task. Mapping upload remains registered but returns before CLI download when there is no mapping.txt (debug does not minify). Build-info stays release-and-non-debuggable only.
Hermes / libreactnative.so symbolication is still an RN-ecosystem gap, not a missing Gradle switch. That residual is documented next to debugSymbolLevel and is not re-raised as blocking.
1. Overall risk: Low
The four knobs a real Android token needs are in the right place: unprefixed app_token, plugin.endpoint when set, pinned NDK on :app, SYMBOL_TABLE on debug and release. The CI placeholder path leaves NDK upload off.
2. Merge recommendation: Safe once CI is green on this merge
13.3 as an example-app Gradle default is complete. Android CI 37058633966 on 3c1fe1e was SUCCESS: extractDebugNativeSymbolTables ran, uploadBugseeDebugMapping ran, uploadBugseeDebugNative did not. This head only merges main (Task 9.7). Do not treat Hermes / libreactnative.so dashboard stacks as proven; that waits on an unstripped artifact source (or 13.5 for JS).
3. Most important issues to fix
None remaining on this head.
4. Positive observations
- Gating the flag on
isPlaceholderTokenmatches runtime (endpoint.ts→DEAD_ENDPOINT) instead of inventing a second rule. - Copying the regex into plain JavaScript is the right constraint:
write-credentials.mjsruns under node, which cannot importendpoint.ts. - Direct
:appNDK pin atnative-versions.json'sandroid.sdkis the same coordinate the wrapper uses, so plugin auto-add does not introduce a 7.x range. plugin.endpointis omitted when unset, which keeps production tokens on the plugin defaulthttps://api.bugsee.com.
Ran write-credentials.mjs for fake token, CI UUID, hyphenless placeholder, placeholder+endpoint, real+endpoint, /v2 endpoint, and iOS-only (node_modules / Jest were not installed here). Decompiled plugin 4.0.7 from Maven Central. Did not wait for in-progress CI on 7dd4dc7; NDK upload is unregistered on the placeholder path, so a red assembleDebug would come from the merge (Task 9.7) or the existing compile path, not from this flag.
Sent by Cursor Automation: Bugsee code review


Summary
android/bugsee.propertiesnow setsplugin.ndk.enabled=truebeside the unprefixedapp_token=key. The file stays gitignored.com.bugsee:bugsee-android-ndk, so the example does not declare it again. This does not upload symbols.Test plan
yarn jest scripts/__tests__/write-credentials.test.ts(5 passed), including a fake token that assertsapp_token=andplugin.ndk.enabled=trueand rejectsplugin.appTokenMade with Cursor