Repository navigation
Task 8.2c: iOS createReport with the SDK attachment limits - #21
Conversation
…through R8 Co-authored-by: Cursor <cursoragent@cursor.com>
…rom render
Banner: Bugsee Android SDK 7.3.0 [beb390dc0].
One handled payload (nonce 6877ef246252):
{"name":"TypeError","reason":"E2E handled 6877ef246252","frames":[{"data":{"member":"bugseeE2EThrowSite"},"debug_id":"8a1c2f4e-0d3b-5e6f-9a7b-6877ef246252"}],"cause":{"name":"RangeError","reason":"inner 6877ef246252"},"signature":"8362dd3b5785297d7d387925b94ce0ea5e857cfc","platform_os":"android","debug_ids":{"http://localhost:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.bareexample&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server":"8a1c2f4e-0d3b-5e6f-9a7b-6877ef246252"}}
Gated release R1–R3 bundles (nonce 824ac61adb58): exactly one crash,
com.bugsee.reactnative.ReactNativeWebException, reason JSON with
"E2E fatal 824ac61adb58". No JavascriptException Bugsee bundle observed
(R2 prediction unmet; assertion left intact for controller ruling).
Thread: exception handled sent tid→comm BugseeRN-except (TASK_COMM_LEN
truncation of BugseeRN-exceptions).
Co-authored-by: Cursor <cursoragent@cursor.com>
Controller ruling: R13's second Bugsee crash is not retained on Android SDK 7.3.0. Logcat still shows FATAL EXCEPTION / JavascriptException and the process dies; Bugsee keeps exactly one crash named ReactNativeWebException. Gated R2/R3 updated; debug case 10 stays it.failing. awaitBundles(1) for the release beforeAll. Release verify (WOD_LX1): R1–R3 PASS; one bundle 894ba5df-af93-4d4b-9678-5d06ec218db4.bundle.zip. Co-authored-by: Cursor <cursoragent@cursor.com>
ExceptionStage registers _bugseeDebugIds synchronously before mounting BugseeE2EThrower, so the map exists for the first render throw. Root polls for a crash with the boundary reason instead of requiring two bundles. Release R1 asserts exactly one ours. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…cannot be lost Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
beta3 0d9c9d0a-9 stores the unhandled report and does not claim override_report.plcrash on the next launch. The one-crash asserts stay it.failing so an empty recovery list cannot pass as the desired outcome. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…e stubbed Co-authored-by: Cursor <cursoragent@cursor.com>
… front Co-authored-by: Cursor <cursoragent@cursor.com>
A late completion still runs after clear. The token it captured is the only one fulfil will honour, so it cannot mint a handle on the next runtime's slot or nil a report that slot already holds. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Deep code review (PR #21,
a05df5a)iOS
createReportis wired through a one-slot registry with reservation tokens, SDK attachment limits enforced at add time, andinvalidateclearing the slot so a reload cannot stay busy. The second commit correctly stops a late SDK completion from minting a handle on the next runtime.The remaining holes are in the other direction of the same overlap, and in when the slot is considered free relative to
uploadReport.Inspected: the Task 8.2c plan, JS
CreatedReport/ error contract, handlerBGSRNReportOps, Android stubs, XCTest coverage, and the public7.0.0-beta3headers (createReportWithCompletion:,uploadReport:completion:,BugseeExtendedReport). XCTests were not re-run here.Findings
Sev Issue P1 invalidateunconditionallyclears the process-wide slot, so a new runtime that already reserved or fulfilled can lose that reportP1 takefrees the slot beforeuploadReportfinishes, so a secondcreateReportis admitted mid-upload (BUSY contract + P5 globals)P2 Attachment size is enforced after unbounded main-thread decode/read Overall risk: Medium
The fill/read/update/add-attachment happy path is careful (all-or-nothing patches, owned file bytes, symlink sizing, P5 canary). Reload-vs-create and upload-vs-create are not.
Merge recommendation: Wait
Do not merge until the two P1s are fixed. The P2 should land with them if screenshots-as-base64 are an expected
addDataAttachmentpath.Most important to fix
- Identity-check
clear(or otherwise own the slot per module), the same way EventBus / report-handler / data-requestdetach:already do.- Keep the slot occupied until the
uploadReportcompletion (handle can still die attake).Positive
Reservation tokens and the two stale-fulfil tests match a real overlap (
createReportvsinvalidateon another queue).validatedPatch:error:keeps handler and created-report validation identical. File attachments are copied at add time, andtestTheSdkSharesAttributesAcrossExtendedReportsis a useful tripwire for lifting P5.Sent by Cursor Automation: Bugsee code review
A second BugseeExtendedReport resets beta3's file-scope attributes. The handle still dies when upload starts. Over-long base64 is rejected before it is decoded, and a file read stops at the 3 MiB cap.
There was a problem hiding this comment.
Stale comment
Deep code review (PR #21,
5f1dfa0)Re-review after
fix(ios): keep the created-report slot until upload finishes.
detachForUpload:/endUpload:close the same-runtime P1: the handle dies at detach, the slot stays taken until theuploadReport:completion, and a secondcreateReportcan no longer-initanotherBugseeExtendedReportmid-copy. The 3 MiB cap is now applied beforeinitWithBase64EncodedString:, file reads are capped withreadDataOfLength:after anNSFileTypeRegularcheck, andtestAnOverlongBase64StringIsRejectedBeforeDecoding/testAnUploadInFlightKeepsTheSlotpin both.The remaining hole is still
invalidate→ unconditionalclearon a process singleton with no owner. Tokens protectfulfilandendUpload:against stale completions; they do not protect a live slot from the dying module.Inspected: Task 8.2c, JS
CreatedReport/E_REPORT_CREATE_BUSY(P5), handlerBGSRNReportOpsvalidatedPatch:, Android 8.2bCreatedReports(same unconditionalclearon that PR), EventBus/handler/data-requestdetach:identity checks, and the new registry tests. XCTests were not re-run here.Findings
Sev Issue P1 invalidateunconditionallyclears the process-wide slot, so a new runtime that already reserved, fulfilled, or is uploading can lose that report — andclearsets_uploading = NO, which reopens the P5 attribute wipe during reload-vs-uploadPrior P1 (
takebeforeuploadReportcompletion) and P2 (unbounded main-thread decode/read) are fixed.Overall risk: Medium
The fill / attach / upload happy path on one runtime is now careful. Reload-vs-create and reload-vs-upload are not, and they sit on the same
clearthe rest of this module already identity-checks everywhere else.Merge recommendation: Wait
Do not merge until
clearis owner-checked (and an in-flight upload keeps_uploadinguntilendUpload:even across a reload).Most important to fix
- Identity-check
clear(claim owner on attach / first reserve;invalidatedrops the slot only if still owner), matching EventBus / report-handler / data-requestdetach:.- On owner change, drop the handle the new JS cannot address, but do not clear
_uploadinguntil that generation'sendUpload:.Positive
detachForUpload:+ generation-stampedendUpload:is the right shape for P5. Stale-fulfil tests, the over-long base64 pre-check, capped file reads, andtestTheSdkSharesAttributesAcrossExtendedReportsremain good tripwires.Sent by Cursor Automation: Bugsee code review
invalidate drops the handle the next runtime cannot use, and leaves the slot taken until uploadReport finishes copying. Clearing that hold let a reload construct another BugseeExtendedReport and wipe beta3's file-scope attributes.
There was a problem hiding this comment.
Stale comment
Deep code review (PR #21,
81ce130)Re-review after
fix(ios): keep an in-flight created-report upload across clear.
clearno longer drops_uploading, so a reload duringuploadReport:cannot-initanotherBugseeExtendedReportmid-copy.testClearDuringUploadKeepsTheSlotUntilEndpins that. Prior P1 (takebefore upload completion) and P2 (unbounded decode/read) stay fixed.The remaining hole is the other half of the overlap the registry already documents (
createReportvsinvalidateon another queue): tokens protect a reservation that exists; they do not protect areservethat has not run yet.Inspected: Task 8.2c / P5–P7, JS
CreatedReport/E_REPORT_CREATE_BUSY, handlerBGSRNReportOps, EventBus/handler/data-requestdetach:,BGSRNRunOnMain, and the created-report XCTests. XCTests were not re-run here.Findings
Sev Issue P1 reserveis insideBGSRNRunOnMain;invalidate→clearcannot cancel that hop, so a reload leaves the process slot taken by a handle no JS holdsPrior thread (
invalidateunconditionalclear): partially addressed. Upload hold acrossclearis done. Steal of a reservation the next runtime already made is the same family; this hop is the failure that does not depend on two module instances.Overall risk: Medium
Fill/read/update/add-attachment and same-runtime upload-vs-create are in good shape. Reload-vs-in-flight-
createReportcan still wedgeE_REPORT_CREATE_BUSYfor the life of the process.Merge recommendation: Wait
Do not merge until a queued
createReportcannot re-occupy the slot afterclear.Most important to fix
- Admit the slot before the async main hop, or skip
reserveonce this module is invalidated —clearalone cannot see work that has not reserved yet.Positive
Reservation tokens still stop a late SDK completion from minting a handle on the next slot. Upload generations plus the
_uploadinghold close the P5-initwipe for an in-flightuploadReport:. Attachment limits are enforced before decode / with a capped file read.testTheSdkSharesAttributesAcrossExtendedReportsremains a useful tripwire for lifting P5.Sent by Cursor Automation: Bugsee code review
invalidate clears the slot on another queue and cannot cancel a block already queued. Reserving inside that hop left the slot taken by a handle the torn-down JS never uploads. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Deep code review (PR #21,
2bcf21d)Re-review after
fix(ios): reserve a created report before the main hop.
reservenow runs on the TurboModule queue beforeBGSRNRunOnMain.invalidate→cleardrops that token. The hop checksreservationIsOpen:and skipscreateReportWithCompletion:when it is gone, so a torn-down runtime cannot-initanotherBugseeExtendedReportor hold the slot.testClearBeforeTheHopClosesTheReservationpins the other-queueclear. Prior P1s (takebefore upload completion; unbounded decode/read; upload hold acrossclear) stay fixed.Inspected:
createReportvsinvalidate/clear,reservationIsOpen:/fulfil:reservation:/_uploading, attachment ops, andBGSRNCreatedReportsTests. XCTests were not re-run here; the author reports 12/12 on simulator6FA9B3E8.Findings
No remaining P0–P3.
Owner-checked
clearis still declined. That is not re-raised: with admit-before-hop, an overlappingclearyieldsnullorE_REPORT_HANDLE_DEADand the nextcreateReportcan admit; it no longer wedgesE_REPORT_CREATE_BUSYfor the process lifetime.Overall risk: Low
Merge recommendation: Safe (into
feat/phase-8-2a; this branch still does not contain the Android registry)Most important to fix
Nothing blocking.
Positive
The hop/clear race is closed at the admission point, not only at
fulfil. Skipping the SDK call when the token is gone avoids a gratuitous P5-init. Upload generations and the 3 MiB / 3-attachment caps remain in place.Sent by Cursor Automation: Bugsee code review
There was a problem hiding this comment.
Stale comment
Deep code review (PR #21,
2bcf21d)Re-review after
fix(ios): reserve a created report before the main hop.Reserving on the calling queue before
BGSRNRunOnMaincloses the queued-reserve wedge:invalidate→cleardrops the token,reservationIsOpen:is NO, and the hop does not callcreateReportWithCompletion:.testClearBeforeTheHopClosesTheReservationpins that. Prior P1 (takebeforeuploadReportcompletion) and P2 (unbounded decode/read) stay fixed. Upload still holds_uploadingacrossclear.The complementary hole is still open:
clearzeros_creatingafter the SDK call has already started. That is the same P5-initwipe the upload path now prevents, but forcreateReportWithCompletion:instead ofuploadReport:.Inspected: Task 8.2c / P5–P7, JS
CreatedReport/E_REPORT_CREATE_BUSY, handlerBGSRNReportOpsvalidatedPatch:, EventBus/handler/data-requestdetach:,BGSRNRunOnMain, the created-report XCTests, and the public7.0.0-beta3headers (createReportWithCompletion:,uploadReport:completion:,BugseeExtendedReport). XCTests were not re-run here.Findings
Sev Issue P1 clearfrees the slot whilecreateReportWithCompletion:is in flight; the next runtime-inits anotherBugseeExtendedReportand can wipe the live report’s attributesPrior thread (
reserveinsideBGSRNRunOnMain): fully addressed for the pre-SDK-call path. Prior thread (invalidateunconditionalclear): not addressed (owner-checkedclearstill declined). The remaining failure does not depend on attach-before-invalidate — serial 0.87 teardown is enough.Overall risk: Medium
Fill/read/update/add-attachment and same-runtime upload-vs-create are in good shape. Reload-vs-in-flight-
createReportafter the SDK call can still corrupt the next report via P5 globals.Merge recommendation: Wait
Do not merge until an in-flight
createReportWithCompletion:keeps the slot until its (possibly stale)fulfil:, the same way an in-flightuploadReport:keeps_uploadinguntilendUpload:.Most important to fix
- Hold the creating slot across
clearuntil that reservation’s completion; do not publish a handle the torn-down JS cannot upload.Positive
Reservation-before-hop plus
reservationIsOpen:is the right check for a queued blockclearcannot cancel. Upload generations plus the_uploadinghold close the P5 wipe foruploadReport:. Attachment limits are enforced before decode / with a capped file read.testTheSdkSharesAttributesAcrossExtendedReportsremains a useful tripwire for lifting P5.Sent by Cursor Automation: Bugsee code review
…shes clear was freeing the slot after createReportWithCompletion: had already started, so a reload could -init another BugseeExtendedReport and wipe the one still being built. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Deep code review (PR #21,
a88e5ea)Re-review after
fix(ios): hold the created-report slot until an in-flight create finishes.
beginCreate:is now the hop’s single gate.NOmeansclearalready dropped the token and the hop skipscreateReportWithCompletion:.YESmarks the SDK call started; a laterclearsets_abandonedand keeps_creatinguntil that reservation’sfulfil:, which frees the slot and does not publish a handle.testClearDuringCreateKeepsTheSlotUntilFulfilpins it. The torn-down JS cannot receivecr-<n>, and the next runtime cannot-initanotherBugseeExtendedReportwhile beta3 is still using the in-flight report’s file-scope attributes.Prior P1s (
takebeforeuploadReportcompletion;reserveafter the main hop; unbounded decode/read; upload hold acrossclear) stay fixed.Inspected: Task 8.2c / P5–P7, JS
CreatedReport/E_REPORT_CREATE_BUSY, handlervalidatedPatch:(extraction only), EventBus/handler/data-requestdetach:,BGSRNRunOnMain,BGSRNCreatedReportsstate machine (reserve/beginCreate:/fulfil:/detachForUpload:/endUpload:/clear), attachment ops (3 / 3 MiB, symlink resolve, capped read), and the public7.0.0-beta3facts already recorded in the plan (createReportWithCompletion:always completes, including nil when not launched). XCTests were not re-run here. GitHub CIios unit (BugseeRNSupport)andios (spm)are SUCCESS on this SHA.Findings
No remaining P0–P3.
Owner-checked
clearis still declined (PRRT_kwDOTk5MSM6n8bjF). That is not re-raised: on serial 0.87 teardown there is no live reservation forinvalidateto steal, and an overlappingclearon older RN still yieldsnull/E_REPORT_HANDLE_DEADrather than a process-lifetimeE_REPORT_CREATE_BUSYor a second-initwhile create/upload is in flight.Overall risk: Low
Merge recommendation: Safe (into
feat/phase-8-2a; this branch still does not contain the Android registry)Most important to fix
Nothing blocking.
Positive
The create path now matches the upload hold: admit before the hop, mark the SDK call in the same lock as the open check, keep the slot until the completion, never publish a handle the torn-down JS cannot upload. Attachment caps still reject before decode / with a 3 MiB+1 file read.
testTheSdkSharesAttributesAcrossExtendedReportsremains the tripwire for lifting P5.Sent by Cursor Automation: Bugsee code review
Mutation was surviving the boundary at severity 5 and any rewrite of the TypeError and RangeError text, which pulled the score under the break threshold. Co-authored-by: Cursor <cursoragent@cursor.com>
The deadline is a third caller into that barrier. On a slow CI runner it fires while the two threads are parked and steals a signal, so the test never finishes. Co-authored-by: Cursor <cursoragent@cursor.com>
Those branches were untested, so their mutants survived and the mutation score stayed under the break threshold. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Deep code review (PR #21,
7f748a4)Re-review after three test-only commits on top of
a88e5ea(fix(ios): hold the created-report slot until an in-flight create finishes). Production iOScreateReport/ registry / attachment code is unchanged.Task 8.2c is the iOS half of
createReport: one process slot (P5, beta3 file-scope attributes), SDK attachment limits enforced at add time (P7: 3 × 3 MiB), andinvalidatedropping a handle the next runtime cannot address. The JSCreatedReport/ error contract and Android stubs are Task 8.2a / 8.2b and are not implemented here.Inspected against callers and surrounding code, not the diff alone: the Task 8.2c plan and verified beta3 facts (
createReportWithCompletion:always completes, including nil when not launched;uploadReport:copies then completes on main); JSCreatedReport,errors.ts(E_REPORT_CREATE_BUSY/E_REPORT_HANDLE_DEAD),NativeBugseespec, andindex.tsJSDoc; handlerBGSRNReportOpsvalidatedPatch:extraction (behavior preserved; created-report ops apply the same dictionary throughBugseeExtendedReportsetters); EventBus / report-handler / data-requestdetach:identity checks vs this registry’s unconditionalclear;BGSRNRunOnMain(inline on main,dispatch_asyncoff it); the fullBGSRNCreatedReportsstate machine (reserve→beginCreate:→fulfil:/_abandonedhold,detachForUpload:/endUpload:,clear); attachment ops (count, empty, 3 MiB char-cap before decode,NSFileTypeRegular+ cappedreadDataOfLength:, symlink resolve, owned copy); and the XCTest + JS suites including the new commits. XCTests and Jest were not re-run in this agent. GitHub CI on this SHA still hadlint, typecheck, unit, mutation,ios unit (BugseeRNSupport), and the iOS example jobs pending at review time. Prior SHAa88e5eahadios unit (BugseeRNSupport)SUCCESS.Findings
No remaining P0–P3.
Prior P1s stay fixed: handle dies at
detachForUpload:while the slot stays taken untilendUpload:;reserveruns before the main hop;beginCreate:is the hop’s gate soclearcannot-inita secondBugseeExtendedReportwhile create/upload is in flight; over-long base64 is rejected before decode and file reads stop at 3 MiB+1.Owner-checked
clearis still declined (PRRT_kwDOTk5MSM6n8bjF). Not re-raised: on serial RN 0.87 teardown there is no live reservation forinvalidateto steal. On older attach-before-invalidate the overlap isnull/E_REPORT_HANDLE_DEAD, not process-lifetimeE_REPORT_CREATE_BUSYand not a second-initmid-copy.The new tests are the right kind of hardening.
BGSRNSettleOnce(0, …)removes the deadline as a third waiter into the two-party barrier (that flake is real:dispatch_aftercan stealgowhile both callers are parked). JS now pins severity 1 and 5, the exactTypeError/RangeErrorstrings, omitted-mimenull, empty path/name, and nativeE_REPORT_ATTACHMENT_REJECTEDwrapping.Overall risk: Low
Merge recommendation: Safe (into
feat/phase-8-2a; this branch still does not contain the Android registry)Most important to fix
Nothing blocking.
Positive
The create path still matches the upload hold: admit before the hop, mark the SDK call in the same lock as the open check, keep the slot until the completion, never publish a handle the torn-down JS cannot upload. Attachment caps still reject before decode / with a bounded file read.
testTheSdkSharesAttributesAcrossExtendedReportsremains the tripwire for lifting P5.validatedPatch:keeps handler and created-report validation identical.Sent by Cursor Automation: Bugsee code review
A shared go semaphore let the faster caller enter the next window and consume the other caller's release, so that caller never arrived and CI timed out. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Deep code review (PR #21,
3db1950)Re-review after
test(ios): keep each settle-once window on its own release. Production iOScreateReport/ registry / attachment code is unchanged sincea88e5ea.Task 8.2c is the iOS half of
createReport: one process slot (P5, beta3 file-scope attributes), SDK attachment limits enforced at add time (P7: 3 × 3 MiB), andinvalidatedropping a handle the next runtime cannot address. The JSCreatedReport/ error contract and Android stubs are Task 8.2a / 8.2b and are not implemented here.Inspected against callers and surrounding code, not the diff alone: the Task 8.2c plan and verified beta3 facts (
createReportWithCompletion:always completes, including nil when not launched;uploadReport:copies then completes on main); JSCreatedReport,errors.ts(E_REPORT_CREATE_BUSY/E_REPORT_HANDLE_DEAD),NativeBugseespec, andindex.tsJSDoc; handlerBGSRNReportOpsvalidatedPatch:extraction (behavior preserved; created-report ops apply the same dictionary throughBugseeExtendedReportsetters); EventBus / report-handler / data-requestdetach:identity checks vs this registry’s unconditionalclear;BGSRNRunOnMain(inline on main,dispatch_asyncoff it); the fullBGSRNCreatedReportsstate machine (reserve→beginCreate:→fulfil:/_abandonedhold,detachForUpload:/endUpload:,clear); attachment ops (count, empty, 3 MiB char-cap before decode,NSFileTypeRegular+ cappedreadDataOfLength:, symlink resolve, owned copy); and the XCTest + JS suites including the new commits. Adversarial checks included Fast Refresh overlapping an in-flight create/upload, a late SDK completion afterclear, doubleupload(), a fourth / oversize attachment, and a TOCTOU grow between stat and read. XCTests and Jest were not re-run in this agent. GitHub CI on this SHA was still queued at review time. Prior SHAa88e5eahadios unit (BugseeRNSupport)SUCCESS; its red job waslint, typecheck, unit, mutation(the later test commits).Findings
No remaining P0–P3.
Prior P1s stay fixed: handle dies at
detachForUpload:while the slot stays taken untilendUpload:;reserveruns before the main hop;beginCreate:is the hop’s gate soclearcannot-inita secondBugseeExtendedReportwhile create/upload is in flight; over-long base64 is rejected before decode and file reads stop at 3 MiB+1.Owner-checked
clearis still declined (PRRT_kwDOTk5MSM6n8bjF). Not re-raised: on serial RN 0.87 teardown there is no live reservation forinvalidateto steal. On older attach-before-invalidate the overlap isnull/E_REPORT_HANDLE_DEAD, not process-lifetimeE_REPORT_CREATE_BUSYand not a second-initmid-copy.The latest commit is the right flake fix. A shared
gosemaphore let the faster settle-once caller leave window 0, enter window 1, and consume the other caller’s release, so that caller never arrived (caller 3 timed outon CI). Separate enter/release pairs per window close that. Combined withBGSRNSettleOnce(0, …), the deadline is no longer a third waiter into the two-party barrier.Overall risk: Low
Merge recommendation: Safe (into
feat/phase-8-2a; this branch still does not contain the Android registry)Most important to fix
Nothing blocking.
Positive
The create path still matches the upload hold: admit before the hop, mark the SDK call in the same lock as the open check, keep the slot until the completion, never publish a handle the torn-down JS cannot upload. Attachment caps still reject before decode / with a bounded file read.
testTheSdkSharesAttributesAcrossExtendedReportsremains the tripwire for lifting P5.validatedPatch:keeps handler and created-report validation identical.Sent by Cursor Automation: Bugsee code review
Keep this branch's created-report registry. Keep main's split exception executors, the beta3 recovery comment, and omitted dialog fields as nil.
There was a problem hiding this comment.
Deep code review (PR #21, 601eded)
Re-review after Merge main into this branch. Production iOS createReport / registry / attachment code is unchanged since a88e5ea.
Task 8.2c is the iOS half of createReport: one process slot (P5, beta3 file-scope attributes), SDK attachment limits enforced at add time (P7: 3 × 3 MiB), and invalidate dropping a handle the next runtime cannot address. The JS CreatedReport / error contract is Task 8.2a (now on main). Android is still the 8.2a stubs; the Android registry is Task 8.2b.
The merge kept this branch’s registry and took main’s split ExceptionExecutors, the beta3 override_report.plcrash comment, and omitted dialog fields as nil. Android createReport still resolves null with a single method each — no stub/implementation collision.
Inspected against callers and surrounding code, not the diff alone: the Task 8.2c plan and verified beta3 facts (createReportWithCompletion: always completes, including nil when not launched; uploadReport: copies then completes on main); JS CreatedReport, errors.ts (E_REPORT_CREATE_BUSY / E_REPORT_HANDLE_DEAD), NativeBugsee spec, and index.ts JSDoc; handler BGSRNReportOps validatedPatch: extraction (behavior preserved; created-report ops apply the same dictionary through BugseeExtendedReport setters); EventBus / report-handler / data-request detach: identity checks vs this registry’s unconditional clear; BGSRNRunOnMain (inline on main, dispatch_async off it); the full BGSRNCreatedReports state machine (reserve → beginCreate: → fulfil: / _abandoned hold, detachForUpload: / endUpload:, clear); attachment ops (count, empty, 3 MiB char-cap before decode, NSFileTypeRegular + capped readDataOfLength:, symlink resolve, owned copy); merge of BugseeModule.mm / BugseeModule.java against main; and the XCTest + JS suites. Adversarial checks included Fast Refresh overlapping an in-flight create/upload, a late SDK completion after clear, double upload(), a fourth / oversize attachment, a TOCTOU grow between stat and read, and a second createReport during uploadReport:. XCTests and Jest were not re-run in this agent. GitHub CI on this SHA was still pending at review time. Prior SHA 3db1950 had CI SUCCESS.
Findings
No remaining P0–P3.
Prior P1s stay fixed: handle dies at detachForUpload: while the slot stays taken until endUpload:; reserve runs before the main hop; beginCreate: is the hop’s gate so clear cannot -init a second BugseeExtendedReport while create/upload is in flight; over-long base64 is rejected before decode and file reads stop at 3 MiB+1.
Owner-checked clear is still declined (PRRT_kwDOTk5MSM6n8bjF). Not re-raised: on serial RN 0.87 teardown there is no live reservation for invalidate to steal. On older attach-before-invalidate the overlap is null / E_REPORT_HANDLE_DEAD, not process-lifetime E_REPORT_CREATE_BUSY and not a second -init mid-copy.
Overall risk: Low
Merge recommendation: Safe (into main; this branch still does not contain the Android registry)
Most important to fix
Nothing blocking.
Positive
The merge is the right three-way split: iOS registry kept, Android still the 8.2a stubs, exception executors and dialog-nil behavior taken from main. The create path still matches the upload hold: admit before the hop, mark the SDK call in the same lock as the open check, keep the slot until the completion, never publish a handle the torn-down JS cannot upload. Attachment caps still reject before decode / with a bounded file read. testTheSdkSharesAttributesAcrossExtendedReports remains the tripwire for lifting P5. validatedPatch: keeps handler and created-report validation identical.
Sent by Cursor Automation: Bugsee code review


Summary
createReportkeeps one outstanding report and enforces the SDK limits up front: at most 3 attachments, each at most 3 MiB.fulfilwrites only for the generation token captured at reserve time.clearmakes older tokens stale.stringByResolvingSymlinksInPath.{"description":null}clears the description and leaves the summary.Test plan
6FA9B3E8(23 in the fix round, 0 failures). First full run was 209 testsMade with Cursor