feat(app): support macOS 13 Ventura - #2874
Conversation
Observation is macOS 14 and has no back-deploy library, so the deployment target could not move while the app used it. Every `@Observable` class becomes `ObservableObject` with `@Published`, every `@Bindable` becomes `@ObservedObject` or `@StateObject`, and the ten `withObservationTracking` sites become Combine sinks that hop a run-loop turn, because `objectWillChange` fires before the value lands. The macOS 14 APIs are either replaced or gated. `ContentUnavailableView` becomes `UnavailableStateView` with the same three initialisers. `DisclosureTableRow` forces the whole `Table` to branch, because `@TableRowBuilder` rejects an availability check inside it. TipKit, SOCKS proxying and `onKeyPress` are absent on 13; each site says what is lost and why the surface still works without it. The OpenSSL dylibs are rebuilt at 13.0. They load at dyld time, so a 14.0 minimum there would have refused to start on Ventura even though the app binary was correct. The static archives keep their own minimum: they link statically, so it is metadata rather than a load-time contract.
One thing this PR does not solve, and it has to be handled before releaseThe plugin registry has no way to say what macOS a binary needs. So once the app runs on Ventura, a Ventura user browsing the registry resolves a binary that was built at a 14.0 deployment target, downloads it, and Two ways out:
(1) alone leaves a hole; (2) is the durable answer but changes the manifest schema and Worth recording: |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
# Conflicts: # CHANGELOG.md # Packages/TableProEditor/Sources/TableProEditorKit/Controller/TextViewController+Lifecycle.swift # Packages/TableProEditor/Sources/TableProEditorKit/Find/FindViewController.swift # TablePro/Core/Compare/CompareSyncSession.swift # TablePro/Core/Services/Infrastructure/UpdaterBridge.swift # TablePro/Core/Sync/SyncCoordinator.swift # TablePro/Models/UI/MultiRowEditState.swift # TablePro/ViewModels/WelcomeViewModel.swift # TablePro/Views/Compare/CompareDataPlansView.swift # TablePro/Views/Compare/CompareOptionsView.swift # TablePro/Views/Components/MagnifiableCanvasView.swift # TablePro/Views/ConnectionForm/ViewModels/AuthPaneViewModel.swift # TablePro/Views/QueryPlan/QueryPlanDiagramView.swift # TablePro/Views/QueryPlan/QueryPlanResultView.swift # TablePro/Views/Settings/GeneralSettingsView.swift # TablePro/Views/Toolbar/ConnectionSwitcherPopover.swift # TablePro/Views/Welcome/WelcomeActionsPanel.swift # TablePro/Views/Welcome/WelcomeConnectionList.swift # TablePro/Views/Welcome/WelcomeConnectionRow.swift # TablePro/Views/Welcome/WelcomeConnectionsPanel.swift # TablePro/Views/Welcome/WelcomeContextMenus.swift # TablePro/Views/Welcome/WelcomeGroupRows.swift # TablePro/Views/Welcome/WelcomePresentations.swift # TablePro/Views/Welcome/WelcomeWindowView.swift
# Conflicts: # CHANGELOG.md # CLAUDE.md # TablePro/Core/Services/Infrastructure/MainWindowToolbar.swift # TablePro/Views/Editor/QueryEditorView.swift # TablePro/Views/Main/Child/MainEditorContentView.swift # docs/development/setup.mdx # docs/features/overview.mdx # docs/index.mdx # docs/installation.mdx # project.yml
Lowers the deployment target from macOS 14.0 to 13.0.
Why it could not move before
Observation is macOS 14 and Apple ships no back-deploy library for it. The toolchain's
swift-5.5/macosxdirectory holds exactly one dylib,libswift_Concurrency.dylib; there is nolibswiftObservation. So@Observablecannot run on 13 at all, and 133 classes used it.A first build at 13.0 reported 982 availability errors. 968 of them were Observation.
What changed
@Observableclasses toObservableObject+@Published.@ObservationIgnoredproperties stay unpublished, and a property written on every layout pass that no view reads stays unpublished too, or the strip re-renders through every window resize.@Bindableto@ObservedObject/@StateObject, plus 83 holders that had no wrapper at all. Those are the dangerous ones: under@Observablea plainlet x: Tin a view still tracked, underObservableObjectit does not, and it compiles either way.withObservationTrackingsites to Combine sinks. Two semantics change: the sink wakes for any published property rather than the one the closure read, so the hot sites compare values first; andobjectWillChangefires before the value lands, so delivery hops a run-loop turn.onChangeclosures to the single-value form. Four sites genuinely used the old value and getonValueChange, which keeps the previous value in@State.macOS 14 APIs are replaced or gated:
ContentUnavailableView(90 sites)UnavailableStateView, same three initialisersscrollPosition(id:anchor:)PreferenceKeyDisclosureTableRow@TableRowBuilderrejects an availability check, so the wholeTablebranches and the columns are sharedonKeyPressProxyConfigurationNSMenu.paletteCADisplayLinkbackgroundProminence,accessoryBarAction,alternatingRowBackgrounds,inspectorTrackingSeparator,NSTextInsertionIndicator,symbolEffect,quaternarySystemFill,AccessibilityNotification,NSApp.activate(),loadViewIfNeeded()The OpenSSL dylibs are rebuilt at 13.0. They load at dyld time, so a 14.0 minimum there refuses to start on Ventura however correct the app binary is. Every Mach-O in the bundle is now at or below 13.0. The static archives keep their own minimum on purpose: they link statically, so it is metadata, not a load-time contract.
What is verified, and what is not
Verified here: build clean,
swiftlint --strictclean, 19,802 unit tests pass, no Mach-O in the bundle above 13.0, and the app launches and renders.Not verified: the app has never run on Ventura. This machine is macOS 27 and GitHub retired the
macos-13runner in December 2025, so nothing in CI can execute it either. Running it on 14+ exercises the#availabletrue branches, not the fallbacks.Also worth a reviewer's attention: of roughly 317 consumer sites in this conversion only about 90 are ones the compiler can check. The rest build clean and fail at runtime. A six-way audit with adversarial verification found 69 such sites and they are fixed here, but a green build proves nothing about that class of defect.
QueryInsightsView.isUnlockedis the shape to look for: it callsLicenseManager.shared.isFeatureAvailable(_:), which readsstatusandcurrentTier, so it needed a wrapper even though the call site has parentheses.Test failures on this machine
8 unit tests (
AWSSSOFetchTests,SSEEventStreamTests) and 5 UI tests (BackgroundLaunchDockPresenceUITests,ColumnJumpUITests) fail here. All of them fail identically on unmodifiedmain, so they are a local baseline, not a regression. 11 tests that assert macOS 14 API behaviour are gated;ChatTurnObservationTestsis rewritten againstobjectWillChangebecause it asserted per-property granularity that no longer exists.