Skip to content

feat(settings): add Android mobile-data on|off - #3636

Merged
thymikee merged 10 commits into
callstack:mainfrom
mikolajadamowicz:feat/android-mobile-data
Oct 16, 2026
Merged

thymikee merged 10 commits into
callstack:mainfrom
mikolajadamowicz:feat/android-mobile-data

Conversation

@mikolajadamowicz

@mikolajadamowicz mikolajadamowicz commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds settings mobile-data on|off for Android, so a run on a streaming app can move from Wi-Fi to cellular and back and check the "streaming on mobile data" warnings.

agent-device settings wifi off
agent-device settings mobile-data on   # mobileData: enabled

Node: client.settings.update({ setting: 'mobile-data', state: 'off' })

  • Runs svc data enable|disable, then polls the global mobile_data row through pollUntilSettled (2 s deadline, 100 ms interval). A cancelled request fails with the typed request-canceled error, like the alert and fill polls.
  • If the row never matches, the command fails with mobile-data-not-applied or mobile-data-unreadable and says whether the switch was dispatched.
  • Every target without adb refuses up front with UNSUPPORTED_OPERATION (setting-unsupported-on-leaf). --app is refused with INVALID_ARGS and setting_app_not_consumed.
  • The read-back covers single-SIM targets only. A multi-SIM device keeps the switch per subscription, so the command can fail there even when the switch took effect. I have no dual-SIM run to show which row to read, so that case is documented, not handled.

Test plan

Use an Android emulator or phone with a SIM. S is its adb serial.

  1. pnpm build && pnpm build:android && pnpm clean:daemon
  2. pnpm ad settings mobile-data off --platform android --serial $S --json returns mobileData: disabled, and adb -s $S shell settings get global mobile_data prints 0. on returns enabled and 1.
  3. mobile-data off --app com.example.app fails with INVALID_ARGS and setting_app_not_consumed, and the row stays 1.
  4. Restore with settings mobile-data on.

Validation

Steps 2 and 3 ran on a local Android emulator (emulator-5554) with the build from d4f476e:

Command Result adb shell settings get global mobile_data
settings mobile-data off --json mobileData: "disabled" 0
settings mobile-data on --json mobileData: "enabled" 1
settings mobile-data off --app com.example.app --json INVALID_ARGS, reason: setting_app_not_consumed, dispatched: "no" 1 (unchanged)

The emulator was left with mobile data on. pnpm check:affected --run passes at d4f476e. The device-lane replay suites are GitHub-only and did not run locally.

Not covered: multi-SIM devices, and a ping check that traffic actually moves between Wi-Fi and cellular.

View guided diff

`settings mobile-data on|off` switches mobile data for the default data
SIM on adb-backed Android targets through `svc data enable|disable`. It
then reads the stored switch back until the value matches the request,
within a 2 s budget, and reports `mobileData`. On one SIM the switch is
read from the global `mobile_data` row. On a multi-SIM device it is read
from `mobile_data<subId>` for the default data subscription
(`multi_sim_data_call`). A switch that never settles fails with
COMMAND_FAILED instead of reporting a change that did not happen.
QA automation can use it to move a streaming session from Wi-Fi to
cellular and back, and to check how the app warns about streaming on
mobile data.

On iOS, tvOS, and visionOS, the daemon refuses the setting before
admission with UNSUPPORTED_OPERATION (reason
setting-unsupported-on-leaf), because agent-device has no mobile-data
control for Apple targets and simulators have no cellular radio.
…very non-Android target

Mobile-data read-back:
- Choose the stored row before `svc data` runs, from the active modem
  count (`persist.radio.multisim.config`), never from which rows exist.
  A stale `mobile_data<subId>` row on a single-modem device, or a seeded
  plain row on a multi-modem device, no longer decides the result.
- Each sample reads one row.
- Sample through absent or unreadable values, using a `Deadline` and the
  request's abort signal.
- Report `mobile-data-not-applied` or `mobile-data-unreadable` as typed
  reasons, with `settingKey` and `storedValue` in the details.
- A failure before `svc data` discloses `dispatched: no`; every failure
  after it discloses `unknown`.

Refusals:
- The daemon refuses mobile-data on every non-Android target before
  admission, through one shared leaf-refusal response, so a HarmonyOS or
  Linux session keeps its ref frame.
- The Apple and Limrun iOS owners throw the same typed refusal.
- `--app` is forwarded and refused with `setting_app_not_consumed`,
  because the switch is device-wide.
- The macOS unsupported list now includes mobile-data.
- Help and the commands and Limrun docs describe the refusal accurately
  for physical iPhones.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 19 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/platform-apple/src/core/app-settings.ts">

<violation number="1" location="packages/platform-apple/src/core/app-settings.ts:66">
P2: macOS exits through the earlier `isMacOs` branch, so this guard never runs there and `mobile-data` gets the generic `INVALID_ARGS` response instead of the shared unsupported-operation refusal. Move the mobile-data guard ahead of the macOS branch.</violation>
</file>

<file name="packages/daemon/src/execution/handlers/__tests__/snapshot-settings-handler.test.ts">

<violation number="1" location="packages/daemon/src/execution/handlers/__tests__/snapshot-settings-handler.test.ts:411">
P3: This list omits the supported `vega` and `web` platforms, so the test does not verify the pre-admission refusal for every non-Android target as its name claims. Add representative devices for both platforms.</violation>
</file>

<file name="packages/platform-apple/src/core/__tests__/app-settings.test.ts">

<violation number="1" location="packages/platform-apple/src/core/__tests__/app-settings.test.ts:193">
P2: This test asserts `dispatched: 'no'` but discards the fake tool's invocation log, so a command could run and be swallowed before the same refusal is returned. Capture `calls` and assert it is empty.

(Based on your team's feedback about typed interaction refusals.) .</violation>
</file>

<file name="packages/contracts/src/settings.ts">

<violation number="1" location="packages/contracts/src/settings.ts:227">
P2: This classifies every state as device-level, so `settings mobile-data cellular --app X` is rejected as `setting_app_not_consumed` before Android can return its invalid-state error. Gate this on `readSettingState(state)` as `locationAppScope` does.</violation>
</file>

Tip: cubic used a learning from your PR history. Let your coding agent read cubic learnings directly with the cubic MCP.

View guided diff | Re-trigger cubic

Comment thread packages/platform-android/src/settings.ts Outdated
throw new AppError('INVALID_ARGS', getUnsupportedMacOsSettingMessage(setting));
}
const normalized = setting.toLowerCase();
if (normalized === 'mobile-data') throw mobileDataUnsupportedError(device.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: macOS exits through the earlier isMacOs branch, so this guard never runs there and mobile-data gets the generic INVALID_ARGS response instead of the shared unsupported-operation refusal. Move the mobile-data guard ahead of the macOS branch.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/platform-apple/src/core/app-settings.ts, line 66:

<comment>macOS exits through the earlier `isMacOs` branch, so this guard never runs there and `mobile-data` gets the generic `INVALID_ARGS` response instead of the shared unsupported-operation refusal. Move the mobile-data guard ahead of the macOS branch.</comment>

<file context>
@@ -61,9 +62,10 @@ export async function setIosSetting(
     throw new AppError('INVALID_ARGS', getUnsupportedMacOsSettingMessage(setting));
   }
+  const normalized = setting.toLowerCase();
+  if (normalized === 'mobile-data') throw mobileDataUnsupportedError(device.id);
   requireSimulatorDevice(device, 'settings');
   await ensureBootedSimulator(device);
</file context>

Comment on lines +193 to +201
await withFakeAppleTool(unexpectedArgs, async () => {
for (const device of [IOS_TEST_SIMULATOR, TVOS_TEST_SIMULATOR]) {
await assertRejectsAppError(() => setIosSetting(device, 'mobile-data', 'off'), {
code: 'UNSUPPORTED_OPERATION',
reason: 'setting-unsupported-on-leaf',
dispatched: 'no',
});
}
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This test asserts dispatched: 'no' but discards the fake tool's invocation log, so a command could run and be swallowed before the same refusal is returned. Capture calls and assert it is empty.

(Based on your team's feedback about typed interaction refusals.) .

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/platform-apple/src/core/__tests__/app-settings.test.ts, line 193:

<comment>This test asserts `dispatched: 'no'` but discards the fake tool's invocation log, so a command could run and be swallowed before the same refusal is returned. Capture `calls` and assert it is empty.

(Based on your team's feedback about typed interaction refusals.) .</comment>

<file context>
@@ -189,6 +189,18 @@ test('setIosSetting biometric refuses an Apple TV simulator before posting anyth
 });
 
+test('setIosSetting mobile-data refuses every Apple leaf before spawning anything', async () => {
+  await withFakeAppleTool(unexpectedArgs, async () => {
+    for (const device of [IOS_TEST_SIMULATOR, TVOS_TEST_SIMULATOR]) {
+      await assertRejectsAppError(() => setIosSetting(device, 'mobile-data', 'off'), {
</file context>
Suggested change
await withFakeAppleTool(unexpectedArgs, async () => {
for (const device of [IOS_TEST_SIMULATOR, TVOS_TEST_SIMULATOR]) {
await assertRejectsAppError(() => setIosSetting(device, 'mobile-data', 'off'), {
code: 'UNSUPPORTED_OPERATION',
reason: 'setting-unsupported-on-leaf',
dispatched: 'no',
});
}
});
await withFakeAppleTool(unexpectedArgs, async ({ calls }) => {
for (const device of [IOS_TEST_SIMULATOR, TVOS_TEST_SIMULATOR]) {
await assertRejectsAppError(() => setIosSetting(device, 'mobile-data', 'off'), {
code: 'UNSUPPORTED_OPERATION',
reason: 'setting-unsupported-on-leaf',
dispatched: 'no',
});
}
assert.deepEqual(calls, []);
});

Comment thread packages/contracts/src/settings.ts Outdated
return family === 'macos-host' ? 'device-level' : 'app-scoped';
}
if (normalizedSetting === 'location') return locationAppScope(family, state);
if (normalizedSetting === 'mobile-data') return family === 'mobile' ? 'device-level' : 'unknown';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This classifies every state as device-level, so settings mobile-data cellular --app X is rejected as setting_app_not_consumed before Android can return its invalid-state error. Gate this on readSettingState(state) as locationAppScope does.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/contracts/src/settings.ts, line 227:

<comment>This classifies every state as device-level, so `settings mobile-data cellular --app X` is rejected as `setting_app_not_consumed` before Android can return its invalid-state error. Gate this on `readSettingState(state)` as `locationAppScope` does.</comment>

<file context>
@@ -223,6 +224,7 @@ export function settingsAppScope(
     return family === 'macos-host' ? 'device-level' : 'app-scoped';
   }
   if (normalizedSetting === 'location') return locationAppScope(family, state);
+  if (normalizedSetting === 'mobile-data') return family === 'mobile' ? 'device-level' : 'unknown';
   return 'unknown';
 }
</file context>
Suggested change
if (normalizedSetting === 'mobile-data') return family === 'mobile' ? 'device-level' : 'unknown';
if (normalizedSetting === 'mobile-data') {
return family === 'mobile' && readSettingState(state) !== undefined ? 'device-level' : 'unknown';
}

Comment thread website/docs/docs/commands.md Outdated
Comment thread packages/platform-android/src/settings.ts Outdated
kind: 'emulator',
booted: true,
},
{ platform: 'linux', id: 'linux-host', name: 'Linux Desktop', kind: 'device', booted: true },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: This list omits the supported vega and web platforms, so the test does not verify the pre-admission refusal for every non-Android target as its name claims. Add representative devices for both platforms.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/daemon/src/execution/handlers/__tests__/snapshot-settings-handler.test.ts, line 411:

<comment>This list omits the supported `vega` and `web` platforms, so the test does not verify the pre-admission refusal for every non-Android target as its name claims. Add representative devices for both platforms.</comment>

<file context>
@@ -372,6 +374,122 @@ test('settings usage hint documents canonical faceid states', async () => {
+    kind: 'emulator',
+    booted: true,
+  },
+  { platform: 'linux', id: 'linux-host', name: 'Linux Desktop', kind: 'device', booted: true },
+];
+
</file context>
Suggested change
{ platform: 'linux', id: 'linux-host', name: 'Linux Desktop', kind: 'device', booted: true },
{ platform: 'linux', id: 'linux-host', name: 'Linux Desktop', kind: 'device', booted: true },
{ platform: 'vega', id: 'vega-tv', name: 'Vega TV', kind: 'device', target: 'tv' },
{ platform: 'web', id: 'web-browser', name: 'Browser', kind: 'device' },

Comment thread website/docs/docs/commands.md Outdated
@thymikee

Copy link
Copy Markdown
Member

Thanks for this. The feature is useful, but the PR is large for one Android switch: +752 lines, and only about 60 of them switch mobile data. Here is what I think could be smaller, reviewed at 6b94f11.

  1. Multi-SIM row selection. resolveAndroidMobileDataSettingKey copies how the telephony service picks its storage row, and it adds a probe before dispatch, the "refuse before switching" path and 4 tests. Could the read-back use the live data state instead (for example dumpsys telephony.registry)? Or could it read only the plain mobile_data row and say in the docs that multi-SIM is not covered yet? Either way most of the key logic and the split dispatch disclosure would go away.

  2. Refusals outside the daemon. The daemon already refuses mobile-data on every non-Android target before admission. The extra throws in platform-apple/src/core/app-settings.ts and provider-limrun/src/ios-settings.ts, mobileDataUnsupportedError, and their tests only cover callers that skip the daemon. Is there a real path that needs them? If not, I'd drop them, and the AppleSettingLeafRefusal → SettingLeafRefusal rename would no longer be needed either.

  3. withDispatchDisclosure. This is a new local wrapper around discloseDispatch. Other sites call discloseDispatch(error, ...) inline. I'd do the same here, or add one shared helper in kernel errors, not a private copy.

  4. The poll loop. awaitAndroidMobileData is another hand-written Deadline + sleep + for (;;) loop. platform-android already has several (alert.ts, ime-state.ts, fill-verification.ts), and app-lifecycle.ts has probeBeforeDeadline. Can this reuse one of them?

  5. Tests. The 15 Android tests overlap. "Samples again when stored late" and "samples through an absent read" test the same loop, and on/off can be one table-driven test. I think about half would cover the same behavior.

  6. Comments and help. About 40% of the new production lines are comments, and several repeat the help text. The cliDetail addition is about 150 words. Two or three sentences would do: Android only, reports the stored mobileData state, fails with mobile-data-not-applied or mobile-data-unreadable.

None of this changes the behavior. It is about keeping the patch at the size of the feature.

@thymikee

Copy link
Copy Markdown
Member

Thanks for the PR. At 6b94f11 I found one problem that should be fixed before merge. The Android single-modem path is covered by the live run in the PR body, which I accepted from the description and did not re-run. Both Smoke Tests jobs were still pending when I checked, so I cannot say yet what CI shows. I have no conflict information.

The multi-SIM branch in resolveAndroidMobileDataSettingKey picks mobile_data<subId> whenever persist.radio.multisim.config is dsds, dsda or tsts, and no live run has covered it. If that row is wrong on a real dual-SIM phone, the switch is dispatched and then the read-back polls the wrong row. The command fails with mobile-data-not-applied even though data was switched. Most physical Android phones are dual-SIM, so this is the main real-device case. Please either drop the branch and read only the plain mobile_data row, with the docs saying multi-SIM read-back is not covered yet, or post a dual-SIM settings mobile-data off|on --json run whose mobileData matches adb shell settings get global mobile_data<subId>.

Could the feature be much smaller? A mobile-data case in setAndroidSetting could run svc data enable|disable and poll only the plain global mobile_data row. It could use the airplane-style read helper, or a bounded per-read timeoutMs plus the request signal on every adb call. The daemon's pre-admission refusal would then be the single refusal for non-Android targets. That would let you drop the multi-SIM key resolution, the Apple and Limrun owner refusals, mobileDataUnsupportedError, the SettingLeafRefusal rename and withDispatchDisclosure, and cut the cliDetail paragraph to two sentences. It looks like roughly 60-80 production lines. No ADR is needed, as long as the docs say multi-SIM read-back stays uncovered until a dual-SIM run shows which row to read. Is there a reason this does not work?

Not blocking, and you can take or leave it: the owner-side refusals in app-settings.ts and the Limrun iOS settings code repeat the refusal the daemon already makes at snapshot-settings.ts:347, so three sites now refuse one setting. Keeping the daemon refusal and deleting the copies would be simpler, unless a caller reaches setIosSetting without the daemon. I only found the daemon route.

On the open inline threads, the first four hold. The signal is not checked before the key probe or svc data (thread, P1). Bad-state validation runs after the app refusal (thread, P2). The settle error reads only the final sample (thread, P2). The row read has no timeoutMs (thread, P2). One lower-priority thread on missing vega and web test devices also holds (thread). Three threads do not apply and you can resolve them. The macOS INVALID_ARGS refusal is intended and documented (thread). The app-settings.test.ts case runs under a fake tool that throws on any spawn, so its result would not match the typed refusal, and it is moot if the owner refusal goes (thread). The commands.md bullet matches the code (thread).

Before merge, remove the unvalidated multi-SIM branch or post the dual-SIM run, then answer the size questions above.

mikolajadamowicz and others added 4 commits October 15, 2026 15:44
Read back only the global mobile_data row and document that multi-SIM
devices are not covered until a dual-SIM run shows which row to read.
Drop the Apple and Limrun owner refusals, mobileDataUnsupportedError, the
SettingLeafRefusal rename and withDispatchDisclosure; the daemon's
pre-admission check is now the only non-Android refusal.

Check the request signal before svc data and pass it, with a per-read
timeout bounded by the settle budget, to every adb call. Move the poll
into a shared sampleUntilSettled helper that the two alert loops now use
too. Leave a bad state with --app to the owner's INVALID_ARGS, cover vega
and web in the daemon refusal test, collapse the Android tests into
tables, and shorten the help and docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files (changes from recent commits).

Tip: Get a Slack DM when cubic finishes reviewing your PRs. Connect Slack

View guided diff | Re-trigger cubic

Comment thread website/docs/docs/commands.md Outdated
Comment thread packages/provider-limrun/src/interaction-operations.ts Outdated
@thymikee

Copy link
Copy Markdown
Member

Thanks for the update. At 28106dd the checks are green, and the multi-SIM probe and the app-scope guard are gone, so the earlier points on those are fixed. Two things still need work before merge.

The read-back loop in awaitAndroidMobileData (settings.ts#L323) is a hand-written poll loop. pollUntilSettled in @agent-device/host-kit/retry already owns that loop (retry.ts#L199), and alert.ts and fill-verification.ts in this package use it. The copy behaves differently. signal.throwIfAborted() at lines 314 and 330 throws a raw AbortError instead of the typed request-canceled error, and the catch at line 319 only wraps AppError. So a cancelled settings mobile-data request fails differently from a cancelled alert or fill poll. Please route the read, parse and compare through pollUntilSettled with the 2000 ms deadline and 100 ms interval, and build the settle error from the last value it returns. Every bounded settle poll in platform-android should go through that helper, so cancellation is the typed error everywhere.

The live run in the PR body was taken at 124d05f, before the multi-SIM probe was removed and the read-back loop was rewritten, and the body still describes the dropped mobile_data<subId> selection. Once the loop change lands, please run this on an Android emulator or phone with a SIM and post the output. Run settings mobile-data off --json and then on --json. Each must show mobileData disabled or enabled and match adb shell settings get global mobile_data (0 or 1). Also run mobile-data off --app com.example.app and show INVALID_ARGS with setting_app_not_consumed. Please update the PR body to match.

Not blocking, take or leave: commit 28106dd made Limrun Android refuse with UNSUPPORTED_OPERATION, but limrun.md#L76 still says it runs over the ADB tunnel, and commands.md, the CHANGELOG and the catalog help say "adb-backed Android" or "Android only" without naming the backends that serve it, so naming local adb Android (emulator or USB device) and saying Limrun Android and WebDriver providers refuse would fit the platform-family rule in AGENTS.md.

On the open inline threads, the commands.md:675 macOS wording thread still applies and needs the "macOS answers INVALID_ARGS" line corrected to UNSUPPORTED_OPERATION: #3636 (comment). The Limrun thread (#3636 (comment)) does not apply as a code defect, because the refusal is a deliberate scope cut, and only the limrun.md:76 claim remains. These do not apply and can be resolved: the Apple owner guard (#3636 (comment)) was removed in 6fdbc52; the app-settings.test.ts case (#3636 (comment)) was deleted in 6fdbc52; the cellular app-scope thread (#3636 (comment)) is rejected earlier by parseSettingsMutation; the per-platform refusal test thread (#3636 (comment)) is covered by the shared unsupported cell. These are fixed or benign and can be resolved: signal handling (#3636 (comment)), per-read timeout (#3636 (comment)), final-read error reason (#3636 (comment)), and non-Android --app handling (#3636 (comment)).

I did not run tests or a device. I did not check whether the daemon normalizes a raw AbortError into a typed response. The loop finding rests on pollUntilSettled being the established typed-cancel path in this package. I also did not confirm that Limrun Android would serve svc data over its tunnel.

Before merge, the read-back needs to go through pollUntilSettled, the single-SIM off, on and --app run needs to be posted at the new head, and the macOS doc line needs fixing.

@thymikee

Copy link
Copy Markdown
Member

The code is clean at d4f476e. The cancellation, probe-timeout and settle-error fixes from the earlier review (#3636 (comment)) are all in, and the Limrun Android and docs gaps are closed too. The single reported check passes, and there are no conflicts.

Not blocking, so take or leave: the two cancellation tests in https://github.com/callstack/agent-device/blob/d4f476e/packages/platform-android/src/__tests__/settings.test.ts#L632 use a bare assert.rejects, so they would also pass with the old raw AbortError. Using assertRejectsAppError with code COMMAND_FAILED, the request-canceled details.reason, and dispatched: 'no' in the up-front case would pin the typed error. Limrun Android mobile-data is now available (https://github.com/callstack/agent-device/blob/d4f476e/packages/provider-limrun/src/interaction-operations.ts#L362) but only a local emulator was run live, so one settings mobile-data off --json run on Limrun Android, or a note in the PR body that it was not run, would close that.

I did not re-run the emulator validation or any local tests. The emulator run is the one reported in the PR body at d4f476e. Limrun Android shares the setAndroidSetting route over the ADB tunnel with wifi and airplane. Multi-SIM read-back stays uncovered by design and is documented.

On the open threads: all of the earlier review threads are either fixed or no longer apply, so none still applies to merge. These do not apply, so please resolve them: the Apple owner guard was removed, and app-settings.ts has no mobile-data branch (#3636 (comment)). The app-settings.test.ts mobile-data case was deleted with the owner refusal (#3636 (comment)). parseSettingsMutation rejects the bad state cellular before app scope is checked, and settings.test.ts:628 asserts INVALID_ARGS (#3636 (comment)). Non-Android targets use the shared unsupported default in each settingsRuntimeOperationFacts table, so a per-platform list adds nothing (#3636 (comment)). These are fixed at head, so please resolve them as well: #3636 (comment), #3636 (comment), #3636 (comment), #3636 (comment), #3636 (comment) and #3636 (comment).

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 16, 2026
@thymikee
thymikee merged commit 87fe3ea into callstack:main Oct 16, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants