@cubis/foundry 0.3.71 → 0.3.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. package/CHANGELOG.md +23 -2
  2. package/dist/cli/core.js +9 -22
  3. package/dist/cli/core.js.map +1 -1
  4. package/package.json +1 -1
  5. package/src/cli/core.ts +13 -22
  6. package/workflows/powers/accessibility/POWER.md +83 -94
  7. package/workflows/powers/accessibility/SKILL.md +82 -94
  8. package/workflows/powers/agent-design/POWER.md +201 -0
  9. package/workflows/powers/agent-design/SKILL.md +198 -0
  10. package/workflows/powers/agent-design/references/clarification-patterns.md +153 -0
  11. package/workflows/powers/agent-design/references/skill-testing.md +164 -0
  12. package/workflows/powers/agent-design/references/workflow-patterns.md +226 -0
  13. package/workflows/powers/agentic-eval/POWER.md +62 -0
  14. package/workflows/powers/agentic-eval/SKILL.md +59 -0
  15. package/workflows/powers/agentic-eval/references/rubric-and-regression-checklist.md +11 -0
  16. package/workflows/powers/api-designer/POWER.md +43 -71
  17. package/workflows/powers/api-designer/SKILL.md +43 -71
  18. package/workflows/powers/api-patterns/POWER.md +42 -56
  19. package/workflows/powers/api-patterns/SKILL.md +42 -57
  20. package/workflows/powers/architecture-designer/POWER.md +43 -60
  21. package/workflows/powers/architecture-designer/SKILL.md +43 -60
  22. package/workflows/powers/ask-questions-if-underspecified/POWER.md +51 -3
  23. package/workflows/powers/auth-architect/POWER.md +69 -0
  24. package/workflows/powers/auth-architect/SKILL.md +66 -0
  25. package/workflows/powers/auth-architect/references/session-token-policy-checklist.md +45 -0
  26. package/workflows/powers/behavioral-modes/POWER.md +100 -9
  27. package/workflows/powers/c-pro/POWER.md +105 -0
  28. package/workflows/powers/c-pro/SKILL.md +102 -0
  29. package/workflows/powers/c-pro/references/build-systems-and-toolchains.md +148 -0
  30. package/workflows/powers/c-pro/references/common-ub-and-portability.md +166 -0
  31. package/workflows/powers/c-pro/references/debugging-with-sanitizers.md +205 -0
  32. package/workflows/powers/c-pro/references/memory-safety-and-build-checklist.md +60 -0
  33. package/workflows/powers/c-pro/references/posix-and-platform-apis.md +244 -0
  34. package/workflows/powers/changelog-generator/POWER.md +127 -63
  35. package/workflows/powers/changelog-generator/SKILL.md +126 -63
  36. package/workflows/powers/ci-cd-pipelines/POWER.md +156 -0
  37. package/workflows/powers/ci-cd-pipelines/SKILL.md +153 -0
  38. package/workflows/powers/ci-cd-pipelines/references/github-actions-patterns.md +160 -0
  39. package/workflows/powers/ci-cd-pipelines/references/pipeline-security-checklist.md +57 -0
  40. package/workflows/powers/cli-developer/POWER.md +152 -95
  41. package/workflows/powers/cli-developer/SKILL.md +152 -95
  42. package/workflows/powers/cpp-pro/POWER.md +111 -0
  43. package/workflows/powers/cpp-pro/SKILL.md +108 -0
  44. package/workflows/powers/cpp-pro/references/concurrency-primitives.md +266 -0
  45. package/workflows/powers/cpp-pro/references/move-semantics-and-value-types.md +149 -0
  46. package/workflows/powers/cpp-pro/references/performance-and-profiling.md +191 -0
  47. package/workflows/powers/cpp-pro/references/raii-and-modern-cpp-checklist.md +87 -0
  48. package/workflows/powers/cpp-pro/references/template-and-concepts-patterns.md +205 -0
  49. package/workflows/powers/csharp-pro/POWER.md +47 -22
  50. package/workflows/powers/csharp-pro/SKILL.md +47 -22
  51. package/workflows/powers/dart-pro/POWER.md +68 -0
  52. package/workflows/powers/dart-pro/SKILL.md +65 -0
  53. package/workflows/powers/dart-pro/references/isolate-and-concurrency.md +180 -0
  54. package/workflows/powers/dart-pro/references/null-safety-and-async-patterns.md +133 -0
  55. package/workflows/powers/dart-pro/references/package-structure-and-linting.md +193 -0
  56. package/workflows/powers/dart-pro/references/sealed-records-patterns.md +173 -0
  57. package/workflows/powers/dart-pro/references/testing-and-mocking.md +235 -0
  58. package/workflows/powers/database-design/POWER.md +47 -33
  59. package/workflows/powers/database-design/SKILL.md +47 -33
  60. package/workflows/powers/database-optimizer/POWER.md +43 -64
  61. package/workflows/powers/database-optimizer/SKILL.md +43 -64
  62. package/workflows/powers/database-skills/POWER.md +59 -93
  63. package/workflows/powers/database-skills/SKILL.md +59 -93
  64. package/workflows/powers/debugging-strategies/POWER.md +69 -0
  65. package/workflows/powers/debugging-strategies/SKILL.md +66 -0
  66. package/workflows/powers/debugging-strategies/references/reproduce-isolate-verify-checklist.md +42 -0
  67. package/workflows/powers/deep-research/POWER.md +67 -0
  68. package/workflows/powers/deep-research/SKILL.md +64 -0
  69. package/workflows/powers/deep-research/references/multi-round-research-loop.md +80 -0
  70. package/workflows/powers/design-system-builder/POWER.md +130 -116
  71. package/workflows/powers/design-system-builder/SKILL.md +130 -116
  72. package/workflows/powers/devops-engineer/POWER.md +120 -57
  73. package/workflows/powers/devops-engineer/SKILL.md +120 -57
  74. package/workflows/powers/docker-kubernetes/POWER.md +94 -0
  75. package/workflows/powers/docker-kubernetes/SKILL.md +91 -0
  76. package/workflows/powers/docker-kubernetes/references/dockerfile-optimization-checklist.md +35 -0
  77. package/workflows/powers/docker-kubernetes/references/kubernetes-deployment-patterns.md +59 -0
  78. package/workflows/powers/documentation-templates/POWER.md +158 -127
  79. package/workflows/powers/documentation-templates/SKILL.md +158 -127
  80. package/workflows/powers/drizzle-expert/POWER.md +66 -0
  81. package/workflows/powers/drizzle-expert/SKILL.md +63 -0
  82. package/workflows/powers/drizzle-expert/references/runtime-pairing-matrix.md +16 -0
  83. package/workflows/powers/drizzle-expert/references/schema-and-migration-playbook.md +18 -0
  84. package/workflows/powers/error-ux-observability/POWER.md +144 -131
  85. package/workflows/powers/error-ux-observability/SKILL.md +143 -131
  86. package/workflows/powers/fastapi-expert/POWER.md +46 -60
  87. package/workflows/powers/fastapi-expert/SKILL.md +46 -60
  88. package/workflows/powers/firebase/POWER.md +65 -0
  89. package/workflows/powers/firebase/SKILL.md +62 -0
  90. package/workflows/powers/firebase/references/platform-routing.md +16 -0
  91. package/workflows/powers/firebase/references/rules-and-indexes-checklist.md +11 -0
  92. package/workflows/powers/flutter-design-system/POWER.md +63 -0
  93. package/workflows/powers/flutter-design-system/SKILL.md +60 -0
  94. package/workflows/powers/flutter-design-system/references/shared-widgets.md +29 -0
  95. package/workflows/powers/flutter-design-system/references/tokens-and-theme.md +34 -0
  96. package/workflows/powers/flutter-drift/POWER.md +65 -0
  97. package/workflows/powers/flutter-drift/SKILL.md +62 -0
  98. package/workflows/powers/flutter-drift/references/migrations.md +22 -0
  99. package/workflows/powers/flutter-drift/references/query-patterns.md +26 -0
  100. package/workflows/powers/flutter-feature/POWER.md +65 -0
  101. package/workflows/powers/flutter-feature/SKILL.md +62 -0
  102. package/workflows/powers/flutter-feature/references/architecture-rules.md +85 -0
  103. package/workflows/powers/flutter-feature/references/composite-provider.md +58 -0
  104. package/workflows/powers/flutter-feature/references/outbox-pattern.md +87 -0
  105. package/workflows/powers/flutter-feature/references/testing-patterns.md +218 -0
  106. package/workflows/powers/flutter-go-router/POWER.md +64 -0
  107. package/workflows/powers/flutter-go-router/SKILL.md +61 -0
  108. package/workflows/powers/flutter-go-router/references/guards-and-deeplinks.md +20 -0
  109. package/workflows/powers/flutter-go-router/references/typed-routes.md +27 -0
  110. package/workflows/powers/flutter-offline-sync/POWER.md +62 -0
  111. package/workflows/powers/flutter-offline-sync/SKILL.md +59 -0
  112. package/workflows/powers/flutter-offline-sync/references/outbox-full.md +44 -0
  113. package/workflows/powers/flutter-repository/POWER.md +64 -0
  114. package/workflows/powers/flutter-repository/SKILL.md +61 -0
  115. package/workflows/powers/flutter-repository/references/drift-patterns.md +21 -0
  116. package/workflows/powers/flutter-repository/references/retrofit-patterns.md +20 -0
  117. package/workflows/powers/flutter-riverpod/POWER.md +70 -0
  118. package/workflows/powers/flutter-riverpod/SKILL.md +67 -0
  119. package/workflows/powers/flutter-riverpod/references/async-and-mutations.md +19 -0
  120. package/workflows/powers/flutter-riverpod/references/async-lifecycle.md +19 -0
  121. package/workflows/powers/flutter-riverpod/references/provider-selection.md +20 -0
  122. package/workflows/powers/flutter-riverpod/references/testing.md +21 -0
  123. package/workflows/powers/flutter-riverpod/references/version-matrix.md +24 -0
  124. package/workflows/powers/flutter-state-machine/POWER.md +62 -0
  125. package/workflows/powers/flutter-state-machine/SKILL.md +59 -0
  126. package/workflows/powers/flutter-state-machine/references/app-state-contract.md +23 -0
  127. package/workflows/powers/flutter-state-machine/references/ui-rendering.md +14 -0
  128. package/workflows/powers/flutter-testing/POWER.md +64 -0
  129. package/workflows/powers/flutter-testing/SKILL.md +61 -0
  130. package/workflows/powers/flutter-testing/references/offline-sync-tests.md +16 -0
  131. package/workflows/powers/flutter-testing/references/test-layers.md +33 -0
  132. package/workflows/powers/frontend-code-review/POWER.md +137 -0
  133. package/workflows/powers/frontend-code-review/SKILL.md +134 -0
  134. package/workflows/powers/frontend-code-review/references/common-antipatterns.md +86 -0
  135. package/workflows/powers/frontend-code-review/references/performance-budgets.md +56 -0
  136. package/workflows/powers/frontend-code-review/references/review-checklists.md +47 -0
  137. package/workflows/powers/frontend-design/POWER.md +163 -362
  138. package/workflows/powers/frontend-design/SKILL.md +163 -362
  139. package/workflows/powers/game-development/POWER.md +57 -140
  140. package/workflows/powers/game-development/SKILL.md +57 -140
  141. package/workflows/powers/geo-fundamentals/POWER.md +64 -126
  142. package/workflows/powers/geo-fundamentals/SKILL.md +64 -127
  143. package/workflows/powers/git-workflow/POWER.md +135 -0
  144. package/workflows/powers/git-workflow/SKILL.md +132 -0
  145. package/workflows/powers/git-workflow/references/pr-review-checklist.md +63 -0
  146. package/workflows/powers/golang-pro/POWER.md +46 -35
  147. package/workflows/powers/golang-pro/SKILL.md +46 -35
  148. package/workflows/powers/graphql-architect/POWER.md +44 -62
  149. package/workflows/powers/graphql-architect/SKILL.md +44 -62
  150. package/workflows/powers/i18n-localization/POWER.md +118 -103
  151. package/workflows/powers/i18n-localization/SKILL.md +118 -103
  152. package/workflows/powers/java-pro/POWER.md +47 -22
  153. package/workflows/powers/java-pro/SKILL.md +47 -22
  154. package/workflows/powers/javascript-pro/POWER.md +47 -34
  155. package/workflows/powers/javascript-pro/SKILL.md +47 -34
  156. package/workflows/powers/kotlin-pro/POWER.md +46 -23
  157. package/workflows/powers/kotlin-pro/SKILL.md +46 -23
  158. package/workflows/powers/legacy-modernizer/POWER.md +43 -60
  159. package/workflows/powers/legacy-modernizer/SKILL.md +43 -60
  160. package/workflows/powers/mcp-builder/POWER.md +65 -0
  161. package/workflows/powers/mcp-builder/SKILL.md +62 -0
  162. package/workflows/powers/mcp-builder/references/testing-and-evals.md +17 -0
  163. package/workflows/powers/mcp-builder/references/transport-and-tool-design.md +17 -0
  164. package/workflows/powers/microservices-architect/POWER.md +43 -70
  165. package/workflows/powers/microservices-architect/SKILL.md +43 -70
  166. package/workflows/powers/mobile-design/POWER.md +110 -345
  167. package/workflows/powers/mobile-design/SKILL.md +110 -345
  168. package/workflows/powers/mongodb/POWER.md +67 -0
  169. package/workflows/powers/mongodb/SKILL.md +64 -0
  170. package/workflows/powers/mongodb/references/mongodb-checklist.md +20 -0
  171. package/workflows/powers/mysql/POWER.md +67 -0
  172. package/workflows/powers/mysql/SKILL.md +64 -0
  173. package/workflows/powers/mysql/references/mysql-checklist.md +20 -0
  174. package/workflows/powers/neki/POWER.md +67 -0
  175. package/workflows/powers/neki/SKILL.md +64 -0
  176. package/workflows/powers/neki/references/neki-checklist.md +18 -0
  177. package/workflows/powers/nestjs-expert/POWER.md +45 -91
  178. package/workflows/powers/nestjs-expert/SKILL.md +45 -91
  179. package/workflows/powers/nextjs-developer/POWER.md +51 -44
  180. package/workflows/powers/nextjs-developer/SKILL.md +51 -44
  181. package/workflows/powers/nodejs-best-practices/POWER.md +48 -29
  182. package/workflows/powers/nodejs-best-practices/SKILL.md +48 -29
  183. package/workflows/powers/observability/POWER.md +109 -0
  184. package/workflows/powers/observability/SKILL.md +106 -0
  185. package/workflows/powers/observability/references/alerting-and-slo-checklist.md +87 -0
  186. package/workflows/powers/observability/references/opentelemetry-setup-guide.md +121 -0
  187. package/workflows/powers/openai-docs/POWER.md +61 -0
  188. package/workflows/powers/openai-docs/SKILL.md +58 -0
  189. package/workflows/powers/openai-docs/references/official-source-playbook.md +10 -0
  190. package/workflows/powers/performance-profiling/POWER.md +61 -114
  191. package/workflows/powers/performance-profiling/SKILL.md +61 -114
  192. package/workflows/powers/php-pro/POWER.md +116 -0
  193. package/workflows/powers/php-pro/SKILL.md +113 -0
  194. package/workflows/powers/php-pro/references/architecture-and-di.md +239 -0
  195. package/workflows/powers/php-pro/references/modern-php-features.md +189 -0
  196. package/workflows/powers/php-pro/references/performance-and-deployment.md +197 -0
  197. package/workflows/powers/php-pro/references/php84-strict-typing-checklist.md +161 -0
  198. package/workflows/powers/php-pro/references/testing-and-static-analysis.md +235 -0
  199. package/workflows/powers/playwright-e2e/POWER.md +85 -0
  200. package/workflows/powers/playwright-e2e/SKILL.md +82 -0
  201. package/workflows/powers/playwright-e2e/references/locator-trace-flake-checklist.md +80 -0
  202. package/workflows/powers/postgres/POWER.md +67 -0
  203. package/workflows/powers/postgres/SKILL.md +64 -0
  204. package/workflows/powers/postgres/references/postgres-checklist.md +20 -0
  205. package/workflows/powers/prompt-engineer/POWER.md +47 -30
  206. package/workflows/powers/prompt-engineer/SKILL.md +47 -30
  207. package/workflows/powers/python-pro/POWER.md +47 -36
  208. package/workflows/powers/python-pro/SKILL.md +47 -36
  209. package/workflows/powers/react-best-practices/POWER.md +56 -33
  210. package/workflows/powers/react-best-practices/SKILL.md +56 -33
  211. package/workflows/powers/react-expert/POWER.md +47 -37
  212. package/workflows/powers/react-expert/SKILL.md +47 -37
  213. package/workflows/powers/redis/POWER.md +67 -0
  214. package/workflows/powers/redis/SKILL.md +64 -0
  215. package/workflows/powers/redis/references/redis-checklist.md +19 -0
  216. package/workflows/powers/ruby-pro/POWER.md +118 -0
  217. package/workflows/powers/ruby-pro/SKILL.md +115 -0
  218. package/workflows/powers/ruby-pro/references/modern-ruby-features.md +189 -0
  219. package/workflows/powers/ruby-pro/references/object-design-patterns.md +220 -0
  220. package/workflows/powers/ruby-pro/references/performance-and-profiling.md +224 -0
  221. package/workflows/powers/ruby-pro/references/ruby-concurrency-and-testing.md +190 -0
  222. package/workflows/powers/ruby-pro/references/testing-and-rspec.md +236 -0
  223. package/workflows/powers/rust-pro/POWER.md +45 -31
  224. package/workflows/powers/rust-pro/SKILL.md +45 -31
  225. package/workflows/powers/security-engineer/POWER.md +129 -0
  226. package/workflows/powers/security-engineer/SKILL.md +126 -0
  227. package/workflows/powers/seo-fundamentals/POWER.md +59 -102
  228. package/workflows/powers/seo-fundamentals/SKILL.md +59 -102
  229. package/workflows/powers/serverless-patterns/POWER.md +171 -0
  230. package/workflows/powers/serverless-patterns/SKILL.md +168 -0
  231. package/workflows/powers/skill-creator/POWER.md +90 -0
  232. package/workflows/powers/skill-creator/SKILL.md +87 -0
  233. package/workflows/powers/skill-creator/references/platform-formats.md +181 -0
  234. package/workflows/powers/skill-creator/references/schemas.md +430 -0
  235. package/workflows/powers/spec-miner/POWER.md +49 -57
  236. package/workflows/powers/spec-miner/SKILL.md +49 -57
  237. package/workflows/powers/sqlite/POWER.md +67 -0
  238. package/workflows/powers/sqlite/SKILL.md +64 -0
  239. package/workflows/powers/sqlite/references/sqlite-checklist.md +19 -0
  240. package/workflows/powers/sre-engineer/POWER.md +123 -64
  241. package/workflows/powers/sre-engineer/SKILL.md +123 -64
  242. package/workflows/powers/static-analysis/POWER.md +121 -77
  243. package/workflows/powers/static-analysis/SKILL.md +121 -77
  244. package/workflows/powers/stripe-best-practices/POWER.md +140 -17
  245. package/workflows/powers/stripe-best-practices/SKILL.md +139 -17
  246. package/workflows/powers/supabase/POWER.md +67 -0
  247. package/workflows/powers/supabase/SKILL.md +64 -0
  248. package/workflows/powers/supabase/references/supabase-checklist.md +19 -0
  249. package/workflows/powers/swift-pro/POWER.md +118 -0
  250. package/workflows/powers/swift-pro/SKILL.md +115 -0
  251. package/workflows/powers/swift-pro/references/concurrency-patterns.md +165 -0
  252. package/workflows/powers/swift-pro/references/protocol-and-generics.md +172 -0
  253. package/workflows/powers/swift-pro/references/sendable-and-isolation.md +116 -0
  254. package/workflows/powers/swift-pro/references/swift-concurrency-and-protocols.md +260 -0
  255. package/workflows/powers/swift-pro/references/testing-and-packages.md +192 -0
  256. package/workflows/powers/tailwind-patterns/POWER.md +71 -240
  257. package/workflows/powers/tailwind-patterns/SKILL.md +71 -240
  258. package/workflows/powers/testing-patterns/POWER.md +155 -10
  259. package/workflows/powers/testing-patterns/SKILL.md +155 -10
  260. package/workflows/powers/typescript-pro/POWER.md +47 -38
  261. package/workflows/powers/typescript-pro/SKILL.md +47 -38
  262. package/workflows/powers/vitess/POWER.md +67 -0
  263. package/workflows/powers/vitess/SKILL.md +64 -0
  264. package/workflows/powers/vitess/references/vitess-checklist.md +19 -0
  265. package/workflows/powers/vulnerability-scanner/POWER.md +146 -10
  266. package/workflows/powers/vulnerability-scanner/SKILL.md +146 -10
  267. package/workflows/powers/web-perf/POWER.md +43 -170
  268. package/workflows/powers/web-perf/SKILL.md +43 -170
  269. package/workflows/powers/webapp-testing/POWER.md +43 -164
  270. package/workflows/powers/webapp-testing/SKILL.md +43 -164
  271. package/workflows/workflows/agent-environment-setup/platforms/antigravity/rules/GEMINI.md +65 -42
  272. package/workflows/workflows/agent-environment-setup/platforms/claude/rules/CLAUDE.md +8 -6
  273. package/workflows/workflows/agent-environment-setup/platforms/codex/rules/AGENTS.md +65 -41
  274. package/workflows/workflows/agent-environment-setup/platforms/copilot/rules/copilot-instructions.md +8 -6
  275. package/workflows/workflows/agent-environment-setup/shared/rules/STEERING.md +9 -8
  276. package/workflows/workflows/agent-environment-setup/shared/rules/overrides/codex.md +1 -1
@@ -0,0 +1,172 @@
1
+ # Protocol and Generics
2
+
3
+ ## Protocol design principles
4
+
5
+ ### Minimal protocol requirements
6
+
7
+ ```swift
8
+ // Good — focused contract
9
+ protocol Identifiable {
10
+ associatedtype ID: Hashable
11
+ var id: ID { get }
12
+ }
13
+
14
+ // Bad — too many requirements force unnecessary implementations
15
+ protocol DataSource {
16
+ func count() -> Int
17
+ func item(at: Int) -> Any
18
+ func add(_ item: Any) // not all data sources are mutable
19
+ func remove(at: Int) // not all data sources support removal
20
+ }
21
+ ```
22
+
23
+ - Define the smallest set of requirements that captures the abstraction.
24
+ - Split large protocols into composable pieces (`Readable`, `Writable` instead of `ReadWriteStore`).
25
+ - Use protocol extensions for default implementations of non-essential behavior.
26
+
27
+ ### Protocol composition
28
+
29
+ ```swift
30
+ typealias UserStore = Identifiable & Codable & Sendable
31
+
32
+ func save<T: Identifiable & Encodable>(_ item: T) throws {
33
+ let data = try JSONEncoder().encode(item)
34
+ try storage.write(data, forKey: "\(T.ID.self):\(item.id)")
35
+ }
36
+ ```
37
+
38
+ - Use `&` composition to combine protocols at use sites instead of creating combined protocols.
39
+ - Use `typealias` for frequently used compositions.
40
+
41
+ ## Opaque types (`some`)
42
+
43
+ ```swift
44
+ // Return type is known to the compiler, hidden from callers
45
+ func makeParser() -> some Parser {
46
+ JSONParser() // concrete type is fixed
47
+ }
48
+
49
+ // In SwiftUI — the canonical use case
50
+ var body: some View {
51
+ VStack {
52
+ Text("Hello")
53
+ Button("Tap") { action() }
54
+ }
55
+ }
56
+ ```
57
+
58
+ - `some Protocol` preserves type identity — the compiler tracks the concrete type at compile time.
59
+ - Zero runtime overhead compared to existentials.
60
+ - Cannot return different concrete types from different code paths.
61
+ - Use `some` in return types and stored properties when the caller doesn't need to know the concrete type.
62
+
63
+ ## Existential types (`any`)
64
+
65
+ ```swift
66
+ // Dynamic dispatch — concrete type resolved at runtime
67
+ var repositories: [any Repository] = [
68
+ PostgresRepository(),
69
+ InMemoryRepository(),
70
+ ]
71
+
72
+ func process(repo: any Repository) {
73
+ // uses dynamic dispatch
74
+ }
75
+ ```
76
+
77
+ - `any Protocol` has boxing overhead: heap allocation for the existential container.
78
+ - Required when you need heterogeneous collections of protocol-conforming types.
79
+ - Required when the concrete type varies at runtime.
80
+ - Cannot use protocols with `Self` requirements or associated types directly as `any` (use type erasure or constrained generics).
81
+
82
+ ### Opening existentials
83
+
84
+ ```swift
85
+ func processAny(_ item: any Identifiable) {
86
+ // Swift 5.7+ can "open" existentials into generics
87
+ process(item) // calls the generic version below
88
+ }
89
+
90
+ func process<T: Identifiable>(_ item: T) {
91
+ print(item.id)
92
+ }
93
+ ```
94
+
95
+ ## Associated types
96
+
97
+ ```swift
98
+ protocol Collection {
99
+ associatedtype Element
100
+ associatedtype Index: Comparable
101
+
102
+ var startIndex: Index { get }
103
+ var endIndex: Index { get }
104
+ subscript(position: Index) -> Element { get }
105
+ }
106
+ ```
107
+
108
+ - Use associated types when the protocol needs to express relationships between types.
109
+ - Add constraints to associated types (`associatedtype Element: Sendable`) to propagate requirements.
110
+ - Use `where` clauses for complex constraints:
111
+
112
+ ```swift
113
+ extension Collection where Element: Equatable {
114
+ func contains(_ element: Element) -> Bool {
115
+ // ...
116
+ }
117
+ }
118
+ ```
119
+
120
+ ## Generic constraint patterns
121
+
122
+ ### Constrained extensions
123
+
124
+ ```swift
125
+ extension Array where Element: Numeric {
126
+ var sum: Element {
127
+ reduce(.zero, +)
128
+ }
129
+ }
130
+
131
+ extension Sequence where Element: Hashable {
132
+ var unique: [Element] {
133
+ var seen = Set<Element>()
134
+ return filter { seen.insert($0).inserted }
135
+ }
136
+ }
137
+ ```
138
+
139
+ ### Generic type with constraints
140
+
141
+ ```swift
142
+ struct Cache<Key: Hashable & Sendable, Value: Sendable> {
143
+ private var storage: [Key: Value] = [:]
144
+
145
+ mutating func set(_ value: Value, forKey key: Key) {
146
+ storage[key] = value
147
+ }
148
+
149
+ func get(_ key: Key) -> Value? {
150
+ storage[key]
151
+ }
152
+ }
153
+ ```
154
+
155
+ ### Primary associated types (Swift 5.7+)
156
+
157
+ ```swift
158
+ protocol Repository<Model> {
159
+ associatedtype Model: Identifiable
160
+
161
+ func find(id: Model.ID) async throws -> Model?
162
+ func save(_ model: Model) async throws
163
+ }
164
+
165
+ // Use in constrained contexts without full generic signatures
166
+ func processRepo(_ repo: some Repository<User>) async throws {
167
+ let user = try await repo.find(id: userID)
168
+ }
169
+ ```
170
+
171
+ - Primary associated types simplify common generic usage with `some Protocol<ConcreteType>` syntax.
172
+ - Reduces the need for manual type erasure wrappers.
@@ -0,0 +1,116 @@
1
+ # Sendable and Isolation
2
+
3
+ ## Sendable conformance checklist
4
+
5
+ | Type | Sendable? | Notes |
6
+ | --------------------------------------------------------- | --------------------- | ------------------------------------------------- |
7
+ | `struct` with all `Sendable` stored properties | Automatic | No annotation needed in most cases. |
8
+ | `enum` with all `Sendable` associated values | Automatic | Including cases with no associated values. |
9
+ | `actor` | Always `Sendable` | Actors are `Sendable` by definition. |
10
+ | `final class` with immutable `Sendable` stored properties | Explicit | Must declare `: Sendable` conformance. |
11
+ | `class` with mutable state and manual synchronization | `@unchecked Sendable` | Requires manual audit of all access paths. |
12
+ | `class` with no synchronization | Not Sendable | Must be redesigned or isolated to a single actor. |
13
+
14
+ ## Isolation boundaries
15
+
16
+ ### Crossing isolation domains
17
+
18
+ ```swift
19
+ actor DataStore {
20
+ private var items: [Item] = []
21
+
22
+ // Value types cross boundaries safely
23
+ func snapshot() -> [Item] {
24
+ items // [Item] is Sendable if Item is Sendable
25
+ }
26
+ }
27
+
28
+ // From non-isolated context:
29
+ let store = DataStore()
30
+ let items = await store.snapshot() // crosses isolation boundary
31
+ ```
32
+
33
+ ### The `sending` parameter (Swift 6)
34
+
35
+ ```swift
36
+ // Transfer ownership of a non-Sendable value into an actor
37
+ func process(_ item: sending Item) async {
38
+ // item is now owned by this isolation domain
39
+ // caller cannot use item after this call
40
+ }
41
+ ```
42
+
43
+ - `sending` allows passing non-Sendable values across boundaries when ownership is transferred.
44
+ - The compiler enforces that the caller does not retain a reference after the call.
45
+ - Prefer `sending` over `@unchecked Sendable` when transferring ownership is the real intent.
46
+
47
+ ## Auditing @unchecked Sendable
48
+
49
+ When marking a class `@unchecked Sendable`, verify:
50
+
51
+ 1. **All mutable state** is protected by a lock, serial queue, or other synchronization mechanism.
52
+ 2. **No stored property** is a non-Sendable reference type accessed without synchronization.
53
+ 3. **No method** exposes internal mutable state by reference.
54
+ 4. **Subclasses** (if any) cannot break the synchronization contract.
55
+
56
+ ```swift
57
+ final class AtomicCounter: @unchecked Sendable {
58
+ private let lock = NSLock()
59
+ private var _value: Int = 0
60
+
61
+ var value: Int {
62
+ lock.lock()
63
+ defer { lock.unlock() }
64
+ return _value
65
+ }
66
+
67
+ func increment() {
68
+ lock.lock()
69
+ defer { lock.unlock() }
70
+ _value += 1
71
+ }
72
+ }
73
+ ```
74
+
75
+ - Always use `final class` with `@unchecked Sendable` to prevent subclass violations.
76
+ - Prefer `OSAllocatedUnfairLock` (iOS 16+/macOS 13+) over `NSLock` for better performance.
77
+ - Document the synchronization strategy in a comment next to the conformance.
78
+
79
+ ## Closure isolation
80
+
81
+ ```swift
82
+ // @Sendable closure — can only capture Sendable values
83
+ func runDetached(_ work: @escaping @Sendable () async -> Void) {
84
+ Task.detached { await work() }
85
+ }
86
+
87
+ // Non-Sendable capture will produce a compiler error
88
+ class ViewController {
89
+ var state: [String] = [] // not Sendable
90
+
91
+ func bad() {
92
+ runDetached {
93
+ self.state.append("oops") // ERROR: captured non-Sendable self
94
+ }
95
+ }
96
+
97
+ func good() {
98
+ let snapshot = state // copy to Sendable value
99
+ runDetached { [snapshot] in
100
+ print(snapshot) // OK — snapshot is Sendable
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ - `@Sendable` closures enforce Sendable captures at compile time.
107
+ - Capture value copies or Sendable references in the capture list.
108
+ - Use `@MainActor in` closure syntax to isolate closures to the main actor.
109
+
110
+ ## Migration strategy
111
+
112
+ 1. Enable `-strict-concurrency=targeted` first to see warnings without breaking the build.
113
+ 2. Fix `Sendable` conformance for types that cross boundaries (DTOs, config, events).
114
+ 3. Escalate to `-strict-concurrency=complete` once targeted warnings are resolved.
115
+ 4. Convert `@unchecked Sendable` uses to proper actors where feasible.
116
+ 5. Use `sending` parameters to eliminate remaining `@unchecked Sendable` workarounds.
@@ -0,0 +1,260 @@
1
+ # Swift Concurrency and Protocols
2
+
3
+ ## Actor design
4
+
5
+ ### When to use actors
6
+
7
+ ```swift
8
+ actor BankAccount {
9
+ private var balance: Decimal
10
+
11
+ init(initialBalance: Decimal) {
12
+ self.balance = initialBalance
13
+ }
14
+
15
+ func deposit(_ amount: Decimal) {
16
+ balance += amount
17
+ }
18
+
19
+ func withdraw(_ amount: Decimal) throws -> Decimal {
20
+ guard balance >= amount else {
21
+ throw BankError.insufficientFunds
22
+ }
23
+ balance -= amount
24
+ return amount
25
+ }
26
+
27
+ // nonisolated for properties that don't need isolation
28
+ nonisolated var description: String { "BankAccount" }
29
+ }
30
+ ```
31
+
32
+ - Use `actor` when mutable state needs thread-safe access from multiple callers.
33
+ - Actor methods are implicitly `async` when called from outside the actor.
34
+ - Use `nonisolated` for computed properties or methods that don't access mutable state.
35
+ - Keep actor methods fast — long-running work blocks other callers waiting for the actor.
36
+
37
+ ### Global actors
38
+
39
+ ```swift
40
+ @globalActor
41
+ actor DatabaseActor {
42
+ static let shared = DatabaseActor()
43
+ }
44
+
45
+ @DatabaseActor
46
+ class DatabaseManager {
47
+ func query(_ sql: String) async throws -> [Row] { /* ... */ }
48
+ }
49
+ ```
50
+
51
+ - Use `@MainActor` for all UI-bound code. Never dispatch to main queue manually.
52
+ - Create custom global actors for subsystems that need serial execution (database, file system).
53
+ - Annotate classes, methods, or properties — not entire modules.
54
+
55
+ ## Sendable conformance
56
+
57
+ ### Value types (automatic Sendable)
58
+
59
+ ```swift
60
+ // Automatically Sendable — all stored properties are Sendable
61
+ struct UserDTO: Sendable {
62
+ let id: UUID
63
+ let name: String
64
+ let email: String
65
+ }
66
+
67
+ // Enums with Sendable associated values are Sendable
68
+ enum Result<Success: Sendable, Failure: Error>: Sendable {
69
+ case success(Success)
70
+ case failure(Failure)
71
+ }
72
+ ```
73
+
74
+ ### Reference types (manual Sendable)
75
+
76
+ ```swift
77
+ // Must prove thread safety manually
78
+ final class ThreadSafeCache: @unchecked Sendable {
79
+ private let lock = NSLock()
80
+ private var storage: [String: Any] = [:]
81
+
82
+ func get(_ key: String) -> Any? {
83
+ lock.lock()
84
+ defer { lock.unlock() }
85
+ return storage[key]
86
+ }
87
+ }
88
+ ```
89
+
90
+ - `@unchecked Sendable` requires manual audit — the compiler trusts your claim.
91
+ - Prefer actors over `@unchecked Sendable` classes when possible.
92
+ - Use `sending` parameter modifier (Swift 6) to transfer ownership without requiring `Sendable`.
93
+
94
+ ### Closure Sendable rules
95
+
96
+ ```swift
97
+ // Closure must capture only Sendable values
98
+ func runOnBackground(_ work: @Sendable () async -> Void) {
99
+ Task { await work() }
100
+ }
101
+
102
+ // Capture list with Sendable values only
103
+ let name = "Alice" // String is Sendable
104
+ runOnBackground { [name] in
105
+ print(name) // OK — captured Sendable value
106
+ }
107
+ ```
108
+
109
+ ## Structured concurrency
110
+
111
+ ### TaskGroup
112
+
113
+ ```swift
114
+ func fetchAllUsers(ids: [Int]) async throws -> [User] {
115
+ try await withThrowingTaskGroup(of: User.self) { group in
116
+ for id in ids {
117
+ group.addTask {
118
+ try await api.fetchUser(id: id)
119
+ }
120
+ }
121
+ var users: [User] = []
122
+ for try await user in group {
123
+ users.append(user)
124
+ }
125
+ return users
126
+ }
127
+ }
128
+ ```
129
+
130
+ - Use `TaskGroup` for fan-out/fan-in patterns. Child tasks are automatically cancelled if the group scope exits.
131
+ - `withThrowingTaskGroup` propagates the first error and cancels remaining child tasks.
132
+
133
+ ### Task cancellation
134
+
135
+ ```swift
136
+ func processItems(_ items: [Item]) async throws {
137
+ for item in items {
138
+ // Check cancellation before each unit of work
139
+ try Task.checkCancellation()
140
+ await process(item)
141
+ }
142
+ }
143
+
144
+ // Or check without throwing
145
+ if Task.isCancelled {
146
+ // Clean up and return partial results
147
+ return partialResults
148
+ }
149
+ ```
150
+
151
+ - Always check `Task.isCancelled` or call `Task.checkCancellation()` in loops.
152
+ - Cancellation is cooperative — tasks are not killed automatically.
153
+ - Clean up resources in cancellation paths (close files, cancel network requests).
154
+
155
+ ### AsyncSequence and AsyncStream
156
+
157
+ ```swift
158
+ // Producing async events
159
+ func events() -> AsyncStream<Event> {
160
+ AsyncStream { continuation in
161
+ let observer = NotificationCenter.default.addObserver(...) { notification in
162
+ continuation.yield(Event(from: notification))
163
+ }
164
+ continuation.onTermination = { _ in
165
+ NotificationCenter.default.removeObserver(observer)
166
+ }
167
+ }
168
+ }
169
+
170
+ // Consuming
171
+ for await event in events() {
172
+ handle(event)
173
+ }
174
+ ```
175
+
176
+ ## Protocol-oriented architecture
177
+
178
+ ### Protocol as capability contract
179
+
180
+ ```swift
181
+ protocol UserRepository {
182
+ func find(id: UUID) async throws -> User?
183
+ func save(_ user: User) async throws
184
+ func delete(id: UUID) async throws
185
+ }
186
+
187
+ // Concrete implementation is internal
188
+ struct PostgresUserRepository: UserRepository {
189
+ func find(id: UUID) async throws -> User? { /* ... */ }
190
+ func save(_ user: User) async throws { /* ... */ }
191
+ func delete(id: UUID) async throws { /* ... */ }
192
+ }
193
+ ```
194
+
195
+ ### Protocol extensions for defaults
196
+
197
+ ```swift
198
+ protocol Cacheable: Identifiable {
199
+ var cacheKey: String { get }
200
+ var ttl: TimeInterval { get }
201
+ }
202
+
203
+ extension Cacheable {
204
+ var cacheKey: String { "\(Self.self):\(id)" }
205
+ var ttl: TimeInterval { 300 } // 5 minutes default
206
+ }
207
+ ```
208
+
209
+ - Use extensions for sensible defaults. Keep required methods minimal.
210
+
211
+ ### Opaque vs existential types
212
+
213
+ ```swift
214
+ // Opaque: compiler knows the concrete type (zero-cost)
215
+ func makeUser() -> some UserRepository {
216
+ PostgresUserRepository()
217
+ }
218
+
219
+ // Existential: runtime type erasure (has boxing overhead)
220
+ func getRepository() -> any UserRepository {
221
+ condition ? PostgresUserRepository() : InMemoryUserRepository()
222
+ }
223
+ ```
224
+
225
+ | Feature | `some Protocol` | `any Protocol` |
226
+ | ---------------------- | ------------------------------ | ---------------------------------- |
227
+ | Performance | Zero-cost (static dispatch) | Boxing overhead (dynamic dispatch) |
228
+ | Can vary return type | No — always same concrete type | Yes — different types allowed |
229
+ | Use as stored property | Only in generic context | Yes, directly |
230
+
231
+ - Prefer `some` by default. Use `any` only when you need heterogeneous collections or dynamic type selection.
232
+ - Use `any Protocol` in function parameters when multiple concrete types must be accepted.
233
+
234
+ ## Testing with protocols
235
+
236
+ ```swift
237
+ @Test
238
+ func testUserCreation() async throws {
239
+ let repo = MockUserRepository()
240
+ let service = UserService(repository: repo)
241
+
242
+ let user = try await service.createUser(name: "Alice")
243
+
244
+ #expect(user.name == "Alice")
245
+ #expect(repo.savedUsers.count == 1)
246
+ }
247
+
248
+ struct MockUserRepository: UserRepository {
249
+ var savedUsers: [User] = []
250
+
251
+ mutating func save(_ user: User) async throws {
252
+ savedUsers.append(user)
253
+ }
254
+ // ...
255
+ }
256
+ ```
257
+
258
+ - Inject protocols, test with mocks. Never test against real databases in unit tests.
259
+ - Use Swift Testing `@Test` and `#expect` for new test targets.
260
+ - Use `confirmation()` for testing actor-isolated code that emits events.