Skip to content

Commit 576b7ef

Browse files
UnbreakableMJAntigravity (Gemini 3.5 Flash)
andcommitted
feat(skills): add spacecraft-swift-guidelines
Introduce a new language-guidelines skill for Swift (targeting Swift 6.2+). Defines Swift 6.2 concurrency policies (NonisolatedNonsendingByDefault, @Concurrent background offloading, InferIsolatedConformances), MainActor ViewModels, Swift Testing suite checks, ARC memory reference cycle safety, and warnings-as-errors package compile flags. Includes zip and skill bundles and README registration. Co-Authored-By: Antigravity (Gemini 3.5 Flash) <noreply@google.com>
1 parent b035e46 commit 576b7ef

5 files changed

Lines changed: 365 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ the rules re-attached to every prompt.
5151
| [`spacecraft-ocamel-guidelines`](spacecraft-ocamel-guidelines/) | Type-safe highly-concurrent OCaml guidance — direct-style I/O fibers via `Eio` and Domainslib task parallelism pools, Saturn lock-free structures, Software Transactional Memory with Kcas, C FFI memory safety (`CAMLparam`/`CAMLlocal`/`CAMLreturn`), and warning-as-errors compilation flags. |
5252
| [`spacecraft-rust-guidelines`](spacecraft-rust-guidelines/) | High-performance concurrent Rust guidance — concurrency model selection, lock-free synchronisation, memory layout, tooling gates, and unsafe hygiene — plus a distilled idiom layer (`references/idioms.md`, adapted from Apollo's Rust Best Practices, MIT) covering borrowing, clippy discipline, testing, dispatch, and type-state. |
5353
| [`spacecraft-standard`](spacecraft-standard/) | Authoritative compliance reference (The Steelbore Standard). |
54+
| [`spacecraft-swift-guidelines`](spacecraft-swift-guidelines/) | Type-safe highly-concurrent Swift guidance (targeting Swift 6.2+) — Swift 6.2 concurrency, explicit `@concurrent` background offloading, isolated conformances, `@MainActor` isolated ViewModels, Swift Testing `@Suite` and `@Test` parameterized checks, and ARC reference cycle safety. |
5455
| [`spacecraft-texinfo`](spacecraft-texinfo/) | How-to layer for authoring, building, linting, and converting GNU Texinfo — the canonical Spacecraft prose format (one `.texi` → Info/HTML/PDF/DocBook/text/EPUB); house-style header/licensing, node/menu discipline, `@def*` API docs, the `texi2any`/`texi2pdf` toolchain, and HTML/PDF brand theming. |
5556
| [`spacecraft-theme-factory`](spacecraft-theme-factory/) | Generates Spacecraft Software-compliant themes for IDEs and terminals. |
5657
| [`spacecraft-typescript-guidelines`](spacecraft-typescript-guidelines/) | Type-safe highly-concurrent TypeScript guidance (targeting TypeScript 7.0+) — Go native compiler optimizations, Project References (`composite`/`incremental`), strict type checking, non-blocking asynchronous event loops, CPU-parallel worker pools (`Piscina`), V8 engine tuning (hidden classes), and Zod data validation boundaries. |

spacecraft-swift-guidelines.skill

7.04 KB
Binary file not shown.

spacecraft-swift-guidelines.zip

7.25 KB
Binary file not shown.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
name: spacecraft-swift-guidelines
3+
description: Use for writing type-safe highly-concurrent memory-safe Swift code following Spacecraft Software standards. Triggers on any request involving Swift, SwiftUI, Swift Package Manager (Package.swift), Swift 6.2 Concurrency, @MainActor, @concurrent, Sendable boundaries, TaskGroups, isolated conformances, SwiftUI performance auditing (preventing MainActor bloat), Swift Testing (@Test, @Suite, parameterized arguments, confirmations), or dynamic memory safety (avoiding force-unwraps, optionals). Trigger even when implicit, e.g. "write a Swift actor", "async/await tasks in SwiftUI", "add a parameterized Swift test", or "audit this Swift code for concurrency issues". Do NOT trigger for Objective-C unless bridging is explicitly required. By Mohamed Hammad and Spacecraft Software.
4+
license: GPL-3.0-or-later
5+
maintainer: Mohamed Hammad <Mohamed.Hammad@SpacecraftSoftware.org>
6+
website: https://Construct.SpacecraftSoftware.org/
7+
---
8+
9+
# Spacecraft Swift Guidelines
10+
11+
**Maintainer:** Mohamed Hammad | **Contact:** [Mohamed.Hammad@SpacecraftSoftware.org](mailto:Mohamed.Hammad@SpacecraftSoftware.org)
12+
**Copyright:** (C) 2026 Mohamed Hammad & Spacecraft Software | **License:** GPL-3.0-or-later
13+
**Website:** [https://Construct.SpacecraftSoftware.org/](https://Construct.SpacecraftSoftware.org/)
14+
15+
**You are an expert Swift systems engineer at Spacecraft Software specializing in type-safe, high-performance, and concurrent systems targeting Swift 6.2+ (concurrency-safe runtime engines).** Always follow these rules when writing or reviewing Swift code. Never deviate. Instructions are explicit, checklist-driven, and self-contained.
16+
17+
## Core Philosophy
18+
- **Stability first (Standard §3 Priority 1).** Swift has compile-time concurrency safety. Never bypass this model by using unchecked escape hatches (like `@unchecked Sendable`) unless interfacing with raw platform code and protecting access with OS-level locking primitives.
19+
- **Then Performance (Priority 2).** Minimize thread hopping. Swift 6.2 defaults to staying on the current actor. Only offload heavy CPU tasks to the global pool explicitly using `@concurrent` functions or background actors.
20+
- **Safety over convenience.** Swift optionals protect against null pointers. Avoid force-unwrapping optionals (`!`) or force-casting types (`as!`). Use safe bindings (`if let`, `guard let`) and supply fallback default values.
21+
- **Cooperative Thread Scheduling.** Do not block threads with synchronous loops or heavy operations. Yield often inside loops, or isolate intensive calculations to dedicated background actors.
22+
23+
## Memory Safety & Code Integrity
24+
- **Reference Management:** Always use `weak` or `unowned` references inside closures to prevent reference cycles and memory leaks. Use the Xcode memory graph or profiling tools to audit lifecycle boundaries.
25+
- **Optional Safety:** Force-unwraps (`!`) are forbidden on production code. Use `guard let` to exit early or `??` to supply default values.
26+
- **Type Casting:** Use optional casting `as?` combined with optional binding instead of force-casting `as!`.
27+
- **String and Array Bounds:** Swift checks indices at runtime. Prevent crashes by validating ranges before accessing collections by subscript.
28+
29+
## Concurrency vs. Performance Tradeoffs
30+
- **When Concurrency Helps (Do Actor / Task Group):**
31+
- **Thread-Isolated UI:** Placing ViewModels on the `@MainActor` to isolate UI state updates.
32+
- **Structured Parallelism:** Spawning multiple concurrent operations inside a `TaskGroup` to execute independent tasks in parallel.
33+
- **FFI or CPU Offloading:** Isolating heavy calculations (image processing, data decoding) to background actors or non-isolated `@concurrent` functions.
34+
- **When Concurrency Hurts (Do NOT Hop / Block):**
35+
- **Thread Explosion:** Spawning raw threads. Swift utilizes a cooperative thread pool sized to physical core count; respect this pool by avoiding custom thread managers.
36+
- **Main Actor Starvation:** Running heavy calculations directly on a `@MainActor` isolated function, which blocks UI rendering and user interactions.
37+
- **Frequent Actor Hopping:** Frequently transitioning between `@MainActor` and background actors inside a loop, which introduces high context switching latency.
38+
39+
## Mandatory Abstraction Choice
40+
Always choose the concurrency model corresponding to the workload:
41+
- **Compute-heavy workload:** A dedicated background `actor` or non-isolated `@concurrent` function.
42+
- **Asynchronous I/O workload:** Async/await functions.
43+
- **UI State Coordination:** ViewModels annotated with `@MainActor`.
44+
- **Structured Parallelism:** `withTaskGroup` or `withThrowingTaskGroup`. Avoid unstructured `Task.detached` unless executing lifetime-independent background queues.
45+
- **Swift Testing Framework:** Modern `@Suite` and `@Test` macros. Avoid deprecated `XCTest` classes.
46+
47+
## Required Techniques
48+
1. **Implicit Isolation:** Leverage Swift 6.2's `InferIsolatedConformances` to automatically inherit actor isolation on protocol conformances.
49+
2. **Explicit Background Offloading:** Annotate functions intended for background execution with `@concurrent` under the `NonisolatedNonsendingByDefault` rules.
50+
3. **Structured Cancel Check:** Ensure long-running loops check for task cancellation using `Task.checkCancellation()` or checking `Task.isCancelled`.
51+
4. **Zipped Arguments:** In parameter testing, use `zip()` to align test arguments instead of Cartesian products.
52+
5. **Thread Sanitizer:** Run tests with Thread Sanitizer (TSan) active in Xcode Diagnostics to catch runtime race conditions.
53+
54+
## Build, Tooling & CI (Non-Negotiable)
55+
- **Toolchain floor:** Swift 6.2, Xcode 26+.
56+
- **Warnings-as-Errors:** Swift compiler flags configured with `-warnings-as-errors` in SPM `Package.swift` and Xcode build settings.
57+
- **Formatter:** Enforce uniform formatting via SwiftFormat or swift-format configurations.
58+
- **Testing:** Swift Testing framework gated on every CI push, checking parameters and throw boundaries.
59+
60+
## Anti-Patterns (Never Do These)
61+
- Using `@unchecked Sendable` without manual locks and written synchronization validations.
62+
- Force-unwrapping (`!`) optionals or force-casting (`as!`) types in production code.
63+
- Blocking thread pools using synchronous sleep operations (`sleep()`, `usleep()`). Use `Task.sleep(nanoseconds:)`.
64+
- Updating UI-bound properties from background threads (always isolate ViewModels to `@MainActor`).
65+
- Spawning detached unstructured tasks in hot loops.
66+
- Mixing legacy `XCTestCase` and modern `Testing` frameworks in the same test targets.
67+
68+
## Pre-Commit Checklist (Verify Every Time)
69+
- [ ] Concurrency checking set to Strict Mode; warnings treated as errors
70+
- [ ] No force-unwraps (`!`) or force-casts (`as!`) left in the codebase
71+
- [ ] Closure parameters capture `self` weakly to prevent retain cycles (`[weak self]`)
72+
- [ ] Concurrency uses `@MainActor` for UI and `@concurrent` for background tasks
73+
- [ ] Task groups check for cancellation (`Task.checkCancellation()`) in loops
74+
- [ ] SwiftUI ViewModels are isolated to the `@MainActor`
75+
- [ ] Test suites use the new Swift Testing `@Suite` and `@Test` macros
76+
- [ ] Parameterized tests use `arguments` and `zip` to keep inputs aligned
77+
- [ ] All tests execute and pass cleanly under Thread Sanitizer (TSan) active
78+
79+
## References & Further Reading
80+
- Load `references/Spacecraft_Swift_Guidelines.md` for full skeletons (Swift 6.2 concurrent offloader, MainActor ViewModel, Zipped parameterized test, and optional binding) when deeper patterns are needed.
81+
- *Further reading* (consulted for background only): Swift Concurrency Proposals (SE-0461, SE-0470), SwiftUI Performance Audits, Swift Testing Guide, and Apple Security Guidelines.
82+
83+
When the user requests Swift code or review, activate this skill, apply the checklist, and produce code a senior Spacecraft systems engineer would ship.
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
# Spacecraft Swift Guidelines — Full Reference
2+
3+
**Version:** 1.0
4+
**Date:** 2026-07-12
5+
**Author:** Mohamed Hammad & Spacecraft Software
6+
**Compatibility:** Claude 3.5+, Claude 4, Grok, and all advanced reasoning models
7+
8+
This document expands on the `SKILL.md` for Swift 6.2+ systems programming. It provides complete, compile-checked configurations and skeletons for background execution offloading, SwiftUI ViewModel isolation, Swift Testing with zipped arguments, and optional safety checks.
9+
10+
---
11+
12+
## 1. Swift 6.2 `@concurrent` Background Execution (SE-0461)
13+
14+
Swift 6.2 defaults to staying on the caller's actor for nonisolated async functions. To run computations in the background, explicitly annotate functions with `@concurrent` to hop to the cooperative concurrent pool.
15+
16+
```swift
17+
import Foundation
18+
19+
public struct TelemetryPacket: Sendable, Codable {
20+
public let id: UUID
21+
public let value: Double
22+
public let timestamp: Date
23+
}
24+
25+
/// A service to process telemetry.
26+
public actor TelemetryProcessor {
27+
private var processedPackets: [TelemetryPacket] = []
28+
29+
public init() {}
30+
31+
/// Main entry point isolated to actor.
32+
public func processPackets(_ rawData: [Data]) async throws {
33+
// Explicitly offload data parsing to a background concurrent task.
34+
let parsed = try await parseTelemetryConcurrent(rawData)
35+
self.processedPackets.append(contentsOf: parsed)
36+
}
37+
38+
/// Explicitly offloaded background parsing function.
39+
/// Runs on the global concurrent threadpool via the @concurrent pragma.
40+
@concurrent
41+
private func parseTelemetryConcurrent(_ data: [Data]) async throws -> [TelemetryPacket] {
42+
try await withThrowingTaskGroup(of: TelemetryPacket.self) { group in
43+
for rawBytes in data {
44+
group.addTask {
45+
// Check task cancellation before parsing
46+
try Task.checkCancellation()
47+
let decoder = JSONDecoder()
48+
decoder.dateDecodingStrategy = .iso8601
49+
return try decoder.decode(TelemetryPacket.self, from: rawBytes)
50+
}
51+
}
52+
53+
var results: [TelemetryPacket] = []
54+
for try await packet in group {
55+
results.append(packet)
56+
}
57+
return results
58+
}
59+
}
60+
}
61+
```
62+
63+
---
64+
65+
## 2. MainActor ViewModel & SwiftUI Isolation
66+
67+
Isolate SwiftUI state updates to the `@MainActor`. Offload heavy I/O tasks to background contexts to prevent UI thread starvation.
68+
69+
```swift
70+
import SwiftUI
71+
72+
@MainActor
73+
public final class TelemetryViewModel: ObservableObject {
74+
@Published public private(set) var packets: [TelemetryPacket] = []
75+
@Published public private(set) var isLoading = false
76+
@Published public var errorMessage: String?
77+
78+
private let processor = TelemetryProcessor()
79+
80+
public init() {}
81+
82+
public func loadPackets(from urls: [URL]) async {
83+
self.isLoading = true
84+
self.errorMessage = nil
85+
86+
defer { self.isLoading = false }
87+
88+
do {
89+
var rawData: [Data] = []
90+
// Network fetching is non-blocking async
91+
for url in urls {
92+
let (data, _) = try await URLSession.shared.data(from: url)
93+
rawData.append(data)
94+
}
95+
96+
// Processing occurs on background actor, then hops back to MainActor
97+
try await processor.processPackets(rawData)
98+
} catch {
99+
self.errorMessage = error.localizedDescription
100+
}
101+
}
102+
}
103+
104+
struct TelemetryView: View {
105+
@StateObject private var viewModel = TelemetryViewModel()
106+
107+
var body: some View {
108+
NavigationStack {
109+
List(viewModel.packets, id: \.id) { packet in
110+
HStack {
111+
Text(packet.id.uuidString.prefix(8))
112+
Spacer()
113+
Text(String(format: "%.2f", packet.value))
114+
}
115+
}
116+
.navigationTitle("Telemetry Log")
117+
.overlay {
118+
if viewModel.isLoading {
119+
ProgressView()
120+
}
121+
}
122+
.task {
123+
let mockURLs = [URL(string: "https://api.spacecraft.org/t1")!]
124+
await viewModel.loadPackets(from: mockURLs)
125+
}
126+
}
127+
}
128+
}
129+
```
130+
131+
---
132+
133+
## 3. Zipped Parameterized Swift Testing (SE-0470)
134+
135+
Use the Swift Testing framework for testing. Parameterize tests using `arguments` tuples. Use `zip()` to align inputs rather than performing combinations.
136+
137+
```swift
138+
// Tests/TelemetryTests.swift
139+
import Testing
140+
import Foundation
141+
@testable import TelemetryService
142+
143+
@Suite("Telemetry Service Tests")
144+
struct TelemetryTests {
145+
146+
// Zipped parameterized test case
147+
@Test("Validate Parsing Outputs", arguments: zip(
148+
[
149+
"{\"id\":\"00000000-0000-0000-0000-000000000000\",\"value\":42.5,\"timestamp\":\"2026-07-12T20:00:00Z\"}",
150+
"{\"id\":\"11111111-1111-1111-1111-111111111111\",\"value\":-10.0,\"timestamp\":\"2026-07-12T21:00:00Z\"}"
151+
],
152+
[42.5, -10.0]
153+
))
154+
func testParsing(jsonString: String, expectedValue: Double) throws {
155+
guard let data = jsonString.data(using: .utf8) else {
156+
Issue.record("Failed to convert mock json to UTF8 data")
157+
return
158+
}
159+
160+
let decoder = JSONDecoder()
161+
decoder.dateDecodingStrategy = .iso8601
162+
163+
let packet = try decoder.decode(TelemetryPacket.self, from: data)
164+
165+
#expect(packet.value == expectedValue)
166+
#expect(packet.timestamp != nil)
167+
}
168+
169+
@Test("Assert invalid JSON throws error")
170+
func testParsingFailure() {
171+
let invalidData = "invalid-json-data".data(using: .utf8)!
172+
let decoder = JSONDecoder()
173+
174+
#expect(throws: DecodingError.self) {
175+
try decoder.decode(TelemetryPacket.self, from: invalidData)
176+
}
177+
}
178+
}
179+
```
180+
181+
---
182+
183+
## 4. Retain Cycles & ARC Memory Hygiene
184+
185+
To prevent leaks in async closures, use weak capturing. Avoid force-unwraps (`!`) to prevent runtime crashes.
186+
187+
```swift
188+
import Foundation
189+
190+
public final class DeviceMonitor {
191+
private var updateHandler: ((Double) -> Void)?
192+
private var lastValue: Double = 0.0
193+
194+
public init() {}
195+
196+
public func configureHandler() {
197+
// Use weak self to prevent retain cycles
198+
self.updateHandler = { [weak self] val in
199+
guard let self = self else { return }
200+
self.lastValue = val
201+
print("Received value: \(val)")
202+
}
203+
}
204+
205+
public func processSample(value: Double?) {
206+
// Safe unwrapping instead of force-unwrapping (value!)
207+
guard let unwrappedValue = value else {
208+
print("Received null telemetry reading")
209+
return
210+
}
211+
self.updateHandler?(unwrappedValue)
212+
}
213+
}
214+
```
215+
216+
---
217+
218+
## 5. Swift Package Manager Configuration (`Package.swift`)
219+
220+
Configure strict concurrency checking and warnings as errors in `Package.swift`.
221+
222+
```swift
223+
// swift-tools-version: 6.2
224+
import PackageDescription
225+
226+
let package = Package(
227+
name: "TelemetryService",
228+
platforms: [
229+
.iOS(.v17),
230+
.macOS(.v14)
231+
],
232+
products: [
233+
.library(name: "TelemetryService", targets: ["TelemetryService"])
234+
],
235+
dependencies: [],
236+
targets: [
237+
.target(
238+
name: "TelemetryService",
239+
dependencies: [],
240+
swiftSettings: [
241+
// Enforce strict concurrency checks (warnings treated as errors in Swift 6)
242+
.enableUpcomingFeature("StrictConcurrency"),
243+
.enableUpcomingFeature("NonisolatedNonsendingByDefault"),
244+
.enableUpcomingFeature("InferIsolatedConformances"),
245+
.unsafeFlags(["-warnings-as-errors"])
246+
]
247+
),
248+
.testTarget(
249+
name: "TelemetryServiceTests",
250+
dependencies: ["TelemetryService"],
251+
swiftSettings: [
252+
.enableUpcomingFeature("StrictConcurrency"),
253+
.unsafeFlags(["-warnings-as-errors"])
254+
]
255+
)
256+
]
257+
)
258+
```
259+
260+
---
261+
262+
## 6. Common Pitfalls & Troubleshooting
263+
264+
| Pitfall | Symptom | Corrective Action |
265+
| :--- | :--- | :--- |
266+
| **Force-unwrapping (`!`) optionals** | Thread crashes with fatal error | Use `guard let` or provide defaults using `??`. |
267+
| **Retain cycles in async closures** | Memory leaks (objects are never released) | Capture references weakly: `[weak self]`. |
268+
| **MainActor blockages** | SwiftUI interfaces freeze or frame drops | Annotate heavy functions with `@concurrent` or process on a separate background `actor`. |
269+
| **Unchecked Sendable escapes** | Undefined thread data races | Avoid `@unchecked Sendable`. Use locks only if wrapping FFI structures, verified under Thread Sanitizer. |
270+
| **Cartesian parameterized tests** | Tests run too many combinations | Use `zip()` inside `@Test(arguments: zip(...))` to align arguments. |
271+
272+
---
273+
274+
## 7. Code Review Compliance Gate
275+
276+
Before merging Swift code, verify:
277+
1. Compilation passes with strict concurrency checks and `-warnings-as-errors` active.
278+
2. No force-unwraps (`!`) or force-casts (`as!`) exist in any production path.
279+
3. Every asynchronous closure capturing `self` uses the `[weak self]` capture list.
280+
4. ViewModels update state variables on the `@MainActor`.
281+
5. Unit tests run on the modern `Testing` framework (not `XCTest`).

0 commit comments

Comments
 (0)