Repository navigation
Commit 937ccdc
feat(ios-runner): key runner startup failures on typed reasons (#2688)
* refactor(ios-runner): give the host DevToolsSecurity probe its own module
runner-session.ts is 1,181 lines, so the next behavior owed a split first. The
host developer-tools security probe is a self-contained preflight: it reads a
macOS setting for this machine, not the iPhone's Developer Mode toggle, and
today nothing in its name or its home says which machine it speaks for.
Pure move. The startup step key is renamed to say what it actually verifies, and
the existing coverage in runner-session.test.ts carries unchanged because the
probe consumes the same runner host port.
* feat(ios-runner): key runner startup failures on typed reasons
A `build-for-testing` failure was the one Apple failure shape with no typed
reason: `runner-artifact.ts` threw COMMAND_FAILED with a hint picked by
substring-matching the lowercased message plus a JSON dump of the details, and
nothing downstream could switch on which signing problem it was. `AGENTS.md`
keys behavior on typed reasons and details, never error text, so the build path
was the exception to the rule.
`classifyRunnerStartupFailure` is now the one classifier reachable from that
catch, and it reads `RUNNER_ERROR_RULES` rather than adding a second table: a row
either carries recovery verdicts, a `buildFailure` reason and hint, or both. The
reason and the hint beside it therefore cannot disagree, and an unproven cause is
never claimed -- `build_failed_unclassified` keeps the cache-recovery hint it
already gave. The host `DevToolsSecurity` refusal, which had a hint and no reason
at all, now publishes its own reason keyed on the typed status it read, and that
reason says host so it can never be read as the device's Developer Mode toggle.
`resolveRunnerBuildFailureHint` is gone, not kept as a pass-through. Reasons are
recorded as fixtures carrying the tool output, the command, the Xcode, and how
the line reached the file; each one is driven through the real build catch and
asserted on the normalized envelope, because every case is COMMAND_FAILED and the
reason is the assertion.
* refactor(ios-runner): reach the host dev-tools probe only when a device needs it
A static edge from `runner-session.ts` to the new module grew three Apple facade
closures by one module each (app-lifecycle, doctor, runner-operations), which the
eager-import-closure ratchet refuses: the runner subtree is eagerly evaluated to
answer a simulator request, and this preflight only ever runs for a physical
iOS device. Function-scoped import keeps the preflight where it belongs without
paying for it on the paths that can never use it.
* fix(ios-runner): classify a build failure only from what xcodebuild published
The startup rules read the whole `details` bag as JSON, and `execFailureDetails` puts
`cmd`/`args` in that bag. A caller who pinned a profile therefore handed the profile rule
its trigger: an unrelated Swift compile error classified as
`signing_provisioning_profile_missing` and lost the cache-recovery hint. The same bag holds
the `reason` and `hint` this classifier publishes, so a re-wrapped failure would match its
own verdict. `runnerToolText` now builds the one haystack a startup rule may read — our
message plus the tool's stdout and stderr — and the argv case has a fixture that proves a
pinned profile is not evidence (#2680).
Reading only `details` also dropped the message on the floor, so a failure the exec layer
raised as a plain `Error` (which the catch wraps with `String(err)`) became unclassified
while the same sentence in `stdout` classified. The message is in the haystack now, and a
`message-only` fixture keeps both carriers at parity.
`signing_style_conflict` is removed rather than kept as a guess: the hint named a
`CODE_SIGN_STYLE` env lever that does not exist and claimed a cause nothing captured. The
conflicting-settings line keeps a row so the profile row below cannot answer it with
missing-profile advice, but it publishes `build_failed_unclassified` until a capture shows
which setting disagrees and which lever clears it. Versioned help and the installation docs
no longer list the withdrawn reason, and `.device-evidence/CHECKLIST.md` gained the capture
that would let a follow-up claim it.
Provenance got honest vocabulary. `OBSERVED_ON` stamped invented sentences as observed on
Xcode 26.2, and one invocation was recorded as the producer of seven configurations that
cannot coexist; nothing here was captured, so entries now say `shipped-sniff-trigger` (the
matched substrings shipped before #2680, sentence reconstructed) or `invented-shape`, carry
`xcodeVersion: 'unobserved'`, and omit `command` until a run records one.
* fix(apple): take the exec result type from host-kit and thin the fixture assertion body
#2689 derived the runner host port from the modules it fronts, so `ExecResult` is read
from `@agent-device/host-kit/command` now rather than restated in `runner/host.ts`.
The per-fixture assertion body had grown past the complexity the Fallow audit allows a
changed file: the envelope checks move into `assertFailureEnvelope` and the tool-output
check into `assertToolOutputReachable`, so each recorded shape is still asserted through
the same path and the test body reads as one call.
* fix(apple): make a named provisioning profile earn its reason
One bare `provisioning profile` substring was the shipped sniffer's trigger, and it is a phrase a
failing build prints while talking about something else: the codesign invocation, a settings dump, a
note about the profile it used. Each row now requires the profile plus the complaint Xcode attaches
to it — its `IDEProvisioningErrorDomain` diagnostic, "doesn't include", "has expired" — and a
mention that says nothing keeps the cache-recovery advice it already had.
* fix(apple): require a profile and its complaint in one line
A whole-log AND proves two phrases exist, not that one qualifies the other: a note about the profile
the build used, three lines above an unrelated expired-certificate warning, published
`signing_provisioning_profile_missing` for a profile that was fine. The profile rows now read one
line at a time and the expiry row asks for Xcode's own `has expired` phrase. The rules table grows a
`toolTextLineIncludesAll` axis beside `toolTextIncludesAll`, and the bundle-identifier row that also
paired two phrases moves onto it so no startup row is left reading a whole log; its cross-line
negative rides along. `signing_no_profiles_for_bundle_id` shares the `PROFILE_UNUSABLE` advice
instead of spelling it out a third time.
`.device-evidence/CHECKLIST.md` belongs to the merged #2682 lane, so this stack's capture sheet lives
beside it as `CHECKLIST-runner-failures.md`.
* test(ios-runner): record the captured profile row and the host gating the rest need
Co-Authored-By: Apex <noreply@callstack.com>
---------
Co-authored-by: Apex <noreply@callstack.com>1 parent 42ad0bc commit 937ccdc
11 files changed
Lines changed: 1115 additions & 53 deletions
File tree
- .device-evidence
- packages/platform-apple/src/runner
- __tests__
- src/commands/schema
- website/docs/docs
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
38 | 37 | | |
39 | 38 | | |
40 | 39 | | |
| |||
437 | 436 | | |
438 | 437 | | |
439 | 438 | | |
440 | | - | |
441 | | - | |
442 | | - | |
443 | | - | |
444 | | - | |
445 | | - | |
446 | | - | |
447 | | - | |
448 | | - | |
449 | 439 | | |
450 | 440 | | |
451 | 441 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
0 commit comments