From ac455c9822a8059dc9c39e779f8e6b6df462ed4c Mon Sep 17 00:00:00 2001 From: Denis Sheikherev Date: Thu, 15 Oct 2026 16:25:19 +0700 Subject: [PATCH] refactor(options)!: drop detect.kill, which iOS SDK 7.0.0-beta7 removes The iOS SDK registered com.bugsee.option.detect.kill but never read it (bugsee-cocoa#203) and removes it in 7.0.0-beta7 (bugsee-cocoa#237); Android never had it. - IOSLaunchOptions.detectAndReportKill: removed, with its accessor test. - option-keys.json: the key is gone, as cli-extract-option-keys.ts would produce from the SDK. - e2e: [OPT-068], the it.failing pin for #203 that waited for a report after SIGKILL, is removed with its `kill` scenario. No SDK reports a plain SIGKILL: iOS cannot tell it from a swipe-kill. - e2e ids are positions in option-keys.json, so the hardcoded ids after 068 move down by one (070 -> 069 ... 098 -> 097). BREAKING CHANGE: IOSLaunchOptions.detectAndReportKill is removed. Co-Authored-By: Claude Opus 5.5 --- docs/design/2026-09-15-sdk-design.md | 2 +- examples/bare/e2e/option-effects.test.ts | 41 ++++--------------- examples/bare/e2e/options-readback.test.ts | 2 +- examples/bare/scenarios/api-constants.ts | 5 +-- .../src/options/IOSLaunchOptions.ts | 7 ---- .../src/options/__tests__/accessors.test.ts | 1 - .../react-native/src/options/option-keys.json | 1 - 7 files changed, 12 insertions(+), 47 deletions(-) diff --git a/docs/design/2026-09-15-sdk-design.md b/docs/design/2026-09-15-sdk-design.md index 8d8381ec..20e7f26d 100644 --- a/docs/design/2026-09-15-sdk-design.md +++ b/docs/design/2026-09-15-sdk-design.md @@ -219,7 +219,7 @@ AndroidLaunchOptions extends … videoMode, logsUseAllSources, the detect.exit family, triggerByNotification/Broadcast, ndk, maxPendingReports/ReportAge, … IOSLaunchOptions extends … captureAVPlayer, machExceptions, bluetoothStatus, - diskSpace, killDetection, style, … + diskSpace, style, … ``` `createDefaultLaunchOptions()` selects by `Platform.OS`, unchanged. diff --git a/examples/bare/e2e/option-effects.test.ts b/examples/bare/e2e/option-effects.test.ts index 50e6052a..19cc91c5 100644 --- a/examples/bare/e2e/option-effects.test.ts +++ b/examples/bare/e2e/option-effects.test.ts @@ -36,7 +36,7 @@ import { } from './harness'; import { LUMA_BRIGHT_MIN, LUMA_DARK_MAX, imageSize, regionLuma } from './media'; import { beginRetainingSuite, endRetainingSuite, frameCount } from './observe'; -import { type DeviceLog, type LogLine, adbStatus, devicectl, devicePidsOfApp, pidOf } from './scenario'; +import { type DeviceLog, type LogLine, adbStatus, devicePidsOfApp, pidOf } from './scenario'; import { centreRegion, uiDump } from './screen'; import { type StubServer, deviceStubUrl, releaseDeviceStub, startStubServerFor } from './stub-server'; @@ -238,9 +238,9 @@ describeDevice(`launch option effects on ${TARGET_NAME}`, () => { }); // ------------------------------------------------------------------------- - // Exit and kill detection + // Exit detection - on(['A'])('[OPT-094][OPT-027][FLOW-46] detect.exit.user_requested: a force-stop is reported at the next launch, not without it', async () => { + on(['A'])('[OPT-093][OPT-027][FLOW-46] detect.exit.user_requested: a force-stop is reported at the next launch, not without it', async () => { const after = async (name: string): Promise => { await clearBundles(); const first = await launch(name, 'idle'); @@ -262,29 +262,6 @@ describeDevice(`launch option effects on ${TARGET_NAME}`, () => { expect(exit.length).toBeGreaterThan(0); }); - /** - * iOS 7.0.0-beta5: nothing in the library reads detect.kill -- it is only - * registered (BGSOptionsDescriptors.m) -- and a SIGKILL while running - * files nothing at the next launch (XS, 2026-10-07). Filed: bugsee-cocoa#203. - */ - (HERE === 'X' ? it.failing : it.skip)('[OPT-068] detect.kill: a SIGKILL is reported at the next launch [known: iOS beta5 never reads detect.kill (bugsee-cocoa#203)]', async () => { - await clearBundles(); - const first = await launch('kill', 'idle'); - await apiMarker(log!, 'eff idle case=kill', first.run.scenario.nonce, 10_000, first.run.start); - await new Promise(resolve => setTimeout(resolve, 5_000)); - for (const pid of await devicePidsOfApp()) { - await devicectl('process', 'signal', '--pid', String(pid), '--signal', 'SIGKILL'); - } - expect(await waitForExit(15_000)).toBe(true); - await launch('kill', 'idle'); - await new Promise(resolve => setTimeout(resolve, 20_000)); - const names = await listBundles(); - const bundles = names.length === 0 ? [] : await awaitBundles(names.length, 1_000); - await stopApp(); - report('kill bundles', bundles.map(b => ({ type: b.request.type, summary: b.request.summary }))); - expect(bundles.length).toBeGreaterThan(0); - }); - // ------------------------------------------------------------------------- // Hang and HTTP error detection @@ -550,7 +527,7 @@ describeDevice(`launch option effects on ${TARGET_NAME}`, () => { // ------------------------------------------------------------------------- // Android: all sources, FLAG_SECURE, handler timeout - on(['A'])('[OPT-070] capture.logs.allsources: another process\'s logcat line reaches the report only with the option', async () => { + on(['A'])('[OPT-069] capture.logs.allsources: another process\'s logcat line reaches the report only with the option', async () => { const has = async (name: string): Promise<{ other: boolean; tags: string[] }> => { const key = `${name}--ready`; if (!cache.has(key)) { @@ -583,7 +560,7 @@ describeDevice(`launch option effects on ${TARGET_NAME}`, () => { expect(extra.length).toBeGreaterThan(0); }); - on(['A'])('[OPT-071] capture.respect-flag-secure: a FLAG_SECURE window is blacked out by default and recorded when off', async () => { + on(['A'])('[OPT-070] capture.respect-flag-secure: a FLAG_SECURE window is blacked out by default and recorded when off', async () => { const centre = async (name: string): Promise => { const outcome = await uploaded(name, 'secure'); const shot = (own(outcome, name).binaries.get('screenshot') ?? [])[0]; @@ -597,7 +574,7 @@ describeDevice(`launch option effects on ${TARGET_NAME}`, () => { expect(ignored).toBeGreaterThanOrEqual(LUMA_BRIGHT_MIN); }); - on(['A'])('[OPT-080] config.report-handler-callback-timeout lowers the live handler deadline', async () => { + on(['A'])('[OPT-079] config.report-handler-callback-timeout lowers the live handler deadline', async () => { const deadline = async (name: string): Promise => { const outcome = await uploaded(name, 'handler'); const lines = log!.all(/BugseeRN.*report handler rh-\d+ phase=\w+ deadline=(\d+)/, outcome.run.start); @@ -643,15 +620,15 @@ describeDevice(`launch option effects on ${TARGET_NAME}`, () => { return cache.get(key)!; }; - on(['A'])('[OPT-081] config.report-processing-in-process=false reads back as set', async () => { + on(['A'])('[OPT-080] config.report-processing-in-process=false reads back as set', async () => { const { options } = await outOfProcess(); expect(jsonAfter(options.text, 'values')).toEqual({ 'com.bugsee.option.config.report-processing-in-process': false }); }); - on(['A'])('[OPT-081] config.report-processing-in-process=false still files the report (network on, dead endpoint)', async () => { + on(['A'])('[OPT-080] config.report-processing-in-process=false still files the report (network on, dead endpoint)', async () => { const { run, bundles } = await outOfProcess(); expect(bundles.map(b => b.request.summary)).toContain(`api-eff-out-of-process-${run.scenario.nonce}`); }); - it.skip('[OPT-098][FLOW-05b] reporting.triggers.broadcast: not covered -- the receiver is not exported and needs a signature permission; no in-app sender exists', () => {}); + it.skip('[OPT-097][FLOW-05b] reporting.triggers.broadcast: not covered -- the receiver is not exported and needs a signature permission; no in-app sender exists', () => {}); }); diff --git a/examples/bare/e2e/options-readback.test.ts b/examples/bare/e2e/options-readback.test.ts index 8121179d..f66b1532 100644 --- a/examples/bare/e2e/options-readback.test.ts +++ b/examples/bare/e2e/options-readback.test.ts @@ -21,7 +21,7 @@ * * `config.data-encryption` (iOS) is read back by option-effects.test.ts * (`env-diff`), not here: it would encrypt this run's bundle. Likewise - * `config.report-processing-in-process` (Android, OPT-081): off, it files no + * `config.report-processing-in-process` (Android, OPT-080): off, it files no * report, and this run needs one. */ import { type PulledBundle } from './bundles'; diff --git a/examples/bare/scenarios/api-constants.ts b/examples/bare/scenarios/api-constants.ts index a5e78d58..13343282 100644 --- a/examples/bare/scenarios/api-constants.ts +++ b/examples/bare/scenarios/api-constants.ts @@ -80,7 +80,7 @@ export const READBACK_ANDROID: Readonly> = { [`${P}config.max-pending-reports`]: 9, [`${P}config.report-handler-callback-timeout`]: 12, // config.report-processing-in-process=false files no report on the - // WOD_LX1 (option-effects.test.ts OPT-081), which this run needs for the + // WOD_LX1 (option-effects.test.ts OPT-080), which this run needs for the // environment record: read back there instead. [`${P}detect.anr.sampling`]: false, [`${P}detect.exit.bg_low_memory_as_error`]: true, @@ -123,7 +123,6 @@ export const READBACK_IOS: Readonly> = { [`${P}config.build-type`]: 'api-e2e-type', [`${P}detect.crash.fill_empty_exception_stacks`]: true, [`${P}detect.crash.swift_async_stacktraces`]: false, - [`${P}detect.kill`]: true, /** BugseeStyleDusk (1); the default is BugseeStyleSystem (3). */ [`${P}reporting.ui.style`]: 1, }; @@ -161,7 +160,6 @@ export const ACCESSOR_KEYS = { captureAVPlayer: `${P}capture.avplayer`, captureMachExceptions: `${P}capture.mach-exceptions`, captureDiskSpace: `${P}capture.disk-space`, - detectAndReportKill: `${P}detect.kill`, }, } as const; @@ -192,7 +190,6 @@ export const EFFECT_OPTIONS: Readonly