# iOS Device Benchmarking with `devicectl`

> **Collective Library edition.** This is the complete technical report. Private filesystem paths, internal run identifiers, campaign-control notes, and repository navigation were removed. Technical claims, code, measurements, evidence labels, citations, corrections, and falsification criteria are preserved.

September 6, 2026

This field guide covers the shell-operated tooling layer for running a Core ML measurement app on a physical iPhone: build and install, stage model data, launch and monitor, collect durable results, inspect compute plans, and recover crash evidence. It is reusable operating guidance, not a verdict on any the reference implementation model or certification campaign.

## Executive Summary

- `devicectl device copy to` is not `cp`. **Firsthand implementation evidence:** copying a file to a missing parent inside `appDataContainer` can exit without creating anything; copying the containing directory works. Verify every transfer.
- Never use `--remove-existing-content true` casually. Current command help describes destination-directory cleanup, but **firsthand implementation evidence** shows it emptied the entire app data container.
- In `device process launch`, every token after the positional bundle identifier is application `argv`. Put every `devicectl` option before that positional argument.
- `--console` connects standard streams and waits for exit, but **firsthand implementation evidence** shows ordinary Swift `print` output can remain invisible because stdout is block-buffered. Emit critical progress to stderr and write final receipts to `Documents`.
- Crash evidence is separate from app data. `systemCrashLogs` is a supported file-service domain and can contain both app and Core ML or ANE service failures.
- An on-device `MLComputePlan` is target-specific anticipated placement, not a trace of a completed prediction. Read `deviceUsage(for:)` and `estimatedCost(of:)`, then use runtime telemetry for an execution claim.
- A shell with no Xcode account signed in needs a manually managed development profile and matching development identity. This is firsthand the reference implementation behavior, not a claim that every CI signing setup must be manual.
- Community reports about fixed iPhone memory ceilings, JIT compilation spikes, AOT paging, background suspension, and re-signing are useful hypotheses. They remain labeled until reproduced on the target tuple.

## Evidence Labels

- **Current command help:** reproduced with Xcode 26.6 and `devicectl` 518.33. Re-run `xcrun devicectl help ...` after changing Xcode.
- **Documented API:** current Apple Core ML documentation retrieved through Context7 library `/websites/developer_apple_coreml`.
- **Firsthand implementation evidence:** reproduced by the local iOS harness workflow and recorded in the linked harness README or research brief.
- **Community / unverified:** synthesized from the raw report's public sources. Keep the recipe, but test it on the exact hardware, OS, Xcode, app, and model before relying on it.

## 1. Operating Model

A robust run has five explicit boundaries:

```text
signed .app
    -> install
    -> stage one immutable input directory
    -> launch one configuration
    -> pull one result receipt and all relevant crash evidence
```

Treat the host, the app container, and system diagnostics as separate stores. A successful command invocation is not proof that a file arrived, an app completed, a model used the requested device, or no system daemon crashed.

For automation, prefer `--json-output <path>` where `devicectl` supports it. Current command help states that a user-provided JSON file is the only supported interface for programs consuming command output. Human-readable stdout is not a stable parser contract.

Use privacy-safe run identifiers in paths and receipts. Do not record device identifiers, device names, signing credentials, private audio paths, or transcript content.

## 2. Build and Install a Signed App

`devicectl device install app` installs an already signed `.app`; it does not solve signing or provisioning:

```bash
xcrun devicectl device install app \
  --device "<device-id>" \
  --json-output install.json \
  "/path/to/Benchmark.app"
```

The placeholder device ID is operational input only. Do not persist it in a public receipt.

### 2.1. Manual signing when no Xcode account is signed in

**Firsthand implementation evidence:** automatic signing with `-allowProvisioningUpdates` failed with a "No Accounts" error when the build host had no account signed into Xcode. An Xcode-managed development profile was then rejected under manual signing. A non-Xcode-managed development profile that included the registered target device worked with manual signing:

```bash
xcodebuild \
  -project Benchmark.xcodeproj \
  -scheme Benchmark \
  -configuration Release \
  -destination "generic/platform=iOS" \
  -derivedDataPath .build/xcode \
  CODE_SIGN_STYLE=Manual \
  CODE_SIGN_IDENTITY="Apple Development" \
  PROVISIONING_PROFILE_SPECIFIER="<manual-profile-name>" \
  build
```

The signing identity's private key and the provisioning profile must be available to the shell. The profile must authorize the app identifier, entitlements, team, and target device. Unlocking a keychain can fix private-key access errors, but it does not invent a missing Xcode account or repair a mismatched profile.

```bash
security find-identity -v -p codesigning
security cms -D -i "/path/to/profile.mobileprovision"
codesign -d --entitlements :- "/path/to/Benchmark.app"
codesign --verify --deep --strict --verbose=2 "/path/to/Benchmark.app"
```

Do not print keychain passwords, private keys, or full provisioning payloads into CI logs.

### 2.2. Archive and export

The raw report's archive/export route is worth keeping for CI systems that produce an archive. Xcode 26.6 marks export method `development` deprecated; use `debugging`.

```bash
xcodebuild archive \
  -workspace Benchmark.xcworkspace \
  -scheme Benchmark \
  -destination "generic/platform=iOS" \
  -archivePath .build/Benchmark.xcarchive \
  CODE_SIGN_STYLE=Manual \
  CODE_SIGN_IDENTITY="Apple Development" \
  PROVISIONING_PROFILE_SPECIFIER="<manual-profile-name>"

xcodebuild -exportArchive \
  -archivePath .build/Benchmark.xcarchive \
  -exportPath .build/export \
  -exportOptionsPlist ExportOptions.plist
```

A minimal current export configuration can name the profile rather than embedding private identifiers:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>method</key>
  <string>debugging</string>
  <key>signingStyle</key>
  <string>manual</string>
  <key>signingCertificate</key>
  <string>Apple Development</string>
  <key>provisioningProfiles</key>
  <dict>
    <key>com.example.benchmark</key>
    <string>Benchmark Development</string>
  </dict>
</dict>
</plist>
```

**Community / unverified:** some headless setups require provisioning profiles to be installed under `~/Library/MobileDevice/Provisioning Profiles/` using the profile's internal identifier as the filename. Other tooling accepts a profile name or identifier in `provisioningProfiles`. Inspect the active Xcode version's `xcodebuild -help`; do not assume one naming convention is universal.

### 2.3. Re-signing and signing automation

**Community / worth trying:** re-signing a prebuilt app or IPA can work when the executable, embedded frameworks, entitlements, app identifier, and profile all agree. Sign nested code before the containing app:

```bash
for framework in Payload/Benchmark.app/Frameworks/*.framework; do
  codesign --force --sign "<development-identity>" "$framework"
done

codesign --force \
  --sign "<development-identity>" \
  --entitlements Entitlements.plist \
  Payload/Benchmark.app
```

This recipe is incomplete for bundles containing extensions, app clips, nested apps, or other signed code. Enumerate and verify the actual bundle graph; do not apply `--deep` as a substitute for understanding it.

**Community:** fastlane `match`, `sigh`, and `cert` can synchronize the same profile-and-identity inputs. They reduce distribution friction but do not change Apple's signing contract. `altool` and `notarytool` are not the mechanism for installing a development build on a registered iOS device.

### Signing: do this / avoid this

| Do this | Avoid this |
| --- | --- |
| Verify the identity, profile, entitlements, and final app before install. | Treat a keychain unlock as a fix for missing account or profile authorization. |
| Use a manually managed development profile when the shell has no usable Xcode account. | Feed an Xcode-managed profile to a build explicitly configured for manual signing. |
| Re-run `xcodebuild -help` for the installed Xcode's export keys. | Keep using deprecated export method `development`; current Xcode calls it `debugging`. |
| Keep credentials and device identifiers out of receipts. | Dump profile contents or signing secrets into logs. |

## 3. Stage and Verify App-Container Data

### 3.1. Copy a directory, not a file into a missing parent

The basic app-container copy syntax is:

```bash
xcrun devicectl device copy to \
  --device "<device-id>" \
  --domain-type appDataContainer \
  --domain-identifier com.example.benchmark \
  --source ./run-input \
  --destination Documents/run-input \
  --json-output copy.json
```

**Firsthand implementation evidence:** a file-to-file copy whose destination parent did not already exist completed without producing the target file. Copying the whole local directory created the destination directory and transferred its contents. Therefore:

1. Build one local staging directory for each logical payload.
2. Copy that directory as a unit.
3. List the remote destination after every copy.
4. Verify expected names, sizes, and, when practical, content hashes in the app before loading a model.

Current command help says `copy to` skips files that have not been modified and supports repeated `--source` flags. It documents an overall `--timeout`, but it does not promise resumable transfer. **Unverified hypothesis:** interrupted multi-gigabyte transfers must be restarted. Design staging to be idempotent and independently verifiable.

### 3.2. List the domain directly

The raw report correctly identified a direct file-listing command:

```bash
xcrun devicectl device info files \
  --device "<device-id>" \
  --domain-type appDataContainer \
  --domain-identifier com.example.benchmark \
  --subdirectory Documents/run-input \
  --recurse \
  --json-output files.json
```

Current help confirms `--subdirectory`, recursive listing, filtering, sorting, and JSON output. Use this rather than treating a zero exit status from `copy to` as proof.

### 3.3. `--remove-existing-content` can wipe the container

Current `copy to` help describes `--remove-existing-content` as removing files from the destination directory and says it applies only to directory transfers.

**Firsthand the reference implementation contradiction:** `--remove-existing-content true` emptied the entire app data container, not only the named subtree. The observed behavior is more destructive than the help text implies. Do not use this flag in a qualifying workflow.

The safer pattern is in-app, allow-listed cleanup:

```swift
let fileManager = FileManager.default
let staleDirectory = documentsURL.appendingPathComponent("bundles/stale", isDirectory: true)
if fileManager.fileExists(atPath: staleDirectory.path) {
    try fileManager.removeItem(at: staleDirectory)
}
```

Constrain deletion to a known child beneath a known app-owned root. Refuse absolute paths, `..`, symlinks that escape the root, or an empty run identifier.

### 3.4. Other domains

Current command help lists `temporary`, `appDataContainer`, `appGroupDataContainer`, and `systemCrashLogs`.

For an App Group, use `appGroupDataContainer` and the App Group identifier, not the application bundle identifier:

```bash
xcrun devicectl device info files \
  --device "<device-id>" \
  --domain-type appGroupDataContainer \
  --domain-identifier group.com.example.benchmark \
  --json-output group-files.json
```

**Documented platform constraint, externally synthesized:** the app and extensions must carry matching App Group entitlements. Treat App Group staging as a separate security boundary, not an alias for the app container.

### File transfer: do this / avoid this

| Do this | Avoid this |
| --- | --- |
| Copy a prepared directory when the destination parent may not exist. | Assume file-to-file copy creates intermediate directories. |
| List and verify the remote subtree after every transfer. | Treat a quiet or zero-exit copy as proof of arrival. |
| Make app-side cleanup narrow and allow-listed. | Use `--remove-existing-content true` in a qualifying run. |
| Restart and re-verify an interrupted transfer. | Assume undocumented resume semantics. |

## 4. Launch and Monitor One Configuration

### 4.1. Argument ordering is a hard boundary

Current command help defines the grammar as `<bundle-identifier-or-path> [<command-line-arguments> ...]`. **Firsthand implementation evidence:** every token after the positional bundle identifier was forwarded to the launched app.

```bash
xcrun devicectl device process launch \
  --device "<device-id>" \
  --terminate-existing \
  --console \
  --environment-variables '{"BENCHMARK_MODE":"latency"}' \
  com.example.benchmark \
  --model-path Documents/run-input/encoder.mlmodelc \
  --iterations 100
```

Here `--model-path` and `--iterations` belong to the app. Every `devicectl` option, including `--device`, `--console`, `--environment-variables`, and `--terminate-existing`, appears before the bundle identifier.

No `--` separator is required by the documented grammar. Do not introduce one without checking the installed tool's help and the app's observed `argv`.

### 4.2. Environment variables have two supported routes

The raw report said environment variables must be passed with `--environment-variables`. Current command help documents two routes:

1. Pass a JSON dictionary before the bundle identifier.
2. Export host variables with a `DEVICECTL_CHILD_` prefix.

```bash
export DEVICECTL_CHILD_BENCHMARK_MODE=latency
xcrun devicectl device process launch \
  --device "<device-id>" \
  com.example.benchmark
```

An explicit `--environment-variables` dictionary overrides prefixed caller variables. Do not put secrets into either route; process environments and logs are not a credential vault.

### 4.3. Lifecycle options

- `--activate` is the default where supported and requests foreground activation.
- `--terminate-existing` kills an existing app instance before launch where supported. Use it when a clean process is part of the measurement contract, not as an unconditional default.
- `--start-stopped` launches suspended for debugger attachment.
- `--console` connects standard streams, waits for termination, and forwards catchable signals.
- `--timeout` limits the `devicectl` command. It is not proof that the app persisted or completed after the host command exits.

Inspect running processes separately:

```bash
xcrun devicectl device info processes \
  --device "<device-id>" \
  --filter "name CONTAINS[c] 'Benchmark'" \
  --json-output processes.json
```

**Community / unverified:** launching through `devicectl` may avoid some launch-time behavior seen with icon launches. Do not convert that anecdote into a watchdog guarantee. Measure startup, foreground state, suspension, and termination on the target OS.

### Process launch: do this / avoid this

| Do this | Avoid this |
| --- | --- |
| Put all `devicectl` options before the bundle identifier. | Append `--device`, `--console`, or environment configuration after the bundle identifier. |
| Make one launch represent one immutable configuration. | Reuse an unknown running process and infer which inputs it loaded. |
| Use JSON process listings and an app-owned done marker. | Infer successful completion from "process exists" or `devicectl` exit alone. |
| Use `--terminate-existing` only when clean launch semantics are intended. | Treat termination as harmless when the prior process may own an incomplete receipt. |

## 5. Capture Progress and Durable Results

### 5.1. `--console` does not make Swift `print` durable

**Firsthand implementation evidence:** plain Swift `print(...)` produced no visible output under `--console`; stdout was block-buffered because it was not attached to an interactive terminal. Stderr worked, and a file written under `Documents` could be pulled reliably.

Use stderr for progress:

```swift
import Foundation

func emitProgress(_ message: String) {
    FileHandle.standardError.write(Data((message + "\n").utf8))
}
```

Use a file plus an atomic done marker for the final machine-readable result:

```swift
let payload = try JSONEncoder().encode(result)
let temporaryURL = resultsURL.appendingPathComponent("\(runID).json.tmp")
let finalURL = resultsURL.appendingPathComponent("\(runID).json")
try payload.write(to: temporaryURL, options: .atomic)
try FileManager.default.moveItem(at: temporaryURL, to: finalURL)
try Data().write(to: resultsURL.appendingPathComponent("\(runID).done"))
```

Pull it after the done marker appears:

```bash
xcrun devicectl device copy from \
  --device "<device-id>" \
  --domain-type appDataContainer \
  --domain-identifier com.example.benchmark \
  --source "Documents/results/<run-id>.json" \
  --destination "./results/<run-id>.json" \
  --json-output pull-result.json
```

Validate the receipt schema, run ID, configuration identity, model signature, and completion status after transfer.

### 5.2. Unified logging

The raw report's OSLog advice remains useful: unified logging survives beyond one stdout pipe, but dynamic fields may be private unless marked public. Never mark private audio, transcripts, credentials, or device identifiers public merely to simplify debugging.

Historical device collection is supported by the host `/usr/bin/log collect`:

```bash
sudo /usr/bin/log collect \
  --device-udid "<device-id>" \
  --last 15m \
  --output benchmark.logarchive

/usr/bin/log show \
  --archive benchmark.logarchive \
  --predicate 'process == "Benchmark"' \
  --style ndjson
```

**Correction to the raw report:** on the verified host, `/usr/bin/log stream --help` has no `--device`, `--device-name`, or `--device-udid` option. The raw `log stream --device-udid ...` recipe is not valid there. For live output, use `devicectl ... --console` with stderr, an app-owned progress file, or a separately verified device-log tool. Re-check the installed OS before using a remote `log stream` recipe.

### Console and log capture: do this / avoid this

| Do this | Avoid this |
| --- | --- |
| Send short progress messages to stderr. | Use Swift `print` as the only receipt channel under `--console`. |
| Write final JSON to `Documents` and pull it after an atomic done marker. | Parse transient console prose as the result of record. |
| Mark only non-sensitive OSLog fields public. | Expose private content to defeat `<private>` redaction. |
| Use `log collect --device-udid` for historical archives. | Publish the unsupported `log stream --device-udid` command. |

## 6. Recover Crash Evidence

`systemCrashLogs` is a current `devicectl` file-service domain:

```bash
xcrun devicectl device copy from \
  --device "<device-id>" \
  --domain-type systemCrashLogs \
  --source . \
  --destination ./crashes \
  --json-output pull-crashes.json
```

List before pulling when a focused selection is useful:

```bash
xcrun devicectl device info files \
  --device "<device-id>" \
  --domain-type systemCrashLogs \
  --json-output crash-files.json
```

Apple crash reports commonly use `.ips`. Correlate by process, timestamp, run window, and launch metadata rather than filename alone:

```bash
jq -r '(.procName // .process // "unknown") + " - " + (.timestamp // "unknown")' \
  crash.ips
```

Some `.ips` files use a JSON metadata line followed by another JSON object; others vary by OS. Inspect the format before hard-coding `head -n 1`.

**Community / worth checking:** Core ML workloads can fail in out-of-process services such as E5 runtime or ANE compiler processes, so an app-name-only scan may miss the root cause. Pull the domain around a bounded run window and inspect all new reports. The exact service names and report schemas are OS-version dependent.

Jetsam termination is not necessarily a catchable Swift error. Treat a missing done marker, vanished process, and fresh resource-limit report as a correlated failure requiring the crash artifact, not as a timeout to retry blindly.

## 7. Keep Long Measurements Alive

For a foreground UIKit harness, disable automatic screen idle while a run is active:

```swift
await MainActor.run {
    UIApplication.shared.isIdleTimerDisabled = true
}
```

Restore the prior setting after completion.

**Community / platform hypothesis:** a standard app can still be suspended after it is backgrounded or the device locks. A `devicectl` launch does not grant indefinite background execution. Keep the measurement app foreground, keep the device in a controlled powered state, and make suspension observable through timestamps and done markers.

Do not claim an audio, location, or other background mode solely to keep a benchmark alive. Use only a mode that the app genuinely performs and Apple's policy permits. If foreground operation is impossible, design the run into resumable bounded units rather than hiding it behind an unrelated entitlement.

Thermal state, battery state, charging, screen state, and other active Core ML clients can change latency. Bind those conditions into the experiment protocol when they matter, but keep device identifiers out of public receipts.

## 8. Memory, JIT, AOT, and Jetsam

The raw report preserves a useful failure model but overstates it as universal:

- **Community reports:** some iPhones exhibit a per-process memory ceiling near 6 GB even when total physical memory is larger.
- **Community reports:** on-device compilation of large Core ML or MPSGraph packages can create transient resident-memory spikes and trigger jetsam or compiler-service failure.
- **Community hypothesis:** ahead-of-time compiled `.mlmodelc` assets can reduce compilation work and permit more file-backed paging than loading an uncompiled package.
- **Community reports:** the increased-memory-limit entitlement may provide limited or device-dependent relief, with different behavior on iPad.

None of those numbers is portable across devices, OS builds, entitlements, model formats, or Core ML revisions. Measure peak physical footprint in the app, record cold-load and warm-run separately, and pair every unexplained termination with `systemCrashLogs`.

Prefer a compiled model for device deployment:

```bash
xcrun coremlcompiler compile \
  "/path/to/Model.mlpackage" \
  .build/compiled
```

**Unverified mechanism:** memory mapping can move some model storage from dirty resident memory to file-backed pages, but `.mlmodelc` is not a promise of zero runtime compilation or safe peak memory. The proof is a target-device cold-load receipt plus crash scan.

## 9. Inspect `MLComputePlan` Correctly

### 9.1. Current documented Swift surface

Context7 verification against Apple Core ML documentation gives these signatures:

```swift
static func load(
    contentsOf url: URL,
    configuration: MLModelConfiguration
) async throws -> MLComputePlan

func deviceUsage(
    for operation: MLModelStructure.Program.Operation
) -> MLComputePlan.DeviceUsage?

func estimatedCost(
    of operation: MLModelStructure.Program.Operation
) -> MLComputePlan.Cost?
```

`deviceUsage(for:)` returns `nil` when usage cannot be determined. Swift `DeviceUsage` exposes `preferred` and `supported` compute devices. `estimatedCost(of:)` exists for ML Program operations and returns an optional cost. `Cost.weight` is documented as an estimated workload fraction from `0.0` to `1.0` over the total model evaluation.

### 9.2. Minimal on-device walk

Pass the compiled `.mlmodelc` URL and the same configuration used for the model run:

```swift
import CoreML
import Foundation

@available(iOS 17.4, *)
func writeComputePlan(
    compiledModelURL: URL,
    configuration: MLModelConfiguration
) async throws {
    let plan = try await MLComputePlan.load(
        contentsOf: compiledModelURL,
        configuration: configuration
    )

    guard case let .program(program) = plan.modelStructure,
          let main = program.functions["main"] else {
        throw BenchmarkError.expectedMLProgram
    }

    for operation in main.block.operations {
        let usage = plan.deviceUsage(for: operation)
        let cost = plan.estimatedCost(of: operation)
        let line = [
            operation.operatorName,
            String(describing: usage?.preferred),
            String(describing: cost?.weight),
        ].joined(separator: "\t")
        FileHandle.standardError.write(Data((line + "\n").utf8))
    }
}
```

The `BenchmarkError` case is app-owned and must be defined by the harness.

### 9.3. What the values prove

- `usage?.preferred` is anticipated preferred placement for that operation under the supplied configuration. It is not a trace proving where a completed prediction executed.
- `usage?.supported` can describe available devices where exposed, but support is not selection.
- `cost?.weight` is an estimate, not milliseconds. Aggregate it within one plan; do not treat it as absolute latency.
- **Firsthand implementation evidence:** `const` operations returned `nil` for both usage and cost in the tested compiled program. Apple documents the optional return and undetermined-usage meaning, not a universal "all const operations are nil" rule. Keep the unwrap for every operation.
- The plan is model-, shape-, configuration-, device-, and OS-specific. A simulator or Mac plan does not certify a physical iPhone.

The raw report called on-device Swift output "irrefutable ground truth." That is too strong. It is more target-specific than an off-device estimate, but it remains a compute plan. Pair it with latency, runtime telemetry, or a trace before claiming actual ANE, GPU, or CPU execution. See the Neural Engine residency guide for that distinction.

## 10. What Not to Do

| Anti-pattern | Why it fails | Do this instead |
| --- | --- | --- |
| Stage a bare file into a missing remote parent. | Firsthand runs silently produced no target file. | Copy one directory and list it afterward. |
| Add `--remove-existing-content true` for cleanliness. | Firsthand runs emptied the whole app container. | Delete an allow-listed subtree inside the app. |
| Put a `devicectl` flag after the bundle identifier. | It becomes app `argv`. | Put every tool option before the positional bundle identifier. |
| Depend on Swift `print` under `--console`. | Buffered stdout can remain silent. | Use stderr for progress and a result file for record. |
| Use `log stream --device-udid`. | That option is absent on the verified host. | Use historical `log collect` or a separately verified live route. |
| Scan only app-named crash files. | Core ML or ANE services may fail independently. | Pull and time-filter the complete `systemCrashLogs` domain. |
| Read preferred compute-plan device as executed device. | The API reports anticipated use. | Pair the plan with runtime evidence. |
| Hard-code a 6 GB jetsam ceiling. | Memory policy varies by target and workload. | Measure peak footprint and collect termination evidence. |
| Assume automatic signing works without an Xcode account. | It failed firsthand with "No Accounts." | Use a matching manually managed development profile. |
| Re-sign only the outer app. | Nested signed code can retain a mismatched identity or entitlement set. | Enumerate, sign inside-out, and verify the final bundle. |

## 11. Debugging Playbook

### Copy reports success but the file is absent

1. List the intended parent with `device info files`.
2. If the parent is absent, copy the containing local directory instead of the file.
3. Pull or app-hash the staged payload before loading it.
4. Preserve the copy JSON and file-list JSON as operational evidence.

### Previous app state disappeared

1. Search the driver command for `--remove-existing-content`.
2. Treat the entire container as potentially wiped.
3. Restore only known public inputs.
4. Remove the flag permanently and move cleanup into bounded app logic.

### The app receives `--device` or other unexpected arguments

1. Capture the app's `CommandLine.arguments` to stderr or a result file.
2. Move every `devicectl` option before the bundle identifier.
3. Keep only app arguments after the bundle identifier.

### `--console` is blank

1. Confirm the process exists with `device info processes`.
2. Emit one flushed stderr line.
3. Poll for an app-owned progress or done file.
4. Pull a historical log archive if OSLog was enabled.

### Signing reports "No Accounts"

1. Decide whether the runner is supposed to use an interactive Xcode account. Do not assume.
2. If no account is available, select a manually managed development profile that authorizes the target.
3. Verify that the development identity and private key are visible to the shell.
4. Build with manual signing and inspect the final entitlements before install.

### Signing says the profile is Xcode-managed but manual signing is required

1. Stop mixing an Xcode-managed profile with manual signing.
2. Create or obtain a non-Xcode-managed development profile for the app and registered target.
3. Install it without logging its private payload.
4. Rebuild with `PROVISIONING_PROFILE_SPECIFIER` naming that profile.

### The process vanishes during model load

1. Do not retry immediately.
2. Pull `systemCrashLogs` for the bounded launch window.
3. Check app resource-limit reports and Core ML, E5, or ANE service reports.
4. Separate cold compilation from warm inference.
5. Try an AOT-compiled `.mlmodelc` as a diagnostic, then remeasure peak footprint.

### Compute plan reports no device or no cost

1. Confirm the model is an ML Program and the walked operation belongs to the loaded plan's structure.
2. Keep optional handling; `nil` means the value could not be determined.
3. Record operation name, model signature, compute units, OS, and device class without a unique identifier.
4. Do not replace missing plan data with guessed placement.

## 12. Ingest Decision Log

### Corrected against current Core ML documentation

| Raw-report framing | Correction | Evidence |
| --- | --- | --- |
| On-device `MLComputePlan` is execution ground truth. | `deviceUsage(for:)` reports anticipated usage and returns optional `DeviceUsage`; runtime execution needs separate evidence. | Apple Core ML via Context7 |
| `const` operations return `nil` for usage and cost as an API rule. | The APIs are optional; `deviceUsage` is `nil` when usage cannot be determined. Const-nil is retained as a firsthand observation, not a universal contract. | Apple Core ML via Context7; the reference implementation harness |
| Compute-plan loading was shown without an exact contract. | The exact API is `static func load(contentsOf:configuration:) async throws -> MLComputePlan`. | Apple Core ML via Context7 |
| Cost was treated as available on every operation. | `estimatedCost(of:)` exists but returns `MLComputePlan.Cost?`; `weight` is a `0.0...1.0` estimated workload fraction. | Apple Core ML via Context7 |

### Corrected against current command help

| Raw-report framing | Correction | Evidence |
| --- | --- | --- |
| Environment variables must use `--environment-variables`. | Current `process launch` also accepts caller variables prefixed with `DEVICECTL_CHILD_`; explicit JSON overrides them. | Xcode 26.6 `devicectl` 518.33 help |
| `log stream --device-udid` streams a physical device. | The verified `/usr/bin/log stream` has no device-selector option; `/usr/bin/log collect` does. | macOS 26.6 command help |
| Export method `development` is current. | Xcode 26.6 deprecates it in favor of `debugging`. | `xcodebuild -help` |
| `--terminate-existing` should always be used in CI. | It is appropriate only when terminating prior work is part of the run contract. | Current option semantics |

### Firsthand the reference implementation annotations retained

1. Missing destination parents can make file-to-file `copy to` silently produce nothing; directory copy works.
2. `--remove-existing-content true` emptied the entire app data container, contradicting the narrower current help wording.
3. Tokens after the process-launch bundle identifier are app arguments.
4. Swift `print` was silent under `--console`; stderr and a `Documents` result file worked.
5. With no Xcode account signed in, a manually managed development profile authorizing the target worked and an Xcode-managed profile did not.
6. `systemCrashLogs` is available for crash retrieval.

### Preserved as community or unverified

- Multi-gigabyte transfers lack resume and must restart after interruption.
- `devicectl` launch changes launch-watchdog behavior.
- Foreground activation plus idle-timer suppression is sufficient for a long unattended run.
- A roughly 6 GB per-process ceiling applies to modern iPhones.
- JIT compilation drives transient jetsam failures, while AOT compilation and file-backed mapping reduce the peak.
- Increased-memory-limit entitlements add little headroom on iPhone and more on iPad.
- Core ML, E5 runtime, and ANE compiler services can crash independently of the app.
- Profile filename conventions under `~/Library/MobileDevice/Provisioning Profiles/`.
- Inside-out `codesign` re-signing and fastlane-based credential synchronization.

Each remains concrete enough to test. None is promoted to a target-device fact without a bounded receipt.

### Removed with evidence

- The executable `log stream --device-udid ...` recipe was removed because the verified host rejects that option. The underlying need for live device logging is retained with supported and explicitly unverified alternatives.
- No other substantive mechanism, workaround, deployment route, or failure mode was removed.

### Claim-Coverage Audit

| Raw report section | Substantive items | Disposition |
| --- | --- | --- |
| Executive summary | Container wipe, argv boundary, silent stdout, crash domain, long execution, memory, compute plan, signing | All kept; absolutes corrected or relabeled |
| App-container transfer | Copy to/from, missing parents, file listing, no resume, App Groups, destructive cleanup | All kept; first three verified by command help or firsthand evidence |
| Process launch | Argument order, environment, start-stopped, terminate-existing, process listing | All kept; environment route and unconditional termination corrected |
| Console and unified logging | stderr, result files, OSLog privacy, stream and collect | Kept; unsupported remote `log stream` command removed with evidence |
| Crash retrieval | `systemCrashLogs`, `.ips`, daemon failures, correlation | All kept; schema and daemon names labeled version-dependent |
| Unattended execution | Foreground activation, idle timer, suspension, background modes | All kept as platform or community guidance |
| Memory and jetsam | Approximate ceiling, resource termination, JIT spike, AOT and paging, entitlement | All kept and relabeled unverified |
| `MLComputePlan` | Load, device usage, cost, const nil, on-device versus off-device | All kept; API optionality and proof strength corrected |
| Signing | No Accounts, manual profile, archive/export, profile installation, re-signing, fastlane, unrelated tools | All kept; local requirement separated from universal claims |
| Failure matrix | Silent copy, wipe, argv, signing, jetsam, blank console | All retained in the debugging playbook |

## Works Cited

1. [Apple Core ML: `MLComputePlan.load(contentsOf:configuration:)`](https://developer.apple.com/documentation/coreml/mlcomputeplan-1w21n/load%28contentsof%3Aconfiguration%3A%29) — exact asynchronous Swift load signature.
2. [Apple Core ML: `deviceUsage(for:)`](https://developer.apple.com/documentation/coreml/mlcomputeplan-1w21n/deviceusage%28for%3A%29-9em1q) — optional anticipated device usage for an ML Program operation.
3. [Apple Core ML: `estimatedCost(of:)`](https://developer.apple.com/documentation/coreml/mlcomputeplan-1w21n/estimatedcost%28of%3A%29) — optional operation cost.
4. [Apple Core ML: `Cost.weight`](https://developer.apple.com/documentation/coreml/mlcomputeplan-1w21n/cost/weight) — estimated workload fraction from zero to one.
5. Current Xcode 26.6 command help: `xcrun devicectl help device copy to`, `copy from`, `info files`, `info processes`, `process launch`, and `install app`.
6. Current macOS command help: `/usr/bin/log stream --help` and `/usr/bin/log collect --help`.
7. Current Xcode export help: `xcodebuild -help`.
