core: capture the host-arch slice of fat Xcode builds (R03 iOS crash) - #438
Merged
Conversation
A generic iOS Simulator destination builds every ARCHS slice, so the build log carries one swift-frontend invocation per arch and the capture could return the x86_64 one. The JIT then materialized x86_64 code in the arm64 agent, which died with SIGILL executing an x86_64 prologue. Two layers: XcodeCommandCapture.parse prefers the invocation whose -target matches the arch the agent runs as (log order no longer decides), and stripForeignTargetTriple treats a foreign-arch triple as foreign so Compiler's injected target wins for stale persisted captures. Verified: unit rows on both layers; R03 iOS renders again end-to-end, first with the stale x86_64 persisted capture (strip layer) and then with a fresh capture that now persists arm64 (parse layer). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
obj-p
enabled auto-merge (squash)
July 21, 2026 17:51
obj-p
added a commit
that referenced
this pull request
Jul 21, 2026
…mily design (#439) * docs: re-verify B04/R02/R03 on main ahead of resource-staging family B04 unchanged. R02's blank framebuffer is gone; its Spanish assertion is a fixture defect (String(localized:locale:) cannot select an lproj). R03 macOS unchanged; iOS regressed to an agent SIGILL — the Xcode build-log capture takes an x86_64 simulator invocation that stripForeignTargetTriple accepts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * examples: R02 Spanish assertion via explicit lproj sub-bundle; row closes String(localized:bundle:locale:) does not select the .lproj (locale: affects interpolation formatting only, proven natively against the built bundle), so the 2026-07-15 fixture variant could never display Spanish even against correct staging. The title now resolves through the locale's .lproj sub-bundle with visible staging-failure states. With the mechanism corrected, all R02 surfaces render Recursos cargados (macOS control, iOS single-preview control, iOS index 1 after a live switch) and the row flips to Guard passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * examples: B04 resource assertion via Bundle(for:); row closes Bundle.allFrameworks never lists a framework without ObjC classes (proven natively with a dlopen control), and the JSON sat under Resources/ in a flat iOS framework whose resource directory is the wrapper root. DynamicBadge gains an ObjC marker class, the payload moves to the framework root, and the preview resolves through Bundle(for:) with distinct failure states. With the mechanism corrected the iOS snapshot renders the payload — the EPC-dlopened framework serves its internal resource, so B04 flips to Guard passes. B02's combined render re-verified after the artifact change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: jit-bundle-resolution family design; R03 row updated post-#438 The resource-staging cluster dissolved under re-verification: R02 and B04 were fixture-mechanism defects, R03's iOS crash was the fat-build capture bug (#438). The one genuine gap is Bundle(for:) on JIT-compiled classes resolving to the agent image while only Generated*Symbols.swift gets the #151 wrapper rewrite. Design: an agent-side bundleForClass: hook keyed on class_getImageName == NULL, wrapper path plumbed from CODESIGNING_FOLDER_PATH; stage 2 retires the text rewrite. Amendments from adversarial review with native experiments folded: dladdr is unsound as the discriminator in a Swift process, and imageless JIT-linked SwiftPM package classes are a documented, gated limitation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: fold branch-gate review findings Drop rebase-orphaned commit SHAs from the design doc (cite rows instead), list B04's failure states by stage rather than an incomplete enumeration, and correct the DynamicBadge README's rationale — the marker anchors Bundle(for:), while the allFrameworks ObjC requirement is a separate fact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A generic
iOS Simulatorxcodebuild destination has no active arch, so it builds everyARCHSslice and the build log carries one swift-frontend invocation per arch.XcodeCommandCapture.parsereturned the first module match, which could be the x86_64 slice. The daemon then compiled the preview overlay to x86_64 and the arm64 JIT agent died with SIGILL executing an x86_64 prologue (55 48 89 e5). Deterministic onexamples/regress/xcode-resources(R03's iOS half, regressed since the 2026-07-15 pass).Fix (two layers)
XcodeCommandCapture.parseprefers the invocation whose-targettriple matches the arch the agent runs as; log order no longer decides. A foreign-arch-only log still captures the first match.stripForeignTargetTripletreats a foreign-arch triple as foreign (family match alone no longer keeps it), so Compiler's injected host-arch target wins for stale persisted captures without waiting for re-capture.collectSourceFilesdrops its hardcodedarm64OutputFileMap path forhostArch, finishing the arch parameterization (clangObjectsalready used it).Verification
hostArchwiring, no--targetpassthrough,-sdk-before--targetordering, foreign-arch/foreign-family strips, host keeps.arm64-apple-ios26.2-simulator).-Xcc -IDerivedSources paths survive the strip — additive header search dirs, arch-guarded contents), both local tiers green, manualRegressToolGuardTestsgreen, lint exit 0.Alternative considered
Pinning the arch at the xcodebuild invocation (
ARCHS=<hostArch>) would close the class at the root and halve frontend work, but changes the native build the user's products dir gets (thin instead of fat). Left as named future work; the read-side fix tolerates whatever the build emits.🤖 Generated with Claude Code