Repository navigation
campaign: build-lane tooling for the first beta (N-20..N-25, N-27) - #61
Conversation
ff93993 to
52ec88f
Compare
There was a problem hiding this comment.
Stale comment
Deep review — campaign BUILD-lane tooling (N-20..N-25, N-27)
Reviewed 52ec88f against the generators' callers,
run-ios.shtests, the existing symbol-stub protocol, and.gitignore. This is BUILD-lane scaffolding only (no SDK runtime change), but the generators as landed cannot produce an app, andyarn teston CI will fail.Findings
P0 —
scripts/campaign/lib/*.jsis missing, and.gitignorewould hide it
- Location:
scripts/campaign/gen-rn-app.sh:152(alsogen-expo-app.sh)- Problem: Both generators
nodesix helpers (use-jsc.js,readme-android.js,deviation-gradle-plugin.js,deviation-ios-bundle-phase.js,metro-port.js,workaround-fmt.js). None are in the tree. Root.gitignorehaslib/, which matches any directory namedlib/—git check-ignorereportsscripts/campaign/lib/metro-port.jsas ignored.- Impact:
gen-rn-app.shdies on the first unconditional helper (README Android source-map edits). JSC, Gradle-plugin deviations, Metro port, and the fmt workaround never run.--readme-onlystill fails. Adding the files later with a normalgit addis silently dropped.- Scenario:
scripts/campaign/pack.shthengen-rn-app.sh 0.81(the documented N-21 path).- Fix: Add the helpers (or inline the edits). Negate them in
.gitignore(!scripts/campaign/lib/) or put them under a name git will track (scripts/campaign/helpers/).P1 —
run-ios-configuration.test.tsstill asserts the oldAPP=path
- Location:
examples/bare/scripts/run-ios.sh:71- Problem:
APPis now$APP_DIR/$BUILD_DIR/Build/Products/${CONFIGURATION}-${SDK}/${SCHEME}.app.scripts/__tests__/run-ios-configuration.test.tsstill requiresAPP="ios/build/Build/Products/${CONFIGURATION}-iphoneos/BareExample.app".- Impact: The
jsjob (yarn testin.github/workflows/ci.yml) fails on this PR. The embed-check-follows-configuration contract is no longer pinned.- Scenario: Any CI run of this branch.
- Fix: Update the test to the new interpolation and still require that the embed CLI receives the same
$APPxcodebuild writes (includingios/build-spmandiphonesimulator).P1 — Metro
PORTis last-flag-wins; N-22 × N-23 collide
- Location:
scripts/campaign/gen-rn-app.sh:72-78- Problem: Each flag replaces
PORTinstead of composing it.yarnforces8400+N,pnpm8500+N,--readme-only8600+N, so earlier JSC/readme offsets are discarded. Directory names stay unique (rn081-jscyarnvsrn081-yarn); ports do not.- Impact: Two variants of the same minor share Metro.
launch-check.shstarts bundlers on the same port, and its cleanuplsof | killon that port takes down the other lane. The script's own comment says unique ports exist so "another lane's Metro is never used".- Scenario:
gen-rn-app.sh 0.81 --pm yarnandgen-rn-app.sh 0.81 --engine jsc --pm yarn(or--readme-only --pm yarn) launched together, thenlaunch-check.shdebug on both.- Fix: Encode every variant bit into the port (or hash
DIRinto a free port) and writecampaign.portfrom that. Do not overwrite.P1 — Windows upload stub does not speak the symbol API; the check can false-pass
- Location:
.github/workflows/campaign-windows-hermes.yml:56-62- Problem: The in-repo stub (
packages/react-native/scripts/__tests__/fixtures/symbol-stub-server.js) answersPOST /apps/<token>/symbolswith{code:0,endpoint:"http://127.0.0.1:<port>/put/N"}and then accepts the PUT of the map zip. This job's stub returns{ok:true,url:".../upload"}for every request.@bugsee/cli debug-files uploadwill not PUT the map. The later step only requiresgrep -v /ping stub.logto be non-empty, so the handshake POST (or the/pingprobe if the filter is wrong) greens the job.- Impact: N-25 / HOOK-13 can record "source map reached the stub" without a map landing. A failed Windows Hermes path can also look like an upload success.
- Scenario:
assembleReleasegets far enough to spawnbugsee-cli(or even just the/ping+ a failed POST). The artifact step still uploads.- Fix: Run
symbol-stub-server.js --port 8777 --log ...and assert a PUT whose zip entry has the samedebug_idas the composed map (the unit tests already do this).P2 —
launch-check.shlock is an absolute External2TB path with no timeout
- Location:
scripts/campaign/launch-check.sh:31- Problem:
LOCK=/Volumes/External2TB/Projects/Bugsee/cross/bugsee-react-native/.device-lock.until mkdir "$LOCK"usesmkdirwithout-pand never times out. If the volume is unmounted, every wait fails and the script loops every 30s forever.run-ios.shcomments talk about a repo-relative.device-lock; this path does not share it.- Impact: After a reboot (or on any other checkout) launch-check hangs instead of failing, and it will not serialize with a caller holding the repo lock.
- Scenario: External2TB not mounted; or another lane using
$REPO/.device-lockwhile this script uses the volume path.- Fix: Resolve the lock from the repo root (or
CAMPAIGN_LOCK). Fail if the parent is missing. Keep the blocking acquire, but do not spin onENOENT.Residual (not filed)
- Gradle on
windows-latestinvokeshermesc-preserve-js.shasreact.hermesCommand. That is the N-25 experiment; the job is onpull_requestwithoutcontinue-on-error, so a disprove will red this PR and any laterpackages/react-native/scripts/**change.gen-expo-app.shlses the feedback tarball up front underset -euo pipefail, so a missing feedback pack aborts even without--with-feedback.pack.shwrites both, so the documented path is fine.Overall risk: High
Merge recommendation: Request changes
The N-20/N-21 generators cannot finish, and the
jsunit job will fail on therun-ios.shpath rewrite. Fix those and the Metro port / Windows stub before treating the BUILD lane as usable.Most important to fix
- Land the campaign helpers (and stop
.gitignorefrom eatingscripts/campaign/lib/).- Update
run-ios-configuration.test.tsfor the newAPP=.- Make Metro ports unique across combined
--engine/--pm/--readme-only.- Use the real symbol stub and assert a PUT of the map.
What looks solid
Placeholder tokens and
https://127.0.0.1:9everywhere a campaign app launches. Device allowlist + refused-prefix guard inrun-ios.sh.pack.shfails ifplugin/build/index.jsis missing from the npm tarball (W-2). SPM path backs upios/and restores onEXIT. Consumertscpins removed 6.x APIs with@ts-expect-error. The Windows workflow is clearly marked temporary.Sent by Cursor Automation: Bugsee code review
There was a problem hiding this comment.
Stale comment
Deep review of
c0ad13a(campaign BUILD-lane tooling: N-20..N-25, N-27).This is campaign harness code, not the wrapper. The intended matrix (generate from the packed tarball, build five targets, launch-check, Windows Hermes, SPM
run-ios.sh) cannot actually run as committed: the generators depend on helper modules that are not in the tree, launch-check hangs off-machine, and N-25/N-27 can record a false pass.Overall risk: High
Merge recommendation: Request changesMust fix
- P0 —
scripts/campaign/lib/*.jsare missing, and root.gitignorelib/would ignore them even if added.gen-rn-app.sh/gen-expo-app.shdie on the first helper (readme-android.js,metro-port.js, …). N-20..N-23 cannot generate an app from this PR.- P1 —
launch-check.shtakes a lock at/Volumes/External2TB/Projects/Bugsee/cross/bugsee-react-native/.device-lockwithmkdir(no-p) in an infinite loop. Any machine without that volume hangs forever.- P1 —
IOS_LAUNCH=1treatsBugsee iOS SDKas success. The native banner prints beforeStatus.Launched; a hang at Launching (keychain-34018, placeholder against a live host) is recorded PASS.launch-check.shcorrectly requiresstatus=2only.- P1 —
campaign-windows-hermes.ymlnever installs an Android SDK/NDK, then enables NDK upload via a non-placeholder token.windows-latestcannotassembleReleaseas written, so N-25 does not measure Hermes-on-Windows.Also fix
- P2 —
build-app.shskipscli-assert-framework-embedded.tson simulator targets;run-ios.shalways asserts. Anall/ sim-only cell can PASS without Bugsee.framework.- P2 —
check-16kb.shdocuments APK|AAB but on an AAB skips zipalign, extracts no.so, and prints PASS.Positive: placeholder token +
https://127.0.0.1:9in campaign configs;BugseeLaunchOptions.serializestill runsendpointForso iOS gets/v2; Windows upload uses a stub rather thanapi.bugsee.com;run-ios.shsimulator path correctly uses--console-pty(the e2e learned--consolenever delivers RN stdout).Sent by Cursor Automation: Bugsee code review
There was a problem hiding this comment.
Stale comment
Deep review of 7f0b102 (campaign BUILD-lane tooling: N-20..N-25, N-27).
This is harness code, not the wrapper. The generators,
run-ios.shswitches, 16 KB check, launch-check, and the temporary Windows Hermes job were re-checked against the README Android snippet, the podspec/android/build.gradlenative-versions walk,symbol-stub-server.js,write-credentials.mjs,e2e/device.tsallowlist, andcli-assert-framework-embedded.ts.All prior P0–P2s are fully addressed. No remaining P0–P3.
Prior findings (now closed)
- P0
scripts/campaign/lib/*.jsis committed;.gitignorehas!scripts/campaign/lib/(git ls-fileslists seven helpers;git check-ignoreis clean).- P1 Metro ports compose per variant bit (
8100+minor,+100jsc,+200yarn,+400pnpm,+800readme).- P1
run-ios-configuration.test.tspins the new$APP/$SDK/$BUILD_DIRshape. CIlint, typecheck, unitis green on this SHA.- P1 Windows upload uses
symbol-stub-server.jsand requires a PUT whose zip entrydebug_idmatches the composed map. Run37577419349fails closed: no.hbc, then “no composed-map debug id” — that is the N-25 result, not a handshake false pass.- P1
IOS_LAUNCHaccepts onlyBUGSEE_E2E status=2; the SDK banner is printed, never a pass. Generated RN apps getios-log-mirror.js.- P1
CAMPAIGN_DEVICE_LOCKplus fail-fast if the lock parent is missing (launch-check and emulators sweep).- P1 Synthetic token’s
plugin.ndk.enabledis stripped; the stub lives in the Gradle step; the job uses Gradle’s exit code. windows-latest did reach:app:createBundleReleaseJsAndAssets.- P2
build-app.shios-sim-*now runscli-assert-framework-embedded.tsafter a successful xcodebuild (7f0b102).- P2
check-16kb.shtakes an APK only; zero 64-bit.soexamined is FAIL.Residual (not defects)
- The temporary
campaign-windows-hermes.ymljob is expected red untilhermesc-preserve-js.shproduces.hbcon Windows, or the workflow is deleted after the campaign. It no longer greens without a map PUT.- The
androidCI job’stestDebugUnitTestfailure on this SHA is the bridge unit suite, not this diff.Overall risk: Low
Merge recommendation: Approve
Most important to fix
Nothing remaining for merge. Optional:
continue-on-error(or droppull_request) on the temporary Windows job if a red N-25 check is noisy in the merge box.What looks solid
Placeholder token +
https://127.0.0.1:9in campaign configs;BugseeLaunchOptions.serializestill runsendpointForso iOS gets/v2. Device allowlist + refused-prefix guard inrun-ios.sh.pack.shfails ifplugin/build/index.jsis missing from the npm tarball. SPM path backs upios/and restores onEXIT. Consumertscpins removed 6.x APIs with@ts-expect-error. W-1 copiesnative-versions.jsontonode_modules/where both the podspec (../../from the scoped package) and the Android walk-up find it.Sent by Cursor Automation: Bugsee code review
There was a problem hiding this comment.
Stale comment
Deep review — campaign BUILD-lane tooling at 7f0b102
Prior findings (missing
lib/, colliding Metro ports,run-iostest path, Windows stub protocol, lock hang,IOS_LAUNCH_EXPECTbanner, sim embed skip, AAB false-PASS) are fixed in e0197e6 / 7f0b102. This pass is against the generators,run-ios.sh,launch-check.sh, and the Windows job as they stand now — not the diff in isolation.This is still BUILD-lane scaffolding (no SDK runtime change). The remaining issues are campaign-matrix false FAILs / false PASSes, not a production-app regression.
Findings
P1 — Documented XS launch path cannot pass a Debug campaign app
launch-check.shis android / ios-sim only; the header tells operators to drive the iPhone XS withrun-ios.sh(IOS_APP_DIR,IOS_LAUNCH=1). That path never starts Metro, and generated apps bake a uniqueRCT_METRO_PORT(not 8081). DefaultIOS_CONFIGURATIONis Debug. Status=2 never appears.P2 — Expo N-20 on device has no NSLog mirror
ios-log-mirror.jsleaves Expo's AppDelegate alone.devicectl ... --consoledoes not streamos_log, which is where RN 0.87console.loggoes. Release Expo on the XS also false-FAILs.P2 —
--no-workarounds/--readme-onlydo not mean what the header says
W-3 (fmt C++17) always runs. R-4 (allowBuildsfor pnpm) always runs. Those cells cannot reproduce the bugs they exist to log.P2 —
emulators.sh sweepnever fails, and early launch-check exits skip the TSV
|| trueplusgrep PASS|FAILhides Metro/install crashes that never writelaunch-results.tsv.P2 —
gen-expo-app.shexits 0 if the config plugin did not apply
The twogrep -q … && logchecks are the N-20 assertion and do not fail the generator.Overall risk: Medium
Merge recommendation: Request changes
Fix the XS Debug launch path (start Metro on
campaign.port, or refuse Debug without it) before treating N-27 device cells as green. The P2s are campaign-integrity issues: a sweep or--no-workaroundscell can look like a pass while hiding the finding.Most important to fix
run-ios.shIOS_LAUNCH=1+ Debug + unique Metro port- Gate W-3 on
--no-workarounds(and R-4 on--readme-only)- Make
emulators.sh sweepfail when a launch-check fails, and always write a TSV rowWhat looks solid
Helpers are tracked (
!scripts/campaign/lib/). Ports compose per variant bit.check-16kb.shrefuses AABs and fails when zero 64-bit.sos are examined.ios-sim-*now runs the embed assertion. Windows uses the real symbol stub, dropsplugin.ndk.enabled, and fails on Gradle's exit code.IOS_LAUNCH_EXPECTisBUGSEE_E2E status=2only.Sent by Cursor Automation: Bugsee code review
There was a problem hiding this comment.
Stale comment
Deep review — campaign BUILD-lane tooling at 6ebb951
Reviewed against the generators,
run-ios.sh,launch-check.sh, Expo'ssetPackageInBuildGradle,e2e/scenario.tsmetroArgs/DeviceConsole, and the RN 0.81 / Expo 54–57 AppDelegate templates — not the diff in isolation.6ebb951 is a real fix, not a drive-by. Expo prebuild rewrites
applicationId "…"toapplicationId 'com.bugsee.campaign.expo…'(@expo/config-pluginssetPackageInBuildGradle). The old double-quote-only parse returned empty, so N-20 Android launch-check exited before a TSV row. ios-sim Debug now passes-RCT_jsLocation localhost:<campaign.port>, which is the same leverwarm-simulator-metal.shande2e/scenario.tsalready use, becauseRCT_METRO_PORTon React-Core does not reach a prebuilt core (0.84+). That was the missing piece for simulator Debug.The documented XS path is still
run-ios.sh(IOS_APP_DIR,IOS_LAUNCH=1). That path still does not start Metro and still does not passRCT_jsLocation. This is BUILD-lane scaffolding (no SDK runtime change); remaining issues are campaign-matrix false FAILs / false PASSes.Closed this pass: the prior P2 that Expo's AppDelegate is skipped by
ios-log-mirror.js. Expo SDK 54–57 AppDelegate hasimport Reactand the same multilinedidFinishLaunchingWithOptions … = nil/) -> Bool {the inject regex requires, socampaignMirrorMarkers()is applied. The file header comment is stale; N-20 device--consolecan see markers on Release.CI on this SHA:
lint, typecheck, unitgreen. Windows Hermes job red as expected (no.hbc). Did not run Jest locally (node_modulesabsent). Did confirm theapplicationIdregex against Expo's single-quoted rewrite and the log-mirror regex against Expo 54/57 and RN 0.81 AppDelegate shapes.Findings
P1 —
IOS_LAUNCH=1never starts Metro and never setsRCT_jsLocation
Documented XS / N-27 path. DefaultIOS_CONFIGURATIONis Debug. 0.84+ therefore loads 8081 (another lane's Metro, or nothing). A physical iPhone also cannot uselocalhost.P2 —
--no-workarounds/--readme-onlystill do not mean what the header says
W-3 (fmt C++17) always runs. R-4 (allowBuildsfor pnpm) always runs.P2 —
emulators.sh sweepnever fails; early launch-check exits skip the TSV
|| trueplusgrep PASS|FAILhides Metro/install crashes that never appendlaunch-results.tsv.P2 —
gen-expo-app.shexits 0 if the config plugin did not apply
The twogrep -q … && logchecks are the N-20 assertion and are not fatal.Overall risk: Medium
Merge recommendation: Request changes
Fix the XS Debug launch path (Metro on
campaign.port+RCT_jsLocation, Mac IP anddevicectl --on device) before treating N-27 device cells as green. The P2s are campaign-integrity issues: a sweep or--no-workaroundscell can look like a pass while hiding the finding.Most important to fix
run-ios.shIOS_LAUNCH=1+ Debug: start Metro, pass-RCT_jsLocation(device: LAN host,--before args)- Gate W-3 on
--no-workarounds(and R-4 on--readme-only)- Make
emulators.sh sweepfail when a launch-check fails, and always write a TSV rowWhat looks solid
6ebb951matches the e2e Metro contract on ios-sim. ExpoapplicationIdquotes now parse. Helpers are tracked (!scripts/campaign/lib/). Ports compose per variant bit.check-16kb.shrefuses AABs and fails when zero 64-bit.sos are examined.ios-sim-*runs the embed assertion. Windows uses the real symbol stub, dropsplugin.ndk.enabled, and fails on Gradle's exit code.IOS_LAUNCH_EXPECTisBUGSEE_E2E status=2only. Placeholder token +https://127.0.0.1:9in campaign configs.Sent by Cursor Automation: Bugsee code review
|
android release (windows-latest) is red on purpose: it is a product finding (BLK-07 / Task 13.7), not runner setup. Root cause: the bare example sets Runs 37566757670, 37567458498, 37584777337, 37587420367 (same failure each time; the SDK, NDK and JS bundling all work, the build reaches the Hermes step). So a Hermes release build of any app integrated per the README (bare or Expo, whose plugin writes the same hermesCommand) cannot be built on a Windows host. The fix is product work (a Windows-runnable preserve wrapper, e.g. a 🤖 Generated with Claude Code |
There was a problem hiding this comment.
Stale comment
Deep review — campaign BUILD-lane tooling at 155bfcb
Reviewed against the generators,
run-ios.sh,launch-check.sh,emulators.shsweep,e2e/scenario.ts(nonce + log attachment), and the campaign App templates — not the diff in isolation.155bfcb closes the previous round.
IOS_LAUNCH=1Debug now starts Metro oncampaign.port(elseE2E_METRO_PORT/ 8081), passes-RCT_jsLocation host:port(localhoston sim,E2E_METRO_HOSToren0on device,--beforedevicectlargs), and uses the 180 s budget. W-3 is behind--no-workarounds; R-4 (allowBuilds) is behind--readme-only. Plugin greps ingen-expo-app.share fatal.launch-checkwrites a FAIL TSV row on every exit after the lock;emulators.sh sweepexits 1 when any cell failed. Author verified rn086 Debug on the simulator throughrun-ios.sh(status=2).This is still BUILD-lane scaffolding (no SDK runtime change). One campaign-integrity hole remains on the Android launch path the sweep actually uses.
CI on this SHA:
lint, typecheck, unitgreen. Windows Hermes job red as expected (preserve wrapper is a shell script). Did not run Jest locally (node_modulesabsent).Findings
P2 — Android
launch-checkcan false-PASS on stale logcat and false-FAIL if logcat attaches late
The wait isgrep BUGSEE_E2E status=2in$OUT. The app logs that line once, on a status transition (template/App.tsx/examples/expo/App.js). The e2e harness uses a per-run nonce for exactly this class of stale/missed marker. This script does not.Overall risk: Low
Merge recommendation: Request changes
Fix the Android log attachment before treating
emulators.sh sweepcells as green. The rest of round 2 is solid.Most important to fix
launch-check.shAndroid: succeed-or-exit onlogcat -c, wait until logcat is attached (iOS alreadysleep 2s), and acceptstatus=2only after a freshBUGSEE_E2E launchingfrom this run (or a nonce).What looks solid
155bfcbmatches the e2e Metro contract on the XS/run-ios.shDebug path (start bundler,RCT_jsLocation,devicectl --). Helpers are tracked. Ports compose per variant bit.check-16kb.shrefuses AABs and fails when zero 64-bit.sos are examined. Windows uses the real symbol stub and Gradle's exit code.IOS_LAUNCH_EXPECTisBUGSEE_E2E status=2only. Placeholder token +https://127.0.0.1:9in campaign configs.Sent by Cursor Automation: Bugsee code review
There was a problem hiding this comment.
Stale comment
Deep review — campaign BUILD-lane tooling at 647a021
Reviewed against the generators,
run-ios.sh,launch-check.sh(including the new pid-gated wait),emulators.shsweep,e2e/device.tslogcat/devicectlcontracts, and the Windows Hermes job — not the diff in isolation.647a021 closes the previous round. Android launch-check now fails on
logcat -c,kills andwaits the previous dump, sleeps 2 s beforemonkey(same attach delay as iOS), and treatsstatus=2as a pass only after this run'sBUGSEE_E2E launching online from the same process (-v time(pid)/ compact[pid:). The Windows job iscontinue-on-errorwith the BLK-07 / Task 13.7 root cause written on the job; run 37589901572 is job-red atcreateBundleReleaseJsAndAssetsand workflow-green, which is the intended merge-box behavior untilfix/windows-hermes-releaseremoves the line.All prior P0–P2 threads are fully_addressed. This is still BUILD-lane scaffolding (no SDK runtime change). No remaining correctness holes on the sweep / XS / N-25 paths that would record a false PASS or hide a failed cell.
I replayed
launched_this_runagainst-v timeand compact[pid:tid]fixtures (including hex tids and a subsystem bracket): a lone stalestatus=2FAILs; a same-pid launching→status=2 PASSes; a different-pidstatus=2FAILs.CI:
cion 155bfcb SUCCESS (37587420787).cion this SHA (37589902003) was still queued at review. Did not run Jest locally (node_modulesabsent).Findings
None remaining (P0–P2).
Residual, not a merge blocker: the awk still keys off the first
launchingline in$OUT. A stale launching+status=2 pair left in the logcat buffer after a lyinglogcat -cwould still PASS. That is the old race after the dump has been waited on and-chas been checked; not filing.Overall risk: Low
Merge recommendation: Approve
Most important to fix
Nothing remaining for merge.
What looks solid
IOS_LAUNCH=1Debug starts Metro and passes-RCT_jsLocation(localhost/E2E_METRO_HOSToren0,--fordevicectl). W-3 / R-4 are behind the flags that exist to reproduce them. Plugin greps ingen-expo-app.share fatal. Sweep records a FAIL row on every exit and itself exits 1. Helpers are tracked; ports compose per variant bit;check-16kb.shrefuses AABs and fails when zero 64-bit.sos are examined. Windows uses the real symbol stub and Gradle's exit code. Placeholder token +https://127.0.0.1:9in campaign configs.Sent by Cursor Automation: Bugsee code review
There was a problem hiding this comment.
Stale comment
Deep review — campaign BUILD-lane tooling at d9ed0cb
Reviewed against the generators,
run-ios.sh,launch-check.sh, the Expo plugin’srewriteHermesCommand,bugsee-sourcemaps.gradle’s Windows cmd rewrite, the preserve wrapper, and the temporary Windows workflow — not the diff in isolation.d9ed0cb merges the Task 13.7 / BLK-07 product fix into this campaign branch:
hermesc-preserve-js.jsplus.cmd/.shlaunchers, a per-OShermesCommand, the leftover-.shguard, and a relative launcher whencmdwould cut the absolute path.readme-android.jsnow refuses a split README line and requires both launchers. All prior campaign P0–P2 threads remain fully_addressed.This is still BUILD-lane scaffolding plus the Windows Hermes product path. One merge-integrity hole is new: the job that was allowed to stay red for BLK-07 still has that exception after the fix is in the tree.
Did not run Jest (
node_modulesabsent). CI on this SHA was still in progress at review (ci37924486047,campaign windows hermes37924485585). Last greencion this branch was 37589902003 at 647a021.Findings
P2 —
android-releasestillcontinue-on-errorafter the product fix landed
The comment on that job says thefix/windows-hermes-releasebranch removes the flag so the job gates merge. That fix is now commit d9ed0cb on this PR.expo-android-releaseandandroid-release-spaced-pathalready fail the workflow; this first job is the only one that runs the Windows wrapper tests and the leftover-.shguard.Overall risk: Medium
Merge recommendation: Request changes
Drop
continue-on-erroronandroid-release(and the stale “KNOWN FAILURE” comment) so N-25 actually gates the product path this PR now ships. Campaign generators / launch-check /run-ios.shlook solid.Most important to fix
- Remove
continue-on-error: truefrom.github/workflows/campaign-windows-hermes.ymlandroid-release.What looks solid
Prior campaign holes stay closed: helpers tracked, Metro ports compose per variant bit,
IOS_LAUNCHDebug starts Metro and passes-RCT_jsLocation, W-3/R-4 are behind the flags that exist to reproduce them, launch-check writes a FAIL row on every exit and keysstatus=2to this run’s pid,check-16kb.shrefuses AABs. The preserve wrapper fails closed when hermesc writes no bytecode; the Gradle hook relativizes a Windows launcher thatcmdwould cut, and the README snippet the generator copies is one whole per-OS line.Sent by Cursor Automation: Bugsee code review
There was a problem hiding this comment.
Stale comment
Deep review — campaign BUILD-lane tooling at 037230a
Reviewed against the generators,
run-ios.sh,launch-check.sh,emulators.shsweep, the Expo plugin’srewriteHermesCommand,bugsee-sourcemaps.gradle’s Windows cmd rewrite, the preserve wrapper, and the temporary Windows workflow — not the diff in isolation.037230a closes the previous round.
continue-on-erroris gone fromandroid-release; the comment now describes the job as the blocking N-25 / BLK-07 proof. Windows Hermes run 37924485585 on d9ed0cb (the product fix) is SUCCESS on all three jobs:android-release,expo-android-release, andandroid-release-spaced-path. 037230a is that flag/comment only.All prior campaign P0–P2 threads are fully_addressed. This is still BUILD-lane scaffolding plus the Windows Hermes product path. Two campaign-integrity holes remain.
Did not run Jest (
node_modulesabsent).cion d9ed0cb (37924486047) was still in progress at review.Findings
P2 —
build-app.shiOS embed check has no Node ≥22.18 gate
After the sim-embed fix,build-app.shrunscli-assert-framework-embedded.tswith no version check.run-ios.shalready exits 2 when Node is older, because type-stripping of a.tsentry point only works from 22.18 and older Node throwsERR_UNKNOWN_FILE_EXTENSIONwith exit 1 — the same code as “framework missing”.P2 —
emulators.sh bootcan hold.device-lockforever
adb wait-for-deviceand thesys.boot_completedloop have no timeout. Sweep takes the shared campaign lock beforeboot. A wedged AVD (corrupt image, emulator crash aftercreate) never releases the lock;launch-check/ other sweeps sleep 30s forever. Ctrl-C does run the EXIT trap; an unattended sweep does not.Overall risk: Medium
Merge recommendation: Request changes
The Windows product path and the continue-on-error hole are done. Gate the embed check the same way
run-ios.shdoes, and bound emulator boot so a dead AVD cannot pin the device lock.Most important to fix
- Copy
run-ios.sh’s Node ≥22.18 gate before both iOS assert calls inbuild-app.sh; treat exit 2 as tooling, not an embed miss.- Bound
emulators.sh boot(e.g. 5–10 min); on timeout kill the emulator, drop the lock, fail that AVD.What looks solid
037230a makes N-25 blocking. Helpers are tracked; Metro ports compose per variant bit;
IOS_LAUNCHDebug starts Metro and passes-RCT_jsLocation; W-3/R-4 are behind the flags that exist to reproduce them; launch-check writes a FAIL row on every exit and keysstatus=2to this run’s pid;check-16kb.shrefuses AABs. The preserve wrapper fails closed when hermesc writes no bytecode; the leftover-.shguard and cmd-safe relative rewrite are the Windows customer path, and that path is green on windows-latest including a path with spaces and parentheses.Residual, not filed:
run-ios.shstill proceeds if Metro/statusnever saysrunning(false FAIL after 180s, not a false PASS). The leftover-.shguard’s suggested fix is the READMEbugseeDirform; Expo prebuild writesHERMES_COMMAND_EXPRinstead, and--no-cleanonly migrates the exact legacy plugin.shline — bare README upgrades havebugseeDirand paste correctly.Sent by Cursor Automation: Bugsee code review
There was a problem hiding this comment.
Stale comment
Deep review — campaign BUILD-lane tooling at 18732ae
Reviewed against the generators,
run-ios.sh,launch-check.sh,emulators.shsweep, the Expo plugin’srewriteHermesCommand,bugsee-sourcemaps.gradle’s Windows cmd rewrite, the preserve wrapper, and the temporary Windows workflow — not the diff in isolation.18732ae closes the previous round. Both remaining campaign P2s are fixed:
- Node ≥22.18 gate.
build-app.shembed_checknow runs the samenode -eversion check asrun-ios.shbeforecli-assert-framework-embedded.ts. An older Node’sERR_UNKNOWN_FILE_EXTENSION(exit 1, the same code as a missing framework) is recorded asTOOLINGwith the gate’s message, never as an embed FAIL. Bothios-sim-*andios-device-*go through this helper;overallstill exits 1.- Bounded emulator boot.
emulators.sh bootdropped unboundedadb wait-for-device. Thesys.boot_completedwait usesBOOT_TIMEOUT(default 600 s). On timeout the emulator is killed,bootexits 3, andsweeprecords that AVD as FAIL,rmdirs.device-lock, and continues with the next AVD.All prior campaign P0–P2 threads are fully_addressed. This is still BUILD-lane scaffolding plus the Windows Hermes product path. No remaining correctness holes that would record a false PASS, hide a failed cell, or pin the shared device lock.
Did not run Jest (
node_modulesabsent). This environment’s Node is 22.14.0 — the case the new gate is for.ciand Windows Hermes last completed on d9ed0cb (37924486047 SUCCESS, 37924485585 all three jobs SUCCESS). 18732ae only touchesbuild-app.sh/emulators.sh, so the Windows workflow correctly does not re-run.Findings
None remaining (P0–P3).
Overall risk: Low
Merge recommendation: Approve
Most important to fix
Nothing remaining for merge.
What looks solid
18732ae matches
run-ios.shon the embed-check Node floor and no longer lets a dead AVD hold.device-lock. Helpers are tracked; Metro ports compose per variant bit;IOS_LAUNCHDebug starts Metro and passes-RCT_jsLocation; W-3/R-4 are behind the flags that exist to reproduce them; launch-check writes a FAIL row on every exit and keysstatus=2to this run’s pid;check-16kb.shrefuses AABs. The preserve wrapper fails closed when hermesc writes no bytecode; the leftover-.shguard and cmd-safe relative rewrite are the Windows customer path, and that path is green on windows-latest including a path with spaces and parentheses. N-25 is blocking (continue-on-erroris gone).Residual, not filed:
run-ios.shstill proceeds if Metro/statusnever saysrunning(false FAIL after 180 s, not a false PASS). If an emulator process never appears on ADB, timeoutemu killis a no-op and that qemu may linger — the campaign lock is still released.Sent by Cursor Automation: Bugsee code review
Generator for one bare app per React Native minor integrated from the packed tarball by the package README (deviations and workarounds logged), Expo SDK 54-57 apps from examples/expo, JSC and package-manager variants with a consumer type-check, the 16 KB alignment check, a temporary windows-latest Hermes release workflow, run-ios.sh delivery/target/app switches (SPM), launch checks and the emulator sweep AVDs. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…e build-spm 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- un-ignore scripts/campaign/lib (the root .gitignore's lib/) - Metro ports compose per variant flag, no collisions - run-ios.sh IOS_LAUNCH passes only on BUGSEE_E2E status=2 - launch-check/emulators: CAMPAIGN_DEVICE_LOCK, fail fast on a missing lock dir - check-16kb: APK only; zero 64-bit libraries examined is a FAIL - windows workflow: the repo's symbol stub, PUT with the composed map's debug id asserted, no NDK upload, Gradle's exit code decides - ios-log-mirror: BUGSEE_E2E markers reach NSLog in generated apps 🤖 Generated with [Claude Code](https://claude.com/claude-code)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
…ts simulator Debug at the app's Metro with RCT_jsLocation 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- run-ios.sh IOS_LAUNCH Debug: the app's own Metro (started if needed), -RCT_jsLocation host:port (devicectl after --), 180 s budget - gen-rn-app: W-3 only with workarounds, R-4 only without --readme-only - gen-expo-app: a prebuild without the plugin's Gradle/bundle-phase edits fails - launch-check writes a FAIL row on every early exit; emulators.sh sweep exits non-zero when any launch failed 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…b continue-on-error (BLK-07) - launch-check: logcat -c checked, previous dump waited for, 2 s attach, PASS needs status=2 after this launch's own 'launching' line from the same pid - campaign-windows-hermes: continue-on-error with the BLK-07 / Task 13.7 root cause; the job still runs red; the fix branch fix/windows-hermes-release removes the line 🤖 Generated with [Claude Code](https://claude.com/claude-code)
) * Android: Hermes release builds on Windows hosts (Task 13.7, BLK-07) React Native runs react.hermesCommand through `cmd /c` on Windows (BundleHermesCTask getHermescCommand -> windowsAwareCommandLine), and a user-set command is kept as is (detectOSAwareHermesCommand). cmd cannot run hermesc-preserve-js.sh: it exited 0, wrote no bytecode, and the task failed later with NoSuchFileException on index.android.bundle.hbc. - The wrapper's work moves to scripts/hermesc-preserve-js.js (Node). Two launchers start it: hermesc-preserve-js.sh (macOS, Linux; existing builds keep working) and hermesc-preserve-js.cmd (Windows, CRLF via .gitattributes). hermesc is found as before, with win64-bin/hermesc.exe on Windows. - The wrapper exits non-zero whenever no bytecode came out: hermesc exited 0 with no or an empty -out (a stale file is removed first), was killed, could not start, or no -out was given. - hermesCommand picks the launcher when Gradle configures: System.getProperty("os.name").startsWith("Windows") ? .cmd : .sh, so one build.gradle serves a repo shared across macOS, Linux and Windows. README, bare example and the Expo plugin write it. - Expo plugin: the exact line an earlier prebuild wrote (the .sh on every OS) is moved to the per-OS one; a user's own hermesCommand that names hermesc-preserve-js stays. Corpus cases for both. - bugsee-sourcemaps.gradle: on Windows a Hermes bundle task whose hermesCommand names a .sh fails before hermesc, with the line to use. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * campaign: Windows Hermes release job covers Expo and the .sh guard The windows-latest workflow now also runs the wrapper tests on Windows (the .cmd through cmd /c with the repository's hermesc.exe), checks that a .sh hermesCommand fails the bundle task with the fix before hermesc, and builds the Expo example after an `expo prebuild` on the runner: composed map debug id, the same id in the APK bytecode, and the upload to the stub. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Preserve wrapper: tests for every helper; drop a redundant setter check Scoped mutation run (stryker.plugin.json, --mutate on hermesc-preserve-js.js and the hermesCommand rewrite in gradle.ts): 93.86 -> 98.25, the wrapper at 100. The setter-call check before the legacy match could not change the outcome (a setter's value carries its closing bracket), so it goes. The command-line entry runs only in a child process and is excluded from mutation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Preserve wrapper tests: absolute paths and real paths that hold on Windows The windows-latest run showed three test-only failures: a rootless path gains a drive letter when resolved, and the runner's temp directory comes back in 8.3 short form from realpathSync. The launcher tests (the .cmd through cmd /c with hermesc.exe) passed there. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * README: hermesCommand on one line; the campaign extractor checks it whole Cursor review (PR 65): scripts/campaign/lib/readme-android.js copies the README's hermesCommand with a one-line match, so the two-line per-OS value was cut after `new File(new File(bugseeDir, "scripts"),` and every generated bare app would fail to configure. The README keeps the value on one line, the shape the Expo plugin writes, and the extractor now refuses a value whose brackets do not close on its line or that does not name both launchers. Test: the real README goes through the extractor whole, and a split value is refused. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Preserve wrapper tests: resolveFrom compares native real paths (Windows 8.3) Cursor review (PR 65): the resolveFrom test still used realpathSync, which keeps the runner's 8.3 temp path, while require.resolve returns the long form; it failed on windows-latest before the release build ran. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * campaign: the Windows guard step exits 0 once the expected failure is seen pwsh ended the step with Gradle's last exit code, the very failure the step expects; run 37593316440 printed 'guard: failed with the fix, before hermesc' and still went red. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * campaign: Windows bare release from a path with spaces and parentheses Same release build, debug-id and stub-upload checks as the bare job, from a checkout under 'my projects (x86)/bugsee rn': React Native runs hermesCommand through cmd /c, whose quote handling changes when the command path holds spaces or ( ). 🤖 Generated with [Claude Code](https://claude.com/claude-code) * campaign: the spaced-path job builds from a short root Under the workspace, 'my projects (x86)/bugsee rn' pushed the New Architecture codegen objects past Windows' 260-character limit, and CMake failed before any JavaScript step. That is React Native's path-length limit, not the spaces; the job now copies the checkout to 'C:/s (x86)/b rn'. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Android: Windows hermesCommand survives a project path with spaces and ( ) The new windows-latest job from 'C:/s (x86)/b rn' (run 37601601358) failed in createBundleReleaseJsAndAssets with "'C:\s' is not recognized": React Native runs hermesCommand through cmd /c, and cmd strips the quotes around a command path that holds spaces together with ( ) & ^ @ < > |, then runs it cut at the first space. React Native passes its own paths relative to the project root and runs hermesc from there; on Windows the hook now does the same for hermesCommand when its absolute path would be cut (another drive, or a relative path that would be cut too, keeps it as written). README says so. The spaced-path job also splits its artifact, since upload-artifact needs one root. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Android: the Windows relative hermesCommand may hold @ Run 37602820088 still ran the absolute launcher: the relative form, node_modules\@bugsee\..., was rejected for its @. That character only matters inside cmd's quote rule; an unquoted relative path is cut only by a space or an operator (& < > ^ |), which is now the whole check. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Android: Windows hermesCommand rewrite also covers ( ) without a space Cursor review (PR 65): c34ceba dropped ( ) from the check, so an absolute launcher path like C:\Users\John(US)\... (no space, so Java does not quote it) was kept, and cmd groups at the bracket. Two checks now: an absolute path holding a space or ( ) & < > @ ^ | is given relative to the project root, and that relative path is used unless it holds a space or ( ) & < > ^ | (@ is fine unquoted). The helper is kept on the project, and the real-Gradle hook test runs it on eight paths: the campaign's spaced path with @, John(US), plain, an operator, another tree, and an already relative path. README names both shapes. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…is fixed The job was allowed to fail while the Windows hermesCommand defect was open. #65 fixed it, so drop continue-on-error and describe the job as the blocking N-25 proof it now is. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…boot wait build-app.sh ran the .ts embed check without the Node version gate run-ios.sh has, so an older Node's ERR_UNKNOWN_FILE_EXTENSION (exit 1) was recorded as an embed FAIL. It now checks first and records TOOLING instead. emulators.sh waited for boot without a limit while a sweep held the shared device lock. The wait is bounded (BOOT_TIMEOUT, default 600 s); on timeout the emulator is killed, the sweep records the AVD as FAIL, releases the lock and moves on. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
18732ae to
c460da8
Compare
There was a problem hiding this comment.
Deep review — campaign BUILD-lane tooling at c460da8
Re-reviewed #61 at c460da8 (prior 18732ae). Base is main @ d957f55. The campaign scripts are unchanged vs the last approve; this synchronize rebases them with the Windows Hermes product fix (BLK-07 / Task 13.7), which is how that work reaches main.
Looked at the generators (gen-rn-app.sh / gen-expo-app.sh + scripts/campaign/lib/*), build-app.sh / embed_check, emulators.sh boot|sweep, launch-check.sh (including the launching-then-status=2 awk), run-ios.sh, the Windows Hermes workflow, and the customer-facing wrapper path (hermesc-preserve-js.js + .cmd/.sh, plugin HERMES_COMMAND_EXPR, bugsee-sourcemaps.gradle cmd-safe rewrite and .sh-on-Windows guard). Also checked Expo SDK 54/57 Podfile templates: react_native_post_install( is multi-line, so metro-port.js / workaround-fmt.js still match.
All 24 prior threads remain fully_addressed (helpers committed; composed Metro ports; embed path + Node ≥22.18 as TOOLING; stub PUT + debug_id; lock parent fail-fast; launch-check FAIL rows; plugin-apply greps fail the generator; status=2 only after this launch’s launching line; Windows job required; boot wait bounded).
No remaining P0–P3.
Did not run Jest (node_modules absent). Node in this environment is 22.14.0 (the gated embed-check case). CI on c460da8 was still in flight at review time — the three Windows Hermes jobs are now required proofs, so they need to go green before merge.
Overall risk: Low
Merge recommendation
Approve. Merge once CI is green, especially android release (windows-latest) / Expo / spaced-path.
Most important issues to fix
None.
Positive observations
- Old Node is
TOOLING(rc 99), not an embed FAIL, matchingrun-ios.sh. - A wedged AVD no longer holds
.device-lockforever:BOOT_TIMEOUT(600s), sweep records FAIL, unlocks, continues. - One
build.gradleserves macOS/Linux/Windows (hermesCommandpicks.cmdvs.shat configure time); leftover.shon Windows fails indoFirstwith the README line, not a later missing.hbc. readme-android.jscopies the README hermesCommand as one per-OS line and refuses a split value.
Sent by Cursor Automation: Bugsee code review


Beta campaign BUILD lane tooling (PREP-build). Evidence and commands:
campaign-prep-build.mdin the campaign directory.scripts/campaign/gen-rn-app.sh(N-21, N-22, N-23): one bare app per RN minor 0.81-0.87 from the npm-packed tarball, integrated by the package README; README gaps (DEVIATION R-n) and product-bug workarounds (WORKAROUND W-n) are logged by name and can be switched off (--readme-only,--no-workarounds).--engine jsc,--pm npm|yarn|pnpm,--smoke <dir>for the N-01 module; consumertsc(API-48/49) with the template TypeScript and TS 6.scripts/campaign/gen-expo-app.sh+examples/expo/App.js(N-20): Expo SDK 54-57 apps, config plugin, deep-link scenario, markers.scripts/campaign/check-16kb.sh(N-24),build-app.sh,launch-check.sh,emulators.sh(API 24/30/36 AVDs + sweep),pack.sh.examples/bare/scripts/run-ios.sh(N-27):IOS_DELIVERY=spm,IOS_TARGET=simulator,IOS_APP_DIR,IOS_LAUNCH..github/workflows/campaign-windows-hermes.yml(N-25, TEMPORARY, delete after the campaign). It fails by design of the finding: Hermes release on Windows stops atcreateBundleReleaseJsAndAssets(index.android.bundle.hbcmissing;hermesc-preserve-js.shis a shell script) — BLK-07 / Task 13.7.Results (beta5 tarball, cc78c64): 14 Hermes apps (0.81-0.86, Expo 54-57, 0.87 via npm/Yarn/pnpm, README-only control) build Android Debug/Release and iOS sim Debug + device Debug/Release, and launch on the WOD_LX1 (Debug+Release) and the simulator (Debug); rn086 Release launches on the XS; SPM on the simulator passes; rn081 launches on API 24/30/36 emulators. Product findings for the campaign: native-versions.json missing from the tarball (pod install and Gradle fail for npm consumers), consumer tsc fails on RN 0.87, README gaps (static serialize, Gradle plugin, iOS bundle phase, pnpm allowBuilds),
yarn packdrops the Expo plugin build. JSC is blocked by third-party issues.🤖 Generated with Claude Code