Repository navigation
VirtualDisplay: the BOOL return's encoding follows the architecture - #87
Conversation
`applySettings:` is the one selector in `privateAPISurface` that returns `BOOL`, and its encoding was spelled "B@:@". That is what the Objective-C runtime reports only where `OBJC_BOOL_IS_BOOL` holds, which is arm64. On x86_64 macOS `BOOL` is `signed char`, so the runtime reports "c@:@", `Runtime.method` threw `Failure.changedSignature`, and every virtual display fell back to streaming the real window although `CGVirtualDisplay` was present and working. Found on an Intel Mac (Core i5-8500B, Apple T2) on macOS 15.7.3, where `--virtual-display-selftest` reported: FAIL CGVirtualDisplay applySettings: changed signature: expected B@:@, found c@:@ With the encoding taken per architecture the same selftest reports all 17 selectors present, and creates, brings online at 2x, warps the cursor onto and destroys a display normally. No change on arm64: the encoding there is the "B@:@" it always was. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sj4qVTN3JiDaQL1FjyycXv
|
From a pass over all the open pull requests (nothing is decided yet): this pairs with #88, which makes Sill.app universal, and with both as they are the x86_64 slice would refuse the virtual display on macOS 26 Intel Macs, because the tester in #62 ran an x86_64 build on macOS 26.7.1 that passed the self-test with |
Main moved on since this branch began at 985a733, to d1fa97e (Saffsanity#85, Saffsanity#74, Saffsanity#77, Saffsanity#75, Saffsanity#79, Saffsanity#80, Saffsanity#78, Saffsanity#98, Saffsanity#153 and Saffsanity#142). None of them touched Sources/SillHost/VirtualDisplay.swift, so the merge is clean and this pull request's change applies to main as it is now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s ObjCBool
This branch took applySettings:'s encoding from the architecture ("c@:@"
on x86_64, "B@:@" on arm64). But the spelling comes from how the Mac's
CoreGraphics was built, and x86_64 has spelled it both ways:
- An Intel Mac mini with macOS 15.7.3 reported "c@:@" (this pull request).
- An Intel machine with macOS 26.7.1 passed the self test with an x86_64
build of 985a733 (build 585), which expected "B@:@" alone (Saffsanity#62). The
encoding itself was not printed.
- Under Rosetta on macOS 27.0.1 this Mac reads c24@0:8@16; natively it
reads B24@0:8@16.
With #if arch, the x86_64 slice that Saffsanity#88 builds would have refused the
virtual display on macOS 26 Intel Macs, the newest macOS they can run.
What changes, as Noah asked here on 2026-10-19:
- privateAPISurface writes the return "B" again. Runtime.method also
accepts it spelled "c" (VirtualDisplay.TypeEncoding.accepted), on every
architecture. There is no #if arch, so CI's arm64 build compiles the
only path. A refusal now reads "expected B@:@ or c@:@, found ...".
- applySettings: returns ObjCBool, which is BOOL on each architecture.
On x86_64 any byte but 0 is YES, which is right for both spellings; a
Swift Bool takes AL as it comes. On arm64 it compiles to the same code
as the Bool before.
- The comment that named Failure.changedSignature went with #if arch. The
new one names Failure.signatureChanged, the case's real name.
- normalized moves into TypeEncoding beside accepted. Both are pure, for
a check (next commit).
docs/DEVELOPMENT.md says what the self test checks first, and names the
two spellings.
Verified on this Mac (M2 Pro, macOS 27.0.1):
- swift build -c release, arm64 and --arch x86_64 (own scratch path):
only the known CaptureProbe warning, plus --arch's notice that x86_64
is deprecated.
- --virtual-display-selftest, arm64 and under arch -x86_64. A temporary
switch, not committed, skipped its pointer warp, HID move and
ScreenCaptureKit call. "private API: all 17 selectors present" with
B24@0:8@16 natively and c24@0:8@16 under Rosetta. The 1000x700 display
came online at 2000x1400 (applySettings: returned YES through ObjCBool)
and was gone 53 and 66 ms after destroy. Exit 0 both times.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inst measured encodings Neither CI nor any Mac here ever reads applySettings: spelled "c" except under Rosetta. So without a check, nothing would catch the previous commit's rule if it broke. The rule is pure (VirtualDisplay.TypeEncoding), so it gets a check, as CLAUDE.md's conventions ask. What it checks: - Every method's encoding, as method_getTypeEncoding gave it on an M2 Pro with macOS 27.0.1, natively and under Rosetta, passes for its entry. These come from a probe that only looks the methods up. - applySettings: as reported from Intel Macs passes too: "c@:@" on macOS 15.7.3 (Saffsanity#87) and "B@:@" on macOS 26.7.1 (Saffsanity#62, inferred). - The surface has one entry per measured method, written without offsets. - A BOOL return passes spelled "B" or "c". Nothing else passes: not another type, not a BOOL argument, not a void or object return; an entry written "c" stays "c". - normalized removes the offsets and nothing else. It compiles VirtualDisplay.swift whole, as VirtualDisplayProbe does. Only the static surface and TypeEncoding run, so it looks up no private class and makes no display. Runtime.method's three lines that call the rule are glue, which the self test exercises. 141 checks; 13 of 13 mutants caught: the c spelling dropped, only c, every return or any B widened, "C" for "c", the c before the B, "c" widened to B, the offsets kept or alone kept, applySettings: written c, setHiDPI: written as a BOOL, a method left off, an entry with offsets. Listed in Tests/checks/README.md, CLAUDE.md's Layout, docs/DEVELOPMENT.md and ci.yml's mutants matrix. run-all.sh with it, keychain, origin, clientlink and settings-window: all passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ry slice Noah wrote here on 2026-10-19 that whether releases go universal is still open in Saffsanity#62. As this branch stood, make-app.sh made every build universal, which settles that question. The next release.sh run would ship an x86_64 slice that has never streamed on an Intel Mac, and every --install --open would take twice as long. What changes: - make-app.sh builds both slices only with SILL_UNIVERSAL=1. That path is this pull request's own, unchanged: one build per triple, its own scratch path, lipo. Unset, it builds for this Mac's architecture as before, and still refreshes .build/release/SillMenuBar. Measured on an M2 Pro with Xcode 27.1 (2026-10-20): 50 s cold against 97 s universal; after a one-line host change, 21 s against 42 s. - release.sh's check_signature reads every slice. codesign verifies every architecture but shows only this Mac's, so an x86_64 slice without Developer ID, the hardened runtime or a timestamp would have passed. It now loops over lipo -archs with codesign --architecture, and reads each slice's entitlements once, into a variable (not a pipe into grep -q). - docs/DEVELOPMENT.md says how to build a universal Sill.app for an Intel tester. README, the site, the App Store text and the cask's depends_on arch stay Apple silicon until the x86_64 slice has streamed on an Intel Mac. CLAUDE.md's Layout and Build and run say the same. Verified on this Mac (M2 Pro, macOS 27.0.1, Xcode 27.1): - swift build -c release, arm64 and --arch x86_64 (own scratch path): only the known CaptureProbe warning, plus --arch's x86_64 deprecation notice. - make-app.sh without --install: unset gives "arm64"; SILL_UNIVERSAL=1 gives "x86_64 arm64". Both: minos 14.0 and sdk 27.0 on every slice, codesign --verify --deep --strict passes, build 702. - A dry run of release signing, universal (SILL_RELEASE_DRY_RUN=1, Developer ID, no profile): both slices have Developer ID, the hardened runtime and a timestamp; check_signature passes; spctl says "Unnotarized Developer ID". The bundle was deleted after. - check_signature stops a development build at "(x86_64) is not signed with Developer ID". Against a stand-in codesign whose x86_64 slice lacks the hardened runtime, main's check_signature passes and this one fails. - With Saffsanity#87's change applied and a temporary switch (not committed) that skips the self test's pointer warp, HID move and ScreenCaptureKit call, the universal binary's --virtual-display-selftest passes on both slices: B24@0:8@16 on arm64, c24@0:8@16 on x86_64 under Rosetta, all 17 selectors, the display online and destroyed. - Without Saffsanity#87, the x86_64 slice fails ("expected B@:@, found c@:@"), so the two ship together. - Tests/checks/run-all.sh dmg-layout keychain update-policy clientlink: all passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main moved from d1fa97e to 9a8e30c with Saffsanity#136 (the Apps list's folders, Saffsanity#76), which added the installed-apps check. It and this branch each added a check to ci.yml's one-line mutants matrix, which conflicted: the line now lists both, installed-apps and virtual-display-api, in sorted order with the 43 it had. Tests/checks/README.md and CLAUDE.md merged by themselves and keep both checks' rows and Layout entries. Saffsanity#136 did not touch VirtualDisplay.swift. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ySettings: call The check compared a hand copy of Runtime.method's decision with TypeEncoding, so it could not tell when Runtime.method itself stopped using the rule. With Runtime.method's guard back to main's equality, which is this pull request's bug, or with the applySettings: call expecting "c@:@", which would refuse the display on every Apple silicon Mac, all 141 checks still passed (the review of fcc4957). Two internal ways into the private Runtime, each used by the code as well as by the check: - VirtualDisplay.methodProblem(cls:selector:encoding:) gives Runtime.method's decision for one entry of the surface: nil, or the line checkPrivateAPI lists. checkPrivateAPI now asks it for every entry, setDispatchQueue: still standing in for setQueue:, with the same lines as before. - VirtualDisplay.applySettings(_:to:) is Runtime.applySettings moved out of Runtime, its body unchanged; init sends applySettings: through it. The check makes NSObject subclasses at run time (objc_allocateClassPair, class_addMethod) instead of copying the decision: - Every encoding it judged by hand (measured, reported or made up) is put on a method of such a class and judged by methodProblem. - Three more classes have an applySettings: typed B24@0:8@16, c24@0:8@16 and C24@0:8@16, answering what the NSNumber they are sent says. methodProblem takes the first two for the surface's "B@:@" and refuses the third with "... changed signature: expected B@:@ or c@:@, found C@:@". applySettings(_:to:) reads YES and NO from the first two, and the third is refused before it is called. - A method a class lacks and a class that is not there give their lines. No private class is looked up and no display is made. 152 checks, 0 failed (141 before); compiled for x86_64 and run under Rosetta, the same. 17 of 17 mutants caught, each by a failing check: the 13 before, and four of the glue: Runtime.method's guard back to one spelling, Runtime.method without normalized, applySettings: sent expecting "c@:@", and applySettings:'s NO read as YES. ApplyFn returning Bool is not among them: on arm64 that compiles to the same code as ObjCBool, so no arm64 run can catch it. Comments: the macOS 26.7.1 machine in Saffsanity#62 runs macOS through OpenCore, and its "B" is inferred; TypeEncoding's sources are measured on Apple silicon and reported from Intel machines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Tests/checks/README.md: virtual-display-api's row says what runs now (Runtime.method's decision and the applySettings: call, on classes the check makes at run time), 152 checks and 17 mutants, and what CI does not see: on arm64 the only "c" methods are the check's own, and ObjCBool compiles to the same code as Bool there. The row also says the macOS 26.7.1 "B@:@" is inferred, not printed, from build 585 passing the self test on an OpenCore machine (Saffsanity#62). The paragraph on the counts says the check came with Saffsanity#87. - docs/DEVELOPMENT.md said macOS has spelled the BOOL both ways on Intel Macs. Now: an Intel Mac mini with macOS 15.7.3 printed "c" (Saffsanity#87); "B" on Intel is inferred from that OpenCore machine; Apple silicon reads "B", and "c" under Rosetta. - CLAUDE.md's Layout says what the check runs, and that the Intel encodings are reported, not measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Three commits were added on this branch since fcc4957; the head is now 71aec66.
Verified on an M2 Pro with macOS 27.0.1: release builds for arm64 and x86_64; the check and its mutants, and the check built for x86_64 and run under Rosetta; Nothing has run on Intel hardware; the merge commit will say so. It merges once CI passes on this head, with #88 right after it. |
…ding) into pencil-pressure CI's mutants matrix keeps both new checks, pen and virtual-display-api. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
make-app.sh built Sill.app with a plain swift build, which builds for the Mac that runs it. Every Sill.app so far is arm64 only for that reason. It now builds the menu bar app once for arm64 and once for x86_64, each with its own scratch path under .build/universal, and joins the two slices with lipo. vtool, the icon and the signature use the universal binary as before. Not one swift build --arch arm64 --arch x86_64: that needs Xcode's XCBuild, and with the Command Line Tools alone it stopped at once. Not one shared .build: under Xcode 27 each switch of triple cost a 16 s relink, so no rebuild stayed at ~2 s. The x86_64 slice still needs #87 for the virtual display. Each slice compiles on its own, so #87's #if arch(x86_64) lands in the right one. Checked: Tests/checks/run-all.sh, all passed. make-app.sh with Xcode 27.1: universal, minos 14.0 and sdk 27.0 in both slices, codesign --verify --deep --strict passes, 2.3 s unchanged. make-app.sh with the Command Line Tools alone (Swift 6.3.3): universal, the generic icon as before. The universal app's --encoder-selftest: 150 of 150 hardware frames, as an arm64-only build. Not run on an Intel Mac.
Main gained Saffsanity#110 (Shift-Return and Shift-Tab), Saffsanity#136 (apps in folders, the installed-apps check), Saffsanity#87 (the virtual display's BOOL encoding, the virtual-display-api check) and Saffsanity#88 (a universal Sill.app on request). Merged so this branch builds and checks against today's main. Only ci.yml's one-line mutants matrix conflicted: both sides kept, sorted (46 checks: main's installed-apps and virtual-display-api beside this branch's pairing-sharing; ledger has no mutants). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ffsanity#88 beside Send Audio Main gained Saffsanity#110 (Shift+Return and Shift+Tab from an iPad's keyboard reach the Mac with the shift: InputOverlay, KeyChords and the key-strokes check), Saffsanity#87 (VirtualDisplay's BOOL return read as "B" or "c", with its new virtual-display-api check) and Saffsanity#88 (Sill.app universal with SILL_UNIVERSAL=1, release.sh checking every slice). Two conflicts, both lists, both sides kept: - ci.yml's mutants matrix: the sorted union, 49 checks, which are exactly the folders with a mutants.py (the sound's audio-codec, audio-packetizer, audio-playout and ledger, and main's virtual-display-api). - Tests/checks/README.md: the opening list names both the sound's checks and the virtual display's encodings; the history keeps main's virtual-display-api sentence, then the audio branch's. CLAUDE.md and docs/DEVELOPMENT.md merged by themselves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he universal Mac app) into pencil-pressure-rebased Only ci.yml's mutants matrix conflicted: it lists both new checks, pen and virtual-display-api, sorted (46 checks, every folder with a mutants.py). CLAUDE.md, the checks' README and DEVELOPMENT.md merged by themselves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Intel) into display-stepping ci.yml's mutants matrix gained virtual-display-api on main and display-stepping here: both kept, sorted. CLAUDE.md, docs/DEVELOPMENT.md and Tests/checks/README.md merged by themselves (main's Layout, Build and run and check rows beside this branch's). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd the universal Mac app) into thumbnail-hold Conflicts kept both sides: CI's mutants matrix (thumbnail-hold and virtual-display-api, sorted), the checks README's opening and its history line, and CLAUDE.md's list of checks. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…, Saffsanity#87, Saffsanity#88) Main gained Shift+Return and Shift+Tab from the iPad (Saffsanity#110), the virtual display's BOOL encodings with their check virtual-display-api (Saffsanity#87), and a universal Sill.app on request (Saffsanity#88). Three files conflicted, each resolved keeping both sides: ci.yml's mutants matrix as the sorted union (display-wake and virtual-display-api, every check folder but ledger), and the lists of what the pure checks decide in Tests/checks/README.md (its intro and provenance note) and docs/DEVELOPMENT.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main gained Saffsanity#110 (Shift+Return and Shift+Tab from a hardware keyboard: InputOverlay, KeyChords and the key-strokes check), Saffsanity#87 (the virtual display's BOOL encodings, its virtual-display-api check) and Saffsanity#88 (a universal Sill.app with SILL_UNIVERSAL=1). Only ci.yml's mutants matrix conflicted: both new checks kept, keyframe-recovery and virtual-display-api, in sorted order. None of it touches the display path, the host's window commands, kind 44 or the keyframe check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto main Merged locally from Saffsanity/sill pull/66/head (fe6c001) onto main (4d990e9). Conflicts: - WindowCatalog.findInstalledApps: main's InstalledApps.find (Saffsanity#76, Saffsanity#135) kept, with the PR's Finder from CoreServices added after it. - ci.yml: the mutants matrix is the union of both lists. - Tests/checks/README.md: main's key-strokes, installed-apps and remote-rules rows; the PR's protocol row. Fix after the merge: VirtualDisplay.resize called Runtime.applySettings, which Saffsanity#87 replaced with VirtualDisplay.applySettings(_:to:). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main gained Saffsanity#110 (Shift+Return and Shift+Tab), Saffsanity#136 (apps in folders), Saffsanity#87 (the virtual display's BOOL encoding, the virtual-display-api check) and Saffsanity#88 (a universal Sill.app on request). Two conflicts, each keeping both sides: ci.yml's mutants matrix (connection-list and virtual-display-api, sorted) and the checks README's sentence on where each check came from. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…affsanity#88) Main gained Saffsanity#110 (at 2814629, already merged here, so nothing of it is new), Saffsanity#87 (the virtual display's BOOL encoding, with the virtual-display-api check) and Saffsanity#88 (a universal Mac app for Intel testers). Two textual conflicts, lists where each side added an entry: CI's mutants matrix keeps text-composition and virtual-display-api, and CLAUDE.md's list of checks both. The checks' README and DEVELOPMENT.md merged by themselves; the sentence listing the pure checks is wrapped again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main gained Saffsanity#110 (Shift+Return and Shift+Tab reach the Mac from an iPad: InputOverlay, KeyChords and the key-strokes check) and Saffsanity#87 (VirtualDisplay's BOOL return spelled "B" or "c", with the virtual-display-api check). Neither touches a file this branch changes but CLAUDE.md's Layout, docs/DEVELOPMENT.md and Tests/checks/README.md, whose lines merged by themselves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thank you @kyleparisi, your encoding fix is in the Mac nightly, the first universal download, Apple silicon and Intel in one app! Since you have the 2018 Mac mini, you may well be the first to run this build on a real Intel Mac: with Sill for iPhone and iPad 0.5.5 (5) on TestFlight or the App Store's 0.5.1, I'd love to hear here (or in #62) whether the virtual display comes up and what frame rate you get. Nightlies build as 0.5.5 with rising build numbers and Sill's update check never offers them, so you install them yourself; 0.5.1 stays the supported release. |
applySettings:is the one selector inVirtualDisplay.Runtime.privateAPISurfacethat returnsBOOL, and its expected encoding was the literal"B@:@". That is what the Objective-C runtime reports only whereOBJC_BOOL_IS_BOOLholds, which is arm64. On x86_64 macOSBOOLissigned char, so the runtime reports"c@:@",Runtime.methodthrowsFailure.changedSignature, and the virtual display is given up on even thoughCGVirtualDisplayis present and working normally.The fix takes the encoding per architecture. No behaviour change on arm64 — the encoding there is the
"B@:@"it has always been.I appreciate this is a file that deliberately refuses to guess about private API, which is exactly why the wrong expectation is worth correcting: the guard is doing its job, it is just checking against a spelling that only one architecture uses.
How it shows up
swift run -c release SillHost --virtual-display-selfteston an Intel Mac, before:After:
In a running host the symptom is quieter: every
--virtual-displaypick logs theVirtual display fallback …line and streams the real window, so it reads as "the private API moved" rather than "this Mac spellsBOOLdifferently."Environment
Macmini8,1— 6-core Intel Core i5-8500B @ 3.0 GHz, Apple T2, Intel UHD 630swiftlang-6.1.2.1.2 clang-1700.0.13.5), macOS 15.5 SDK985a733(main)iPhone17,5), Sill 0.5.1 (4) from the App StoreNote this is not the documented toolchain (Xcode 27 on macOS 26/27), because Xcode 27 cannot be installed on macOS 15. Built with
swift build -c releaseandScripts/make-app.shunder Command Line Tools only.Context: what else an Intel build needs
Not part of this PR, recorded in case it is useful to anyone else arriving here. The repository is otherwise architecture-clean — no
#if arch(...)anywhere inSources/oriOSClient/, and noARCHSpinning in the Mac build scripts. The arm64-only binary is a consequence ofswift builddefaulting to the host architecture, exactly asScripts/release.sh's own comment anticipates ("The site says Apple silicon: change that if this ever lists x86_64"). The encoding above was the single genuine architecture dependency I found, and it is invisible to a grep because it lives in a string literal.One further change is needed to compile on macOS 15, which I am deliberately not proposing:
StreamProtocol/RemoteIdentity.swiftcallsSecIdentityCreate, which is declared inSecurity/SecIdentity.hin the macOS 26 SDK and no earlier one (macOS 15.5's header has onlySecIdentityCreateWithCertificate). The symbol itself has shipped inSecurity.frameworkfor years —dlsymfinds it on macOS 15.7.3 — so a local@_silgen_namedeclaration returningUnmanaged<SecIdentity>?(CF Create rule) is enough to build. That is me compiling against an SDK the project does not claim to support, so it belongs in my tree, not yours.Performance on this hardware, for the record
The virtual display works, but Apple silicon's encoder is doing much more of the work than an Intel/T2 machine can. Posting the numbers because the README's Apple silicon requirement is well justified on throughput grounds, and anyone finding this issue should know what to expect rather than assume a misconfiguration:
cap.complete 60→enc.out 37,enc.mailboxDrop 23The network is not the constraint; the encoder is, at roughly 27 ms/frame where Apple silicon manages 9. Glass-to-glass lands near 80–110 ms rather than the 40–60 ms the brief targets. Dropping Resolution to Standard helps considerably more here than it would on Apple silicon.
Two T2-specific notes that may interest you independent of Intel:
Cannot open AVE instance, there appears to be another instance already open!→err = -12915. The slow-state session replacement inHEVCEncoder(replacesSlowSessions, on by default) opens a new session alongside the live one, which cannot succeed on this hardware. In practice it never fired during real use —SILL_TEST_ENCODER_RECYCLE=0is the escape hatch — but the "two sessions share one engine" assumption documented inCLAUDE.mdis arm64-specific.--encoder-selftestfails on this machine for the same reason: its 256×256 launch probe still holds the engine when the stream-sized session opens. Normal host startup is unaffected, since the probe is released before streaming begins.Tested
Tests/checks/run-all.sh— 39 of 40 pass. The exception isduo, which fails for a reason unrelated to this change and would fail the same way on an unmodifiedmainwith this toolchain: on Swift 6.1.2 the type checker gives up on a literalCGFloatsum in the check's own source.That check compiles only
iOSClient/DuoPosture.swiftand its ownmain.swift, neither of which this PR touches. Swift 6.3 under Xcode 27 evidently handles the expression; annotating the literals (or splitting the sum) would make the check build on older toolchains too, if that is worth anything to you.swift build -c release, andScripts/make-app.sh(ad hoc signed;actoolis unavailable without Xcode, so the icon is generic)--virtual-display-selftestbefore and after, output aboveSill.app 0.5.1 running as the host: paired with the App Store iPhone app via QR over the TLS home door, streamed the whole desktop at 4096×2304 and individual windows (Chrome, iTerm2), switching sources live
No encoder fallback, hang, or slow-state replacement in the log across the session
Not tested: anything on arm64 — I have no Apple silicon Mac, so the unchanged
"B@:@"path is reasoned about rather than run. The iOS app was not built (it needs the iOS 27.1 SDK, unreachable on macOS 15); the App Store build was used instead. If a reproducer uses a shallow clone, note thatmake-app.shderivesCFBundleVersionfromgit rev-list --count HEADand will report a wrong build number.On Intel support generally
I am not asking you to support Intel Macs, and closing this is a perfectly reasonable call — the throughput numbers above make the case for the Apple silicon requirement better than any argument would. The encoding fix stands on its own though: it is two lines, changes nothing on arm64, and makes the private-API guard check what the platform actually reports instead of rejecting a working method.