Skip to content

feat(boot): let an unscoped boot pick the newest of several shut-down devices - #4042

Merged
thymikee merged 5 commits into
callstack:mainfrom
KrzysztofMoch:fix/unscoped-boot-pick
Oct 29, 2026
Merged

thymikee merged 5 commits into
callstack:mainfrom
KrzysztofMoch:fix/unscoped-boot-pick

Conversation

@KrzysztofMoch

@KrzysztofMoch KrzysztofMoch commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

boot --platform ios fails with AMBIGUOUS_MATCH on any Mac with several iPhone simulators, which includes every stock Xcode install. Closes #4041.

boot --pick newest is an explicit opt-in. It decides only when every equally preferred local match is shut down: mobile over TV, then the newest OS version, then the name. Booted ties, provider devices and other commands still refuse, so #1880's guarantee holds. A selection record (reason newest-bootable-local) and the CLI output report the pick, and an ambiguous boot now suggests the opt-in.

agent-device boot --platform ios --pick newest   # SDK: devices.boot({ platform: 'ios', pick: 'newest' })
→ Boot ready: iPhone 17 (ios), picked by --pick newest from 3 matching devices

A second commit ranks iPads by appleOs rather than by name, so a renamed iPad no longer ties with iPhones. 28 files changed.

Validation

  • check:affected --run --head daf6f912d (66 checks): everything passes except 3 timing tests (daemon-client, Android fill) under load. Those pass 64/64 when run alone, and main shows the same daemon-client errors on this host. 9 unreached checks (docs, wire-compat, flags) pass when run directly.
  • Review round 167663c5a: lint, typecheck, focused tests (device-selection, boot handler, commands, MCP), and the mcp-metadata, command-docs, docs, wire-compat and progress-model gates all pass.
  • Each new test fails with its fix removed.
  • Live on macOS 26.5 / Xcode 26.6 with a private set (iPhone 17 Pro, iPhone 17, iPad Pro):
    • plain boot refuses;
    • --pick newest boots iPhone 17;
    • two booted devices still refuse.
  • A renamed-iPad set fails at main 144bd59 and passes here.

Changes made by Claude Opus 5.5 running in Claude Code (T3 Code).

Device selection ranked an Apple device as a tablet only when its name
matched /\bipad\b/. A renamed iPad simulator therefore tied with every
iPhone and turned an otherwise resolvable request into AMBIGUOUS_MATCH.

Discovery already stamps appleOs from the device type, so rank by it and
keep the name regex only for records that predate the discriminant.
…down devices

A boot that names no device fails with AMBIGUOUS_MATCH whenever several
equally preferred devices match. That covers every stock Xcode install,
which ships more than one iPhone simulator on one runtime, so a test runner
cannot boot "an iPhone" without listing devices and choosing one itself.

The refusal is deliberate (callstack#1880): a quietly chosen device answers
successfully about the wrong device. `boot --pick newest` (SDK:
`devices.boot({ pick: 'newest' })`) is an explicit opt-in, so the caller
has said any match will do. It decides only when every equally preferred
match is shut down: nothing runs on them yet to be misread, and once one
boots, booted-over-offline resolves later unscoped commands to it. It picks
a mobile target over a TV, then the newest OS version, then the name. It
never picks between booted devices or provider devices, and other commands
keep refusing.

Boot responses now carry the same `selection` evidence as open, with the
new reason `newest-bootable-local`, and the CLI line names the pick.
Copilot AI balanced review requested due to automatic review settings October 29, 2026 11:15
@vercel

vercel Bot commented Oct 29, 2026

Copy link
Copy Markdown

@KrzysztofMoch is attempting to deploy a commit to the Callstack Team on Vercel.

A member of the Team first needs to authorize it.

@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.

1 issue found across 28 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="src/commands/management/device.ts">

<violation number="1" location="src/commands/management/device.ts:64">
P3: `selection` is advertised only as an unconstrained object, so MCP/schema consumers cannot discover or validate the new selection fields. Describe its four contract fields while retaining additive properties.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread website/docs/docs/commands.md Resolved
Comment thread src/commands/management/device.ts Resolved

Copilot AI 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.

🟡 Changes recommended

The cold-pick guard can create ambiguous simulator matches by treating a booting device as shut down, and existing local sessions can incorrectly report that no boot occurred after a successful boot.

2 open issues
What changed in this PR

Adds an explicit boot --pick newest opt-in for ambiguous, shut-down local devices while preserving the default refusal to choose silently.

Changes:

  • Wires the boot-only policy through CLI, SDK, daemon resolution, and request claims.
  • Reports selection evidence in boot responses and CLI output, with documentation and regression tests.
  • Uses appleOs to keep renamed iPads ranked below iPhones.
File Description
website/​docs/​docs/​commands.md Documents the opt-in and its limits.
website/​docs/​docs/​client-api.md Adds SDK usage and selection evidence.
src/​commands/​management/​output.ts Names explicit picks in CLI output.
src/​commands/​management/​output.test.ts Tests picked and ordinary boot output.
src/​commands/​management/​device.ts Adds boot input metadata and response schema.
src/​commands/​command-flags.ts Forwards the pick option.
src/​client/​client-normalizers.ts Recognizes the new selection reason.
src/​cli/​parser/​__tests__/​args-parse-session.test.ts Tests boot-only flag acceptance.
scripts/​integration-progress-model.ts Records local-only flag coverage ownership.
packages/​session-journal/​src/​session-event-action.ts Adds the pick enum to safe boot flags.
packages/​kernel/​src/​device.ts Implements cold-pick ordering and iPad classification.
packages/​kernel/​src/​device.test.ts Tests renamed and legacy iPad ranking.
packages/​device-selection/​src/​dispatch-resolve.ts Passes the policy through inventory resolution.
packages/​device-selection/​src/​device-selection-resolver.ts Applies local picks and emits selection evidence.
packages/​device-selection/​src/​__tests__/​dispatch-resolve.test.ts Tests policy propagation for iOS and Android.
packages/​device-selection/​src/​__tests__/​device-selection-resolver.test.ts Tests ordering and refusal conditions.
packages/​daemon/​src/​sessions/​handlers/​session-device-status-response.ts Includes selection metadata in boot responses.
packages/​daemon/​src/​sessions/​handlers/​session-boot.ts Boots the selected target and reports evidence.
packages/​daemon/​src/​sessions/​handlers/​__tests__/​session-device-status-response.test.ts Updates response-shape assertions.
packages/​daemon/​src/​sessions/​handlers/​__tests__/​session-boot.test.ts Tests policy forwarding, evidence, and hints.
packages/​daemon/​src/​server/​request-execution-scope.ts Uses boot selection when resolving device claims.
packages/​daemon/​src/​resources/​session-device-resolution.ts Adds boot-specific selection and ambiguity hints.
packages/​contracts/​src/​request-envelope.ts Adds the execution option type.
packages/​contracts/​src/​device.ts Adds boot-result selection metadata.
packages/​contracts/​src/​client-device-view.ts Exposes the SDK boot policy.
packages/​contracts/​src/​client-app.ts Declares the new selection reason.
packages/​contracts/​src/​cli-flags.ts Types the CLI pick flag.
packages/​command-registry/​src/​flag-definitions-target.ts Registers --pick and its help text.

Review effort: Balanced

Comment thread packages/kernel/src/device.ts Resolved
The --pick hint was appended to every ambiguous boot, including provider
and booted ties that the opt-in cannot settle. Boot now passes a typed
intent to the selection resolver, which knows the inventory source and
whether a shut-down tie exists, and adds the hint only there.

Also document that device ranking (phone over iPad) applies before the
pick, align the --pick usage text with the field description, and
describe the selection fields in the boot output schema.
Copilot AI balanced review requested due to automatic review settings October 29, 2026 11:22

@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 9 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Copilot AI 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.

🔵 Needs a closer look

Boot-event accounting skips session-bound local simulators, causing successful boots to incorrectly report bootOccurred: false.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@thymikee

Copy link
Copy Markdown
Member

The code looks good at 167663c, and I found nothing that needs a change. The only failing check is Vercel, and it looks unrelated: the fork deploy waits for a Callstack member to authorize it, so no build ran. I did not run the live check myself. I accepted the run summary in the PR body because the reported states match the code. I checked the kernel and boot-handler tests by reading them, not by running them without their fixes.

Not blocking, and you can take or leave these: the name tie-break in packages/kernel/src/device.ts#L757 is alphabetical, so on a stock Xcode 26 set --pick newest ranks "iPhone 16e" before "iPhone 17", so it would boot the oldest model; the help text and commands.md could say the name order is not a device-age order, or the policy could use a name that does not promise the newest device. BOOT_PICK_HINT in packages/device-selection/src/device-selection-resolver.ts#L41 only shows the CLI spelling, so it could also show pick: "newest" for MCP and Node callers. In packages/daemon/src/sessions/handlers/session-boot.ts#L138 the ?? selection cannot fire, because markSelectionBootOccurred returns undefined only for undefined input.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 29, 2026
Review follow-ups: with equal OS versions the name tie-break is
alphabetical, so iPhone 16e sorts before iPhone 17; say so wherever the
order is documented. The ambiguity hint also names the Node/MCP spelling,
and markSelectionBootOccurred gains an overload so boot needs no fallback.
Copilot AI balanced review requested due to automatic review settings October 29, 2026 12:38
@KrzysztofMoch

Copy link
Copy Markdown
Contributor Author

[claude-opus-5-5] responding on behalf of Krzysztof

Thanks, @thymikee. All three suggestions are in d3af7a8:

  • The name tie-break: the help text, the DeviceBootOptions JSDoc and commands.md now say the name order is alphabetical, not device age, with the iPhone 16e / iPhone 17 example. I kept the newest name because it describes the primary key, the OS version, and changing it would rename a public value.
  • The ambiguity hint now also shows pick: "newest" for Node and MCP callers.
  • markSelectionBootOccurred has an overload for a defined selection, so the boot handler drops the ?? selection fallback.

@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: Review your code locally with the cubic CLI to iterate faster.

View guided diff | Re-trigger cubic

Comment thread website/docs/docs/commands.md Resolved
Comment thread src/commands/management/device.ts Resolved

Copilot AI 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.

🟢 Approval recommended

No active review issues are recorded for the explicit boot --pick newest opt-in.

No open issues 🎉

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 29, 2026 12:42

Copilot AI 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.

🟢 Approval recommended

No active review issues block the opt-in boot selection change.

No open issues 🎉

Review effort: Balanced

@thymikee
thymikee merged commit 4c8bb4a into callstack:main Oct 29, 2026
13 of 14 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.

boot --platform ios fails with AMBIGUOUS_MATCH on a stock Xcode install

3 participants