Emit SF Symbols 6 templates so the widget catalog builds on Xcode 16.4 - #338
Merged
Ryanmello07 merged 2 commits intoSep 3, 2026
Merged
Conversation
…e 16.4 CI has been red since 315d6bb added the widgets target: Assets.xcassets: error: Template format 7.0 is newer than the version that this software supports (6.0) at CompileAssetCatalogVariant in URnetworkWidgets. Nothing outside the repo changed -- the runner image and the Xcode pin (16.4) are the same as the last green run. 315d6bb simply never ran CI: it was pushed together with its child d826f34, and Actions builds only a push's HEAD, so the docs-only commit was the first run that compiled the new catalog. gen_connector_symbols.py hardcodes a Template v.7.0 banner and emits SF Symbols 7 style metadata, because it was written on Xcode 26. Fix the generator rather than the SVGs, so the next regeneration does not reintroduce it, and re-run it. The banner drops to v.6.0 ("Requires Xcode 16 or greater"), and all four -sfsymbols-* properties go, none of which a 6.0 parser knows and none of which this symbol uses -- it is a single static layer with no variable value and no Draw animation: -sfsymbols-motion-group SF Symbols 7 Draw animation -sfsymbols-draw-reverses-motion-groups SF Symbols 7 Draw animation -sfsymbols-layer-tags v7 per-layer identity token -sfsymbols-variable-value-mode picks color vs. draw; only a choice in v7 The three layer classes stay (with empty bodies) so each path's class attribute still binds the monochrome / hierarchical / multicolor layers; .defaults goes, having carried nothing but two of the properties above. No geometry changes: every path's d= is byte-identical to the previous export, and the compiled Assets.car keeps the same rendition names and counts (four Vector Glyphs per symbol, the four interpolation sources), each glyph just ~123 bytes smaller where the v7 metadata was. Not verified by building: this machine has no Xcode 16.4, only Xcode-beta 27.0, whose actool accepts both 6.0 and 7.0 -- so a local compile proves nothing about CI. The argument here is structural. The CI Xcode pin is untouched, and both symbols are kept (the outline variant is currently unreferenced but stays, per QUICKCONNECT.md). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014vN7zh8WeQYCtirhcA3aWw
CI pins Xcode 16.4, whose macOS SDK is 15.5. ControlCenter, ControlWidget, ControlWidgetConfiguration, ControlWidgetToggle, StaticControlConfiguration and ControlValueProvider are all annotated @available(iOS 18.0, macOS 26.0, watchOS 26.0, *), so on that SDK the declarations do not exist at all and "Build for macOS (unsigned)" fails with error: 'ControlCenter' is unavailable in macOS The existing #available(iOS 18.0, macOS 26.0, *) guards cannot fix this: they are runtime checks, and the compiler still needs the declaration to be present in the SDK it compiles against. Only a compile-time platform test can keep the macOS leg from referring to symbols its SDK lacks, so guard the three sites with #if os(iOS). The @available guards stay exactly as they were, because they are still the correct runtime check on iOS. - WidgetRefresh.reloadControl(): body wrapped, not deleted. The method is called from reloadAll(), which the app, the packet tunnel extension and the widget extension all call, and all three build for macOS. It stays a no-op there rather than a missing method. - QuickConnectControl: the whole file, since every type it names is macOS 26. - URnetworkWidgetBundle: the control is dropped from the macOS bundle, which stays valid with the three Home Screen widgets. Info.plist declares no control-specific keys. The Control Center / Lock Screen / Action button toggle is iOS-only in practice and could never have compiled for macOS against this SDK, so nothing that works today is removed. Every line compiled for iOS is byte-for-byte unchanged: the diff is 28 added lines, all preprocessor directives and comments, with no existing line modified. Audited the rest of the widget, app and tunnel sources against the SDK's own availability annotations for other post-15.5 symbols that the first error could have masked; the Control family above is the complete set. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014vN7zh8WeQYCtirhcA3aWw
Ryanmello07
added a commit
that referenced
this pull request
Sep 9, 2026
CI has been red on main since 2026-09-03. Every run fails in the same
place, before any artwork is read:
error: Template format 7.0 is newer than the version that this
software supports (6.0)
app/network/Assets.xcassets:./ur.symbols.connector.fill.symbolset:
The SVG file provided for the symbol image set is not suitable
The build dies there, so three steps never run at all: the extension size
budget, the whole macOS leg of a check named "iOS + macOS", and the unit
tests. Inside the iOS step the app target is never compiled either -- its
Swift task is scheduled and cancelled milliseconds later -- so main has
had no compile coverage of the app, and no test coverage at all, for six
days and roughly 25k lines.
This is a regression of a fix that already landed. #338 downgraded the
symbols to Template v.6.0 and added gen_connector_symbols.py, whose
docstring states the constraint: CI pins Xcode 16.4 and its actool
rejects a newer template outright. That fix generated only the widgets
catalog. A later SF Symbols 7 export landed a fresh copy of the same
symbol in app/network, which nothing here owned, so the constraint
silently did not apply to it.
Regenerate that copy from the same script. The diff is the version stamp
and the SF Symbols 7 style attributes -- motion groups and layer tags,
which the pinned toolchain cannot read anyway; not one path element
changes. Verified by generating into a temp directory and diffing: the
script reproduces the committed widgets catalog byte for byte, so its
output is exactly what has been building in CI all along.
Also record in the docstring that TWO catalogs carry these symbols and
that both are subject to the 6.0 rule, with the commands for each.
Generating only one of them is precisely how the constraint was lost.
Claude-Session: https://claude.ai/code/session_01AWV4MaF9JBcQppSX9UxATa
Co-authored-by: Claude Opus 5 (1M context) <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.
mainhas been red since 2026-09-02. This fixes the error CI actually hits. It does not turn the pipeline green on its own — see "What this does not fix" below.The failure
Why it started with a docs-only commit
d826f34("update") changed onlyPARITY.mdandQUICKCONNECT.md, so it looks like an impossible cause. It isn't the cause. Its parent315d6bb2("add widgets", 44 files) created theURnetworkWidgetstarget and both symbol sets, and never ran CI: the two commits were pushed together, and Actions builds only a push's head commit.d826f34is simply the first run that compiled its parent's new catalog.app/widgets/returns 404 at the last green commit.The runner image (
macos-15-arm64,20260727.0256.1) and the Xcode pin (16.4,16F6) are byte-identical between the last green run and the red ones. Nothing outside the repo changed.The fix
gen_connector_symbols.pyhardcodedTemplate v.7.0andRequires Xcode 26 or greater, and emitted SF Symbols 7-only style properties. This fixes the generator and re-runs it, rather than hand-editing the SVGs — otherwise the next regeneration reintroduces the bug.Removed, all four inert for a single static layer with no variable value and no Draw animation:
-sfsymbols-motion-group-sfsymbols-draw-reverses-motion-groups-sfsymbols-layer-tags-sfsymbols-variable-value-modeThe Xcode pin is left alone — its comment documents it as load-bearing for the gomobile
iossimulator/arm64slice.Evidence
Path geometry is untouched — SHA of all
d="…"data is identical before and after.No layers were lost. Compiled both catalogs and diffed
assetutil --info: identical rendition names and counts (4 Vector Glyphs + 9 Image previews per symbol), each glyph ~123 bytes smaller — that is metadata leaving, not a layer. Rasterised output is pixel-identical.The version banner is an upper-bound gate, not a stricter schema. Verified empirically rather than assumed: on an otherwise byte-identical file, banners v1.0–v7.0 compile clean and v8.0/v9.0 fail with the same
Corrupt Contentmessage shape, the toolchain substituting its own maximum. So a file declaring 6.0 passes a toolchain whose ceiling is 6.0.Honest limitation: this was not validated against Xcode 16.4. No 16.4 on the machine that produced it — only Xcode 26 beta, whose
actoolaccepts 6.0 and 7.0 alike and therefore compiles the broken catalog cleanly too. Every check above is structural. CI is the first real test.What this does not fix
The iOS device build and the simulator tests should now pass. The "Build for macOS (unsigned)" step will then fail on a separate, pre-existing problem in the same commit, which the symbol error was masking (actool aborts at the first failure):
app/network/Shared/Widgets/WidgetRefresh.swift:28referencesControlCenter.shared.reloadControls, andapp/widgets/Control/QuickConnectControl.swiftis aControlWidget. On macOS these begin at macOS 26, and Xcode 16.4 ships the macOS 15.5 SDK. The#available(iOS 18.0, macOS 26.0, *)guard is a runtime check — it does not help when the symbol is absent from the SDK being compiled against, so this fails at compile time.WidgetRefresh.swiftis compiled into three targets, so it is not confined to the widget.That needs a decision from whoever added the feature —
#if canImport, an availability-guarded file, or excluding the control from the macOS leg — so it is deliberately not bundled here.Suggested follow-up
315d6bb2reachedmainwith zero CI runs because Actions builds only a push's head commit. Routing changes of that size through PRs (or building every commit of a push) would have caught both problems before merge.🤖 Generated with Claude Code
https://claude.ai/code/session_014vN7zh8WeQYCtirhcA3aWw