@mrciphersmith/keryx 0.3.2 → 0.3.5

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 (164) hide show
  1. package/dist/cli.js +4745 -2482
  2. package/dist/core.js +66 -10
  3. package/package.json +1 -1
  4. package/src/gdskills/bundled/install-manifest.json +578 -2
  5. package/src/gdskills/bundled/rules/core/model-selection.mdc +18 -0
  6. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +1 -1
  7. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.md +1 -1
  8. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.md +1 -1
  9. package/src/gdskills/bundled/skills/quality/deploy/SKILL.md +1 -1
  10. package/src/gdskills/bundled/skills/review/review-jev-contract/SKILL.md +193 -0
  11. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +81 -21
  12. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +4 -4
  13. package/src/gdskills/bundled/stacks/c-cpp/agent-refs.json +4 -0
  14. package/src/gdskills/bundled/stacks/c-cpp/governance/eval.json +1777 -0
  15. package/src/gdskills/bundled/stacks/c-cpp/governance/scout.json +31 -0
  16. package/src/gdskills/bundled/stacks/c-cpp/pack.json +42 -0
  17. package/src/gdskills/bundled/stacks/c-cpp/rules/coding-style.mdc +80 -0
  18. package/src/gdskills/bundled/stacks/c-cpp/rules/patterns.mdc +87 -0
  19. package/src/gdskills/bundled/stacks/c-cpp/rules/security.mdc +90 -0
  20. package/src/gdskills/bundled/stacks/c-cpp/rules/testing.mdc +83 -0
  21. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-build-fix/SKILL.md +153 -0
  22. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-build-fix/evals.json +74 -0
  23. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-code-review/SKILL.md +132 -0
  24. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-code-review/evals.json +73 -0
  25. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-implementation/SKILL.md +151 -0
  26. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-implementation/evals.json +74 -0
  27. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-testing/SKILL.md +152 -0
  28. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-testing/evals.json +74 -0
  29. package/src/gdskills/bundled/stacks/ci-github-gitlab/agent-refs.json +4 -0
  30. package/src/gdskills/bundled/stacks/ci-github-gitlab/governance/eval.json +1295 -0
  31. package/src/gdskills/bundled/stacks/ci-github-gitlab/governance/scout.json +26 -0
  32. package/src/gdskills/bundled/stacks/ci-github-gitlab/pack.json +41 -0
  33. package/src/gdskills/bundled/stacks/ci-github-gitlab/rules/patterns.mdc +77 -0
  34. package/src/gdskills/bundled/stacks/ci-github-gitlab/rules/security.mdc +144 -0
  35. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-build-fix/SKILL.md +121 -0
  36. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-build-fix/evals.json +73 -0
  37. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-code-review/SKILL.md +139 -0
  38. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-code-review/evals.json +73 -0
  39. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-implementation/SKILL.md +147 -0
  40. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-implementation/evals.json +74 -0
  41. package/src/gdskills/bundled/stacks/csharp-dotnet/agent-refs.json +4 -0
  42. package/src/gdskills/bundled/stacks/csharp-dotnet/governance/eval.json +1881 -0
  43. package/src/gdskills/bundled/stacks/csharp-dotnet/governance/scout.json +33 -0
  44. package/src/gdskills/bundled/stacks/csharp-dotnet/pack.json +38 -0
  45. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/coding-style.mdc +100 -0
  46. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/patterns.mdc +107 -0
  47. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/security.mdc +86 -0
  48. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/testing.mdc +89 -0
  49. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-build-fix/SKILL.md +143 -0
  50. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-build-fix/evals.json +77 -0
  51. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-code-review/SKILL.md +121 -0
  52. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-code-review/evals.json +77 -0
  53. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-implementation/SKILL.md +134 -0
  54. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-implementation/evals.json +76 -0
  55. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-testing/SKILL.md +130 -0
  56. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-testing/evals.json +77 -0
  57. package/src/gdskills/bundled/stacks/docker-k8s-terraform/agent-refs.json +4 -0
  58. package/src/gdskills/bundled/stacks/docker-k8s-terraform/governance/eval.json +865 -0
  59. package/src/gdskills/bundled/stacks/docker-k8s-terraform/governance/scout.json +16 -0
  60. package/src/gdskills/bundled/stacks/docker-k8s-terraform/pack.json +46 -0
  61. package/src/gdskills/bundled/stacks/docker-k8s-terraform/rules/coding-style.mdc +74 -0
  62. package/src/gdskills/bundled/stacks/docker-k8s-terraform/rules/patterns.mdc +81 -0
  63. package/src/gdskills/bundled/stacks/docker-k8s-terraform/rules/security.mdc +146 -0
  64. package/src/gdskills/bundled/stacks/docker-k8s-terraform/rules/testing.mdc +61 -0
  65. package/src/gdskills/bundled/stacks/docker-k8s-terraform/skills/docker-k8s-terraform-build-fix/SKILL.md +151 -0
  66. package/src/gdskills/bundled/stacks/docker-k8s-terraform/skills/docker-k8s-terraform-build-fix/evals.json +74 -0
  67. package/src/gdskills/bundled/stacks/docker-k8s-terraform/skills/docker-k8s-terraform-review/SKILL.md +135 -0
  68. package/src/gdskills/bundled/stacks/docker-k8s-terraform/skills/docker-k8s-terraform-review/evals.json +76 -0
  69. package/src/gdskills/bundled/stacks/flutter-dart/agent-refs.json +4 -0
  70. package/src/gdskills/bundled/stacks/flutter-dart/governance/eval.json +1849 -0
  71. package/src/gdskills/bundled/stacks/flutter-dart/governance/scout.json +33 -0
  72. package/src/gdskills/bundled/stacks/flutter-dart/pack.json +41 -0
  73. package/src/gdskills/bundled/stacks/flutter-dart/rules/coding-style.mdc +98 -0
  74. package/src/gdskills/bundled/stacks/flutter-dart/rules/patterns.mdc +88 -0
  75. package/src/gdskills/bundled/stacks/flutter-dart/rules/security.mdc +91 -0
  76. package/src/gdskills/bundled/stacks/flutter-dart/rules/testing.mdc +101 -0
  77. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-build-fix/SKILL.md +134 -0
  78. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-build-fix/evals.json +79 -0
  79. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-code-review/SKILL.md +124 -0
  80. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-code-review/evals.json +74 -0
  81. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-implementation/SKILL.md +139 -0
  82. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-implementation/evals.json +77 -0
  83. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-testing/SKILL.md +134 -0
  84. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-testing/evals.json +74 -0
  85. package/src/gdskills/bundled/stacks/kotlin-android/agent-refs.json +4 -0
  86. package/src/gdskills/bundled/stacks/kotlin-android/governance/eval.json +1889 -0
  87. package/src/gdskills/bundled/stacks/kotlin-android/governance/scout.json +34 -0
  88. package/src/gdskills/bundled/stacks/kotlin-android/pack.json +38 -0
  89. package/src/gdskills/bundled/stacks/kotlin-android/rules/coding-style.mdc +89 -0
  90. package/src/gdskills/bundled/stacks/kotlin-android/rules/patterns.mdc +96 -0
  91. package/src/gdskills/bundled/stacks/kotlin-android/rules/security.mdc +90 -0
  92. package/src/gdskills/bundled/stacks/kotlin-android/rules/testing.mdc +89 -0
  93. package/src/gdskills/bundled/stacks/kotlin-android/skills/compose-implementation/SKILL.md +150 -0
  94. package/src/gdskills/bundled/stacks/kotlin-android/skills/compose-implementation/evals.json +77 -0
  95. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-build-fix/SKILL.md +151 -0
  96. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-build-fix/evals.json +76 -0
  97. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-code-review/SKILL.md +139 -0
  98. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-code-review/evals.json +78 -0
  99. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-testing/SKILL.md +131 -0
  100. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-testing/evals.json +77 -0
  101. package/src/gdskills/bundled/stacks/php-laravel/agent-refs.json +4 -0
  102. package/src/gdskills/bundled/stacks/php-laravel/governance/eval.json +1829 -0
  103. package/src/gdskills/bundled/stacks/php-laravel/governance/scout.json +33 -0
  104. package/src/gdskills/bundled/stacks/php-laravel/pack.json +41 -0
  105. package/src/gdskills/bundled/stacks/php-laravel/rules/coding-style.mdc +82 -0
  106. package/src/gdskills/bundled/stacks/php-laravel/rules/patterns.mdc +80 -0
  107. package/src/gdskills/bundled/stacks/php-laravel/rules/security.mdc +80 -0
  108. package/src/gdskills/bundled/stacks/php-laravel/rules/testing.mdc +82 -0
  109. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-build-fix/SKILL.md +143 -0
  110. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-build-fix/evals.json +74 -0
  111. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-code-review/SKILL.md +126 -0
  112. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-code-review/evals.json +76 -0
  113. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-implementation/SKILL.md +140 -0
  114. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-implementation/evals.json +75 -0
  115. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-testing/SKILL.md +124 -0
  116. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-testing/evals.json +74 -0
  117. package/src/gdskills/bundled/stacks/ruby-rails/agent-refs.json +4 -0
  118. package/src/gdskills/bundled/stacks/ruby-rails/governance/eval.json +1673 -0
  119. package/src/gdskills/bundled/stacks/ruby-rails/governance/scout.json +33 -0
  120. package/src/gdskills/bundled/stacks/ruby-rails/pack.json +42 -0
  121. package/src/gdskills/bundled/stacks/ruby-rails/rules/coding-style.mdc +69 -0
  122. package/src/gdskills/bundled/stacks/ruby-rails/rules/patterns.mdc +93 -0
  123. package/src/gdskills/bundled/stacks/ruby-rails/rules/security.mdc +90 -0
  124. package/src/gdskills/bundled/stacks/ruby-rails/rules/testing.mdc +89 -0
  125. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-build-fix/SKILL.md +143 -0
  126. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-build-fix/evals.json +73 -0
  127. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-code-review/SKILL.md +134 -0
  128. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-code-review/evals.json +71 -0
  129. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-implementation/SKILL.md +141 -0
  130. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-implementation/evals.json +72 -0
  131. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-testing/SKILL.md +125 -0
  132. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-testing/evals.json +72 -0
  133. package/src/gdskills/bundled/stacks/sql-db/agent-refs.json +4 -0
  134. package/src/gdskills/bundled/stacks/sql-db/governance/eval.json +1829 -0
  135. package/src/gdskills/bundled/stacks/sql-db/governance/scout.json +30 -0
  136. package/src/gdskills/bundled/stacks/sql-db/pack.json +40 -0
  137. package/src/gdskills/bundled/stacks/sql-db/rules/coding-style.mdc +69 -0
  138. package/src/gdskills/bundled/stacks/sql-db/rules/patterns.mdc +134 -0
  139. package/src/gdskills/bundled/stacks/sql-db/rules/security.mdc +74 -0
  140. package/src/gdskills/bundled/stacks/sql-db/rules/testing.mdc +83 -0
  141. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-build-fix/SKILL.md +147 -0
  142. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-build-fix/evals.json +72 -0
  143. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-code-review/SKILL.md +132 -0
  144. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-code-review/evals.json +73 -0
  145. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-implementation/SKILL.md +153 -0
  146. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-implementation/evals.json +77 -0
  147. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-testing/SKILL.md +129 -0
  148. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-testing/evals.json +73 -0
  149. package/src/gdskills/bundled/stacks/swift-ios/agent-refs.json +4 -0
  150. package/src/gdskills/bundled/stacks/swift-ios/governance/eval.json +1803 -0
  151. package/src/gdskills/bundled/stacks/swift-ios/governance/scout.json +32 -0
  152. package/src/gdskills/bundled/stacks/swift-ios/pack.json +38 -0
  153. package/src/gdskills/bundled/stacks/swift-ios/rules/coding-style.mdc +92 -0
  154. package/src/gdskills/bundled/stacks/swift-ios/rules/patterns.mdc +112 -0
  155. package/src/gdskills/bundled/stacks/swift-ios/rules/security.mdc +78 -0
  156. package/src/gdskills/bundled/stacks/swift-ios/rules/testing.mdc +90 -0
  157. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-build-fix/SKILL.md +144 -0
  158. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-build-fix/evals.json +75 -0
  159. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-code-review/SKILL.md +122 -0
  160. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-code-review/evals.json +75 -0
  161. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-testing/SKILL.md +131 -0
  162. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-testing/evals.json +75 -0
  163. package/src/gdskills/bundled/stacks/swift-ios/skills/swiftui-implementation/SKILL.md +149 -0
  164. package/src/gdskills/bundled/stacks/swift-ios/skills/swiftui-implementation/evals.json +76 -0
@@ -0,0 +1,32 @@
1
+ [
2
+ {
3
+ "query": "Use when implementing or extending a feature in a SwiftUI/iOS app -- state ownership (@State/@Binding/@Environment/@Observable), Swift concurrency (async/await, actors, @MainActor, TaskGroup, Sendable), and view composition.",
4
+ "decision": "create",
5
+ "topMatch": "flutter-dart/flutter-implementation",
6
+ "recordedAt": "2026-09-25T15:32:07.026Z",
7
+ "skillName": "swiftui-implementation"
8
+ },
9
+ {
10
+ "query": "Use when a Swift/iOS test suite needs writing, extending, or fixing -- Swift Testing's @Test/#expect/#require, parameterized tests, legacy XCTest, and mocking network/persistence dependencies at a protocol boundary rather than the type under test's internals.",
11
+ "decision": "fork",
12
+ "topMatch": "csharp-dotnet/dotnet-testing",
13
+ "recordedAt": "2026-09-25T15:35:21.070Z",
14
+ "skillName": "swift-testing",
15
+ "justification": "Nearest match csharp-dotnet/dotnet-testing tests C# with xUnit/NUnit/Moq, a different language and tooling entirely; no existing test skill covers Swift Testing's @Test/#expect, XCTest, or Swift protocol-boundary mocking."
16
+ },
17
+ {
18
+ "query": "Use when reviewing a Swift/iOS change for concurrency, memory, and safety risks -- force-unwraps, retain cycles from closures capturing self, missing @MainActor isolation, @unchecked Sendable used to silence checks, and secrets stored outside the Keychain. Read-only, no edits.",
19
+ "decision": "create",
20
+ "topMatch": "csharp-dotnet/dotnet-code-review",
21
+ "recordedAt": "2026-09-25T15:32:07.629Z",
22
+ "skillName": "swift-code-review"
23
+ },
24
+ {
25
+ "query": "Use when xcodebuild/swift build fails, or a Swift 6 strict-concurrency/Sendable error, SwiftLint failure, or failing test blocks the build -- resolves the root cause instead of force-unwrapping, adding @unchecked Sendable, or disabling a lint rule to silence the check.",
26
+ "decision": "fork",
27
+ "topMatch": "ts-js-node/nodejs-build-fix",
28
+ "recordedAt": "2026-09-25T15:35:21.350Z",
29
+ "skillName": "swift-build-fix",
30
+ "justification": "Nearest match ts-js-node/nodejs-build-fix fixes tsc/ESM/eslint errors for Node/TS, not xcodebuild/Swift 6 concurrency/Sendable/SwiftLint failures; each build-fix skill is scoped to its own toolchain's specific failure surface."
31
+ }
32
+ ]
@@ -0,0 +1,38 @@
1
+ {
2
+ "id": "swift-ios",
3
+ "family": "framework",
4
+ "modules": ["swift-ios-rules", "swift-ios-skills"],
5
+ "detectionMarkers": ["ios"],
6
+ "provenance": { "origin": "authored", "sourceRef": "flow 336, Wave 4 batch 4" },
7
+ "stability": "experimental",
8
+ "skills": {
9
+ "implement": ["swiftui-implementation"],
10
+ "test": ["swift-testing"],
11
+ "review": ["swift-code-review"],
12
+ "build-fix": ["swift-build-fix"],
13
+ "migrate": []
14
+ },
15
+ "agentProfile": {
16
+ "displayName": "Swift/iOS",
17
+ "auditFocus": [
18
+ "force-unwrapping (`!`) or force-try (`try!`) on a value that can genuinely be nil or throw, especially on network/decoded data",
19
+ "an `@Observable` model or any UI-touching type not isolated to `@MainActor`, risking a cross-actor data race",
20
+ "a closure captured strongly by `self` in a long-lived callback (completion handler, Combine sink, stored closure) causing a retain cycle",
21
+ "a secret, API key, or auth token stored in `UserDefaults` or hardcoded in source instead of the Keychain",
22
+ "state ownership mismatches: `@State` for a value that is actually shared/mutated by a parent, or a legacy `@StateObject` recreated inline instead of owned once",
23
+ "`@unchecked Sendable` or a blanket concurrency-checking suppression applied to silence the compiler instead of fixing the actual data-race shape"
24
+ ],
25
+ "buildCommands": [
26
+ "xcodebuild build -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>' (or swift build for a SwiftPM package)",
27
+ "xcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>' (or swift test)",
28
+ "swiftlint",
29
+ "swift-format lint --recursive . (or swiftformat --lint . depending on the project's configured formatter)"
30
+ ],
31
+ "fixGuardrails": [
32
+ "never mark a type `@unchecked Sendable` to silence a strict-concurrency error without actually proving and documenting why its mutable state is safe",
33
+ "never force-unwrap (`!`) or force-try (`try!`) just to clear a compiler warning about an optional or a throwing call",
34
+ "never disable a SwiftLint/swift-format rule repo-wide (or with a blanket `// swiftlint:disable`) to make one finding disappear",
35
+ "never delete or skip a failing test, or loosen its assertion, to reach a green build"
36
+ ]
37
+ }
38
+ }
@@ -0,0 +1,92 @@
1
+ ---
2
+ extends: common
3
+ paths: ["**/*.swift"]
4
+ metadata:
5
+ origin: authored
6
+ ---
7
+
8
+ # Swift/iOS coding style
9
+
10
+ Narrows `core-common-rules`' stack-agnostic style rules to modern Swift
11
+ (6.x) and SwiftUI idiom. Applies only to `*.swift` files — everything not
12
+ Swift-specific still comes from the common rules this file `extends`.
13
+
14
+ ## Naming and structure
15
+
16
+ - Types (`struct`, `class`, `enum`, `protocol`) are `UpperCamelCase`;
17
+ properties, methods, and cases are `lowerCamelCase` — never
18
+ `snake_case` for either.
19
+ - Protocol names read as a capability (`Fetchable`, `Cacheable`) or a
20
+ role noun (`DataSource`, `Delegate`); do not suffix a protocol with
21
+ `Protocol`.
22
+ - An identifier's name shrinks with its scope: a tight closure parameter
23
+ can be `$0`/a one-letter name, a public API member gets a full
24
+ descriptive name.
25
+ - File name matches the primary type it declares (`OrderService.swift`
26
+ declares `OrderService`); one primary type per file for anything
27
+ public.
28
+
29
+ ## Value types vs reference types
30
+
31
+ - Default to `struct` (and `enum` for closed sets of cases) for model and
32
+ state types — value semantics mean a copy cannot be mutated out from
33
+ under another owner, which is what SwiftUI's data flow assumes.
34
+ - Reach for `class` only when you need reference semantics on purpose:
35
+ shared mutable state across owners, identity that must be preserved
36
+ (`===`), or Objective-C interop. Justify a `class` model type in review
37
+ rather than defaulting to it out of habit from other languages.
38
+ - A `class` used as SwiftUI-observed state is marked `@Observable` (see
39
+ `patterns.mdc`) and, when its mutable state is touched from view code,
40
+ isolated to `@MainActor`.
41
+
42
+ ## Guard for early exit
43
+
44
+ - Use `guard let`/`guard` with an early `return`/`continue`/`throw` to
45
+ unwrap a precondition and keep the "happy path" unindented, rather than
46
+ nesting the whole function body inside an `if let`.
47
+ - Prefer a single `guard` with multiple comma-separated conditions over a
48
+ pyramid of nested `if let`s when several optionals must all be present
49
+ before the function can proceed.
50
+
51
+ ## Optionals
52
+
53
+ - Treat `!` (force-unwrap) and `try!` (force-try) as a last resort, not a
54
+ convenience — reserve them for a value whose absence is a genuine
55
+ programmer error that should crash in development (an `IBOutlet` wired
56
+ in a storyboard, a compile-time-guaranteed non-nil literal), never for
57
+ network responses, decoded JSON, user input, or anything else that can
58
+ legitimately be nil or throw in production.
59
+ - Prefer `guard let`/`if let`, nil-coalescing (`??`) with a real default,
60
+ or `try`/`try?` with explicit handling. Use `#require(...)` (Swift
61
+ Testing) or `XCTUnwrap` in tests instead of `!` when a test needs to
62
+ unwrap and fail with a clear message if the value is missing.
63
+ - Chain optional access with `?.`/optional chaining rather than
64
+ force-unwrapping an intermediate step in a chain.
65
+
66
+ ## @Observable vs legacy ObservableObject
67
+
68
+ - For code targeting iOS 17+, model types that drive SwiftUI view
69
+ updates use the `@Observable` macro, not the legacy
70
+ `ObservableObject`/`@Published` combination — `@Observable` tracks
71
+ property-level access automatically, so a view only re-renders for the
72
+ properties it actually reads, where `@Published` re-renders on any
73
+ change to the whole object.
74
+ - Mark an `@Observable` class `@MainActor` unless the project has set a
75
+ module-wide default actor isolation to `MainActor` — this keeps its
76
+ mutable state confined to the main actor by construction (see
77
+ `patterns.mdc` for the concurrency implications).
78
+ - Only reach for `ObservableObject`/`@Published`/`@StateObject`/
79
+ `@ObservedObject` when the project's minimum deployment target
80
+ predates iOS 17, or an existing codebase has not yet migrated; do not
81
+ introduce the legacy pattern in new code on a project that already
82
+ targets iOS 17+.
83
+
84
+ ## Formatting and linting
85
+
86
+ - Format with the project's configured formatter (`swift-format` or
87
+ `swiftformat`) before finishing a change; do not hand-format around a
88
+ formatter that is already configured in the project.
89
+ - Fix a SwiftLint finding at its root cause; do not silence it with a
90
+ blanket `// swiftlint:disable` covering more than the one line it
91
+ actually applies to, and never disable a rule repository-wide to clear
92
+ one finding.
@@ -0,0 +1,112 @@
1
+ ---
2
+ extends: common
3
+ paths: ["**/*.swift"]
4
+ metadata:
5
+ origin: authored
6
+ ---
7
+
8
+ # Swift/iOS patterns
9
+
10
+ Narrows `core-common-rules`' stack-agnostic design guidance to idiomatic
11
+ Swift concurrency and SwiftUI state ownership. Applies only to `*.swift`
12
+ files.
13
+
14
+ ## Swift concurrency: async/await and structured concurrency
15
+
16
+ - Prefer `async`/`await` over completion-handler callbacks for new
17
+ asynchronous code — it reads linearly and composes with structured
18
+ concurrency instead of nesting closures.
19
+ - Start concurrent child work with `async let` (a small, fixed number of
20
+ parallel tasks) or `TaskGroup`/`withThrowingTaskGroup` (a dynamic or
21
+ unbounded set of child tasks); both guarantee every child task is
22
+ awaited or cancelled before the parent scope exits, unlike a bare
23
+ unstructured `Task {}` with no owner to join it. (`Task {}` is
24
+ "unstructured" — it inherits the creating context's actor and priority
25
+ but nothing tracks its lifetime; `Task.detached {}` is a stronger,
26
+ rarely-needed form that inherits neither — do not use the two names
27
+ interchangeably.)
28
+ - SwiftUI's `.task { }` modifier closure is already async — it is the
29
+ boundary, not a place to wrap another `Task {}` inside it. Reach for a
30
+ bare `Task {}` only at a genuine synchronous-to-async boundary with no
31
+ async closure already available (a button action's `Void`-returning
32
+ handler, a delegate callback); give it an explicit reason it does not
33
+ need to be joined. Prefer `.task { }` directly on a SwiftUI view over a
34
+ manually created `Task` when the work should be tied to the view's
35
+ lifetime (it is cancelled automatically when the view disappears).
36
+ - Respect cancellation in long-running async work: check
37
+ `Task.isCancelled`/call `try Task.checkCancellation()` in a loop, so a
38
+ cancelled parent actually stops the child's work instead of running to
39
+ completion regardless.
40
+
41
+ ## Actors and @MainActor
42
+
43
+ - Use `actor` to protect mutable state that multiple tasks touch
44
+ concurrently — its methods are implicitly isolated, so the compiler
45
+ (not a convention) prevents unsynchronized access, the same guarantee
46
+ a manual lock only provides by discipline.
47
+ - Since the iOS 18 SDK, `View` conformance is itself `@MainActor`-isolated
48
+ — a view's own `body` and any `@State`/`@Binding` kept directly on the
49
+ view struct are already main-actor-isolated automatically, with no
50
+ explicit annotation needed. That isolation does NOT extend to a
51
+ SEPARATE type: mark any standalone type whose state SwiftUI reads or
52
+ mutates `@MainActor` explicitly — view models, `@Observable` stores, or
53
+ any other type outside the `View` struct itself that a `body` touches.
54
+ Isolate at the type level (`@MainActor final class ...`) rather than
55
+ sprinkling `@MainActor` on individual methods, unless only some of the
56
+ type's methods genuinely need main-actor isolation.
57
+ - Cross an actor boundary explicitly with `await`; do not reach for
58
+ `@unchecked Sendable` or `nonisolated(unsafe)` to make a boundary
59
+ error disappear — either the type's state genuinely needs no
60
+ isolation (make that case explicitly, with a comment), or it needs a
61
+ real actor/lock, not a suppression.
62
+
63
+ ## Sendable conformance
64
+
65
+ - A value crossing a concurrency boundary (passed into a `Task`, an
66
+ actor method, or a `TaskGroup` child) must be `Sendable`: a `struct`
67
+ or `enum` with only `Sendable` members is `Sendable` for free; a
68
+ `final class` with only immutable (`let`) stored properties can
69
+ declare conformance explicitly.
70
+ - Do not slap `@unchecked Sendable` on a class to silence a
71
+ strict-concurrency diagnostic without actually auditing and
72
+ documenting why its mutable state cannot race — that trades a
73
+ compile-time guarantee for an unchecked promise, which is exactly the
74
+ class of bug Swift 6's data-race safety exists to catch.
75
+ - Under the Swift 6 language mode, treat a "Sendable" or "actor
76
+ isolation" compiler error as a real potential data race to fix at the
77
+ root (add an actor, make the type immutable, or copy the value before
78
+ crossing), not friction to suppress.
79
+
80
+ ## SwiftUI state ownership
81
+
82
+ - `@State` owns a value the view itself creates and is the sole owner
83
+ of — a simple value type, or (iOS 17+) an `@Observable` reference type
84
+ the view instantiates directly (`@State private var model = Model()`,
85
+ not `@StateObject` for `@Observable` types).
86
+ - `@Binding` is for a child view that needs to both read and mutate a
87
+ value it does not own — the parent passes `$value`, and the child
88
+ writes through the binding instead of receiving a copy it cannot
89
+ propagate changes from.
90
+ - `@Environment` is for values that are ambient to a whole subtree
91
+ (theme, a shared service, a feature flag) rather than threaded
92
+ explicitly through every initializer; do not reach for it as a
93
+ shortcut to avoid passing an explicit dependency that only one or two
94
+ views actually need.
95
+ - A view that receives an `@Observable` model from a parent and needs to
96
+ pass a binding to one of its properties down further uses `@Bindable`,
97
+ not a manually reconstructed `Binding(get:set:)`.
98
+
99
+ ## Anti-patterns to flag
100
+
101
+ - A retain cycle from a closure (completion handler, Combine `sink`,
102
+ stored callback) that captures `self` strongly when the closure
103
+ outlives the call that created it — use `[weak self]` and unwrap, or
104
+ `[unowned self]` only when `self`'s lifetime is provably guaranteed to
105
+ exceed the closure's.
106
+ - Lifting a value into `@State`/`@StateObject` at the view that merely
107
+ displays it, when a parent further up actually owns and mutates it —
108
+ that duplicates state instead of using `@Binding`/`@Observable`
109
+ references, and the two copies drift.
110
+ - A massive view or view-model type that owns navigation, networking,
111
+ and persistence together — split by responsibility the same way a
112
+ "god package"/"god object" is flagged in any other stack.
@@ -0,0 +1,78 @@
1
+ ---
2
+ extends: common
3
+ paths: ["**/*.swift"]
4
+ metadata:
5
+ origin: authored
6
+ ---
7
+
8
+ # Swift/iOS security
9
+
10
+ Narrows `core-common-rules`' stack-agnostic security rules to
11
+ iOS/Apple-platform-specific risks and the safe framework API to use
12
+ instead. Applies only to `*.swift` files.
13
+
14
+ ## Secrets and credential storage
15
+
16
+ - Store credentials, tokens, and refresh tokens in the Keychain
17
+ (`Security` framework, or a thin wrapper around it) — never in
18
+ `UserDefaults`, which is unencrypted plist storage readable by
19
+ anything with filesystem access to the app's container, and never in a
20
+ plain file the app writes itself.
21
+ - Never hardcode an API key, client secret, or signing credential as a
22
+ string literal in source. Load it from a build-time configuration
23
+ (an `.xcconfig` value injected into `Info.plist`, a secrets manager
24
+ fetched at runtime) that is excluded from source control, and treat a
25
+ literal key found in a diff as a finding, not a style nit.
26
+ - Set an appropriate Keychain accessibility level
27
+ (`kSecAttrAccessibleWhenUnlockedThisDeviceOnly` or stricter) for
28
+ anything sensitive — the default accessibility can survive a device
29
+ backup/restore onto different hardware, which is usually not the
30
+ intended threat model for a session token.
31
+
32
+ ## Network security (ATS and transport)
33
+
34
+ - Leave App Transport Security (ATS) at its default (HTTPS-only,
35
+ TLS 1.2+); do not add `NSAllowsArbitraryLoads` or a blanket
36
+ `NSExceptionDomains` bypass to `Info.plist` to work around a backend
37
+ that is not yet on HTTPS — fix the backend, or scope an ATS exception
38
+ to the exact domain and the exact minimum relaxation needed, with a
39
+ comment saying why.
40
+ - Validate TLS the platform's normal way (`URLSession`'s default trust
41
+ evaluation); do not implement a `URLSessionDelegate` that accepts any
42
+ server certificate (`.performDefaultHandling` bypassed with
43
+ unconditional trust) outside of a short-lived local/test
44
+ configuration, and never ship that in production.
45
+
46
+ ## Biometric authentication
47
+
48
+ - Treat a `LAContext` biometric (Face ID/Touch ID) result as a *local
49
+ presence* gate, not proof of identity to a remote server on its own —
50
+ a successful `evaluatePolicy` unlocks a locally-held secret (a
51
+ Keychain item, a locally cached credential); it does not substitute
52
+ for a real authentication token when talking to a backend.
53
+ - Check the specific `LAError` case on failure (`.userCancel`,
54
+ `.biometryNotAvailable`, `.biometryLockout`, ...) and present a
55
+ fallback (passcode, credential re-entry) rather than treating every
56
+ failure identically or silently retrying.
57
+ - Do not cache "biometric succeeded" as a long-lived boolean flag read
58
+ later by unrelated code paths — re-evaluate at the point access is
59
+ actually needed, scoped to what that specific action requires.
60
+
61
+ ## Input handling and injection-adjacent risks
62
+
63
+ - Parameterize any `NSPredicate`/Core Data query built from
64
+ user-influenced input rather than interpolating the value directly
65
+ into the predicate format string — the same injection-shaped risk as
66
+ building SQL by string concatenation.
67
+ - Validate/sanitize any URL or deep link the app opens
68
+ (`UIApplication.open`, a Universal Link handler) before acting on it —
69
+ a deep link is untrusted input from outside the process, not a value
70
+ to trust and route on directly.
71
+
72
+ ## Logging
73
+
74
+ - Never log a token, password, or full PII payload at a level that
75
+ reaches persistent device logs (`print`, unredacted `os_log`/`Logger`
76
+ interpolation) — use `Logger`'s privacy-redaction (`\(value,
77
+ privacy: .private)`) for anything sensitive, or omit it from the log
78
+ entirely.
@@ -0,0 +1,90 @@
1
+ ---
2
+ extends: common
3
+ paths: ["**/*.swift"]
4
+ metadata:
5
+ origin: authored
6
+ ---
7
+
8
+ # Swift/iOS testing
9
+
10
+ Narrows `core-common-rules`' stack-agnostic testing rules to Swift
11
+ Testing (the current default for new test code) and legacy XCTest, where
12
+ the project has not yet migrated. Applies only to `*.swift` files.
13
+
14
+ ## Swift Testing vs XCTest
15
+
16
+ - For new test code on a toolchain that supports it, prefer the Swift
17
+ Testing framework (`import Testing`, `@Test` functions, `#expect`/
18
+ `#require` macros) over XCTest — it gives clearer failure messages
19
+ (`#expect` captures the evaluated sub-expressions), native
20
+ parameterized tests, and tests run in parallel by default.
21
+ - Swift Testing does not yet replace XCTest everywhere: UI automation
22
+ (`XCUITest`) and performance tests (`XCTMetric`/`measure`) still run
23
+ on XCTest, and an existing XCTest suite does not need a wholesale
24
+ rewrite just to adopt Swift Testing — the two frameworks coexist in
25
+ the same target. Match whichever the project's existing test target
26
+ already uses for a given kind of test; introduce Swift Testing for new
27
+ unit-test coverage rather than mixing conventions within one file.
28
+ - A Swift Testing function is `@Test func name() async throws { ... }`
29
+ (not `test`-prefixed, no `XCTestCase` subclass needed); assert with
30
+ `#expect(condition)` for a check that should record a failure and
31
+ continue, or `try #require(optional)` for one that must stop the test
32
+ immediately if it fails (the Swift Testing equivalent of
33
+ `XCTUnwrap`/`XCTAssert...` followed by an early return).
34
+
35
+ ## Structure and naming
36
+
37
+ - One `@Test` (or `XCTest` method) per behavior being verified; a
38
+ descriptive test name (`@Test("returns nil for an empty cart")` or a
39
+ method named `test_returnsNil_whenCartIsEmpty`) over `test1`/`test2`.
40
+ - Use Swift Testing's `arguments:` parameterization for the same
41
+ assertion repeated over several inputs, instead of a hand-rolled loop
42
+ inside one test function or several copy-pasted test functions that
43
+ differ only by input.
44
+ - Group related tests with a `struct`/`enum` namespace and Swift
45
+ Testing's `@Suite`, or an `XCTestCase` subclass for legacy code,
46
+ matching whatever the target already does.
47
+
48
+ ## Mocking at the protocol boundary
49
+
50
+ - Mock external dependencies — network clients, persistence
51
+ (`UserDefaults`, Core Data, a database layer), platform services
52
+ (location, notifications) — at a protocol boundary the production code
53
+ already depends on, never by mocking the type under test's own
54
+ internal collaborators or reaching into its private state.
55
+ - Define (or reuse) a narrow protocol for the dependency (`protocol
56
+ OrderClient { func fetchOrder(id: String) async throws -> Order }`),
57
+ inject a real conforming type in production and a test double
58
+ conforming to the same protocol in tests — the type under test never
59
+ needs to know it is under test.
60
+ - Do not mock one layer too deep (stubbing a private helper method, or
61
+ a concrete `URLSession` call inside a class instead of the protocol
62
+ that wraps it) — that couples the test to an implementation detail and
63
+ breaks on a harmless refactor instead of only on an actual behavior
64
+ change.
65
+
66
+ ## Async and concurrency in tests
67
+
68
+ - Mark a test `async` and `await` the async call under test directly —
69
+ Swift Testing and modern `XCTestCase` both support `async` test
70
+ methods natively; do not reach for an `XCTestExpectation`/semaphore to
71
+ bridge an `async` API into a synchronous-looking test unless the
72
+ project's minimum toolchain predates async test support.
73
+ - Never synchronize with a fixed delay (`Thread.sleep`/`Task.sleep` used
74
+ as a guess at "enough time") to wait for concurrent work to finish —
75
+ `await` the async call, join a `TaskGroup`, or await an
76
+ `XCTestExpectation` with a real fulfillment signal instead of a timed
77
+ guess.
78
+ - Annotate a test `@MainActor` when it exercises `@MainActor`-isolated
79
+ view-model/state code, so the test itself runs on the same actor its
80
+ subject requires.
81
+
82
+ ## Determinism
83
+
84
+ - A test must not depend on real network access, the real Keychain, or
85
+ wall-clock time; inject a fake/in-memory conforming type at the
86
+ protocol boundary and, for time-dependent logic, inject a clock/date
87
+ provider instead of calling `Date()` directly inside the code under
88
+ test.
89
+ - A bug fix gets a regression test that fails before the fix and passes
90
+ after; new behavior gets new test coverage in the same change.
@@ -0,0 +1,144 @@
1
+ ---
2
+ name: swift-build-fix
3
+ description: "Use when xcodebuild/swift build fails, or a Swift 6 strict-concurrency/Sendable error, SwiftLint failure, or failing test blocks the build -- resolves the root cause instead of force-unwrapping, adding @unchecked Sendable, or disabling a lint rule to silence the check."
4
+ triggers:
5
+ - "xcodebuild is failing"
6
+ - "swift build error"
7
+ - "fix this Swift 6 concurrency error"
8
+ - "SwiftLint is failing"
9
+ - "resolve this Sendable conformance error"
10
+ - "this Swift test is failing, fix the build"
11
+ metadata:
12
+ origin: authored
13
+ category: build-fix
14
+ version: "1.0.0"
15
+ compatible_harnesses: "claude,codex,cursor,zed,opencode"
16
+ license: "MIT"
17
+ ---
18
+
19
+ # Swift/iOS build fix
20
+
21
+ Resolve an `xcodebuild`/`swift build` failure, a Swift 6 strict-
22
+ concurrency or `Sendable` conformance error, a SwiftLint/swift-format
23
+ failure, or a failing test blocking the build — with the smallest change
24
+ that fixes the actual root cause. `rules/coding-style.mdc` and
25
+ `rules/patterns.mdc` govern what a "correct" fix looks like; this skill
26
+ never reaches for a suppression instead of a fix.
27
+
28
+ ## Workflow
29
+
30
+ ### Step 1: Reproduce and classify
31
+
32
+ ```bash
33
+ xcodebuild build -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'
34
+ # or, for a Swift package:
35
+ swift build
36
+ ```
37
+
38
+ Run the project's configured linter/formatter if present (`swiftlint`,
39
+ `swift-format lint`/`swiftformat --lint`). Read the exact error text and
40
+ classify it:
41
+
42
+ - **Compile error** (undefined symbol, type mismatch, wrong argument
43
+ count/label).
44
+ - **Concurrency/Sendable** (`Sendable` conformance error, an actor-
45
+ isolation error, a Swift 6 strict-concurrency diagnostic).
46
+ - **Optional-binding warning** (a `guard`/`if let` the compiler flags as
47
+ always-succeeding or a value it infers as never-nil).
48
+ - **Dependency/toolchain** (Swift Package Manager resolution failure, a
49
+ CocoaPods/Carthage mismatch, an Xcode/Swift toolchain version the
50
+ project's minimum predates).
51
+ - **Lint/format finding** (SwiftLint rule, swift-format/swiftformat
52
+ diagnostic).
53
+ - **Failing test** blocking a scheme that runs tests as part of build.
54
+
55
+ ### Step 2: Fix by category
56
+
57
+ **Concurrency/Sendable:** read exactly what the compiler says is
58
+ crossing the boundary unsafely. If the type's mutable state genuinely
59
+ needs protecting, isolate it with an `actor` or `@MainActor`; if it is
60
+ genuinely immutable, conform it to `Sendable` properly (all stored
61
+ properties `Sendable`, or an explicit, justified conformance). Only use
62
+ `@unchecked Sendable` when you can state in the report exactly why the
63
+ type's access pattern is safe despite the compiler being unable to prove
64
+ it — never as a default move to clear the error.
65
+
66
+ **Optional-binding warning:** fix the actual type/control-flow issue the
67
+ compiler is pointing at (a value that genuinely cannot be nil should not
68
+ be declared `Optional`; a value that can be nil needs the `guard`/`if
69
+ let` the compiler is questioning). Never force-unwrap (`!`) to silence
70
+ the warning instead of addressing why the compiler flagged it.
71
+
72
+ **Dependency/toolchain:** for a Swift Package Manager resolution
73
+ failure, check `Package.resolved` against `Package.swift`'s declared
74
+ requirements before bumping a version by hand; for a toolchain mismatch,
75
+ confirm the project's actual minimum Swift/Xcode version before changing
76
+ `swift-tools-version` or the deployment target just to make an error
77
+ disappear.
78
+
79
+ **Lint/format finding:** fix the underlying issue the rule names (a real
80
+ force-unwrap, a genuinely too-long function, an unused variable). Never
81
+ add a blanket `// swiftlint:disable` covering more than the one flagged
82
+ line, and never disable a rule repository-wide in `.swiftlint.yml` to
83
+ clear one finding without discussing why the rule itself is wrong for
84
+ this codebase.
85
+
86
+ **Failing test:** read the failure and fix the actual regression it
87
+ caught; do not delete, skip (`.disabled()`/`XCTSkip` used to dodge
88
+ rather than genuinely skip an environment-specific case), or loosen the
89
+ test's assertion just to reach a green build.
90
+
91
+ ### Step 3: Verify
92
+
93
+ ```bash
94
+ xcodebuild build -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'
95
+ xcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'
96
+ ```
97
+
98
+ Re-run the project's linter/formatter if it was part of the original
99
+ failure. All must exit 0 before reporting done.
100
+
101
+ ### Step 4: Report
102
+
103
+ ```
104
+ Fixed: Sendable conformance error in OrderCache
105
+ - Root cause: OrderCache held mutable state accessed from two tasks
106
+ with no isolation; converted it to an actor
107
+ - xcodebuild build/test both pass, swiftlint clean
108
+ ```
109
+
110
+ State the root cause in one sentence, not just "fixed the error."
111
+
112
+ ## Rules
113
+
114
+ - Find and fix the smallest change that addresses the actual root cause
115
+ — never widen a fix beyond what the failure requires.
116
+ - NEVER mark a type `@unchecked Sendable` to silence a strict-
117
+ concurrency error without stating, in the report, exactly why its
118
+ mutable state is safe.
119
+ - NEVER force-unwrap (`!`) or force-try (`try!`) just to clear a
120
+ compiler warning about an optional or a throwing call.
121
+ - NEVER add a blanket `// swiftlint:disable` (or disable a rule
122
+ repository-wide) to make one finding disappear.
123
+ - NEVER delete or skip a failing test to reach a green build.
124
+
125
+ ## Red Flags
126
+
127
+ | Rationalization | Why it is wrong |
128
+ |---|---|
129
+ | "I'll mark this `@unchecked Sendable`, it's the fastest way to clear the error" | Trades a compile-time data-race guarantee for an unchecked promise; audit the actual access pattern or add real isolation instead |
130
+ | "I'll force-unwrap this to silence the compiler's optional-binding warning" | The warning exists because the compiler cannot prove the value is non-nil; force-unwrapping does not fix that, it just moves the failure to a runtime crash |
131
+ | "I'll add `// swiftlint:disable force_unwrapping` for this whole file" | Silences every future violation in the file, not just the one the fix addressed — scope any disable as narrowly as the actual justified exception |
132
+ | "This test is flaky, I'll mark it `.disabled()` for now" | Hides a real regression or a genuine flake worth fixing (non-deterministic async wait, shared state) instead of fixing the underlying cause |
133
+
134
+ ## Verification
135
+
136
+ Do not report the fix done until all of the following hold:
137
+
138
+ - `xcodebuild build`/`swift build` and `xcodebuild test`/`swift test`
139
+ both exit 0.
140
+ - The project's linter/formatter (if configured) exits 0.
141
+ - The change is the smallest one that addresses the stated root cause —
142
+ no unrelated files touched.
143
+ - The report states the root cause in one sentence, not just "build now
144
+ passes."