@mrciphersmith/keryx 0.3.3 → 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 (67) hide show
  1. package/dist/cli.js +125 -51
  2. package/package.json +1 -1
  3. package/src/gdskills/bundled/install-manifest.json +231 -2
  4. package/src/gdskills/bundled/stacks/csharp-dotnet/agent-refs.json +4 -0
  5. package/src/gdskills/bundled/stacks/csharp-dotnet/governance/eval.json +1881 -0
  6. package/src/gdskills/bundled/stacks/csharp-dotnet/governance/scout.json +33 -0
  7. package/src/gdskills/bundled/stacks/csharp-dotnet/pack.json +38 -0
  8. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/coding-style.mdc +100 -0
  9. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/patterns.mdc +107 -0
  10. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/security.mdc +86 -0
  11. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/testing.mdc +89 -0
  12. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-build-fix/SKILL.md +143 -0
  13. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-build-fix/evals.json +77 -0
  14. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-code-review/SKILL.md +121 -0
  15. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-code-review/evals.json +77 -0
  16. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-implementation/SKILL.md +134 -0
  17. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-implementation/evals.json +76 -0
  18. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-testing/SKILL.md +130 -0
  19. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-testing/evals.json +77 -0
  20. package/src/gdskills/bundled/stacks/flutter-dart/agent-refs.json +4 -0
  21. package/src/gdskills/bundled/stacks/flutter-dart/governance/eval.json +1849 -0
  22. package/src/gdskills/bundled/stacks/flutter-dart/governance/scout.json +33 -0
  23. package/src/gdskills/bundled/stacks/flutter-dart/pack.json +41 -0
  24. package/src/gdskills/bundled/stacks/flutter-dart/rules/coding-style.mdc +98 -0
  25. package/src/gdskills/bundled/stacks/flutter-dart/rules/patterns.mdc +88 -0
  26. package/src/gdskills/bundled/stacks/flutter-dart/rules/security.mdc +91 -0
  27. package/src/gdskills/bundled/stacks/flutter-dart/rules/testing.mdc +101 -0
  28. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-build-fix/SKILL.md +134 -0
  29. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-build-fix/evals.json +79 -0
  30. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-code-review/SKILL.md +124 -0
  31. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-code-review/evals.json +74 -0
  32. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-implementation/SKILL.md +139 -0
  33. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-implementation/evals.json +77 -0
  34. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-testing/SKILL.md +134 -0
  35. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-testing/evals.json +74 -0
  36. package/src/gdskills/bundled/stacks/kotlin-android/agent-refs.json +4 -0
  37. package/src/gdskills/bundled/stacks/kotlin-android/governance/eval.json +1889 -0
  38. package/src/gdskills/bundled/stacks/kotlin-android/governance/scout.json +34 -0
  39. package/src/gdskills/bundled/stacks/kotlin-android/pack.json +38 -0
  40. package/src/gdskills/bundled/stacks/kotlin-android/rules/coding-style.mdc +89 -0
  41. package/src/gdskills/bundled/stacks/kotlin-android/rules/patterns.mdc +96 -0
  42. package/src/gdskills/bundled/stacks/kotlin-android/rules/security.mdc +90 -0
  43. package/src/gdskills/bundled/stacks/kotlin-android/rules/testing.mdc +89 -0
  44. package/src/gdskills/bundled/stacks/kotlin-android/skills/compose-implementation/SKILL.md +150 -0
  45. package/src/gdskills/bundled/stacks/kotlin-android/skills/compose-implementation/evals.json +77 -0
  46. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-build-fix/SKILL.md +151 -0
  47. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-build-fix/evals.json +76 -0
  48. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-code-review/SKILL.md +139 -0
  49. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-code-review/evals.json +78 -0
  50. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-testing/SKILL.md +131 -0
  51. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-testing/evals.json +77 -0
  52. package/src/gdskills/bundled/stacks/swift-ios/agent-refs.json +4 -0
  53. package/src/gdskills/bundled/stacks/swift-ios/governance/eval.json +1803 -0
  54. package/src/gdskills/bundled/stacks/swift-ios/governance/scout.json +32 -0
  55. package/src/gdskills/bundled/stacks/swift-ios/pack.json +38 -0
  56. package/src/gdskills/bundled/stacks/swift-ios/rules/coding-style.mdc +92 -0
  57. package/src/gdskills/bundled/stacks/swift-ios/rules/patterns.mdc +112 -0
  58. package/src/gdskills/bundled/stacks/swift-ios/rules/security.mdc +78 -0
  59. package/src/gdskills/bundled/stacks/swift-ios/rules/testing.mdc +90 -0
  60. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-build-fix/SKILL.md +144 -0
  61. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-build-fix/evals.json +75 -0
  62. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-code-review/SKILL.md +122 -0
  63. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-code-review/evals.json +75 -0
  64. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-testing/SKILL.md +131 -0
  65. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-testing/evals.json +75 -0
  66. package/src/gdskills/bundled/stacks/swift-ios/skills/swiftui-implementation/SKILL.md +149 -0
  67. package/src/gdskills/bundled/stacks/swift-ios/skills/swiftui-implementation/evals.json +76 -0
@@ -0,0 +1,1803 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "reports": [
4
+ {
5
+ "schemaVersion": "1.0.0",
6
+ "skillId": "swift-ios/swiftui-implementation",
7
+ "strictness": "high",
8
+ "trials": 10,
9
+ "triggerAccuracy": {
10
+ "truePositive": 1,
11
+ "falsePositive": 0,
12
+ "positives": 7,
13
+ "negatives": 7
14
+ },
15
+ "evidence": "authored",
16
+ "scenarios": [
17
+ {
18
+ "id": "trigger-positive-1",
19
+ "kind": "trigger-positive",
20
+ "prompt": "Add a detail screen that fetches and displays an order from a backend",
21
+ "strictness": "high",
22
+ "trials": 1,
23
+ "passes": 0,
24
+ "passRate": 0,
25
+ "passAtK": 0,
26
+ "grader": "trigger-rank-fork-family",
27
+ "status": "ran",
28
+ "deterministic": true
29
+ },
30
+ {
31
+ "id": "trigger-positive-2",
32
+ "kind": "trigger-positive",
33
+ "prompt": "This screen's counter should live in the view since only it touches it",
34
+ "strictness": "high",
35
+ "trials": 1,
36
+ "passes": 0,
37
+ "passRate": 0,
38
+ "passAtK": 0,
39
+ "grader": "trigger-rank-fork-family",
40
+ "status": "ran",
41
+ "deterministic": true
42
+ },
43
+ {
44
+ "id": "trigger-positive-3",
45
+ "kind": "trigger-positive",
46
+ "prompt": "The child needs to toggle a setting that lives on its parent screen",
47
+ "strictness": "high",
48
+ "trials": 1,
49
+ "passes": 0,
50
+ "passRate": 0,
51
+ "passAtK": 0,
52
+ "grader": "trigger-rank-fork-family",
53
+ "status": "ran",
54
+ "deterministic": true
55
+ },
56
+ {
57
+ "id": "trigger-positive-4",
58
+ "kind": "trigger-positive",
59
+ "prompt": "Hook up a settings toggle whose state a parent view actually owns",
60
+ "strictness": "high",
61
+ "trials": 1,
62
+ "passes": 0,
63
+ "passRate": 0,
64
+ "passAtK": 0,
65
+ "grader": "trigger-rank-fork-family",
66
+ "status": "ran",
67
+ "deterministic": true
68
+ },
69
+ {
70
+ "id": "trigger-positive-5",
71
+ "kind": "trigger-positive",
72
+ "prompt": "Build a profile screen for an app targeting iOS 17 and later",
73
+ "strictness": "high",
74
+ "trials": 1,
75
+ "passes": 0,
76
+ "passRate": 0,
77
+ "passAtK": 0,
78
+ "grader": "trigger-rank-fork-family",
79
+ "status": "ran",
80
+ "deterministic": true
81
+ },
82
+ {
83
+ "id": "trigger-positive-6",
84
+ "kind": "trigger-positive",
85
+ "prompt": "Kick off a fetch when this screen appears and cancel it if the user navigates away",
86
+ "strictness": "high",
87
+ "trials": 1,
88
+ "passes": 0,
89
+ "passRate": 0,
90
+ "passAtK": 0,
91
+ "grader": "trigger-rank-fork-family",
92
+ "status": "ran",
93
+ "deterministic": true
94
+ },
95
+ {
96
+ "id": "trigger-positive-7",
97
+ "kind": "trigger-positive",
98
+ "prompt": "This screen makes a network call and I need it to not block the main thread",
99
+ "strictness": "high",
100
+ "trials": 1,
101
+ "passes": 1,
102
+ "passRate": 1,
103
+ "passAtK": 1,
104
+ "grader": "trigger-rank-fork-family",
105
+ "status": "ran",
106
+ "deterministic": true
107
+ },
108
+ {
109
+ "id": "trigger-negative-1",
110
+ "kind": "trigger-negative",
111
+ "prompt": "Implement this feature in Kotlin for Android with Jetpack Compose",
112
+ "strictness": "high",
113
+ "trials": 1,
114
+ "passes": 1,
115
+ "passRate": 1,
116
+ "passAtK": 1,
117
+ "grader": "trigger-rank-fork-family",
118
+ "status": "ran",
119
+ "deterministic": true
120
+ },
121
+ {
122
+ "id": "trigger-negative-2",
123
+ "kind": "trigger-negative",
124
+ "prompt": "Add this Flutter widget with a StatefulWidget",
125
+ "strictness": "high",
126
+ "trials": 1,
127
+ "passes": 1,
128
+ "passRate": 1,
129
+ "passAtK": 1,
130
+ "grader": "trigger-rank-fork-family",
131
+ "status": "ran",
132
+ "deterministic": true
133
+ },
134
+ {
135
+ "id": "trigger-negative-3",
136
+ "kind": "trigger-negative",
137
+ "prompt": "Implement this C#/.NET service feature with dependency injection",
138
+ "strictness": "high",
139
+ "trials": 1,
140
+ "passes": 1,
141
+ "passRate": 1,
142
+ "passAtK": 1,
143
+ "grader": "trigger-rank-fork-family",
144
+ "status": "ran",
145
+ "deterministic": true
146
+ },
147
+ {
148
+ "id": "trigger-negative-4",
149
+ "kind": "trigger-negative",
150
+ "prompt": "Implement this React component with the new form fields",
151
+ "strictness": "high",
152
+ "trials": 1,
153
+ "passes": 1,
154
+ "passRate": 1,
155
+ "passAtK": 1,
156
+ "grader": "trigger-rank-fork-family",
157
+ "status": "ran",
158
+ "deterministic": true
159
+ },
160
+ {
161
+ "id": "trigger-negative-5",
162
+ "kind": "trigger-negative",
163
+ "prompt": "Write the equivalent screen in Android using LiveData",
164
+ "strictness": "high",
165
+ "trials": 1,
166
+ "passes": 1,
167
+ "passRate": 1,
168
+ "passAtK": 1,
169
+ "grader": "trigger-rank-fork-family",
170
+ "status": "ran",
171
+ "deterministic": true
172
+ },
173
+ {
174
+ "id": "trigger-negative-6",
175
+ "kind": "trigger-negative",
176
+ "prompt": "Implement a new endpoint in a Go cmd/api binary",
177
+ "strictness": "high",
178
+ "trials": 1,
179
+ "passes": 1,
180
+ "passRate": 1,
181
+ "passAtK": 1,
182
+ "grader": "trigger-rank-fork-family",
183
+ "status": "ran",
184
+ "deterministic": true
185
+ },
186
+ {
187
+ "id": "trigger-negative-7",
188
+ "kind": "trigger-negative",
189
+ "prompt": "Add unit tests for this Swift view model",
190
+ "strictness": "high",
191
+ "trials": 1,
192
+ "passes": 1,
193
+ "passRate": 1,
194
+ "passAtK": 1,
195
+ "grader": "trigger-rank-fork-family",
196
+ "status": "ran",
197
+ "deterministic": true
198
+ },
199
+ {
200
+ "id": "state-ownership-binding",
201
+ "kind": "behavior",
202
+ "prompt": "I have a screen with a toggle whose value the parent view actually owns and reacts to elsewhere on screen. How should the child view that shows the toggle be wired up?",
203
+ "strictness": "high",
204
+ "trials": 10,
205
+ "passes": 10,
206
+ "passRate": 1,
207
+ "passAtK": 1,
208
+ "grader": "judge",
209
+ "status": "ran",
210
+ "trialRecords": [
211
+ {
212
+ "output": "Since the parent owns the value and reacts to it, the child should not own a copy — it needs read access to the current value plus a way to write changes back up. That is exactly what `@Binding` expresses.\n\n```swift\nstruct SettingsToggle: View {\n @Binding var isEnabled: Bool\n\n var body: some View {\n Toggle(\"Enable feature\", isOn: $isEnabled)\n }\n}\n```\n\nThe parent declares and owns the source of truth and passes a projected binding down:\n\n```swift\nstruct SettingsView: View {\n @State private var isEnabled = false\n\n var body: some View {\n VStack {\n SettingsToggle(isEnabled: $isEnabled)\n Text(isEnabled ? \"On — extra controls shown\" : \"Off\")\n }\n }\n}\n```\n\nWhy this shape and not the alternatives:\n\n- **Not `@State` in the child.** That would create a second, independent copy. The toggle would flip locally and the parent's other UI would never update — the two would drift out of sync.\n- **Not `@Environment`.** The dependency is not ambient to a whole subtree; it is one specific parent-child relationship. Pushing a single flag into the environment makes the child harder to reason about and to preview/reuse.\n- **Not passing the raw `Bool` and an `onChange` closure.** That works but reinvents what `@Binding` already expresses, and loses the automatic two-way wiring that `Toggle(isOn:)` expects.\n\nTwo details worth getting right:\n\n1. **If the source of truth is an `@Observable` model you don't own**, the child should take the model plus use `@Bindable` to get bindings into it, rather than `@Binding` on a plain `Bool`:\n\n```swift\nstruct SettingsToggle: View {\n @Bindable var model: SettingsModel\n\n var body: some View {\n Toggle(\"Enable feature\", isOn: $model.isEnabled)\n }\n}\n```\n\n2. **The parent must actually own the storage** — `@State private var isEnabled` on the parent (or an `@Observable` model the parent holds via `@State`). A `@Binding` only ever points back at someone else's owned state; if no ancestor owns it, the value has nowhere stable to live.\n\nSo: parent owns it (`@State` or an `@Observable` model), child receives a `@Binding` (or a `@Bindable` model reference when the value lives in an observable type), and the toggle binds its `isOn` to that projection. That keeps a single source of truth while letting both the child and the rest of the parent's screen stay in sync.",
213
+ "outputSha256": "c8a98e0ee07a4eb65942e03e9f59b7ccd868d09d3c39f9afba8c503d8698a414",
214
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
215
+ "deterministic": [],
216
+ "judge": {
217
+ "verdict": "pass",
218
+ "reason": "Criterion 1: child declares `@Binding var isEnabled: Bool`. Criterion 2: parent shows `SettingsToggle(isEnabled: $isEnabled)` from its own `@State private var isEnabled`. Criterion 3: explains child @State would be a second independent copy so parent's other UI never updates and they drift out of sync. No fail criterion met."
219
+ },
220
+ "passed": true
221
+ },
222
+ {
223
+ "output": "The child should take a `@Binding` to the toggle's value, not own it with `@State`.\n\n```swift\nstruct NotificationToggle: View {\n @Binding var isEnabled: Bool\n\n var body: some View {\n Toggle(\"Notifications\", isOn: $isEnabled)\n }\n}\n```\n\nThe parent owns the source of truth and passes a binding down:\n\n```swift\nstruct SettingsView: View {\n @State private var notificationsEnabled = false // parent owns it\n\n var body: some View {\n Form {\n NotificationToggle(isEnabled: $notificationsEnabled)\n // The parent also reads/reacts to the same value here:\n Text(notificationsEnabled ? \"On\" : \"Off\")\n }\n }\n}\n```\n\nWhy `@Binding` and not `@State`:\n- `@State` in the child would create a *second*, independent copy — the toggle would flip locally but the parent's value (and anything else on screen reacting to it) would never change. That is exactly the bug this choice avoids.\n- `@Binding` is a two-way reference into the parent's storage: the child can read and write it, and the parent sees every change and re-renders anything depending on it.\n\nA few things to keep in mind:\n\n- **The parent must own it** with `@State` (view-owned), `@StateObject`/`@Observable`, or as an `@Environment` value — whichever ownership pattern matches your deployment target and how widely the value is shared. `@Binding` is only ever the *downstream* view of someone else's storage.\n- **If the value lives on an `@Observable` model** (iOS 17+) that the child does *not* own, don't take a `@Binding` to the model — take the model by plain reference and use `@Bindable`:\n\n ```swift\n struct NotificationToggle: View {\n @Bindable var settings: Settings // Settings is @Observable\n var body: some View {\n Toggle(\"Notifications\", isOn: $settings.notificationsEnabled)\n }\n }\n ```\n\n `@Bindable` is the right tool when the binding needs to drill into a property of an observable object the child doesn't own.\n\n- **Don't mirror it with local state.** Avoid the anti-pattern of copying the binding into a `@State` in `onAppear` and syncing it back — that reintroduces the divergence `@Binding` exists to prevent.\n\nSo: parent owns the value (`@State` or an `@Observable` model), child takes `@Binding` (for a plain value) or `@Bindable` (for a property on a model it doesn't own).",
224
+ "outputSha256": "9d85f9e806a0d74194ee85c424a4e48f9488dc3de0b5e1c7d2a5f0f5e52e79cc",
225
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
226
+ "deterministic": [],
227
+ "judge": {
228
+ "verdict": "pass",
229
+ "reason": "Criterion 1: child declares `@Binding var isEnabled: Bool`. Criterion 2: parent owns `@State private var notificationsEnabled` and passes `NotificationToggle(isEnabled: $notificationsEnabled)`. Criterion 3: explains child @State would be a second independent copy so parent's value never changes. No fail criterion met."
230
+ },
231
+ "passed": true
232
+ },
233
+ {
234
+ "output": "The child view should not own the toggle's storage — it should declare the value as a `@Binding` and let the parent keep the actual storage (`@State`, or a `@Bindable`/`@Observable` model property). That gives the parent the source of truth it needs to react to the change elsewhere on screen, while the child gets read/write access without duplicating storage.\n\nConcretely:\n\n```swift\nstruct NotificationToggleRow: View {\n @Binding var isEnabled: Bool\n\n var body: some View {\n Toggle(\"Notifications\", isOn: $isEnabled)\n }\n}\n```\n\nParent side, if the parent owns it directly:\n\n```swift\nstruct SettingsView: View {\n @State private var notificationsEnabled = false\n\n var body: some View {\n VStack {\n NotificationToggleRow(isEnabled: $notificationsEnabled)\n Text(notificationsEnabled ? \"On\" : \"Off\") // parent reacts here\n }\n }\n}\n```\n\nOr, if the value lives on an `@Observable` model the parent owns, move the optional module import out of my head and just mark up the child as taking a binding into an existing binding. There are two practical shapes:\n\n- The parent passes `$model.notificationsEnabled` down. For an `@Observable` model the parent holds as `@State`, `$model.notificationsEnabled` is a valid binding, so the child stays `@Binding var isEnabled: Bool` and does not need to know about the model at all.\n- If the child needs to bind to several properties of an `@Observable` model it does not own, give the child `@Bindable var model: Model` and use `$model.notificationsEnabled` inside it. Use this only when the child genuinely needs multiple bindings into the model; for a single value, a plain `@Binding` keeps the child's dependency narrower.\n\nDo not use `@State` in the child for this. A local `@State` would create a second copy of the value that the parent never sees, so the parent's \"reacts to it elsewhere on screen\" logic would not fire. Do not use `@StateObject`/`ObservableObject` here either if the deployment target supports `@Observable` — that pattern is about ownership, and this child explicitly does not own the value.\n\nTwo details worth getting right:\n\n- The binding's storage must live at or above the point where the parent reacts. If the parent passes the binding down and also displays a derived value (`Text(notificationsEnabled ? ...)`), the `@State` belongs on that parent, not on some intermediate ancestor, or the reaction and the storage could drift.\n- If the parent needs to perform an async side effect when the toggle flips (say, syncing the setting), keep the storage as above and attach the effect with `.onChange(of: notificationsEnabled) { ... }` or `.task(id: notificationsEnabled) { ... }` on the parent, rather than pushing that logic into the child. `.task(id:)` is the better fit when the effect should cancel and restart on each change; `.onChange` when it should just fire.\n\nBottom line: child takes `@Binding` (or `@Bindable` into an `@Observable` model it does not own); parent keeps the storage in `@State` or on its own model and owns the reaction.",
235
+ "outputSha256": "8278957cecfd4cd0d504fba6140474bd3b43fe7df65cb462235cba7c3bcf933c",
236
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
237
+ "deterministic": [],
238
+ "judge": {
239
+ "verdict": "pass",
240
+ "reason": "Criterion 1: child declares `@Binding var isEnabled: Bool`. Criterion 2: parent shows `NotificationToggleRow(isEnabled: $notificationsEnabled)` from its own `@State private var notificationsEnabled`. Criterion 3: explains a local `@State` creates a second copy the parent never sees, so its reaction logic wouldn't fire. No fail criterion met."
241
+ },
242
+ "passed": true
243
+ },
244
+ {
245
+ "output": "The child view should take the toggle's value as a `@Binding`, not own it with `@State`. Ownership stays with the parent; the child only reads and mutates it.\n\n```swift\nstruct ToggleRow: View {\n @Binding var isEnabled: Bool\n\n var body: some View {\n Toggle(\"Enabled\", isOn: $isEnabled)\n }\n}\n```\n\nThe parent owns the source of truth. On iOS 17+ that is typically `@State` for local state, or `@State`/`@Environment` holding an `@Observable` model; on an older target, an `ObservableObject` via `@StateObject`/`@EnvironmentObject`. The parent passes a binding in with `$`:\n\n```swift\nstruct SettingsView: View {\n @State private var isEnabled = false\n\n var body: some View {\n VStack {\n ToggleRow(isEnabled: $isEnabled)\n Text(isEnabled ? \"On\" : \"Off\") // parent reacts here\n }\n }\n}\n```\n\nKey points:\n\n- Do **not** use `@State` in the child for a value the parent owns — that creates a second, divergent source of truth and the parent's \"elsewhere on screen\" reaction won't track the toggle.\n- If the source of truth is an `@Observable` model that the child does **not** own (it's held by a parent or the environment), and the child needs a binding into one of its properties, use `@Bindable` rather than `@Binding` directly:\n\n```swift\nstruct ToggleRow: View {\n @Bindable var settings: Settings // @Observable model, not owned here\n\n var body: some View {\n Toggle(\"Enabled\", isOn: $settings.isEnabled)\n }\n}\n```\n\n- If instead only this view needs the value and the parent does *not* react to it, then the child owning it with `@State` is correct — but that is not the case you described.\n\nSo: parent owns (`@State`, `@StateObject`, or an `@Observable` model held above), child receives it as `@Binding` (or `@Bindable` when binding into a model it doesn't own), and the parent's other UI reads the same owned value so it stays in sync.",
246
+ "outputSha256": "69201760e0efb2f0de32d6a9cb683878b1267fa72b45afe9b090ffcfbcc5d004",
247
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
248
+ "deterministic": [],
249
+ "judge": {
250
+ "verdict": "pass",
251
+ "reason": "Criterion 1: child declares `@Binding var isEnabled: Bool` (not @State). Criterion 2: parent shows `ToggleRow(isEnabled: $isEnabled)` from its own `@State private var isEnabled`. Criterion 3: explains child @State creates a divergent source of truth so parent's reaction won't track the toggle. No fail criterion holds."
252
+ },
253
+ "passed": true
254
+ },
255
+ {
256
+ "output": "The child view that shows the toggle should not own the value — it needs a two-way binding into state the parent owns.\n\nConcretely:\n\n- **Parent owns the state.** The parent declares the source of truth with `@State` (e.g. `@State private var isEnabled = false`) if the parent itself created that value, and reacts to it wherever else it needs to (another child, a computed property, an `.onChange`, a `.task(id:)`, etc.).\n- **Child takes a `@Binding`.** The child view that renders the `Toggle` declares `@Binding var isEnabled: Bool` and passes it straight to `Toggle(\"…\", isOn: $isEnabled)`. Mutating the toggle mutates the parent's state directly; there is one source of truth and no syncing logic.\n\n```swift\nstruct ParentView: View {\n @State private var isEnabled = false // source of truth\n\n var body: some View {\n VStack {\n ToggleRow(isEnabled: $isEnabled) // pass the binding down\n Text(isEnabled ? \"On\" : \"Off\") // parent reacts elsewhere\n }\n }\n}\n\nstruct ToggleRow: View {\n @Binding var isEnabled: Bool // child does NOT own it\n\n var body: some View {\n Toggle(\"Enabled\", isOn: $isEnabled)\n }\n}\n```\n\nKey points and edge cases:\n\n- **Do not use `@State` in the child** for this value. A child `@State` would create a second source of truth that desyncs from the parent the moment the parent's value changes.\n- **If the value lives in an `@Observable` model** (iOS 17+) rather than a plain `@State`, and a child needs a binding into a model it does not own, use `@Bindable`: declare `@Bindable var model: MyModel` in the child and use `$model.isEnabled`. The parent still owns the model (e.g. via `@State` or injected through `@Environment`).\n- **If the value is ambient to a subtree** rather than owned by one specific parent, prefer `@Environment` (or an `@Observable` model in the environment) with `@Bindable` at the point of the binding, instead of threading a `@Binding` through several intermediate views that do not themselves care about it.\n- **Match the project's existing pattern.** Check a neighboring view first: if the codebase is still on `ObservableObject`/`@Published` (pre-iOS-17 target), the equivalent is `@ObservedObject`/`@StateObject` in the parent and `@ObservedObject` (or an explicit `Binding`) in the child — but do not introduce the legacy pattern in new code on an iOS 17+ target.\n\nSo: parent `@State` (the owner), child `@Binding` (a view into it) — or `@Bindable` if the parent hands down an `@Observable` model.",
257
+ "outputSha256": "0f8df16199fbbdc78ae99cb141bd9c140cc669e809fa858784cf01b1a9a41221",
258
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
259
+ "deterministic": [],
260
+ "judge": {
261
+ "verdict": "pass",
262
+ "reason": "Criterion 1: child declares `@Binding var isEnabled: Bool` (\"child does NOT own it\"). Criterion 2: parent shows `ToggleRow(isEnabled: $isEnabled)` from its own `@State private var isEnabled`. Criterion 3: explains child @State \"would create a second source of truth that desyncs from the parent.\" No fail criterion met."
263
+ },
264
+ "passed": true
265
+ },
266
+ {
267
+ "output": "The child should take a `@Binding` to that value, not own it. Since the parent actually owns the state and reacts to it elsewhere, the state's ownership belongs in the parent; the child view only needs the ability to read and mutate it, which is exactly what `@Binding` expresses.\n\nConcretely, assuming the project is on iOS 17+ and the value is a simple `Bool` the parent owns with `@State`:\n\n```swift\nstruct ParentView: View {\n @State private var isEnabled = false\n\n var body: some View {\n ChildToggleView(isEnabled: $isEnabled)\n // ...and elsewhere on screen, something that reacts to isEnabled\n }\n}\n\nstruct ChildToggleView: View {\n @Binding var isEnabled: Bool\n\n var body: some View {\n Toggle(\"Enabled\", isOn: $isEnabled)\n }\n}\n```\n\nKey points for wiring this up:\n\n- Own in the parent, bind in the child. The parent declares the source of truth (`@State` for view-owned state). The child takes `@Binding var isEnabled: Bool` and passes `$isEnabled` straight into `Toggle`'s `isOn`. The child never declares its own `@State` for this value — that would create a second source of truth that drifts from what the parent renders elsewhere.\n\n- Pass it with `$`. When constructing the child, hand it `$isEnabled` (the projected value of the parent's state), not `isEnabled`.\n\n- If the value lives inside an `@Observable` model rather than a plain `@State`, and the child does not own that model, use `@Bindable` in the child instead of `@Binding` where you need to project bindings off the model — or keep `@Binding` to a single field of it. The ownership decision is the same: the parent (or its owning model) holds the source of truth.\n\n- On an older deployment target still on `ObservableObject`, the same shape applies: parent owns it via `@StateObject`/`@ObservedObject` (or `@State` for a plain value), child takes `@Binding`.\n\nThe rule of thumb: `@State` is for state the view itself creates and owns; `@Binding` is for state the view does not own but must mutate — which is exactly this case. Confirm by reading a neighboring view in the project to see which pattern (plain `@State` vs `@Observable` model) the parent is already using, and match it.",
268
+ "outputSha256": "1ebda50d1f92645572e90385a859a3e5b2df8210b28c35c90d4d430400fefded",
269
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
270
+ "deterministic": [],
271
+ "judge": {
272
+ "verdict": "pass",
273
+ "reason": "Criterion 1: names `@Binding var isEnabled: Bool` for the child. Criterion 2: parent passes `ChildToggleView(isEnabled: $isEnabled)` from its own `@State private var isEnabled`. Criterion 3: explains a child `@State` would be 'a second source of truth that drifts from what the parent renders elsewhere.' No fail criterion holds."
274
+ },
275
+ "passed": true
276
+ },
277
+ {
278
+ "output": "The child view should take that value as a `@Binding`, not `@State`.\n\n`@State` means \"this view owns and is the source of truth for this value.\" That's the wrong ownership shape here — the parent owns it and reacts to changes elsewhere. If the child declared `@State var isOn: Bool` and the parent passed in a plain `Bool`, the child would get a private copy; flipping the toggle would mutate only the child's copy, and the parent (and its other UI) would never see the change. So:\n\n```swift\nstruct SomeToggleRow: View {\n @Binding var isOn: Bool\n\n var body: some View {\n Toggle(\"Enable\", isOn: $isOn)\n }\n}\n```\n\nThe parent, which owns the value, passes it with the `$` projection:\n\n```swift\nstruct ParentView: View {\n @State private var isOn = false\n\n var body: some View {\n SomeToggleRow(isOn: $isOn)\n // ... other UI that reacts to isOn\n }\n}\n```\n\nA few details worth pinning down, depending on how the parent stores the value:\n\n- **If the parent owns it as plain `@State`** (or `@AppStorage`, etc.), pass it down with `$isOn` as above. That's the standard answer.\n- **If the parent owns it inside an `@Observable` model** (iOS 17+), the child still declares `@Binding var isOn: Bool`. The intermediate view doesn't need anything special — it just forwards `$model.isOn`. If the *child* receives the whole model object rather than an individual binding and needs to make bindings into it, it declares `@Bindable var model: TheModel` (not `@State`, not `@StateObject`) and then writes `$model.isOn` inside its own body.\n- **If the parent is still on the legacy pattern** (`ObservableObject` + `@Published`), the child is still `@Binding`, and the parent forwards `$viewModel.isOn`. Same ownership rule, different parent-side machinery.\n\nThe invariant that matters: `@Binding` when the value is owned elsewhere and this view only presents and mutates it; `@State` only when this view is genuinely the source of truth. A toggle reflecting parent-owned, parent-reacted-to state is textbook `@Binding`.\n\nOne thing to avoid: don't store the passed-in value into a local `@State` inside the child as a supposed sync mechanism. That reintroduces the private-copy problem (and the classic \"child holds a stale copy after the parent changes it\" bug) — with a binding, the child reads and writes the parent's actual value, so there's nothing to sync.\n\nSince the parent \"reacts to it elsewhere on screen,\" that reaction happens off the parent's owned `isOn` and flows naturally through the binding — no callbacks or delegate closures are needed just to communicate the change back up.",
279
+ "outputSha256": "c2bfd684b218b7d6112bc2255a8dda10d25118df0c3d6e931a4900b8c181f2a3",
280
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
281
+ "deterministic": [],
282
+ "judge": {
283
+ "verdict": "pass",
284
+ "reason": "Criterion 1: child declares `@Binding var isOn: Bool` (not @State). Criterion 2: parent shows `SomeToggleRow(isOn: $isOn)` from its own `@State private var isOn`. Criterion 3: explains a local @State would give a private copy so flipping only mutates the child's copy and the parent never sees the change. No fail criterion holds."
285
+ },
286
+ "passed": true
287
+ },
288
+ {
289
+ "output": "The child view should take a `@Binding<Bool>`, not `@State`. `@State` makes the child the owner; a `@Binding` lets the child read and write a value the parent actually owns, so a toggle change propagates up and the parent's other reactions to it fire correctly.\n\nShape it like this:\n\n```swift\nstruct SettingsRowView: View {\n @Binding var isEnabled: Bool\n\n var body: some View {\n Toggle(\"Enabled\", isOn: $isEnabled)\n }\n}\n```\n\nThe parent owns the source of truth and passes a binding down. Where the parent itself stores that value depends on what else owns it:\n\n- If the parent view is the true owner, the parent holds `@State private var isEnabled = false` and passes `$isEnabled`.\n- If the value lives in an `@Observable` model that the parent does not itself own (e.g. it was injected or passed in), the parent uses `@Bindable var model` (iOS 17+) and passes `$model.isEnabled`. On a pre-iOS-17 target, that is an `ObservableObject` owned with `@StateObject`/`@ObservedObject`, and you pass `$model.isEnabled`.\n- If the value is genuinely ambient to the whole subtree, the parent publishes it through the environment and the child reads it via `@Environment` — but reach for `@Binding` first unless the value really is shared ambient state, since a single owned value with a binding is the clearer expression of \"the parent owns this.\"\n\nA few things to get right:\n\n- Do not mirror the binding into a local `@State` inside the child and sync the two. That creates two sources of truth and they will drift. Read and write through the `@Binding` directly.\n- If the child needs local ephemeral UI state that is unrelated to the parent's value (e.g. an animation flag), that can stay `@State` in the child — just don't duplicate the parent-owned value.\n- Make sure the thing the parent passes is a real binding to its own storage (`$`), not a copy of the current value, or writes from the child won't reach the parent.\n\nSo: parent owns the value (`@State`, or `@Bindable`/`$model…` into an `@Observable` model), child takes `@Binding<Bool>`, and the toggle is bound with `$isEnabled`. That keeps one owner, and the parent's other on-screen reactions update because it holds the source of truth.",
290
+ "outputSha256": "03031075680e603b7e71be6bada4f569d6dd54da06aaab0e785e08777603dfe2",
291
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
292
+ "deterministic": [],
293
+ "judge": {
294
+ "verdict": "pass",
295
+ "reason": "Criterion 1: names `@Binding<Bool>` for the child's toggle param, not @State. Criterion 2: shows parent passing `$isEnabled` from its own `@State private var isEnabled`. Criterion 3: explains local @State makes the child the owner and creates two sources of truth that drift, so changes don't propagate. No fail criterion met."
296
+ },
297
+ "passed": true
298
+ },
299
+ {
300
+ "output": "The child view that shows the toggle should take a `@Binding<Bool>` — the parent owns the actual state via its own `@State` (or an `@Observable` model), and passes a binding down so the child can both read and mutate the value. The child does not create the state, so it must not use `@State` itself; that would give the child its own private copy that the parent never sees.\n\nConcretely:\n\n```swift\nstruct SettingsToggleRow: View {\n @Binding var isEnabled: Bool\n\n var body: some View {\n Toggle(\"Enabled\", isOn: $isEnabled)\n }\n}\n```\n\nParent:\n\n```swift\nstruct SettingsView: View {\n @State private var isEnabled = false\n\n var body: some View {\n VStack {\n SettingsToggleRow(isEnabled: $isEnabled)\n if isEnabled {\n Text(\"Something else reacts to the toggle\")\n }\n }\n }\n}\n```\n\nKey points for this ownership shape:\n\n- **Parent owns, child mutates.** `@State` in the parent is the single source of truth; `@Binding` in the child is just a two-way reference to it. This is exactly the `@Binding` case in the state-ownership rules: a child that mutates state it does not own.\n- **Don't reach for `@State` in the child.** A `@State` in the child is initialized once and then diverges from the parent's value — the parent's \"reacts elsewhere on screen\" logic would be driven by stale or never-updated data.\n- **If the parent's state lives in an `@Observable` model** (iOS 17+) rather than a plain `@State` value, the child receives the model and uses `@Bindable` to get a binding into it — `@Bindable var model: SettingsModel`, then `Toggle(..., isOn: $model.isEnabled)`. `@Binding` is for a plain value; `@Bindable` is the equivalent when the source is an `@Observable` class you do not own.\n- **Don't hoist it into `@Environment`** just to avoid passing it down. `@Environment` is for ambient dependencies shared across a subtree (theme, a session, a client). A single parent whose screen reacts to the value is a direct parent/child relationship — pass the binding explicitly so the data flow stays obvious.\n- **Legacy target caveat:** if the deployment target predates iOS 17 and the project uses `ObservableObject`, the same shape applies — the parent holds `@StateObject`/`ObservableObject` and the child gets a `@Binding` (or the object is passed and the child uses `@ObservedObject` only if it needs to *observe*, not to own).\n\nSo: `@Binding var isEnabled: Bool` in the child, sourced from the parent's owned state.",
301
+ "outputSha256": "ae17a0cf801d3cb0fcdd2cf2643c340be687f24f29c5a90faf592a9cedb039f0",
302
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
303
+ "deterministic": [],
304
+ "judge": {
305
+ "verdict": "pass",
306
+ "reason": "Criterion 1: names `@Binding var isEnabled: Bool` for the child toggle. Criterion 2: parent shows `SettingsToggleRow(isEnabled: $isEnabled)` from its own `@State private var isEnabled`. Criterion 3: explains child `@State` would be a private copy the parent never sees, driving stale data. No fail criterion met."
307
+ },
308
+ "passed": true
309
+ },
310
+ {
311
+ "output": "Because the parent owns the value and reacts to it elsewhere, the child should not hold its own copy — it should take a binding into the parent's state. Wire it like this:\n\n**Child view**\n\n```swift\nstruct SettingsToggleRow: View {\n @Binding var isEnabled: Bool\n\n var body: some View {\n Toggle(\"Enabled\", isOn: $isEnabled)\n }\n}\n```\n\nThe child declares `@Binding var isEnabled: Bool` and passes `$isEnabled` straight into `Toggle`. It never creates or owns the value; it only reads it and writes changes back up.\n\n**Parent view**\n\n```swift\nstruct SettingsView: View {\n @State private var isEnabled = false // the parent owns the value\n\n var body: some View {\n VStack {\n SettingsToggleRow(isEnabled: $isEnabled) // pass a binding down\n if isEnabled {\n Text(\"Enabled — showing extra options\") // parent reacts elsewhere\n }\n }\n }\n}\n```\n\n**Why this shape**\n\n- The parent has `@State private var isEnabled` — it owns the source of truth, which is exactly what you described (the parent reacts to the value elsewhere on screen).\n- The child gets a `@Binding`, so toggling in the child mutates the parent's state, and any other UI in the parent that reads `isEnabled` updates in the same render pass. There is one source of truth, not two copies that drift apart.\n- Do **not** give the child its own `@State private var isEnabled` — that creates an independent copy; the parent would never see the change and the screens would disagree.\n- Do **not** pass the raw `Bool` as a plain `let` and have the child try to mutate something it doesn't own — that won't compile, and it reflects a real ownership mismatch.\n\n**If the parent owns an `@Observable` model instead of plain `@State`**\n\nSame idea, but the child takes a binding into the model property via `@Bindable`:\n\n```swift\n@Observable @MainActor\nfinal class SettingsModel {\n var isEnabled = false\n}\n\nstruct SettingsToggleRow: View {\n @Bindable var model: SettingsModel\n\n var body: some View {\n Toggle(\"Enabled\", isOn: $model.isEnabled)\n }\n}\n```\n\n`@Bindable` is the tool for producing bindings into an `@Observable` object the child does not own — reach for it whenever the \"parent owns it, child edits it\" pattern runs through an observation-based model rather than a plain `@State` value.\n\nOne caveat tied to the project's deployment target: `@Observable`/`@Bindable` needs iOS 17+. On an older target, keep the parent on `ObservableObject` with `@Published var isEnabled` and pass a `@Binding` into the child through `$model.isEnabled` — the ownership shape (parent owns, child binds) is identical; only the observation mechanism differs. Whichever you use, pick the one that matches the rest of the codebase so this screen doesn't diverge from its neighbors.",
312
+ "outputSha256": "b74b15c7dd90ab225586fa506640ca4fe77fe088d2b6ec19f4401a6af2a98832",
313
+ "promptSha256": "e7938e5309f9d0daa55c651a6cdcc0b1e8307fa083482e00da3193491b60fc98",
314
+ "deterministic": [],
315
+ "judge": {
316
+ "verdict": "pass",
317
+ "reason": "Child declares `@Binding var isEnabled: Bool` (criterion 1). Parent owns `@State private var isEnabled` and passes `SettingsToggleRow(isEnabled: $isEnabled)` (criterion 2). Explicitly warns against child's own `@State`: 'creates an independent copy; the parent would never see the change' (criterion 3). No fail criterion met."
318
+ },
319
+ "passed": true
320
+ }
321
+ ]
322
+ },
323
+ {
324
+ "id": "mainactor-async-fetch",
325
+ "kind": "behavior",
326
+ "prompt": "A SwiftUI screen needs to fetch some data from the network when it appears and show a loading state while it waits. How should I structure the concurrency for this?",
327
+ "strictness": "high",
328
+ "trials": 10,
329
+ "passes": 10,
330
+ "passRate": 1,
331
+ "passAtK": 1,
332
+ "grader": "judge",
333
+ "status": "ran",
334
+ "trialRecords": [
335
+ {
336
+ "output": "Structure it around three things: **where the work runs, how it is scoped, and how the loading state is owned.**\n\n**1. Scope the fetch to the view's lifetime with `.task`**\n\n```swift\nstruct OrderDetailView: View {\n @State private var model = OrderDetailModel()\n let orderID: Order.ID\n\n var body: some View {\n content\n .task(id: orderID) {\n await model.load(orderID: orderID)\n }\n }\n\n @ViewBuilder\n private var content: some View {\n switch model.phase {\n case .idle, .loading:\n ProgressView()\n case .loaded(let order):\n OrderDetailContent(order: order)\n case .failed(let error):\n ErrorView(error: error) { Task { await model.load(orderID: orderID) } }\n }\n }\n}\n```\n\n`.task` is the right tool here specifically because it **cancels automatically when the view disappears** and **re-runs when `id` changes** (e.g. navigating from one order to another). Do not use `.onAppear { Task { ... } }` — that task is not tied to the view's lifetime, so it keeps running after the view is gone and you get a stale write into state that no longer represents what's on screen.\n\n**2. Isolate UI-touching state to the main actor**\n\n```swift\n@MainActor\n@Observable\nfinal class OrderDetailModel {\n enum Phase {\n case idle, loading, loaded(Order), failed(Error)\n }\n\n private(set) var phase: Phase = .idle\n private let client: OrderClient // protocol-typed dependency\n\n init(client: OrderClient) { self.client = client }\n\n func load(orderID: Order.ID) async {\n phase = .loading\n do {\n let order = try await client.order(id: orderID)\n // If we were cancelled mid-flight, don't overwrite state.\n try Task.checkCancellation()\n phase = .loaded(order)\n } catch is CancellationError {\n // View went away or id changed; leave state alone.\n } catch {\n phase = .failed(error)\n }\n }\n}\n```\n\nKey points:\n\n- `@MainActor` on the model means every mutation of `phase` and every read from the view is on the main actor by construction — you never hand-hop back to the main thread manually.\n- `async`/`await` carries the suspension through; there is no completion handler to capture `self` strongly or to forget to call on the right queue.\n- `OrderClient` is a protocol so this is testable with an async fake, and `await client.order(id:)` does the network I/O off the main actor inside the actor/`URLSession` boundary while the caller stays main-actor-isolated.\n\n**3. Own the loading state explicitly, not implicitly**\n\nModel the three (or four) states as an enum rather than `isLoading: Bool` + `optionalData` + `optionalError`. The enum makes it impossible to be \"loading and failed and loaded\" at once, and the `switch` in the view forces you to handle every case. This is the piece most people skip and it is the one that prevents the classic \"spinner and error and stale content all visible simultaneously\" bug.\n\n**Cancellation detail worth getting right**\n\nIf `load` is re-entered (rapid id change, retry tap), the previous task's `phase = .loaded(...)` write can land after the new load started. Guarding with `try Task.checkCancellation()` after the `await` — plus the explicit `catch is CancellationError` — is what keeps a cancelled in-flight request from clobbering the newer state. `.task(id:)` cancels the old task for you; the model just needs to honor that cancellation instead of swallowing it.\n\n**What not to do**\n\n- Don't fetch from `init` or from a computed property — no cancellation, no re-run on id change, and it makes the view un-previewable.\n- Don't create an unstructured `Task { }` in `.onAppear` for something that should die with the view.\n- Don't store two booleans (`isLoading`, `didFail`) and hope they stay consistent — use the enum.\n- Don't spawn the fetch on a detached task or a background actor just to \"get off the main thread\"; `URLSession`'s async API is already non-blocking, and staying main-actor-isolated for state is what you want.",
337
+ "outputSha256": "ba032df1d0e881b54a660f7e4b4cc87f40e3f5fb4f366688d50bf9014179c814",
338
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
339
+ "deterministic": [],
340
+ "judge": {
341
+ "verdict": "pass",
342
+ "reason": "Uses `.task(id: orderID)` as fetch entry point (criterion 1), explicitly warns against `.onAppear { Task {} }`. Model is `@MainActor @Observable` with `phase` state (criterion 2). States `.task` cancels automatically when view disappears and adds `Task.checkCancellation()`/`catch is CancellationError` (criterion 3). No fail criterion holds."
343
+ },
344
+ "passed": true
345
+ },
346
+ {
347
+ "output": "Structure it so the fetch is tied to the view's lifetime, runs off the main thread, and hands results back to main-actor state. Concretely:\n\n**1. Own the state on a `@MainActor` observable model (or directly on the view).**\n\nOn iOS 17+, make the model `@Observable` and mark it `@MainActor`, then own it with `@State`:\n\n```swift\n@MainActor\n@Observable\nfinal class FeedModel {\n enum State {\n case idle\n case loading\n case loaded([Item])\n case failed(Error)\n }\n private(set) var state: State = .idle\n\n private let client: FeedClient // protocol-typed dependency\n\n init(client: FeedClient) { self.client = client }\n\n func load() async {\n state = .loading\n do {\n let items = try await client.fetchItems()\n state = .loaded(items)\n } catch {\n state = .failed(error)\n }\n }\n}\n```\n\nThe `@MainActor` annotation is what lets `load()` touch `state` directly without hopping actors manually — every mutation happens on the main actor, and the `await` suspends the main actor while the network call is in flight (it does not block the UI). On an older deployment target, the equivalent is `@MainActor final class FeedModel: ObservableObject` with `@Published private(set) var state`, owned via `@StateObject`.\n\n**2. Kick the fetch off with `.task`, not `onAppear`.**\n\n```swift\nstruct FeedView: View {\n @State private var model: FeedModel\n\n init(client: FeedClient) {\n _model = State(initialValue: FeedModel(client: client))\n }\n\n var body: some View {\n content\n .task {\n await model.load()\n }\n }\n}\n```\n\n`.task` is bound to the view's lifetime: SwiftUI cancels the task automatically when the view disappears, and because `.task` inherits the view's actor context, `await model.load()` runs on the main actor and returns to it — no manual `DispatchQueue.main.async`.\n\nPrefer this over `.onAppear { Task { ... } }`: an unstructured `Task` you create by hand is not cancelled when the view goes away, so a slow request can complete against a model that no longer has a view, or fire again on every reappearance.\n\n**3. Branch the view on the state.**\n\n```swift\n@ViewBuilder\nprivate var content: some View {\n switch model.state {\n case .idle, .loading:\n ProgressView()\n case .loaded(let items):\n List(items) { ItemRow(item: $0) }\n case .failed(let error):\n ErrorView(error: error) { Task { await model.load() } }\n }\n}\n```\n\nAn explicit state enum makes the loading/loaded/failed states exhaustive at compile time and keeps the network layer (`FeedClient`) decoupled from the UI.\n\n**Notes that matter in practice:**\n\n- Put the actual networking behind a protocol (`FeedClient`) and inject it. This is what lets you swap in a stub for previews and `swift-testing`.\n- Make the model's mutable state main-actor-isolated, and keep the `client`'s implementation off the main actor (an `actor`, or a plain `async` function that internally does its work off-main). If the client is `Sendable`, crossing back is clean.\n- Don't reach for `Task.detached` — you want structured cancellation tied to the view, not a free-floating task.\n- If the fetch should survive navigation away and back (e.g. cached), move ownership up to a parent or a longer-lived object and pass it in; otherwise `.task` per screen is exactly right.\n- If multiple independent requests should run together, use a `TaskGroup` inside `load()` and `await` the group before setting `.loaded`.\n\nThat structure gives you automatic cancellation, correct actor isolation with no manual main-thread hops, and a loading state that is part of the type system rather than a loose boolean.",
348
+ "outputSha256": "4c7e18a4fcb9f41033bbdb045666c2f555048f5e5624fa437b5e70374006a5d2",
349
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
350
+ "deterministic": [],
351
+ "judge": {
352
+ "verdict": "pass",
353
+ "reason": "Criterion 1: uses `.task { await model.load() }` bound to view lifetime, explicitly contrasting with `.onAppear { Task { ... } }`. Criterion 2: `@MainActor @Observable final class FeedModel` with `state` mutated on main actor. Criterion 3: states `.task` is cancelled automatically when view disappears and unstructured Task is not. No fail criteria hold."
354
+ },
355
+ "passed": true
356
+ },
357
+ {
358
+ "output": "Structure it around a `@MainActor`-isolated observable model that owns the loading state, plus an `async` call it awaits, with the `Task` scoped to the view's lifetime via `.task`.\n\n**State ownership**\n\nOn iOS 17+, put the loading/data/error state on an `@Observable` class:\n\n```swift\n@MainActor\n@Observable\nfinal class OrderListModel {\n enum LoadState {\n case idle\n case loading\n case loaded([Order])\n case failed(Error)\n }\n\n private(set) var state: LoadState = .idle\n private let client: OrderClient\n\n init(client: OrderClient) {\n self.client = client\n }\n\n func load() async {\n state = .loading\n do {\n let orders = try await client.fetchOrders()\n state = .loaded(orders)\n } catch {\n state = .failed(error)\n }\n }\n}\n```\n\nThe model is created and owned by the view with `@State` (it's the view's own, and the view creates it), and the view reads/mutates it directly:\n\n```swift\nstruct OrderListView: View {\n @State private var model: OrderListModel\n let client: OrderClient\n\n init(client: OrderClient) {\n self.client = client\n _model = State(initialValue: OrderListModel(client: client))\n }\n\n var body: some View {\n content\n .task { await model.load() }\n }\n\n @ViewBuilder\n private var content: some View {\n switch model.state {\n case .idle, .loading:\n ProgressView()\n case .loaded(let orders):\n List(orders) { OrderRow(order: $0) }\n case .failed(let error):\n ErrorView(error: error)\n }\n }\n}\n```\n\n**Why this shape**\n\n- `@MainActor` on the model means every mutation of `state` happens on the main actor, so SwiftUI never sees an off-main write. The `await client.fetchOrders()` suspends; the actor hop back to set `state` is implicit.\n- Awaiting `model.load()` inside `.task` ties the task to the view's lifetime: SwiftUI cancels it when the view disappears, and restarts it if the view's identity changes. That's almost always what you want for an on-appear fetch.\n- If your deployment target is below iOS 17, use `ObservableObject`/`@Published` with `@StateObject` instead, and mark the class `@MainActor` the same way. If a parent owns the model and this view only mutates it, use `@Binding`; if it needs bindings into an `@Observable` it doesn't own, use `@Bindable`.\n\n**Concurrency details that matter**\n\n- Define `OrderClient` as a protocol with an `async throws` method, so tests can inject a stub and you don't hard-wire a URLSession call into the model. Whether the concrete client is an `actor` depends on whether it holds mutable state; a stateless client doesn't need to be one.\n- Thread `async`/`await` all the way through — don't wrap a completion-handler API in a `Task` just to bridge it, and don't nest completion handlers.\n- If you need to kick the load off outside a view's lifetime (e.g. a user-triggered retry that should survive navigation), own the `Task` yourself — `private var loadTask: Task<Void, Never>?`, assign it, cancel/replace as needed — and still `await` from a `@MainActor` context so `state` writes stay isolated.\n- Don't mark the model `@unchecked Sendable` to quiet strict-concurrency diagnostics; `@MainActor` is the correct isolation for UI-touching mutable state.\n\n**Loading state**\n\nKeep it in the model as an explicit enum rather than a separate `isLoading` bool alongside an optional array — a single `LoadState` makes the idle/loading/loaded/failed cases mutually exclusive and stops a \"loaded but also still showing a spinner\" bug from being representable. If you also need pull-to-refresh without blanking existing content, add a separate `isRefreshing` flag so a refresh doesn't drop the loaded list back to `.loading`.\n\nVerify with a build (`xcodebuild build -scheme <Scheme> -destination ...`) and check no new strict-concurrency warnings appear; if the project is on Swift 6 language mode, those are errors and pinpoint exactly which isolation you got wrong.",
359
+ "outputSha256": "7cb3a4f8df1865087bf3afbad28cb21697aa36af57b14af4d4874ade53bf4513",
360
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
361
+ "deterministic": [],
362
+ "judge": {
363
+ "verdict": "pass",
364
+ "reason": "Uses `.task { await model.load() }` as the fetch entry point (criterion 1). Model is `@MainActor @Observable` owning `state`/loading (criterion 2). Explicitly states `.task` ties work to view lifetime and SwiftUI cancels it when the view disappears (criterion 3). No bare Task-in-onAppear anti-pattern; manual Task only for out-of-lifetime retry with cancellation."
365
+ },
366
+ "passed": true
367
+ },
368
+ {
369
+ "output": "Structure it around a view-owned async task that runs in an `@MainActor`-isolated model, awaited from the view's `.task` modifier so it cancels automatically when the view disappears.\n\nConcretely:\n\n**1. Decide where the async work lives.** Push the network call behind a protocol-typed dependency (e.g. `OrderClient`) that the view model holds via initializer injection, not a singleton reached through implicitly. This is also the seam your tests mock against later.\n\n**2. Make the model `@MainActor` and `@Observable`** (iOS 17+) — or `ObservableObject` with `@StateObject` on an older deployment target. Marking the whole model `@MainActor` means its mutable state (the loading flag, the loaded data) is only ever touched on the main actor, so you never need `DispatchQueue.main.async` to hop back for UI updates. The `await` on the network call suspends and resumes back on the main actor for free.\n\n**3. Expose a single `async` method** on the model, e.g. `func load() async` that sets the loading flag, does `do { self.data = try await client.fetch() } catch { self.error = error }`, and clears the flag. Use `try`/`try?`, never `try!` — a network response is not a guaranteed-safe invariant.\n\n**4. Drive it from the view with `.task`**, not `onAppear { Task { ... } }`:\n\n```swift\nstruct OrderDetailView: View {\n @State private var model: OrderDetailModel\n\n var body: some View {\n content\n .task { await model.load() }\n }\n\n @ViewBuilder\n private var content: some View {\n if model.isLoading { ProgressView() }\n else if let error = model.error { ErrorView(error) }\n else if let data = model.data { DataView(data) }\n else { EmptyView() }\n }\n}\n```\n\nWhy `.task` over a manually spawned `Task` in `onAppear`: the task is scoped to the view's lifetime and is cancelled automatically when the view disappears, and it won't re-run spuriously. A `Task { }` you create yourself in `onAppear` outlives the view and needs manual cancellation you will usually forget. If the work genuinely should outlive a single screen (a long upload, a background sync), own it on a longer-lived object instead and say so explicitly — but for \"fetch when this screen appears,\" `.task` is correct.\n\n**5. Loading state belongs in the model, not the view.** Keep `isLoading` as model state so the view stays a pure projection of it and you avoid parallel state that can disagree.\n\nA few things to get right:\n\n- If the load is triggered by a changing input (e.g. an id), use `.task(id: someID)` so it re-runs and cancels the prior load correctly.\n- Don't nest completion handlers — thread `async`/`await` all the way through the call chain.\n- If you fan out multiple independent requests, `withTaskGroup`/`withThrowingTaskGroup` inside the model method is the right tool, still on the `@MainActor` model.\n- Never reach for `@unchecked Sendable` to silence a concurrency diagnostic on the model; if the model is `@MainActor`, its isolation is the answer, not an unchecked promise.\n- Whatever closure you hand to something longer-lived (a `Task`, a Combine `sink`) that captures `self`, capture `[weak self]` where a retain cycle is possible.\n\nThen verify with `xcodebuild build` (or `swift build`) on the target simulator and confirm no new strict-concurrency warnings before calling it done.",
370
+ "outputSha256": "343e025850260bb88d33246f85ff86a2d69af9ad036a58160e6104b31d513720",
371
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
372
+ "deterministic": [],
373
+ "judge": {
374
+ "verdict": "pass",
375
+ "reason": "Criterion 1: uses `.task { await model.load() }` in the view (code block) and explicitly contrasts it with `onAppear { Task { ... } }`. Criterion 2: states model is `@MainActor` and `@Observable`, with loading flag/data isolated to main actor. Criterion 3: explains `.task` is scoped to view lifetime and cancelled automatically when the view disappears. No fail criterion holds."
376
+ },
377
+ "passed": true
378
+ },
379
+ {
380
+ "output": "# Structuring a network fetch with loading state in SwiftUI\n\nThe short answer: let the view own an `@Observable`, `@MainActor` view model, kick off the async work from a `.task` modifier so it is tied to the view lifecycle, and let the view model track an explicit loading/loaded/failed state. Here is the shape of it, plus the reasoning for each decision.\n\n## The state and the model\n\n```swift\nenum LoadState<Value> {\n case idle\n case loading\n case loaded(Value)\n case failed(Error)\n}\n\n@MainActor\n@Observable\nfinal class OrderDetailModel {\n private(set) var state: LoadState<Order> = .idle\n private let client: OrderClient\n\n init(client: OrderClient) {\n self.client = client\n }\n\n func load() async {\n state = .loading\n do {\n let order = try await client.fetchOrder()\n state = .loaded(order)\n } catch {\n state = .failed(error)\n }\n }\n}\n```\n\nKey points:\n\n- **`@MainActor` on the model.** It touches view state, so it should be main-actor isolated. The `await` inside `load()` does not block the main thread — it suspends, and Swift hops the continuation back to the main actor when the call returns. This is the whole point of `async`/`await`: you do not need a background queue, you need isolation.\n- **An explicit `LoadState` enum rather than `isLoading: Bool` + `data: T?` + `error: Error?`.** Three separate optionals can represent impossible states (loading *and* failed at once, loaded with no data). One enum cannot.\n- **The network client is a protocol-typed dependency injected in the initializer.** Even with one concrete implementation, this is what lets `swift-testing` substitute a fake that returns instantly, throws on demand, or hangs to test the loading state.\n\n## The view\n\n```swift\nstruct OrderDetailView: View {\n @State private var model: OrderDetailModel\n\n init(client: OrderClient) {\n _model = State(initialValue: OrderDetailModel(client: client))\n }\n\n var body: some View {\n Group {\n switch model.state {\n case .idle, .loading:\n ProgressView()\n case .loaded(let order):\n OrderContent(order: order)\n case .failed(let error):\n ContentUnavailableView(\n \"Couldn't load order\",\n systemImage: \"exclamationmark.triangle\",\n description: Text(error.localizedDescription)\n )\n }\n }\n .task {\n await model.load()\n }\n }\n}\n```\n\nKey points:\n\n- **`@State` owns the `@Observable` model.** On iOS 17+, `@State` is the correct ownership pattern for a view-created observable — not `@StateObject`, which is the `ObservableObject` era. `@State` survives view redraws but is tied to the view's identity, which is what you want for screen-scoped state.\n- **`.task { }` starts the work, and `.task` cancels it when the view disappears.** This is the crucial part most people get wrong. If you spawn a bare `Task { }` inside `onAppear`, it is not tied to the view's lifecycle — navigate away and it keeps running, and worse, it can still write to `state` after the view is gone. `.task` gives you structured cancellation for free: if the view goes away mid-fetch, the task is cancelled, the `await` throws `CancellationError`, and your `catch` stores a failure state (or you can check `Task.isCancelled` and bail without changing state).\n- **`.task` is keyed to view identity per `id`**, so if the view identity changes, the old task cancels and a new one starts. `.task(id: someValue)` re-runs on that value changing.\n\n## The network client\n\n```swift\nprotocol OrderClient: Sendable {\n func fetchOrder() async throws -> Order\n}\n\n@MainActor\nfinal class LiveOrderClient: OrderClient {\n func fetchOrder() async throws -> Order {\n let (data, response) = try await URLSession.shared.data(from: url)\n guard let http = response as? HTTPURLResponse,\n (200..<300).contains(http.statusCode) else {\n throw OrderClientError.badResponse\n }\n return try JSONDecoder().decode(Order.self, from: data)\n }\n}\n```\n\nThe client itself does not need to be `@MainActor` — URLSession is thread-safe and you are not touching UI. Marking it `Sendable` (or leaving it an unconstrained `struct`/`class` with no mutable state) is what lets it cross actor boundaries when called from the main-actor model. The `decode` throws rather than force-unwrapping the response, so a malformed payload becomes a `.failed` state instead of a crash.\n\n## Things people get wrong here\n\n- **Nesting a `Task { }` inside `onAppear` instead of using `.task`.** The task outlives the view and can write to dissolved state. Use `.task`.\n- **Marking the model's methods `nonisolated` and manually hopping to the main actor with `DispatchQueue.main.async`.** With `@MainActor` + `async`/`await` you do not need manual hops; the runtime handles the isolation hop at each `await`.\n- **Force-unwrapping the decoded response.** `try JSONDecoder().decode(...)` throwing is the correct behavior — the catch turns it into a visible failure state.\n- **A `Task { }` inside the model's `init`.** Then the model starts loading before the view even appears, and there is no clean cancellation handle tied to the view. Kick it off from `.task` in the view.\n- **Capturing `self` strongly in a long-lived closure** (a stored completion handler, a Combine `sink`). If a closure can outlive the model, capture `[weak self]`.\n\n## If you need to coordinate multiple independent fetches\n\nUse a `TaskGroup` and await the group; each child task is isolated and the group awaits all of them before returning, which gives you a natural place to switch to `.loaded` once every piece has arrived:\n\n```swift\nfunc loadAll() async {\n state = .loading\n do {\n async let order = client.fetchOrder()\n async let account = client.fetchAccount()\n let (o, a) = try await (order, account)\n state = .loaded((o, a))\n } catch {\n state = .failed(error)\n }\n}\n```\n\nBoth fetches run concurrently, and the `try await (order, account)` waits for both — no manual counting or completion handlers.\n\n## Verification before calling it done\n\n- Build succeeds (`xcodebuild build`) with no new strict-concurrency warnings.\n- Every new state field has a deliberate ownership choice (`@State` on the view, `@MainActor` on the model).\n- No new force-unwrap or force-try on the decoded response or the HTTP status.\n- The fetch is cancelled when the view disappears — confirm by navigating away mid-load and checking the state does not mutate afterward.",
381
+ "outputSha256": "18b46a2ae6af9bd2b1696cf9d831bd4e2a49af4bbd8a5b3c3106a87c20bac774",
382
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
383
+ "deterministic": [],
384
+ "judge": {
385
+ "verdict": "pass",
386
+ "reason": "Criterion 1: uses `.task { await model.load() }` in the view (shown in OrderDetailView body). Criterion 2: `@MainActor @Observable final class OrderDetailModel` with state/loading flag, explicitly explained. Criterion 3: states '.task cancels it when the view disappears' and discusses CancellationError/Task.isCancelled. No fail criterion: it explicitly warns against bare Task in onAppear."
387
+ },
388
+ "passed": true
389
+ },
390
+ {
391
+ "output": "Structure it as a `@MainActor`-isolated model that owns the async work, kicked off from the view's `.task` modifier — not from `.onAppear` with a manually-created `Task`, and not with a fire-and-forget call that the view cannot cancel.\n\n**Concrete shape (iOS 17+ target):**\n\n```swift\n@MainActor\n@Observable\nfinal class ProfileModel {\n enum State {\n case loading\n case loaded(Profile)\n case failed(Error)\n }\n\n private(set) var state: State = .loading\n private let client: ProfileClient // protocol-typed dependency\n\n init(client: ProfileClient) {\n self.client = client\n }\n\n func load() async {\n state = .loading\n do {\n let profile = try await client.fetchProfile()\n state = .loaded(profile)\n } catch {\n state = .failed(error)\n }\n }\n}\n```\n\n```swift\nstruct ProfileView: View {\n @State private var model: ProfileModel\n\n init(client: ProfileClient) {\n _model = State(initialValue: ProfileModel(client: client))\n }\n\n var body: some View {\n Group {\n switch model.state {\n case .loading:\n ProgressView()\n case .loaded(let profile):\n ProfileContent(profile: profile)\n case .failed(let error):\n ErrorView(error: error) { Task { await model.load() } }\n }\n }\n .task { await model.load() }\n }\n}\n```\n\n**Why each piece matters:**\n\n- **`@MainActor` on the model.** The model mutates `state`, which drives the view, so it must be main-actor-isolated. Marking the whole type `@MainActor` means the compiler enforces that every mutation happens on the main actor — you don't have to sprinkle `await MainActor.run { }` around or hope you remembered.\n\n- **`.task`, not `.onAppear` + `Task {}`.** `.task` ties the launched task's lifetime to the view: it is cancelled automatically when the view disappears. A `Task { }` you create yourself in `.onAppear` is not cancelled for you and can outlive the screen (and keep a stale `self`/model alive). `.task` also re-runs when the view's identity changes, which is usually what you want for a per-screen fetch.\n\n- **`async`/`await` through to the client, no completion handlers.** The model's `load()` is a single `async` function; the network client method is `async throws`. This flattens what would otherwise be a nested completion-handler pyramid and lets the `do/catch` read linearly.\n\n- **The model is `@Observable` and owned with `@State`.** The view creates and owns it, so `@State` is the correct ownership keyword — `@State` on an `@Observable` gives you the object's storage tied to the view's lifetime without `@StateObject`'s legacy `ObservableObject` requirement. (On a pre-iOS-17 deployment target you'd fall back to `ObservableObject` + `@StateObject` + `@Published`, matching whatever the surrounding code already does.)\n\n- **A `State` enum rather than `isLoading: Bool` + `data: Profile?` + `error: Error?`.** The three-bool-and-optionals version allows invalid combinations (`isLoading == true` *and* `data != nil` *and* `error != nil`). An enum makes the loading/loaded/failed cases mutually exclusive by construction, which is also what makes the `switch` in `body` exhaustive and readable.\n\n- **Protocol-typed dependency (`ProfileClient`) injected via the initializer.** This is the seam `swift-testing` mocks against later, and it keeps the model from reaching for a singleton.\n\n**Sendable / cancellation notes:**\n\n- If `ProfileClient` crosses actor boundaries (e.g. an implementation backed by a background actor), its protocol should require `Sendable` conformance, and the values it returns (`Profile`) must be `Sendable` too. Don't reach for `@unchecked Sendable` to dodge a diagnostic here — audit the mutable state instead.\n- Because `.task` cancels on disappear, a long fetch that checks `try Task.checkCancellation()` inside the client will actually stop. If you want a manual retry that survives more than the immediate screen, that's the point to consider a longer-lived owner — but for \"fetch when it appears,\" scoping to `.task` is correct.\n\n**Red flags to avoid here specifically:**\n- Starting the fetch in `.onAppear` with an ad-hoc `Task {}` — no cancellation, easy to double-fire.\n- Force-unwrapping the decoded response (`try!`/`!`) because \"the API always returns it\" — decode failures happen, and a force-unwrap turns a recoverable `.failed` state into a crash.\n- Omitting `@MainActor` and mutating `state` from a background context — that's a data race the concurrency checker should be catching, and silencing it with `@unchecked Sendable` trades a compile-time guarantee for a runtime hope.\n\nThen verify with `xcodebuild build` (and `swiftlint` if configured), confirming no new strict-concurrency warnings were introduced.",
392
+ "outputSha256": "75fc29cea2386a22f4c0f903524a668b218c2cac3768289cf9d2890715030b2b",
393
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
394
+ "deterministic": [],
395
+ "judge": {
396
+ "verdict": "pass",
397
+ "reason": "Answer uses `.task { await model.load() }` as entry point (criterion 1), marks model `@MainActor @Observable` with state driving UI (criterion 2), and explicitly states `.task` is cancelled automatically when the view disappears, plus Task.checkCancellation (criterion 3). It warns against `.onAppear` + bare `Task {}`, so no fail criterion holds."
398
+ },
399
+ "passed": true
400
+ },
401
+ {
402
+ "output": "Structure it so the fetch is owned by a model that is isolated to the main actor, invoked from the view's `.task` modifier, with the actual network work happening through an `async` protocol-typed dependency. Concretely:\n\n**Own the fetch in the view model, not the view body.**\n\n```swift\n@MainActor\n@Observable\nfinal class OrderDetailModel {\n enum LoadState {\n case idle\n case loading\n case loaded(Order)\n case failed(Error)\n }\n\n private(set) var state: LoadState = .idle\n private let client: OrderClient\n\n init(client: OrderClient) {\n self.client = client\n }\n\n func load() async {\n state = .loading\n do {\n let order = try await client.fetchOrder()\n state = .loaded(order)\n } catch {\n state = .failed(error)\n }\n }\n}\n```\n\nThe `@MainActor` on the class is what lets you mutate `state` directly without hopping — everything on this object runs on the main actor, and the `await` boundary inside `load()` is where control temporarily leaves for the network.\n\n**Kick it off with `.task`, not `.onAppear` + `Task`.**\n\n```swift\nstruct OrderDetailView: View {\n @State private var model: OrderDetailModel\n\n init(client: OrderClient) {\n _model = State(initialValue: OrderDetailModel(client: client))\n }\n\n var body: some View {\n Group {\n switch model.state {\n case .idle, .loading:\n ProgressView()\n case .loaded(let order):\n OrderContent(order: order)\n case .failed(let error):\n ErrorView(error: error)\n }\n }\n .task { await model.load() }\n }\n}\n```\n\n`.task` is the right hook because SwiftUI automatically cancels the task when the view disappears, and re-runs the closure when the view's identity changes. If you used `.onAppear { Task { ... } }` you'd get a task with no cancellation story — it keeps running and keeps mutating `model` after the view is gone. `.task` ties the lifetime of the work to the lifetime of the view, which is almost always what you want for \"fetch when it appears.\"\n\n**Keep the network behind a protocol so it's testable and injection is explicit.**\n\n```swift\nprotocol OrderClient: Sendable {\n func fetchOrder() async throws -> Order\n}\n```\n\nMarking it `Sendable` matters if the concrete implementation does its work off the main actor (e.g. an `actor` or a struct wrapping `URLSession`). Then `await client.fetchOrder()` crossing back and forth is checked by the compiler rather than left to convention; you never hand a non-`Sendable` value across the isolation boundary.\n\n**Cancel cooperatively if the work is long.** A bare `URLSession.data(for:)` throws `CancellationError` on its own when the surrounding task is cancelled, and your `catch` already handles it — but if you want the view to end up in `.idle` rather than `.failed` on cancellation, check `Task.isCancelled` in the catch and return early. Don't swallow it silently into an error state the user will see when they just navigated away.\n\n**Two anti-patterns to avoid:**\n\n- Doing the `await` from inside the view body or a synchronous helper with a nested `Task { }` inside `.onAppear` — you lose cancellation and end up racing multiple in-flight fetches if the view reappears quickly.\n- Guarding against re-entry with a boolean flag instead of relying on `.task`'s identity-driven re-run. If you do need to avoid a duplicate fetch when the model is reused, check `state` before setting `.loading` rather than adding a `isLoading` boolean next to the enum — the enum already encodes that.\n\nIf you're on an older deployment target that predates `@Observable`, the same shape holds with `ObservableObject`, `@Published var state`, and `@StateObject` in the view; just note the `.task` modifier is available from iOS 15, so the cancellation story still works.",
403
+ "outputSha256": "d18cb3b7167493cb3741e413688ddc64d29a7e3491096090b4862d83825e52eb",
404
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
405
+ "deterministic": [],
406
+ "judge": {
407
+ "verdict": "pass",
408
+ "reason": "Uses `.task { await model.load() }` as entry point (criterion 1), explicitly contrasts it with `.onAppear { Task { ... } }`. Model is `@MainActor @Observable` with `state` loading flag (criterion 2). States `.task` auto-cancels when view disappears and ties work to view lifetime (criterion 3). No fail criterion: bare Task in onAppear is only warned against."
409
+ },
410
+ "passed": true
411
+ },
412
+ {
413
+ "output": "Structure it around three things: where the `Task` is scoped, what isolation the state lives on, and a protocol boundary for the fetch.\n\n**Where the work runs.** Use the `.task` modifier on the view. It creates a `Task` tied to the view's lifetime and automatically cancels it when the view disappears — that is exactly the lifecycle you want for \"fetch when it appears.\" Do not spawn a bare `Task { }` in `.onAppear`, because nothing cancels it when the view goes away, and it can outlive the screen.\n\n```swift\nstruct OrderDetailView: View {\n @State private var model: OrderDetailModel\n\n init(client: OrderClient) {\n _model = State(initialValue: OrderDetailModel(client: client))\n }\n\n var body: some View {\n content\n .task { await model.load() }\n }\n\n @ViewBuilder\n private var content: some View {\n switch model.state {\n case .idle, .loading: ProgressView()\n case .loaded(let order): OrderDetailContent(order: order)\n case .failed(let error): ErrorView(error: error) { await model.load() }\n }\n }\n}\n```\n\n**The model.** Make it `@Observable` and `@MainActor` so all mutation of view-driving state happens on the main actor, and the `await` points hand control back cleanly:\n\n```swift\n@Observable\n@MainActor\nfinal class OrderDetailModel {\n enum State {\n case idle, loading\n case loaded(Order)\n case failed(Error)\n }\n\n private(set) var state: State = .idle\n private let client: OrderClient\n\n init(client: OrderClient) { self.client = client }\n\n func load() async {\n state = .loading\n do {\n let order = try await client.fetchOrder(id: id)\n state = .loaded(order)\n } catch is CancellationError {\n // view went away; leave state alone\n } catch {\n state = .failed(error)\n }\n }\n}\n```\n\nNote `fetchOrder` is `async throws` through a protocol, so the model never touches a completion handler and there is no force-unwrap of the decoded response — a bad response throws and lands in `.failed`.\n\n**The dependency boundary.** Define the client as a protocol now, even with one implementation, so `swift-testing` can inject a stub and so the model does not depend on a concrete URLSession wrapper:\n\n```swift\nprotocol OrderClient: Sendable {\n func fetchOrder(id: Order.ID) async throws -> Order\n}\n```\n\nKeep it `Sendable`; the concrete implementation should be an immutable struct or an `actor`, not a class with unchecked mutable state. If the client needs shared mutable state, make it an `actor` (or `@MainActor` if it is thin and cheap) rather than marking a class `@unchecked Sendable`.\n\n**Things to watch:**\n\n- Do not store the `Task` in the model and cancel it manually unless the fetch should outlive the view — `.task` already handles cancellation for the view-scoped case. If you *do* own a `Task` on a longer-lived object and capture `self` in it, use `[weak self]`.\n- Handle `CancellationError` explicitly (as above) so a view that disappears mid-fetch does not flip to `.failed` with a cancellation error.\n- If the deployment target is below iOS 17, use `ObservableObject` + `@StateObject` + `@Published` instead, and gate the fetch the same way with `.task` — but do not introduce the legacy pattern in new code on a 17+ target.\n- Loading state is a value, not a pile of booleans. A single `enum State` (or `enum + associated values`) makes the \"loaded/loading/failed\" cases mutually exclusive by construction, so you can never be both loading and loaded.\n\nThat gives you: cancellation tied to the view, all UI state on the main actor, no completion handlers, no force-unwraps, and a seam for testing.",
414
+ "outputSha256": "2a56957d1315dc3433089bfd9cc3fc9cb77ef98fce9146e905b736ee553a7715",
415
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
416
+ "deterministic": [],
417
+ "judge": {
418
+ "verdict": "pass",
419
+ "reason": "Uses `.task { await model.load() }` tied to view lifetime (criterion 1), explicitly says it auto-cancels when view disappears and warns against bare Task in onAppear (criterion 3). Model is `@Observable @MainActor` with state on main actor (criterion 2). Handles CancellationError. No fail criteria hold."
420
+ },
421
+ "passed": true
422
+ },
423
+ {
424
+ "output": "Structure it so the async work is owned by a `@MainActor` model, awaited from a view-scoped `.task`, and threaded through a protocol-typed dependency. Concretely:\n\n**1. Keep the mutable UI state on the main actor.**\nWhatever holds the loading/data/error state should be `@MainActor`-isolated — either an `@Observable` class (iOS 17+) or a view model. That guarantees every mutation of the shown state happens on the main actor without you sprinkling `DispatchQueue.main.async` around.\n\n```swift\n@MainActor\n@Observable\nfinal class OrderDetailModel {\n enum Phase {\n case loading\n case loaded(Order)\n case failed(Error)\n }\n private(set) var phase: Phase = .loading\n\n private let client: OrderClient // protocol, not a concrete type\n\n init(client: OrderClient) { self.client = client }\n\n func load() async {\n phase = .loading\n do {\n let order = try await client.fetchOrder(id: orderID)\n phase = .loaded(order)\n } catch {\n phase = .failed(error)\n }\n }\n}\n```\n\n**2. Own the model with the view, and drive the fetch from `.task`.**\nThe view creates the model (`@State` for an `@Observable`, `@StateObject` for an `ObservableObject` on an older target) and kicks off the load in `.task`. Using `.task` rather than `Task { }` in `onAppear` matters: the task is tied to the view's lifetime, so it auto-cancels if the view disappears, and it re-runs if the view's identity changes.\n\n```swift\nstruct OrderDetailView: View {\n @State private var model: OrderDetailModel\n\n init(client: OrderClient, orderID: Order.ID) {\n _model = State(initialValue: OrderDetailModel(client: client, orderID: orderID))\n }\n\n var body: some View {\n content\n .task { await model.load() }\n }\n\n @ViewBuilder\n private var content: some View {\n switch model.phase {\n case .loading: ProgressView()\n case .loaded(let order): OrderContentView(order: order)\n case .failed(let error): ErrorView(error: error)\n }\n }\n}\n```\n\n**3. Do the actual I/O off the main thread, behind a protocol.**\nThe `OrderClient` protocol defines the boundary; the concrete implementation does the URLSession call (URLSession's async APIs already hop off the main actor for you). Keeping the client protocol-typed is what lets you inject a mock in tests and keeps the view model from depending on a concrete networking type.\n\n```swift\nprotocol OrderClient: Sendable {\n func fetchOrder(id: Order.ID) async throws -> Order\n}\n\nstruct LiveOrderClient: OrderClient {\n func fetchOrder(id: Order.ID) async throws -> Order {\n let (data, response) = try await URLSession.shared.data(from: url)\n // validate response, decode...\n return try JSONDecoder().decode(Order.self, from: data)\n }\n}\n```\n\n**Key decisions and why:**\n\n- **`.task` over `onAppear` + `Task { }`**: `.task` cancels with the view and respects view identity; a bare `Task` in `onAppear` leaks work past dismissal and can fire on every reappear.\n- **Don't launch the fetch from `init`.** Initializers can't await, and starting unstructured work in `init` escapes cancellation. Start it from `.task`.\n- **`await` the model method directly** — no completion handlers. The `async`/`await` chain from `.task` down through the model to the client is what lets cancellation propagate; nesting a completion handler in the middle breaks that.\n- **The model is `@MainActor`; the client is `Sendable`.** That pairing is what makes the strict-concurrency checker happy under Swift 6: the model mutates UI state on the main actor, and the `Sendable` client can be called across the actor boundary safely.\n- **Guard against re-entrancy if the fetch can restart** (pull-to-refresh, retry): either cancel the prior task or ignore stale results, so an earlier slow response doesn't overwrite a newer one.\n\nIf the target is below iOS 17, swap `@Observable` for `ObservableObject` + `@Published` and `@State` for `@StateObject`; the concurrency structure (main-actor model, `.task`, protocol client) is identical either way.",
425
+ "outputSha256": "5ceb9879eb81f07815a381c978e3421b5a4269d6d76f2073563945f46f1ee78d",
426
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
427
+ "deterministic": [],
428
+ "judge": {
429
+ "verdict": "pass",
430
+ "reason": "Answer uses `.task { await model.load() }` as entry point (criterion 1), explicitly contrasts it with `Task {}` in `onAppear`. Model is `@MainActor @Observable` holding phase/loading state (criterion 2). States `.task` auto-cancels when view disappears and re-runs on identity change (criterion 3). No fail criterion: it warns against bare Task in onAppear rather than using it."
431
+ },
432
+ "passed": true
433
+ },
434
+ {
435
+ "output": "Structure the fetch as a `Task` tied to the view's lifetime via the `.task` modifier, await an `async` call on a protocol-typed dependency, and drive a loading state from a view-owned `@Observable` (or `@StateObject`) model marked `@MainActor`. Concretely:\n\n**1. Own the state in a model, not loose in the view**\n\nOn iOS 17+ (default), use `@Observable` + `@MainActor`:\n\n```swift\n@MainActor\n@Observable\nfinal class OrdersModel {\n enum LoadState {\n case idle\n case loading\n case loaded([Order])\n case failed(Error)\n }\n\n private(set) var state: LoadState = .idle\n private let client: OrderClient\n\n init(client: OrderClient) {\n self.client = client\n }\n\n func load() async {\n state = .loading\n do {\n let orders = try await client.fetchOrders()\n state = .loaded(orders)\n } catch {\n state = .failed(error)\n }\n }\n}\n```\n\nKeep the view model on the legacy `ObservableObject`/`@Published`/`@StateObject` shape only if your deployment target predates iOS 17 — match whatever the project already does.\n\n**2. Knock out the dependency behind a protocol**\n\n```swift\nprotocol OrderClient {\n func fetchOrders() async throws -> [Order]\n}\n```\n\nEven with one concrete implementation today, this is the seam tests mock against.\n\n**3. Trigger the fetch from the view with `.task`, not `.onAppear` + `Task {}`**\n\n```swift\nstruct OrdersView: View {\n @State private var model: OrdersModel\n\n init(client: OrderClient) {\n _model = State(initialValue: OrdersModel(client: client))\n }\n\n var body: some View {\n content\n .task { await model.load() }\n }\n\n @ViewBuilder\n private var content: some View {\n switch model.state {\n case .idle, .loading:\n ProgressView()\n case .loaded(let orders):\n List(orders) { OrderRow(order: $0) }\n case .failed(let error):\n ContentUnavailableView(\"Couldn't load orders\",\n systemImage: \"exclamationmark.triangle\",\n description: Text(error.localizedDescription))\n }\n }\n}\n```\n\nKey points here:\n\n- **`.task` scopes the work to the view's lifetime.** SwiftUI starts the `Task` when the view appears and cancels it when the view disappears (and re-runs it if the view's identity changes). This is the main reason to prefer it over `.onAppear { Task { ... } }`, which hands you a detached-ish task you must cancel yourself.\n- **`await model.load()`**, not a nested completion handler — the whole chain stays `async`/`await`, and `load()` is `@MainActor` so its `state` mutations are safe.\n- **Don't put the `await` in `body`.** `body` is not `async` and runs on every render; `.task` is the sanctioned hook.\n\n**4. Loading state as a first-class value**\n\nModeling it as an enum (`idle`/`loading`/`loaded`/`failed`) rather than a separate `isLoading: Bool` plus optional `error` plus optional `orders` makes illegal states unrepresentable and gives you a clean `switch` in the view. Set `.loading` before the `await` so the `ProgressView` shows immediately.\n\n**5. Isolation and cancellation**\n\n- Mark the model `@MainActor` so loading-state mutations never hop threads. The `await client.fetchOrders()` will suspend and run the network work wherever the client's implementation puts it — if the client does its own background work (or is a `URLSession`-based `actor`), that's fine; when it returns, you're back on the main actor to assign `state`.\n- `.task` cancellation propagates: if the view disappears mid-fetch, the `await` throws a `CancellationError`. Decide whether you want to keep the last good state or show a failed state; you may want to check `Task.isCancelled` before overwriting state after an await.\n\n**6. Don't forget the red flags**\n\n- No force-unwrap (`!`) or `try!` anywhere on the fetch result — use `try`/`try?`/`guard let` and route failures into `.failed`.\n- Don't reach for `@unchecked Sendable` to quiet a concurrency warning on the model — the `@MainActor` annotation is the actual fix.\n- If you retain a `Task` in a stored property (you often don't need to with `.task`), capture `[weak self]` to avoid a cycle; a model owning a long-lived task that captures the model strongly leaks.\n- If this is a brand-new screen on an iOS 17+ target, don't introduce `ObservableObject`/`@StateObject` — use `@Observable`/`@State`.\n\nOnce written, verify with `xcodebuild build` (no new strict-concurrency warnings) before calling it done.",
436
+ "outputSha256": "29d177841257be3a4e0b58f07aade9ca82d32d97acbb03742f9db272fe8b3d7b",
437
+ "promptSha256": "fbcc4449812ee602a5192535a3255a571d2212f15c5d0425d31622b96f3583e3",
438
+ "deterministic": [],
439
+ "judge": {
440
+ "verdict": "pass",
441
+ "reason": "Uses `.task { await model.load() }` as entry point (step 3), explicitly contrasting with `.onAppear { Task {} }`. Model marked `@MainActor` with `@Observable` (step 1), and step 5 states `.task` cancellation propagates on view disappearance with CancellationError. All pass criteria concretely shown; no fail criterion holds."
442
+ },
443
+ "passed": true
444
+ }
445
+ ]
446
+ }
447
+ ],
448
+ "verdict": "fail",
449
+ "scope": "bundled",
450
+ "skillDigest": "be191897fe21501a56e474d942f1a6ac395354584e4a30ad3efc20d187d55c77",
451
+ "catalogDigest": "97f9af01aafac82ae21a63c6af2a2f24fcfe067dc32a7cfdcde9a69a91fa9aae",
452
+ "judgePromptVersion": "2026-09-25.1",
453
+ "runner": "deepseek",
454
+ "model": "deepseek-chat",
455
+ "runnerPromptVersion": "2026-09-25.1",
456
+ "recordedAt": "2026-09-25T18:19:43.361Z",
457
+ "judge": "deepseek",
458
+ "judgeModel": "deepseek-chat"
459
+ },
460
+ {
461
+ "schemaVersion": "1.0.0",
462
+ "skillId": "swift-ios/swift-testing",
463
+ "strictness": "high",
464
+ "trials": 10,
465
+ "triggerAccuracy": {
466
+ "truePositive": 3,
467
+ "falsePositive": 0,
468
+ "positives": 7,
469
+ "negatives": 7
470
+ },
471
+ "evidence": "authored",
472
+ "scenarios": [
473
+ {
474
+ "id": "trigger-positive-1",
475
+ "kind": "trigger-positive",
476
+ "prompt": "I need coverage for this view model that talks to a backend, what's the right way to fake the network for it",
477
+ "strictness": "high",
478
+ "trials": 1,
479
+ "passes": 1,
480
+ "passRate": 1,
481
+ "passAtK": 1,
482
+ "grader": "trigger-rank-fork-family",
483
+ "status": "ran",
484
+ "deterministic": true
485
+ },
486
+ {
487
+ "id": "trigger-positive-2",
488
+ "kind": "trigger-positive",
489
+ "prompt": "Write a few test cases for this order validation function",
490
+ "strictness": "high",
491
+ "trials": 1,
492
+ "passes": 0,
493
+ "passRate": 0,
494
+ "passAtK": 0,
495
+ "grader": "trigger-rank-fork-family",
496
+ "status": "ran",
497
+ "deterministic": true
498
+ },
499
+ {
500
+ "id": "trigger-positive-3",
501
+ "kind": "trigger-positive",
502
+ "prompt": "This screen kicks off a background task and I want a deterministic way to wait for it in a test",
503
+ "strictness": "high",
504
+ "trials": 1,
505
+ "passes": 0,
506
+ "passRate": 0,
507
+ "passAtK": 0,
508
+ "grader": "trigger-rank-fork-family",
509
+ "status": "ran",
510
+ "deterministic": true
511
+ },
512
+ {
513
+ "id": "trigger-positive-4",
514
+ "kind": "trigger-positive",
515
+ "prompt": "Add coverage that exercises several different discount inputs for this pricing function",
516
+ "strictness": "high",
517
+ "trials": 1,
518
+ "passes": 0,
519
+ "passRate": 0,
520
+ "passAtK": 0,
521
+ "grader": "trigger-rank-fork-family",
522
+ "status": "ran",
523
+ "deterministic": true
524
+ },
525
+ {
526
+ "id": "trigger-positive-5",
527
+ "kind": "trigger-positive",
528
+ "prompt": "How do I fake persistence for this view model's tests without touching the real database",
529
+ "strictness": "high",
530
+ "trials": 1,
531
+ "passes": 0,
532
+ "passRate": 0,
533
+ "passAtK": 0,
534
+ "grader": "trigger-rank-fork-family",
535
+ "status": "ran",
536
+ "deterministic": true
537
+ },
538
+ {
539
+ "id": "trigger-positive-6",
540
+ "kind": "trigger-positive",
541
+ "prompt": "This async function needs test coverage, what does a good test for it look like",
542
+ "strictness": "high",
543
+ "trials": 1,
544
+ "passes": 1,
545
+ "passRate": 1,
546
+ "passAtK": 1,
547
+ "grader": "trigger-rank-fork-family",
548
+ "status": "ran",
549
+ "deterministic": true
550
+ },
551
+ {
552
+ "id": "trigger-positive-7",
553
+ "kind": "trigger-positive",
554
+ "prompt": "Set up test doubles for the networking layer in this feature's test suite",
555
+ "strictness": "high",
556
+ "trials": 1,
557
+ "passes": 1,
558
+ "passRate": 1,
559
+ "passAtK": 1,
560
+ "grader": "trigger-rank-fork-family",
561
+ "status": "ran",
562
+ "deterministic": true
563
+ },
564
+ {
565
+ "id": "trigger-negative-1",
566
+ "kind": "trigger-negative",
567
+ "prompt": "Write instrumented UI tests with Android's Espresso for this screen",
568
+ "strictness": "high",
569
+ "trials": 1,
570
+ "passes": 1,
571
+ "passRate": 1,
572
+ "passAtK": 1,
573
+ "grader": "trigger-rank-fork-family",
574
+ "status": "ran",
575
+ "deterministic": true
576
+ },
577
+ {
578
+ "id": "trigger-negative-2",
579
+ "kind": "trigger-negative",
580
+ "prompt": "Add widget tests for this Flutter screen using WidgetTester",
581
+ "strictness": "high",
582
+ "trials": 1,
583
+ "passes": 1,
584
+ "passRate": 1,
585
+ "passAtK": 1,
586
+ "grader": "trigger-rank-fork-family",
587
+ "status": "ran",
588
+ "deterministic": true
589
+ },
590
+ {
591
+ "id": "trigger-negative-3",
592
+ "kind": "trigger-negative",
593
+ "prompt": "Write unit tests for this ASP.NET Core controller with xUnit",
594
+ "strictness": "high",
595
+ "trials": 1,
596
+ "passes": 1,
597
+ "passRate": 1,
598
+ "passAtK": 1,
599
+ "grader": "trigger-rank-fork-family",
600
+ "status": "ran",
601
+ "deterministic": true
602
+ },
603
+ {
604
+ "id": "trigger-negative-4",
605
+ "kind": "trigger-negative",
606
+ "prompt": "Add Jest tests for this React component's rendering",
607
+ "strictness": "high",
608
+ "trials": 1,
609
+ "passes": 1,
610
+ "passRate": 1,
611
+ "passAtK": 1,
612
+ "grader": "trigger-rank-fork-family",
613
+ "status": "ran",
614
+ "deterministic": true
615
+ },
616
+ {
617
+ "id": "trigger-negative-5",
618
+ "kind": "trigger-negative",
619
+ "prompt": "Implement this feature in SwiftUI with an async network call",
620
+ "strictness": "high",
621
+ "trials": 1,
622
+ "passes": 1,
623
+ "passRate": 1,
624
+ "passAtK": 1,
625
+ "grader": "trigger-rank-fork-family",
626
+ "status": "ran",
627
+ "deterministic": true
628
+ },
629
+ {
630
+ "id": "trigger-negative-6",
631
+ "kind": "trigger-negative",
632
+ "prompt": "Review this Swift diff for retain cycles",
633
+ "strictness": "high",
634
+ "trials": 1,
635
+ "passes": 1,
636
+ "passRate": 1,
637
+ "passAtK": 1,
638
+ "grader": "trigger-rank-fork-family",
639
+ "status": "ran",
640
+ "deterministic": true
641
+ },
642
+ {
643
+ "id": "trigger-negative-7",
644
+ "kind": "trigger-negative",
645
+ "prompt": "Write pytest fixtures for this Python service",
646
+ "strictness": "high",
647
+ "trials": 1,
648
+ "passes": 1,
649
+ "passRate": 1,
650
+ "passAtK": 1,
651
+ "grader": "trigger-rank-fork-family",
652
+ "status": "ran",
653
+ "deterministic": true
654
+ },
655
+ {
656
+ "id": "mock-network-boundary",
657
+ "kind": "behavior",
658
+ "prompt": "I have a view model that fetches an order from a backend client and I need to test it without hitting the real network. How should I set this up?",
659
+ "strictness": "high",
660
+ "trials": 10,
661
+ "passes": 10,
662
+ "passRate": 1,
663
+ "passAtK": 1,
664
+ "grader": "judge",
665
+ "status": "ran",
666
+ "trialRecords": [
667
+ {
668
+ "output": "Set it up around the protocol boundary, not the view model's internals.\n\n**1. Find or introduce the boundary.** Look at how the view model currently depends on the backend client. Ideally it already takes something like an `OrderClient` protocol through its initializer:\n\n```swift\nprotocol OrderClient {\n func fetchOrder(id: String) async throws -> Order\n}\n\nfinal class OrderDetailModel {\n private let client: OrderClient\n init(client: OrderClient) { self.client = client }\n}\n```\n\nIf it instead reaches for a concrete `URLSession`-based client or a shared singleton, that's the one edit worth making in production code — inject the protocol through the initializer. Do not subclass the concrete client or stub a private method on the view model itself; that couples the test to an implementation detail and proves nothing about the real dependency.\n\n**2. Write a test double conforming to that protocol.** A struct conforming to `OrderClient` is usually enough — return a canned order, or throw a specific error, depending on the case:\n\n```swift\nstruct FakeOrderClient: OrderClient {\n var result: Result<Order, Error>\n func fetchOrder(id: String) async throws -> Order {\n try result.get()\n }\n}\n```\n\nIf you need to assert *what* was requested, hold a recorded `id` or a small actor if the calls happen off the main actor.\n\n**3. Inject it and await the real call.** No expectations or semaphores — just `await`:\n\n```swift\n@Test func loadOrderSucceeds() async throws {\n let model = OrderDetailModel(client: FakeOrderClient(result: .success(.fixture)))\n await model.load(id: \"42\")\n #expect(model.order == .fixture)\n}\n\n@Test func loadOrderSurfacesError() async throws {\n let model = OrderDetailModel(client: FakeOrderClient(result: .failure(OrderError.notFound)))\n await model.load(id: \"42\")\n #expect(model.error == .notFound)\n}\n```\n\n`#expect` records and continues; use `try #require` when a nil value would make the rest of the test meaningless. If the view model is `@MainActor`-isolated, put `@MainActor` on the test too so its state is read under the same isolation.\n\n**4. Cover the cases that matter:** success, the specific error the client throws (assert the thrown/`error` value, not just that something failed), and any empty/deferred state the view model exposes while loading.\n\n**5. Run it:**\n\n```bash\nswift test\n# or\nxcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\n```\n\nA couple of things to avoid: don't wait on the fetch with a `Task.sleep` guess — `await` the call or join a real completion signal; and if a test goes red, fix the test rather than loosening the assertion to `result != nil`, unless it has genuinely caught a bug in the view model, in which case say so instead of quietly changing production code.\n\nMatch whatever framework the target already uses — if the rest of the suite is on `XCTestCase`, use `XCTUnwrap`/`XCTAssert...` and the same fake-client pattern rather than introducing Swift Testing into one file.",
669
+ "outputSha256": "5b1cc4db9f0e315f382ad36a65c3c6bcd93b3de5dd95a9769d1a858b3c015fcf",
670
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
671
+ "deterministic": [],
672
+ "judge": {
673
+ "verdict": "pass",
674
+ "reason": "Answer names an `OrderClient` protocol boundary the view model depends on (step 1 code: `private let client: OrderClient; init(client: OrderClient)`), injects a `FakeOrderClient: OrderClient` test double through that existing initializer (step 3: `OrderDetailModel(client: FakeOrderClient(...))`), and explicitly warns against stubbing private methods or subclassing the concrete client. No fail criterion holds."
675
+ },
676
+ "passed": true
677
+ },
678
+ {
679
+ "output": "Set it up so the test never knows the real client exists — fake the protocol boundary the view model already depends on, not the view model's own internals.\n\n**1. Check what boundary already exists**\n\nLook at the view model's initializer. If it takes an `OrderClient` protocol (or similar) rather than constructing a concrete `URLSession`-backed client itself, that's your injection point. If it instead news up the concrete client internally, you'll need to introduce a protocol seam — but that's a production-code change, which this task should not touch. In that case, flag it rather than editing the view model.\n\nCheck how neighboring tests in the target set up their doubles, and whether the target imports `Testing` or builds on `XCTestCase` — match that, don't mix frameworks in one file.\n\n**2. Write a test double conforming to that protocol**\n\n```swift\nfinal class OrderClientStub: OrderClient {\n var result: Result<Order, Error> = .success(.fixture)\n private(set) var fetchCallCount = 0\n private(set) var lastRequestedID: Order.ID?\n\n func fetchOrder(id: Order.ID) async throws -> Order {\n fetchCallCount += 1\n lastRequestedID = id\n return try result.get()\n }\n}\n```\n\nThis conforms to the same protocol the production code depends on. It is not a subclass override of the view model and does not stub a private method on it — those couple the test to implementation details and break on harmless refactors.\n\n**3. Inject it and test the observable behavior**\n\n```swift\n@MainActor\n@Test func fetchOrder_success_populatesOrder() async throws {\n let stub = OrderClientStub()\n stub.result = .success(.fixture)\n let vm = OrderDetailModel(client: stub)\n\n await vm.load(id: Order.fixture.id)\n\n #expect(vm.order == .fixture)\n}\n\n@MainActor\n@Test func fetchOrder_failure_surfacesError() async throws {\n let stub = OrderClientStub()\n stub.result = .failure(OrderError.notFound)\n let vm = OrderDetailModel(client: stub)\n\n await vm.load(id: Order.fixture.id)\n\n #expect(vm.error as? OrderError == .notFound)\n}\n```\n\n`await` the call directly rather than bridging with an expectation or semaphore, and never `Task.sleep`-and-hope to wait for the fetch — a fixed delay is non-deterministic under CI load. If the view model is `@MainActor`-isolated, mark the test `@MainActor` too.\n\nUse `#expect` for checks that should record and continue; use `try #require(...)` when a nil would make the rest of the test meaningless. Throw in `fetchCallCount`/`lastRequestedID` assertions if the view model's contract includes \"fetches exactly once.\"\n\n**4. Cover the cases that matter**\n\nHappy path, the failure branch (assert the *specific* error, not just `vm.error != nil`), and any boundary input the view model handles specially. If several tests differ only by the stub's canned result, collapse them into one `@Test(arguments: [...])`.\n\n**5. Run and confirm**\n\n`swift test` for a package, or `xcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'` for an app target. Fix the tests, not the source — unless the test has caught a genuine bug, in which case report that instead of silently changing production code. Before finishing, `git status` should show only test files and test doubles touched.",
680
+ "outputSha256": "bbbe58b6b49140c63de598a37f7cc5795898e08549dc005fdc958d85493e42c3",
681
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
682
+ "deterministic": [],
683
+ "judge": {
684
+ "verdict": "pass",
685
+ "reason": "Answer names an `OrderClient` protocol boundary the VM depends on (step 1), injects a conforming `OrderClientStub` via the VM's existing initializer `OrderDetailModel(client: stub)` (step 3), and explicitly rejects stubbing the VM's private methods/subclassing. No fail criterion holds."
686
+ },
687
+ "passed": true
688
+ },
689
+ {
690
+ "output": "Set it up by mocking at the protocol boundary — the backend client the view model already talks to — not by reaching into the view model itself.\n\nAssuming the view model looks something like:\n\n```swift\nprotocol OrderClient {\n func fetchOrder(id: String) async throws -> Order\n}\n\n@MainActor\nfinal class OrderDetailModel {\n private let client: OrderClient\n private(set) var order: Order?\n private(set) var errorMessage: String?\n\n init(client: OrderClient) { self.client = client }\n\n func load(id: String) async {\n do {\n order = try await client.fetchOrder(id: id)\n } catch {\n errorMessage = \"Couldn't load the order.\"\n }\n }\n}\n```\n\nWrite a test double conforming to `OrderClient` — the same protocol the production code depends on — and inject it through the existing initializer. Do not subclass the view model and override `load`, and do not stub a private method.\n\nSwift Testing version:\n\n```swift\nimport Testing\n@testable import MyApp\n\nstruct FakeOrderClient: OrderClient {\n var result: Result<Order, Error>\n func fetchOrder(id: String) async throws -> Order { try result.get() }\n}\n\n@MainActor\nstruct OrderDetailModelTests {\n @Test func loadSetsOrderOnSuccess() async throws {\n let expected = Order(id: \"123\", total: 42.00)\n let model = OrderDetailModel(client: FakeOrderClient(result: .success(expected)))\n\n await model.load(id: \"123\")\n\n let order = try #require(model.order)\n #expect(order.id == \"123\")\n #expect(model.errorMessage == nil)\n }\n\n @Test func loadSetsErrorMessageOnFailure() async {\n let model = OrderDetailModel(\n client: FakeOrderClient(result: .failure(OrderClientError.timeout))\n )\n\n await model.load(id: \"123\")\n\n #expect(model.order == nil)\n #expect(model.errorMessage != nil)\n }\n}\n```\n\nA few points on why it is shaped this way:\n\n**Why the protocol, not the view model's internals.** The view model's only knowledge of the network is that it holds something conforming to `OrderClient`. Faking that protocol gives you a fast, deterministic, offline test that stays valid across refactors of the view model's private helpers — which a subclass-override or private-method-stub test does not.\n\n**`@MainActor` on the test.** The model is main-actor isolated, so the test needs the same isolation to touch `order`/`errorMessage` without a warning. If your model is not isolated, drop it.\n\n**`#require` vs `#expect`.** Use `#require` for a value the rest of the test depends on (here, unwrapping `order`) — it stops the test immediately on failure. Use `#expect` for independent checks.\n\n**Await directly, no sleeps.** `await model.load(id:)` already returns only after the work is done. Never insert `Task.sleep` or a fixed delay to \"give it time\" — that is non-deterministic under CI load and proves nothing.\n\n**Parameterized where inputs differ only by value.** If you later test several IDs or several error kinds, collapse them into one test:\n\n```swift\n@Test(\"loads each order id\", arguments: [\"123\", \"456\", \"789\"])\nfunc loadsOrder(id: String) async throws {\n let model = OrderDetailModel(client: FakeOrderClient(result: .success(Order(id: id, total: 1))))\n await model.load(id: id)\n #expect(try #require(model.order).id == id)\n}\n```\n\n**If the project is still on XCTest**, mirror the same structure with `XCTestCase`, `XCTUnwrap`, and `XCTAssert…` rather than mixing frameworks in one file. Match whatever the target already uses.\n\nThen run it:\n\n```bash\nxcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 16'\n# or, for a package:\nswift test\n```\n\nTwo things to watch for when you wire this up:\n\n- **If no protocol boundary exists yet** — e.g. the view model takes a concrete `URLSession`-backed client — introduce the protocol and have both the real client and the fake conform to it. That is a small production change; keep the fake and the test in the test target, and don't otherwise modify source under test.\n- **The only source change you should ever make here** is the protocol extraction (or an initializer that accepts it). Do not \"fix\" the view model to make a test pass. If a test fails because the view model is genuinely wrong, report that as a caught bug rather than silently editing production code.",
691
+ "outputSha256": "37666d74beeac232ad9c01db6244288bda18aad8f2d37aa347f5249076d9953d",
692
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
693
+ "deterministic": [],
694
+ "judge": {
695
+ "verdict": "pass",
696
+ "reason": "Answer names an `OrderClient` protocol the view model depends on (init(client: OrderClient)), injects a `FakeOrderClient` conforming type through the existing initializer, and explicitly warns against subclassing/overriding load or stubbing private methods. No fail criterion holds."
697
+ },
698
+ "passed": true
699
+ },
700
+ {
701
+ "output": "You want a test double at the protocol boundary, not a mock of the view model's own internals. Here's the shape of it:\n\n**1. Make the dependency protocol-typed.**\n\nIf the view model already takes a concrete client type, look at whether it conforms to (or can conform to) a protocol like:\n\n```swift\nprotocol OrderClientProtocol {\n func fetchOrder(id: Order.ID) async throws -> Order\n}\n```\n\nIf no protocol exists yet, that's the one production change worth making, because the whole \"swap in a fake without hitting the network\" story depends on it. The view model should hold an `OrderClientProtocol`, not a concrete `OrderClient`.\n\n**2. Inject it through the existing initializer.**\n\n```swift\n@MainActor\nfinal class OrderDetailModel {\n private let client: OrderClientProtocol\n init(client: OrderClientProtocol) { self.client = client }\n\n func load() async {\n state = .loading\n do { state = .loaded(try await client.fetchOrder(id: id)) }\n catch { state = .failed(error) }\n }\n}\n```\n\nThe test passes the fake in at `init` — it never reaches into private state to swap anything.\n\n**3. Write the fake in the test target.**\n\n```swift\nstruct FakeOrderClient: OrderClientProtocol {\n var result: Result<Order, Error>\n func fetchOrder(id: Order.ID) async throws -> Order {\n try result.get()\n }\n}\n```\n\nA `Result`-backed fake is enough for the success path, the empty/boundary case, and the thrown-error case, without a mocking library.\n\n**4. Test with the project's framework.**\n\nSwift Testing, if the target has moved to it:\n\n```swift\n@MainActor\nstruct OrderDetailModelTests {\n @Test func loadSucceedsWithFetchedOrder() async throws {\n let order = Order(id: \"1\", total: 42)\n let model = OrderDetailModel(client: FakeOrderClient(result: .success(order)))\n await model.load()\n #expect(model.state == .loaded(order))\n }\n\n @Test func loadSurfacesClientError() async throws {\n let model = OrderDetailModel(client: FakeOrderClient(result: .failure(OrderError.notFound)))\n await model.load()\n #expect(model.state == .failed(OrderError.notFound))\n }\n}\n```\n\n**5. Take the view model's isolation seriously.**\n\nIf `OrderDetailModel` is `@MainActor`, the test must be too, or the `await model.load()` call will hop actors and you'll get confusing failures. Match the isolation — don't fight it.\n\n**Two things to avoid:**\n\n- Don't stub the client's *private* methods or subclass it to override `fetchOrder`. Faking a private method couples the test to an implementation detail; the protocol fake is the boundary the production code actually depends on.\n- Don't \"wait\" for the fetch with `Task.sleep(for: .milliseconds(200))`. `await model.load()` already awaits the real completion. A fixed delay passes locally and flakes on CI under load.\n\nIf the target is still on `XCTestCase`, the same structure holds — just instantiate the model with the fake in `setUp` or per-test, use `XCTAssertEqual`/`XCTUnwrap`, and keep `await`-ing the real call rather than bridging through `XCTestExpectation`.\n\nOne thing worth checking before you write any of this: read one or two neighboring test files first to see whether the project already has a fake-client convention (a shared `FakeOrderClient` in a test helpers file, for instance). Reuse that rather than introducing a second fake for the same protocol.",
702
+ "outputSha256": "3be9c6d9591bd373adbc81d3322529b635cb5e0aa62728a48bf32781e8c0ac73",
703
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
704
+ "deterministic": [],
705
+ "judge": {
706
+ "verdict": "pass",
707
+ "reason": "Answer names an OrderClientProtocol boundary the view model holds (step 1: 'view model should hold an OrderClientProtocol, not a concrete OrderClient'), injects a FakeOrderClient conforming type via the existing init (step 2/3: 'init(client: OrderClientProtocol)', 'OrderDetailModel(client: FakeOrderClient(...))'), and explicitly warns against stubbing private methods/subclassing the client rather than doing it."
708
+ },
709
+ "passed": true
710
+ },
711
+ {
712
+ "output": "Treat the backend client as the protocol boundary and fake it there, not by touching the view model's internals.\n\nConcretely:\n\n1. **Confirm the boundary exists.** The view model should already depend on an abstraction (e.g. `protocol OrderClient { func fetchOrder(id: String) async throws -> Order }`) injected through its initializer, rather than instantiating a concrete `URLSession`-backed client itself. If it doesn't, that's a design gap in the production code, not something to work around with a private-method stub in the test. The test should conform a `StubOrderClient`/`SpyOrderClient` to that same protocol.\n\n2. **Match the target's existing conventions.** Check whether the test target imports `Testing` or is built on `XCTestCase`, and read a neighboring test file for naming and how existing doubles are constructed. Use whichever the target already uses; don't mix frameworks within one file.\n\n3. **Write the double to cover what you need:**\n - happy path — stub returns a valid `Order`\n - error path — stub throws the specific error (e.g. a `NetworkError.timeout`), and assert on *that* error, not just \"it throws\"\n - async behavior — if the view model sets a loading flag, assert it flips true then false around the awaited call\n\n4. **Inject and await; don't sleep.** Pass the double into the view model's initializer, then `await` the call directly:\n\n```swift\n@Test func loadOrder_populatesOrderOnSuccess() async throws {\n let client = StubOrderClient(result: .success(.fixture()))\n let vm = OrderViewModel(client: client)\n await vm.loadOrder(id: \"123\")\n #expect(vm.order?.id == \"123\")\n}\n```\n\nIf you need to assert the loading state mid-flight, use a real signal — an `AsyncStream`/continuation the stub yields from, or a `TaskGroup` join — never `Thread.sleep`/`Task.sleep` as a guess.\n\n5. **If the view model is `@MainActor`-isolated,** mark the test the same way so it exercises the real isolation instead of hopping actors.\n\n6. **Run it:** `xcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'` (or `swift test` for a package), and only report done once it exits 0 and `git status` shows test files only — no changes under the view model or client themselves.",
713
+ "outputSha256": "2cd03ba70f064c9307cc68a8aa05ebb49dea40ce9ea80f8cff01437e43a2f091",
714
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
715
+ "deterministic": [],
716
+ "judge": {
717
+ "verdict": "pass",
718
+ "reason": "Answer names protocol boundary `protocol OrderClient { func fetchOrder... }` the VM depends on (step 1), injects a conforming `StubOrderClient` via the VM's initializer (`OrderViewModel(client: client)` in the code sample), and explicitly rejects stubbing private methods/internals ('not by touching the view model's internals', 'private-method stub in the test'). No fail criterion holds."
719
+ },
720
+ "passed": true
721
+ },
722
+ {
723
+ "output": "Set up the test double at the boundary the view model already depends on, not inside the view model itself.\n\nConcretely:\n\n1. **Find (or define) the protocol boundary.** If `OrderDetailModel` takes an `OrderClient` (or similar) in its initializer — protocol-typed, not the concrete `URLSession`-based type — that protocol is your fake point. If it doesn't exist yet, that's a production-code change, which this skill's rules exclude from a test-writing pass; flag it rather than silently refactoring the view model.\n\n2. **Write a fake conforming to that protocol**, not a subclass of the concrete client and not a stub of the view model's private methods. It should return a canned `Order` on success, and be constructible in a throwing mode for your error-path tests — so you can assert the *specific* error surfaces, not just that something failed.\n\n3. **Inject it through the existing initializer**, e.g. construct the view model with your fake where the production dependency would go.\n\n4. **Await the call directly.** If the fetch is async, `await model.load()` in the test rather than spinning on `XCTestExpectation`/a semaphore, and never `Task.sleep` as a stand-in for \"should be done by now.\"\n\n5. **Match the target's existing framework.** If the test target already imports `Testing`, write `@Test func ... async throws` with `#expect`/`try #require`; if it's still on `XCTestCase`, use `XCTAssert`/`XCTUnwrap` there instead. Read a neighboring test file first for naming and how existing mocks are built.\n\nA useful shape, assuming Swift Testing and the protocol boundary exists:\n\n```swift\nstruct FakeOrderClient: OrderClient {\n var result: Result<Order, Error>\n func fetchOrder(id: Order.ID) async throws -> Order {\n try result.get()\n }\n}\n\n@Test func loadsOrderOnSuccess() async throws {\n let model = OrderDetailModel(\n client: FakeOrderClient(result: .success(.fixture))\n )\n await model.load()\n #expect(model.order?.id == Order.fixture.id)\n}\n\n@Test func surfacesFetchError() async throws {\n let model = OrderDetailModel(\n client: FakeOrderClient(result: .failure(OrderClientError.notFound))\n )\n await model.load()\n #expect(model.error as? OrderClientError == .notFound)\n}\n```\n\nFor a parameterized pass, `@Test(\"...\", arguments: [...])` over the fake's `Result` cases beats copy-pasting one test per outcome.\n\nThe thing to avoid: subclassing the real client or reaching into the view model's private `fetchFromDisk()`-style internals. That couples the test to an implementation detail, breaks on harmless refactors, and never exercises the dependency the view model actually talks to.",
724
+ "outputSha256": "0be3eea10cfa829bded1e187c0fa565f7270f31676ade6a0e9786b4dec46ea69",
725
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
726
+ "deterministic": [],
727
+ "judge": {
728
+ "verdict": "pass",
729
+ "reason": "Answer names an `OrderClient` protocol boundary the view model depends on (step 1, code `struct FakeOrderClient: OrderClient`), injects the fake through the existing initializer (`OrderDetailModel(client: FakeOrderClient(...))`), and explicitly warns against subclassing the real client or reaching into private internals. No fail criterion holds."
730
+ },
731
+ "passed": true
732
+ },
733
+ {
734
+ "output": "Set it up by faking the *protocol* the view model already depends on, not the view model's internals.\n\nFirst, look at how the view model gets its backend client:\n\n- If it takes a concrete `OrderClient` type, you're stuck — either that type already conforms to a protocol, or you define one now (e.g. `protocol OrderFetching { func fetchOrder(id: Order.ID) async throws -> Order }`) and make the view model depend on `any OrderFetching`. That's a source change though — rules say test-only edits, so if the boundary doesn't exist, flag that to whoever owns the code rather than silently refactoring production.\n- If it already takes a protocol, you're in good shape — write a test double conforming to it.\n\nThe test double, matching whatever the project's neighbors do:\n\n```swift\nfinal class FakeOrderClient: OrderFetching {\n var result: Result<Order, Error> = .failure(URLError(.badServerResponse))\n var fetchCallCount = 0\n\n func fetchOrder(id: Order.ID) async throws -> Order {\n fetchCallCount += 1\n return try result.get()\n }\n}\n```\n\nThen inject it and drive the view model directly:\n\n```swift\n@Test func loadOrder_success_exposesOrder() async throws {\n let client = FakeOrderClient()\n client.result = .success(Order(id: \"1\", total: 42))\n let vm = OrderViewModel(client: client)\n\n await vm.load(id: \"1\")\n\n #expect(vm.order?.total == 42)\n #expect(client.fetchCallCount == 1)\n}\n\n@Test func loadOrder_failure_setsErrorMessage() async throws {\n let client = FakeOrderClient()\n client.result = .failure(OrderError.notFound)\n let vm = OrderViewModel(client: client)\n\n await vm.load(id: \"1\")\n\n #expect(vm.errorMessage != nil)\n #expect(vm.order == nil)\n}\n```\n\nKey points to get right:\n\n- **`await` the call, don't wait.** If `load` is async, `await vm.load(id:)` directly. Don't reach for `XCTestExpectation` or a `Task.sleep` guess — if the work happens in a `Task` the view model owns internally, expose its completion or await the state it publishes rather than sleeping.\n- **Assert on what, not just whether.** `#expect(vm.order?.total == 42)` beats `#expect(vm.order != nil)`. The error-case test should assert the specific error surfaced, not just \"something went wrong.\"\n- **`@MainActor` if the view model is.** If it's main-actor-isolated, the test needs the same isolation or the compiler will make you `await` every property access.\n- **Match the target's framework.** If the suite is already `Testing`, use `@Test`/`#expect`/`#require`; if it's still `XCTestCase`, use `XCTAssert`/`XCTUnwrap`. Don't mix within a file.\n\nParameterize the variations instead of copy-pasting test functions — e.g. one `@Test(\"decodes order state\", arguments: [...])` covering several success payloads.\n\nThen run `swift test` (or `xcodebuild test -scheme … -destination 'platform=iOS Simulator,name=…'`), and confirm `git status` shows only test files touched — no edits under the view model or client.",
735
+ "outputSha256": "f1aa40ba7966762b371721717d188a5271ca1183dda3e21d091b524ad76132fd",
736
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
737
+ "deterministic": [],
738
+ "judge": {
739
+ "verdict": "pass",
740
+ "reason": "Names protocol boundary `OrderFetching` the VM depends on (criterion 1), injects FakeOrderClient via existing initializer `OrderViewModel(client: client)` (criterion 2), and never mocks VM private methods/state (criterion 3). No fail criterion holds."
741
+ },
742
+ "passed": true
743
+ },
744
+ {
745
+ "output": "Set it up by faking the dependency at the protocol boundary — not by mocking the view model's own internals.\n\n**1. Confirm (or define) the protocol boundary the view model already depends on.**\n\nYour view model is presumably initialized with something like an `OrderClient`/`OrderFetching` protocol. If it instead hardcodes a concrete network type, that's the real problem — extract or point at the protocol seam first, and inject through the view model's existing initializer. Do not reach into private state to swap anything.\n\n**2. Write a test double conforming to that protocol.**\n\nIn the test file (specifically — this belongs in the test target, not production code unless the project already keeps shared fakes there):\n\n```swift\nstruct OrderClientStub: OrderClient {\n var order: Order?\n var error: Error?\n\n func fetchOrder(id: String) async throws -> Order {\n if let error { throw error }\n guard let order else { throw OrderError.notFound }\n return order\n }\n}\n```\n\nName and shape it to match whatever your Step 1 read of neighboring test files shows — match the project's existing mock conventions rather than this generic sketch.\n\n**3. Inject it and test under the same isolation as the view model.**\n\n```swift\n@MainActor\nstruct OrderViewModelTests {\n @Test func loadsOrder() async throws {\n let stub = OrderClientStub(order: Order(id: \"1\", total: 42))\n let vm = OrderViewModel(client: stub)\n\n await vm.load(id: \"1\")\n\n #expect(vm.order?.id == \"1\")\n }\n\n @Test func surfacesFetchFailure() async throws {\n let stub = OrderClientStub(error: OrderError.network)\n let vm = OrderViewModel(client: stub)\n\n await vm.load(id: \"1\")\n\n #expect(vm.error != nil)\n }\n}\n```\n\nIf your view model is `@MainActor`-isolated (most are), the test needs the same annotation — that's the most common cause of a \"cannot call main actor-isolated\" compile error here.\n\n**Key points to avoid the usual traps:**\n\n- **Fake the protocol, not the view model's own methods.** Stubbing a private `fetchFromDisk()` or subclassing the view model to override internals couples the test to an implementation detail — it'll break on a harmless refactor and won't prove anything about the real dependency. The stub above only replaces the network seam the view model actually depends on.\n- **`await` the call directly.** No `Thread.sleep`/`Task.sleep` to \"give it time,\" no `XCTestExpectation`/semaphore bridging unless your toolchain predates async test support. Just `await vm.load(id:)`.\n- **Cover the error path explicitly.** Assert the *specific* error you injected, not just `err != nil` — that's the case that catches regressions.\n- **Match your target's framework.** If the rest of the target uses XCTest, write `XCTestCase` with `XCTAssert`/`XCTUnwrap`; if it's migrated to Swift Testing, use `@Test`/`#expect`/`#require`. Don't mix frameworks within one file.\n\nRun it with `xcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'` (or `swift test` for a package) and confirm it exits clean before calling it done.\n\nOne thing to flag: if a test fails and the correct fix looks like a change to the view model's production code, stop — tests alone shouldn't drive source edits in this workflow. Report the suspected real bug instead of silently patching production code to make the suite green.",
746
+ "outputSha256": "fa80bbfc48f52a330f2c8c828de239b8abf64064b79c2a638f9a02aee8f4bfc9",
747
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
748
+ "deterministic": [],
749
+ "judge": {
750
+ "verdict": "pass",
751
+ "reason": "Names protocol boundary (OrderClient/OrderFetching) the VM depends on, not concrete type. Shows OrderClientStub conforming type injected via existing initializer (OrderViewModel(client: stub)). Explicitly warns against stubbing private methods/subclassing VM internals. No fail criterion met."
752
+ },
753
+ "passed": true
754
+ },
755
+ {
756
+ "output": "Set up the fake at the protocol boundary the view model already depends on — the backend client — not inside the view model itself.\n\n**1. Check whether a protocol boundary already exists.**\n\nLook at how the view model gets its client today. If it takes a concrete `OrderClient` (a struct/class that does `URLSession` work), the cleanest move is to define a protocol that captures exactly the calls the view model makes, and have both the real client and your test double conform to it:\n\n```swift\nprotocol OrderFetching {\n func fetchOrder(id: String) async throws -> Order\n}\n\nfinal class OrderClient: OrderFetching { /* real URLSession work */ }\n```\n\nThen the view model depends on `OrderFetching`, injected through its initializer:\n\n```swift\nfinal class OrderDetailModel {\n private let client: OrderFetching\n init(client: OrderFetching) { self.client = client }\n // ...\n}\n```\n\nIf the production code already injects at a protocol boundary, use it as-is — don't invent a parallel one.\n\n**2. Build the test double against that protocol.**\n\nNot a subclass override, not a stub of the view model's private state — a standalone type conforming to `OrderFetching`, configured to return a canned `Order` or throw a specific error:\n\n```swift\nstruct FakeOrderClient: OrderFetching {\n var result: Result<Order, Error>\n func fetchOrder(id: String) async throws -> Order {\n try result.get()\n }\n}\n```\n\n**3. Write the tests against the injected fake.**\n\nMatching whatever the target already uses — Swift Testing here:\n\n```swift\n@Test func loadsOrderOnSuccess() async throws {\n let expected = Order(id: \"1\", total: 42)\n let model = OrderDetailModel(client: FakeOrderClient(result: .success(expected)))\n\n await model.load()\n\n #expect(model.order?.id == \"1\")\n}\n\n@Test func surfacesErrorOnFailure() async throws {\n let model = OrderDetailModel(client: FakeOrderClient(result: .failure(OrderError.notFound)))\n\n await model.load()\n\n #expect(model.error != nil)\n}\n\n@Test(\"decodes varying totals\", arguments: [0, 1, 999])\nfunc totalIsPreserved(total: Int) async throws {\n let model = OrderDetailModel(\n client: FakeOrderClient(result: .success(Order(id: \"1\", total: total)))\n )\n await model.load()\n #expect(model.order?.total == total)\n}\n```\n\n**Key points for this setup:**\n\n- The real network is never touched because the view model only ever sees the `OrderFetching` fake.\n- `await` the `load()` call directly — no `XCTestExpectation`, no `Task.sleep`, no semaphore.\n- If the view model is `@MainActor`-isolated, annotate the test the same way so the assertions run on the right actor.\n- Keep the fake configurable (a `Result` property, or a closure) so one double serves success, failure, and boundary cases without multiplying types.\n\n**What to avoid:**\n\n- Don't subclass `OrderClient` and override its methods — that couples you to the real implementation's shape.\n- Don't reach into the view model to swap a private client; if it can't be injected, that's the refactor signal, and it belongs to the production code, not the test.\n- Don't loosen assertions just to get green — a `notFound` test should check the error you actually expect, not just `error != nil`.\n\nIf there's no injection point at all today (the client is hard-wired in the view model's body), the first step is adding the initializer parameter in production code — flag that as a small production change rather than trying to fake around it.",
757
+ "outputSha256": "777f781b49117962187de3cebd980afa5db31a2fcaf16cc8de1010e0477571a4",
758
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
759
+ "deterministic": [],
760
+ "judge": {
761
+ "verdict": "pass",
762
+ "reason": "Answer names a protocol boundary `OrderFetching` the view model depends on (step 1), injects a conforming `FakeOrderClient` through the view model's initializer `init(client: OrderFetching)` (steps 1-3), and explicitly warns against subclassing the concrete client or swapping private state. No mocking of the view model's own private methods."
763
+ },
764
+ "passed": true
765
+ },
766
+ {
767
+ "output": "Set the test up entirely at the protocol boundary, not on the view model's internals.\n\n**1. Find or add the protocol boundary.**\n\nYour view model should depend on an abstraction, not a concrete client. If it currently does:\n\n```swift\nfinal class OrderDetailModel {\n private let client = OrderClient() // concrete\n}\n```\n\nthat is the problem. Introduce (or use the existing) protocol:\n\n```swift\nprotocol OrderFetching {\n func fetchOrder(id: String) async throws -> Order\n}\n\nfinal class OrderDetailModel {\n private let client: OrderFetching\n init(client: OrderFetching) { self.client = client }\n}\n```\n\nInjecting through the initializer is what makes the test possible. Do not subclass `OrderClient` or reach into the view model to stub a private method — that couples the test to an implementation detail and breaks on a harmless refactor.\n\n**2. Write a test double conforming to that protocol.**\n\n```swift\nstruct StubOrderFetcher: OrderFetching {\n var result: Result<Order, Error>\n\n func fetchOrder(id: String) async throws -> Order {\n try result.get()\n }\n}\n```\n\nGive it configurable behavior so you can cover the error path too — a `Result` is enough here; a spy (recording the `id` it was called with) if you also need to assert *what* was requested.\n\n**3. Write the tests (Swift Testing; swap for `XCTestCase` if that target is still on XCTest).**\n\n```swift\nimport Testing\n\n@Suite(\"OrderDetailModel\")\nstruct OrderDetailModelTests {\n\n @Test func loadsOrderOnSuccess() async throws {\n let expected = Order(id: \"1\", total: 42)\n let model = OrderDetailModel(client: StubOrderFetcher(result: .success(expected)))\n\n try await model.load(id: \"1\")\n\n #expect(model.order == expected)\n }\n\n @Test func surfacesFetchError() async throws {\n let model = OrderDetailModel(client: StubOrderFetcher(result: .failure(OrderError.notFound)))\n\n await #expect(throws: OrderError.notFound) {\n try await model.load(id: \"1\")\n }\n }\n}\n```\n\n`#expect` records and continues; use `try #require` for anything the rest of the test depends on being non-nil.\n\n**4. Assert on the client interaction by input, parameterized where it varies only by input.**\n\nIf the view model should pass the id through, make the stub a spy rather than asserting on it indirectly. For several id/expected pairs, use `arguments:` instead of copy-pasted tests:\n\n```swift\n@Test(\"passes the requested id\", arguments: [\"1\", \"2\", \"abc\"])\nfunc requestsCorrectID(id: String) async throws {\n let spy = SpyOrderFetcher(result: .success(.fixture))\n try await OrderDetailModel(client: spy).load(id: id)\n #expect(spy.requestedIDs == [id])\n}\n```\n\n**5. Await directly — never sleep.**\n\n`await model.load(id:)` already gives you determinism. Do not add `Task.sleep` or a semaphore to \"let the call finish\"; that is a non-deterministic guess that fails under CI load. Await the call, or join a real completion signal.\n\n**6. If the view model is `@MainActor`-isolated**, annotate the test the same way so it exercises the real isolation rather than hopping off it:\n\n```swift\n@MainActor\n@Test func loadsOrderOnSuccess() async throws { ... }\n```\n\n**7. Run it.**\n\n```\nxcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\n# or, Swift package:\nswift test\n```\n\nRules to hold to: match the framework and mock style the target already uses; never touch production source (only test files and doubles); fake the *protocol*, never the view model's own internals; and no fixed delays for async. If a test fails, fix the test unless it has genuinely caught a real bug in the view model — in which case report it rather than editing production code.",
768
+ "outputSha256": "6317b850999b49a69e7dc56e84f5735facc8718693f2db0a2c9eb809c6a461f7",
769
+ "promptSha256": "2e4bb69915c6d7ea60483e8abca996218b0428078e7dbc54784106153a387040",
770
+ "deterministic": [],
771
+ "judge": {
772
+ "verdict": "pass",
773
+ "reason": "Answer names protocol boundary `OrderFetching` the view model depends on (step 1), injects `StubOrderFetcher`/`SpyOrderFetcher` conforming types via the view model's initializer `init(client: OrderFetching)` (steps 1-3), and explicitly warns against subclassing OrderClient or stubbing private methods. No fail criterion holds."
774
+ },
775
+ "passed": true
776
+ }
777
+ ]
778
+ },
779
+ {
780
+ "id": "no-fixed-delay-async-wait",
781
+ "kind": "behavior",
782
+ "prompt": "My test starts an async task in a view model and I want to wait for it to finish before asserting on the result. What's the right way to do this?",
783
+ "strictness": "high",
784
+ "trials": 10,
785
+ "passes": 10,
786
+ "passRate": 1,
787
+ "passAtK": 1,
788
+ "grader": "judge",
789
+ "status": "ran",
790
+ "trialRecords": [
791
+ {
792
+ "output": "Await the call directly — don't guess at a delay.\n\nIf the view model exposes an async entry point, the test itself should be async and just `await` it:\n\n```swift\n@Test func loadOrders_populatesOrders() async throws {\n let client = MockOrderClient(result: .success([.fixture]))\n let model = OrderListModel(client: client)\n\n await model.load() // the async work completes before this returns\n\n #expect(model.orders.count == 1)\n}\n```\n\nIf the view model *kicks off* the task rather than exposing something to await (e.g. it stores a `Task` internally, or starts work in `onAppear`/`init`), you have two options, in order of preference:\n\n1. **Expose the task (or an async seam) to the test.** The cleanest fix is for the view model to hold the in-flight `Task` and let the test await it, or to provide an async variant the test can call. This is a small, legitimate production change — a test-visible completion seam — not a test hack.\n\n```swift\n// view model\nprivate(set) var loadTask: Task<Void, Never>?\nfunc startLoading() {\n loadTask = Task { await self.load() }\n}\n\n// test\nfunc testStartLoading() async throws {\n let model = OrderListModel(client: mockClient)\n model.startLoading()\n await model.loadTask?.value // await the real task, no timing guess\n #expect(model.orders.count == 1)\n}\n```\n\n2. **Await a real fulfillment signal.** If the dependency is protocol-based (your `OrderClient` mock), have the mock signal completion via a continuation or an `AsyncStream` the test consumes — the assertion then runs after the real callback, not after a timer.\n\nWhat to avoid:\n\n- `Task.sleep(for: .milliseconds(200))` or `Thread.sleep` — non-deterministic; passes locally, flakes on CI under load. If you find yourself reaching for this, it means you don't have an awaitable seam yet, so go back to option 1.\n- `XCTestExpectation` + `wait(for:timeout:)` when the toolchain supports async tests — it's a bridge that's easy to get wrong; `await` is strictly better.\n- Asserting inside the view model's completion callback captured by the test, when you could just await and assert in the test body — keeps assertions in one place and failures attributable.\n\nThe underlying rule: the test should wait on the *actual unit of work* (a `Task`, an `async` method, a continuation), never on a duration you guessed. If you can't name what you're waiting on, the view model is missing a seam the test needs.\n\nOne caveat specific to this pattern: if the task has to hop to `@MainActor` to mutate `published`/observed state, make the test `@MainActor` too (or the whole test type), otherwise you're reading state off the wrong executor and may see stale values even after a correct await.",
793
+ "outputSha256": "6cee8e4d17b6155493e4448b8d758dd7684050a05c51b70e9074e5992bb5a9eb",
794
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
795
+ "deterministic": [],
796
+ "judge": {
797
+ "verdict": "pass",
798
+ "reason": "Answer awaits the async call directly (`await model.load()` in an async test) and awaits the real Task (`await model.loadTask?.value`), and explains reliability: 'never on a duration you guessed', 'non-deterministic; passes locally, flakes on CI'. It warns against Task.sleep/Thread.sleep rather than recommending it, so no fail criterion holds."
799
+ },
800
+ "passed": true
801
+ },
802
+ {
803
+ "output": "Await the async work directly — don't poll or sleep for it.\n\nIf the view model kicks off its work through a method the test can call, make that method `async` (or expose an `async` entry point) and `await` it in the test, then assert:\n\n```swift\n@Test func loadPopulatesOrders() async throws {\n let client = FakeOrderClient(result: .success([.sample]))\n let model = OrderDetailModel(client: client)\n\n await model.load()\n\n #expect(model.orders == [.sample])\n}\n```\n\nIf the work is fire-and-forget (the view model starts an internal `Task` and returns immediately), the fix is to give the test something real to await rather than guessing a duration:\n\n- **Keep a handle to the task.** Store the `Task` on the view model (`private(set) var loadTask: Task<Void, Never>?`) and `await model.loadTask?.value` in the test. This awaits the actual completion, deterministically.\n- **Expose an async API.** Prefer a `func load() async` that the view's `.task { await model.load() }` calls, so production and test share one awaitable path.\n- **Await a real signal for concurrent work.** If several tasks feed one result, `await withTaskGroup` / await their task handles, or await a fulfillment signal (an `AsyncStream`, a continuation, `confirmation()`) that fires when the work is genuinely done.\n\nWhat not to do:\n\n- `Task.sleep(for: .milliseconds(200))` or `Thread.sleep` as a \"should be enough\" wait — non-deterministic and flaky under CI load.\n- Polling `model.isLoading` in a loop with a delay — same problem, just slower.\n- Bridging to `XCTestExpectation`/a semaphore when the toolchain supports `async` tests — `await` is simpler and doesn't deadlock the main actor.\n\nOne caveat on isolation: if the view model is `@MainActor`-isolated, mark the test `@MainActor` too (or isolate the relevant function) so the awaited call and the assertions run on the same actor and you're not racing the property reads against the write:\n\n```swift\n@MainActor\n@Test func loadPopulatesOrders() async throws { ... }\n```\n\nSame for a legacy `XCTestCase` target — make the test method `async throws` and `await` the call; only reach for an expectation if the underlying API genuinely can't be awaited (e.g. a delegate callback with no async wrapper), and then await the real fulfillment, not a timeout.",
804
+ "outputSha256": "a1aade7652239dd21f3e66a0bfd3a1ba0fd7d253d8e756b332da34f947d02799",
805
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
806
+ "deterministic": [],
807
+ "judge": {
808
+ "verdict": "pass",
809
+ "reason": "Answer awaits the async call directly: `await model.load()` in an `async` test, plus `await model.loadTask?.value` and TaskGroup/AsyncStream/continuation/confirmation() as real joins. It explains reliability: fixed sleeps are 'non-deterministic and flaky under CI load' and 'guessing a duration'. Sleep is only warned against, not recommended."
810
+ },
811
+ "passed": true
812
+ },
813
+ {
814
+ "output": "The right way is to await the actual work — not to insert a guessed delay and not to reach into the view model's internals to poll a flag.\n\n**If the view model exposes the task directly**\n\nHave the method that kicks off the work be `async` (or return the `Task`), and await it in the test:\n\n```swift\n@Test func load_populatesItems() async throws {\n let client = OrderClientStub(result: .success([.fixture()]))\n let vm = OrderDetailModel(client: client)\n\n await vm.load() // await the real work, not a sleep\n\n #expect(vm.items == [.fixture()])\n #expect(client.loadCallCount == 1)\n}\n```\n\n**If the work is fire-and-forget inside the view model**\n\nDon't wait on a timer and don't read a private `isLoading` flag with `Task.sleep` in a retry loop. Instead prefer one of these, in order:\n\n1. **Make the seam awaitable.** Have the view model store the `Task` it launched and expose an internal/testable `func waitForPendingWork() async` that awaits it — or have it expose the task itself. The test awaits that, deterministically.\n2. **Await a real signal.** If the view model publishes completion (an `AsyncStream`, a continuation, a `@Published` state you can await), await the stream's next element or the state transition. This is a real fulfillment signal, not a guessed duration.\n3. **Structured concurrency in the test.** If it launches a `TaskGroup`, the test can `for await` the group or join its tasks.\n\n```swift\n@Test func refresh_finishesLoading() async throws {\n let vm = OrderDetailModel(client: .stub())\n let task = vm.startRefresh() // returns the Task\n await task.value\n #expect(vm.state == .loaded)\n}\n```\n\n**What to avoid**\n\n- `Thread.sleep(forTimeInterval:)` or `Task.sleep(for:)` as a \"should be long enough\" wait — non-deterministic under CI load; it either flakes or silently passes too early.\n- `XCTestExpectation` + semaphore bridging when `await` is available — only use it if the toolchain genuinely predates async test support.\n- Polling a private `isLoading`/`isFinished` flag from outside — that couples the test to internal state rather than the observable outcome, and it's still a race unless the flag is actually synchronized.\n\nThe underlying rule: await the call itself, join the task, or await a real completion signal. Never guess a duration.",
815
+ "outputSha256": "085deb20732ad98d828af83b3a1dc5719618e92e24a5680db85fb1d59f72eefd",
816
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
817
+ "deterministic": [],
818
+ "judge": {
819
+ "verdict": "pass",
820
+ "reason": "Answer awaits the real work: `await vm.load()` in an async test, and `await task.value` on the returned Task. It also names awaiting a real signal (AsyncStream/continuation) and joining a TaskGroup. It explains reliability: fixed sleeps are 'non-deterministic under CI load; it either flakes or silently passes too early.' No fixed sleep is recommended as a wait mechanism."
821
+ },
822
+ "passed": true
823
+ },
824
+ {
825
+ "output": "The right way is to `await` the async call directly instead of trying to wait for a task to finish \"in the background.\" The anti-pattern to avoid is a fixed delay — `Thread.sleep(forTimeInterval:)` or `Task.sleep(for: .milliseconds(200))` — because it's non-deterministic under CI load and either flaky or needlessly slow.\n\nThree approaches, in order of preference:\n\n**1. Have the view model expose something awaitable.**\n\nIf the view model kicks off work internally and you can't await it from outside, that's usually a design signal: give it an async entry point that returns when the work is done, or expose the in-flight `Task` so the test can await it.\n\n```swift\n@Test @MainActor func loadUpdatesState() async throws {\n let vm = OrderDetailModel(client: OrderClientStub())\n await vm.load() // returns only once the work is complete\n #expect(vm.orders.count == 3)\n}\n```\n\n**2. Store and await the `Task`.**\n\nIf the view model deliberately fires-and-forgets internally:\n\n```swift\n@Test @MainActor func loadUpdatesState() async throws {\n let vm = OrderDetailModel(client: OrderClientStub())\n vm.load()\n await vm.loadTask?.value // await the real completion, no guessing\n #expect(vm.orders.count == 3)\n}\n```\n\n**3. Bridge to a real completion signal only if you can't await at all.**\n\nFor legacy or callback-only APIs on an `XCTestCase` target, use `XCTestExpectation` and fulfill it from the actual completion handler — never from a timer:\n\n```swift\nfunc testLoadUpdatesState() async throws {\n let exp = expectation(description: \"load finished\")\n let vm = OrderDetailModel(client: OrderClientStub())\n vm.load { exp.fulfill() }\n await fulfillment(of: [exp], timeout: 2)\n XCTAssertEqual(vm.orders.count, 3)\n}\n```\n\nNote `await fulfillment(of:timeout:)` (the async form), not `wait(for:timeout:)`.\n\n**Two things to watch:**\n\n- **Isolation.** If the view model is `@MainActor`-isolated, mark the test `@MainActor` too (as above) so state can't be mutated from the wrong executor mid-assertion.\n- **Determinism.** Make the stub's async work complete deterministically — resolve it synchronously or via a continuation you control — so the await returns the moment the real signal fires. If the test hangs, that's a genuine \"never completed\" bug surfacing, not something to paper over with a longer timeout.\n\nThe one thing not to do is sleep for a guessed duration and then assert. It passes locally, fails in CI, and doesn't actually prove the work finished.",
826
+ "outputSha256": "612ce76935233b806b4561937de0429aa9aaf6020b6fcc9100022d2d843cafbf",
827
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
828
+ "deterministic": [],
829
+ "judge": {
830
+ "verdict": "pass",
831
+ "reason": "Answer uses `await vm.load()` (test marked async) and `await vm.loadTask?.value` as the real mechanism, plus a fulfilled XCTestExpectation via `await fulfillment(of:)`. It explicitly explains fixed delays are non-deterministic/flaky and 'doesn't actually prove the work finished.' No Task.sleep/Thread.sleep recommended as a wait mechanism."
832
+ },
833
+ "passed": true
834
+ },
835
+ {
836
+ "output": "Await the async work directly rather than waiting on it indirectly.\n\nIf the view model exposes the task/call, just `await` it:\n\n```swift\n@Test func loadsOrder() async throws {\n let model = OrderDetailModel(client: FakeOrderClient())\n await model.load() // the async entry point completes here\n #expect(model.state == .loaded(order))\n}\n```\n\nIf the work is fired off *inside* a synchronous trigger (e.g. a button tap) and the view model doesn't hand back the `Task`, you need one of these instead:\n\n1. **Store and expose the task.** Have the view model keep the `Task` it spawned (commonly `private(set) var loadTask: Task<Void, Never>?`) and `await model.loadTask?.value` in the test. This is the cleanest option and requires only a tiny, test-visible change to the production type — worth it.\n\n2. **Await a real completion signal.** If the view model publishes state (an `@Observable`/`ObservableObject` property, or an `AsyncStream`), await the transition you care about rather than a duration:\n\n```swift\nfor await state in model.states {\n if case .loaded = state { break }\n}\n```\n\n3. **Drain with a task group** only if you truly have several independent concurrent operations to join:\n\n```swift\nawait withTaskGroup(of: Void.self) { group in\n group.addTask { await model.loadA() }\n group.addTask { await model.loadB() }\n}\n```\n\nWhat to avoid:\n\n- `Task.sleep` / `Thread.sleep` as a \"give it a moment\" delay — it's a race under CI load and will flake.\n- `XCTestExpectation` + a manual `fulfill()` bridged into the view model just for the test — that leaks test scaffolding into production code; prefer option 1 or 2. Only fall back to expectations if the target toolchain predates async test support.\n- Polling `model.state` in a `while` loop with a delay.\n\nIf the async entry point is `@MainActor`-isolated, the test needs the same isolation (`@MainActor @Test func ...`) so the await hops back onto the main actor correctly. And the dependency the task calls should be a protocol-typed fake injected through the view model's initializer — that's what makes the await reach a deterministic, already-completed result instead of real network timing.",
837
+ "outputSha256": "384f6cff3b2c4b71474fbc90c4d776990516012fa5fee436bb074fdd43c33511",
838
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
839
+ "deterministic": [],
840
+ "judge": {
841
+ "verdict": "pass",
842
+ "reason": "Answer's core mechanism is `await model.load()` in an async test, plus real joins: `await model.loadTask?.value`, awaiting an AsyncStream state transition, and `withTaskGroup`. It explicitly warns against Task.sleep/Thread.sleep as a flaky race, satisfying criterion 2. No fixed delay is recommended."
843
+ },
844
+ "passed": true
845
+ },
846
+ {
847
+ "output": "Wait on a real signal — never a guessed `Task.sleep`/`Thread.sleep`:\n\n1. **If the view model exposes an async entry point, just `await` it** — the simplest case, and the one to reach for first. If `load()` or similar is `async`, the test is `@Test func loadUpdatesState() async throws { await model.load(); #expect(model.items.count == 3) }`. No waiting primitive needed at all.\n\n2. **If the work is kicked off and not awaited by the caller** (e.g. the task is started internally and the entry point returns synchronously), await a completion signal, in preference order:\n - **`withCheckedContinuation`/`withCheckedThrowingContinuation` bridged from the view model's own completion/observation point** — if it exposes a callback or a publisher, await its fulfillment rather than polling state.\n - **`Observation`/`AsyncStream` bridging**: if the model publishes state changes, `for await state in model.states { if state.isLoaded { break } }` tied to the real signal, not a timeout.\n - **Expose the `Task` and await it**: if the model stores the `Task` (or you can have it be stored), `await model.currentTask?.value` is deterministic — but only if the type already does this or you do it purely in the test double, never by reaching into private state.\n - **XCTestExpectation** with `fulfill()` called from the actual code path that completes the work, and `wait(for:timeout:)` — a *generous* timeout is a safety net for a hang, not the mechanism that decides when the work is done.\n\n3. **Never `Task.sleep(for:)` / `Thread.sleep` as the synchronization mechanism.** It is non-deterministic: fast machines pass, CI under load flakes, and a real regression (the task never completing) turns into a slow test that still passes. A delay is not a signal.\n\n4. **If you need to observe a side effect before asserting**, drive it through the protocol boundary the view model already depends on — e.g. a fake network client whose `fetch()` is `async`, so its completion *is* the signal you await. Don't poll the view model's published properties in a spin loop.\n\n5. **`@MainActor` isolation**: if the view model is main-actor-isolated and you're asserting on its state after awaiting, mark the test `@MainActor` too (or hop with `await MainActor.run { ... }` around the assertion) so the read is isolated the same way the write was.\n\nShort version: make the test's `await` the thing that waits — await the async entry point, or await a real completion signal (continuation/publisher/Task value/expectation fulfilled by the real code path). Anything that waits \"long enough\" is the wrong tool.",
848
+ "outputSha256": "ea86a117453560cfe1446d5758e6d50ef09046e16564ebe6d58889d55612b9fb",
849
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
850
+ "deterministic": [],
851
+ "judge": {
852
+ "verdict": "pass",
853
+ "reason": "Answer's core mechanism is awaiting the async entry point: `@Test func loadUpdatesState() async throws { await model.load(); #expect(...) }` (point 1), plus real signals: withCheckedContinuation, AsyncStream, `await model.currentTask?.value`, and XCTestExpectation fulfilled by the real code path (point 2). Point 3 explicitly rejects Task.sleep/Thread.sleep as non-deterministic guessing, satisfying criterion 2. No fixed delay recommended."
854
+ },
855
+ "passed": true
856
+ },
857
+ {
858
+ "output": "Await the async call directly — don't sleep, don't bridge through a semaphore or expectation.\n\nIf the view model exposes the task (or a method returning an `async` function), the test body just does:\n\n```swift\n@Test func loadOrder() async throws {\n let model = OrderDetailModel(client: StubOrderClient(result: .success(order)))\n await model.load() // or `await model.loadTask?.value`\n #expect(model.state == .loaded(order))\n}\n```\n\nKey points:\n\n**Prefer awaiting the call over polling.** If `load()` is `async`, `await` it. If the view model kicks off a stored `Task` internally, `await model.loadTask?.value` joins that exact task rather than guessing at timing.\n\n**If it's `@MainActor`-isolated, isolate the test too:**\n\n```swift\n@MainActor\n@Test func loadOrder() async throws { ... }\n```\n\nWithout that, you can race the main actor and assert on stale state.\n\n**If there's no awaitable handle and you must observe a completion signal**, use Swift Testing's `confirmation` rather than a delay:\n\n```swift\n@Test func loadOrder() async {\n await confirmation(\"model finished loading\") { done in\n let model = OrderDetailModel(client: StubOrderClient(...))\n model.onFinish = { done() }\n model.load()\n }\n}\n```\n\nFor XCTest targets without async support, use an `XCTestExpectation` fulfilled by the real completion callback — still never a fixed sleep.\n\n**What to avoid:**\n- `try await Task.sleep(for: .milliseconds(200))` before asserting — non-deterministic under CI load; use either a real `await` on the work or a real completion signal, never a guessed duration.\n- Spinning on `while !model.isDone { }` — same problem, plus it can hang the test forever if the work fails.\n- `DispatchSemaphore`/`XCTestExpectation` just to bridge an already-`async` call — the language gives you `await`; use it.\n\nIf you can tell me how the view model triggers the task (`async func` vs. a stored `Task` vs. a completion handler), I can give the exact form.",
859
+ "outputSha256": "a65228164142a32a5e54b8df00438d1c1bb8067667772c60f711fc58b9891b8e",
860
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
861
+ "deterministic": [],
862
+ "judge": {
863
+ "verdict": "pass",
864
+ "reason": "Answer awaits the async call directly (`await model.load()`, `await model.loadTask?.value`) in an `async` test, and offers `confirmation`/`XCTestExpectation` fulfilled by the real callback as equivalent joins. It explains reliability: fixed sleep is 'non-deterministic under CI load', 'never a guessed duration'. No fixed sleep recommended."
865
+ },
866
+ "passed": true
867
+ },
868
+ {
869
+ "output": "Await the async work directly rather than sleeping or polling. How you do that depends on what the view model actually exposes, so pick the one that matches your case:\n\n**1. The view model method itself is async and returns when done.** Just `await` it:\n\n```swift\n@Test func loadPopulatesItems() async throws {\n let viewModel = OrderListViewModel(client: StubOrderClient(items: [.sample]))\n await viewModel.load()\n #expect(viewModel.items == [.sample])\n}\n```\n\n**2. The method kicks off a `Task` internally and returns immediately.** Awaiting the method returns before the work is done, so you need a signal the view model publishes when it finishes. If it exposes an `AsyncStream`, an `AsyncSequence` of state, or a completion callback, await that instead of guessing a delay:\n\n```swift\n@Test func loadPopulatesItems() async throws {\n let viewModel = OrderListViewModel(client: StubOrderClient(items: [.sample]))\n viewModel.load()\n\n // wait for the first non-loading state, not a fixed duration\n for await state in viewModel.stateStream {\n if case .loaded(let items) = state {\n #expect(items == [.sample])\n return\n }\n }\n Issue.record(\"stream ended before reaching .loaded\")\n}\n```\n\n**3. No signal exists at all.** That is the real problem to fix, and it points at the view model's design: an async operation with no observable completion is untestable by construction. The clean fix is to make the work awaitable — either make `load()` `async` and have the `Task` wrapper live at the call site (the view), or expose the in-flight `Task` the view model stores so the test can `await task.value`:\n\n```swift\n// production: store the task you launch\nself.loadTask = Task { await self.fetch() }\n\n// test: await the actual task instead of sleeping\nviewModel.load()\nawait viewModel.loadTask?.value\n#expect(viewModel.items == [.sample])\n```\n\n**4. `@MainActor` view model.** Mark the test `@MainActor` too, so the awaited state mutation and the assertion happen under the same isolation the view model uses:\n\n```swift\n@Test @MainActor func loadPopulatesItems() async throws { ... }\n```\n\nA few things to avoid, since they are the usual traps here:\n\n- `Thread.sleep` / `Task.sleep(for: .milliseconds(...))` as a \"wait\" — non-deterministic; it either flakes on a loaded CI machine or wastes time. Only legitimate if you are deliberately testing time-based debounce logic, and even then prefer a controllable clock.\n- `XCTestExpectation` + `fulfill()` when the call is genuinely awaitable — that bridges async code back into a callback model for no reason, unless the target predates async test support.\n- Polling a property in a loop with a timeout — works but is strictly worse than awaiting a real signal; use it only when there is truly no other hook.\n\nThe short version: await the operation, or await a signal that the operation has completed. Never await a guessed duration. If you tell me what the view model exposes (an `async` method, an `AsyncStream`, a stored `Task`, or a completion callback), I can point at the exact one to use.",
870
+ "outputSha256": "6e4db58f0bf647f72151daf7725fd8bc7ab1b0d31da976a187b2c9bbe715f465",
871
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
872
+ "deterministic": [],
873
+ "judge": {
874
+ "verdict": "pass",
875
+ "reason": "Answer's core mechanism is awaiting: case 1 `await viewModel.load()`, case 2 `for await state in viewModel.stateStream`, case 3 `await viewModel.loadTask?.value` — real joins, no fixed sleep. It explains reliability: 'non-deterministic; it either flakes on a loaded CI machine or wastes time' and 'Never await a guessed duration.' Sleep only warned against, not recommended."
876
+ },
877
+ "passed": true
878
+ },
879
+ {
880
+ "output": "Await the work directly rather than waiting on it from the outside. Concretely:\n\n**If the view model exposes an awaitable entry point, just await it.**\n\n```swift\n@Test func loadPopulatesOrders() async throws {\n let model = OrderDetailModel(client: FakeOrderClient(orders: [.fixture]))\n await model.load() // the async work finishes here\n #expect(model.orders.count == 1)\n}\n```\n\nThe test function itself is `async`, so there is nothing to \"wait for\" separately — the `await` suspends the test until the view model's task completes, and only then does execution reach the assertion.\n\n**If the view model kicks off an unstructured `Task` internally and only exposes fire-and-forget methods**, that's the actual problem, and the fix belongs in the view model's design, not in the test:\n\n- Have `load()` be `async` and return only when the work is done, instead of spawning a detached `Task` and returning immediately. Then the test awaits it as above.\n- If it genuinely must start background work and stay responsive, expose something the test (and real callers) can await — the `Task` handle itself, or an `AsyncStream`/`AsyncSequence` of state changes that the test iterates until it sees the terminal state:\n\n```swift\nfor await state in model.stateStream {\n if case .loaded = state { break }\n}\n```\n\n**If several concurrent tasks are in flight**, await them together rather than one by one with delays:\n\n```swift\nawait withTaskGroup(of: Void.self) { group in\n for id in ids { group.addTask { await model.load(id) } }\n}\n```\n\n**Do not** bridge with `XCTestExpectation` + a semaphore, and do not `Task.sleep` for a guessed duration — both are non-deterministic under CI load, and the sleep in particular will pass locally and flake in CI. `XCTestExpectation` exists for genuinely callback-based APIs with no async surface; if the code already has an `async` entry point, awaiting it is strictly better.\n\n**If the view model is `@MainActor`-isolated**, mark the test `@MainActor` too so the awaited state mutation and the assertion happen on the same actor and the read is race-free:\n\n```swift\n@MainActor\n@Test func loadPopulatesOrders() async throws { ... }\n```\n\nThe one-sentence version: make the async work awaitable at the view model's own boundary and `await` it, rather than trying to detect its completion from outside.",
881
+ "outputSha256": "6c6cd45b21dffa873e49ba11d273185b7b5bb723d5fb8a8cb1a3632aef907962",
882
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
883
+ "deterministic": [],
884
+ "judge": {
885
+ "verdict": "pass",
886
+ "reason": "Answer awaits the async call directly with an async test function (`await model.load()`), joins a TaskGroup (`withTaskGroup`), and iterates an AsyncStream until terminal state — all real synchronization. It explicitly warns against Task.sleep for a guessed duration as non-deterministic/flaky, satisfying criterion 2. No fixed sleep is recommended."
887
+ },
888
+ "passed": true
889
+ },
890
+ {
891
+ "output": "Await the async work directly rather than guessing a delay or bridging with a semaphore. Concretely:\n\n```swift\n@Test @MainActor\nfunc loadFinishes() async throws {\n let model = OrderDetailModel(client: FakeOrderClient())\n await model.load() // await the call itself\n #expect(model.state == .loaded(expectedOrder))\n}\n```\n\nThe key point: if the view model exposes the async operation as an `async` method (or a `Task` you can await), you don't need any waiting primitive at all — `await` resumes exactly when the work completes. A `Task.sleep` or `Thread.sleep` \"just to be safe\" is non-deterministic: it passes on your machine and flakes on a loaded CI runner.\n\nA few cases worth calling out:\n\n**The method itself isn't async, it just spawns a `Task` internally.** Then you can't `await` it directly. The clean fix is to have the view model store the `Task` (or expose one) so the test can await it: `await model.loadTask?.value`. That's still awaiting the real completion signal, not a timer. If the type currently hides the task entirely, that's often worth a small production change to make it testable — but per the rules here, flag that rather than silently editing source.\n\n**You need to wait for several concurrent pieces.** Put them in a `TaskGroup` and await the group, or `await withTaskGroup(of:) { ... }` — again a real join, not a duration.\n\n**The result arrives via a callback/closure rather than a return value.** Use `withCheckedContinuation` (or `withCheckedThrowingContinuation`) to turn the callback into something awaitable:\n\n```swift\ntry await withCheckedThrowingContinuation { cont in\n model.load { result in cont.resume(with: result) }\n}\n```\n\nThat resolves the moment the closure fires — no polling, no fixed delay.\n\n**If the project is on legacy XCTest without async test support,** the sanctioned fallback is an `XCTestExpectation` that the production code actually fulfills, then `await fulfillment(of: [expectation], timeout: 1)`. The timeout is a safety net for a hung test, not the mechanism you rely on to make the assertion timing-correct.\n\nWhat not to do: `Task.sleep`/`Thread.sleep` as a \"should be enough\" guess, and don't loosen the assertion to `result != nil` just because timing made it flaky — that hides the very regression the test exists to catch. Fix the synchronization, keep the assertion specific.",
892
+ "outputSha256": "ff5d8ca18784acbb6fd65046d0331d8a31128540f0136838f3b7ebb6173bab80",
893
+ "promptSha256": "e489aab578a1b56c7c79a52935a340a7e10d2a7a4d8127ca095e758a11882dc8",
894
+ "deterministic": [],
895
+ "judge": {
896
+ "verdict": "pass",
897
+ "reason": "Answer awaits the async call directly (`await model.load()`) in an async test, and offers real joins: `await model.loadTask?.value`, TaskGroup, withCheckedContinuation, and a fulfilled XCTestExpectation. It explicitly explains reliability: `await` resumes exactly when work completes, while Task.sleep/Thread.sleep is non-deterministic and flakes on CI. No fixed delay is recommended."
898
+ },
899
+ "passed": true
900
+ }
901
+ ]
902
+ }
903
+ ],
904
+ "verdict": "fail",
905
+ "scope": "bundled",
906
+ "skillDigest": "9c82fac70e66ce797a2dc5daa73ee1de1f4117819268a2c2dcfe32b7cf93c697",
907
+ "catalogDigest": "97f9af01aafac82ae21a63c6af2a2f24fcfe067dc32a7cfdcde9a69a91fa9aae",
908
+ "judgePromptVersion": "2026-09-25.1",
909
+ "runner": "deepseek",
910
+ "model": "deepseek-chat",
911
+ "runnerPromptVersion": "2026-09-25.1",
912
+ "recordedAt": "2026-09-25T18:21:48.156Z",
913
+ "judge": "deepseek",
914
+ "judgeModel": "deepseek-chat"
915
+ },
916
+ {
917
+ "schemaVersion": "1.0.0",
918
+ "skillId": "swift-ios/swift-code-review",
919
+ "strictness": "high",
920
+ "trials": 10,
921
+ "triggerAccuracy": {
922
+ "truePositive": 2,
923
+ "falsePositive": 2,
924
+ "positives": 6,
925
+ "negatives": 7
926
+ },
927
+ "evidence": "authored",
928
+ "scenarios": [
929
+ {
930
+ "id": "trigger-positive-1",
931
+ "kind": "trigger-positive",
932
+ "prompt": "Review this Swift diff, a new function unwraps the decoded response with an exclamation mark",
933
+ "strictness": "high",
934
+ "trials": 1,
935
+ "passes": 1,
936
+ "passRate": 1,
937
+ "passAtK": 1,
938
+ "grader": "trigger-rank-fork-family",
939
+ "status": "ran",
940
+ "deterministic": true
941
+ },
942
+ {
943
+ "id": "trigger-positive-2",
944
+ "kind": "trigger-positive",
945
+ "prompt": "Check this iOS change for a closure that might be keeping a view model alive too long",
946
+ "strictness": "high",
947
+ "trials": 1,
948
+ "passes": 0,
949
+ "passRate": 0,
950
+ "passAtK": 0,
951
+ "grader": "trigger-rank-fork-family",
952
+ "status": "ran",
953
+ "deterministic": true
954
+ },
955
+ {
956
+ "id": "trigger-positive-3",
957
+ "kind": "trigger-positive",
958
+ "prompt": "Look over this pull request for anything that could crash on a malformed API response",
959
+ "strictness": "high",
960
+ "trials": 1,
961
+ "passes": 0,
962
+ "passRate": 0,
963
+ "passAtK": 0,
964
+ "grader": "trigger-rank-fork-family",
965
+ "status": "ran",
966
+ "deterministic": true
967
+ },
968
+ {
969
+ "id": "trigger-positive-4",
970
+ "kind": "trigger-positive",
971
+ "prompt": "Take a look at this Swift change for concurrency safety before it merges",
972
+ "strictness": "high",
973
+ "trials": 1,
974
+ "passes": 0,
975
+ "passRate": 0,
976
+ "passAtK": 0,
977
+ "grader": "trigger-rank-fork-family",
978
+ "status": "ran",
979
+ "deterministic": true
980
+ },
981
+ {
982
+ "id": "trigger-positive-5",
983
+ "kind": "trigger-positive",
984
+ "prompt": "Review this diff for whether the completion handler here is safe to store",
985
+ "strictness": "high",
986
+ "trials": 1,
987
+ "passes": 0,
988
+ "passRate": 0,
989
+ "passAtK": 0,
990
+ "grader": "trigger-rank-fork-family",
991
+ "status": "ran",
992
+ "deterministic": true
993
+ },
994
+ {
995
+ "id": "trigger-positive-6",
996
+ "kind": "trigger-positive",
997
+ "prompt": "Give this iOS pull request a pass for anything that could leak memory",
998
+ "strictness": "high",
999
+ "trials": 1,
1000
+ "passes": 1,
1001
+ "passRate": 1,
1002
+ "passAtK": 1,
1003
+ "grader": "trigger-rank-fork-family",
1004
+ "status": "ran",
1005
+ "deterministic": true
1006
+ },
1007
+ {
1008
+ "id": "trigger-negative-1",
1009
+ "kind": "trigger-negative",
1010
+ "prompt": "Review this Go diff for goroutine leaks",
1011
+ "strictness": "high",
1012
+ "trials": 1,
1013
+ "passes": 1,
1014
+ "passRate": 1,
1015
+ "passAtK": 1,
1016
+ "grader": "trigger-rank-fork-family",
1017
+ "status": "ran",
1018
+ "deterministic": true
1019
+ },
1020
+ {
1021
+ "id": "trigger-negative-2",
1022
+ "kind": "trigger-negative",
1023
+ "prompt": "Review this Kotlin diff for coroutine cancellation issues",
1024
+ "strictness": "high",
1025
+ "trials": 1,
1026
+ "passes": 1,
1027
+ "passRate": 1,
1028
+ "passAtK": 1,
1029
+ "grader": "trigger-rank-fork-family",
1030
+ "status": "ran",
1031
+ "deterministic": true
1032
+ },
1033
+ {
1034
+ "id": "trigger-negative-3",
1035
+ "kind": "trigger-negative",
1036
+ "prompt": "Review this diff and also fix the bugs you find in the Swift code",
1037
+ "strictness": "high",
1038
+ "trials": 1,
1039
+ "passes": 1,
1040
+ "passRate": 1,
1041
+ "passAtK": 1,
1042
+ "grader": "trigger-rank-fork-family",
1043
+ "status": "ran",
1044
+ "deterministic": true
1045
+ },
1046
+ {
1047
+ "id": "trigger-negative-4",
1048
+ "kind": "trigger-negative",
1049
+ "prompt": "Review this Python code for SQL injection",
1050
+ "strictness": "high",
1051
+ "trials": 1,
1052
+ "passes": 1,
1053
+ "passRate": 1,
1054
+ "passAtK": 1,
1055
+ "grader": "trigger-rank-fork-family",
1056
+ "status": "ran",
1057
+ "deterministic": true
1058
+ },
1059
+ {
1060
+ "id": "trigger-negative-5",
1061
+ "kind": "trigger-negative",
1062
+ "prompt": "Implement a fix for the retain cycle in this Swift closure",
1063
+ "strictness": "high",
1064
+ "trials": 1,
1065
+ "passes": 0,
1066
+ "passRate": 0,
1067
+ "passAtK": 0,
1068
+ "grader": "trigger-rank-fork-family",
1069
+ "status": "ran",
1070
+ "deterministic": true
1071
+ },
1072
+ {
1073
+ "id": "trigger-negative-6",
1074
+ "kind": "trigger-negative",
1075
+ "prompt": "Run a general security review on this codebase",
1076
+ "strictness": "high",
1077
+ "trials": 1,
1078
+ "passes": 1,
1079
+ "passRate": 1,
1080
+ "passAtK": 1,
1081
+ "grader": "trigger-rank-fork-family",
1082
+ "status": "ran",
1083
+ "deterministic": true
1084
+ },
1085
+ {
1086
+ "id": "trigger-negative-7",
1087
+ "kind": "trigger-negative",
1088
+ "prompt": "Review this Swift diff for naming conventions and formatting only",
1089
+ "strictness": "high",
1090
+ "trials": 1,
1091
+ "passes": 0,
1092
+ "passRate": 0,
1093
+ "passAtK": 0,
1094
+ "grader": "trigger-rank-fork-family",
1095
+ "status": "ran",
1096
+ "deterministic": true
1097
+ },
1098
+ {
1099
+ "id": "read-only-review",
1100
+ "kind": "behavior",
1101
+ "prompt": "Review this Swift diff: `let firstItem = response.items.first!` was added right after decoding a network response. What do you find?",
1102
+ "strictness": "high",
1103
+ "trials": 10,
1104
+ "passes": 10,
1105
+ "passRate": 1,
1106
+ "passAtK": 1,
1107
+ "grader": "judge",
1108
+ "status": "ran",
1109
+ "trialRecords": [
1110
+ {
1111
+ "output": "**Finding — force-unwrap on a decoded network response**\n\n`response.items.first!` — force-unwrap (`!`) applied to the result of `first` on a decoded network response.\n\n**Why it matters:** The contents of a decoded network response are external input, not a programmer-guaranteed invariant. If the response is empty (`items == []`) or the schema differs from what this code assumes (a versioned API, a partial/error payload, a proxy returning an unexpected body), `first` returns `nil` and the force-unwrap traps — the app crashes instead of failing gracefully. This is exactly the \"non-guaranteed value\" case the focus list flags; there is no invariant in this diff that makes the array guaranteed non-empty.\n\n**Fix direction (do not apply — this review is read-only):**\n\n```swift\nguard let firstItem = response.items.first else {\n throw NetworkError.emptyResponse // or return, or map to an empty state\n}\n```\n\nDepending on intent, `if let` for a UI empty-state path, or surfacing an explicit error to the caller, are equally valid — the point is that the empty case is handled rather than trapping.\n\n**Scope note:** This is a finding the diff *introduces* (the line was added). If there is pre-existing code elsewhere in the touched file with the same pattern, report it separately as pre-existing rather than attributing it to this change.\n\n**No other categories triggered by the snippet itself:** no closure/`self` capture, no actor isolation or `Sendable` concern, no state-ownership property wrapper, and no secret handling is visible in the added line. To be complete I would still need to scan the rest of the changed `*.swift` files — this answer only covers the one line quoted.\n\n**Confidence:** High that the force-unwrap is unsafe on external input. If there is a documented post-decode invariant upstream (e.g., a validator that rejects empty `items` earlier in the same call path), cite it and downgrade/withdraw this finding — but absent that, treat it as a crash risk in the decoding path.",
1112
+ "outputSha256": "b8f25b0c753a7f777b427603cbd5d69b035f0426c32abb1f8488f35454335e6f",
1113
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1114
+ "deterministic": [],
1115
+ "judge": {
1116
+ "verdict": "pass",
1117
+ "reason": "Names `response.items.first!` force-unwrap (criterion 1). Explains empty/malformed items makes `first` return nil and the unwrap traps, crashing instead of failing gracefully (criterion 2). Gives fix direction with `guard let`/`if let`/error, explicitly says 'do not apply — this review is read-only', no edit claimed (criterion 3). No fail criterion holds."
1118
+ },
1119
+ "passed": true
1120
+ },
1121
+ {
1122
+ "output": "Finding — force-unwrap on an externally-sourced value.\n\n**Pattern:** `let firstItem = response.items.first!` on a freshly decoded network response.\n\n**Why it matters (crash risk):** `response.items.first` returns `nil` for an empty array, and a network response is not a guaranteed invariant — it's controlled by a server you don't own and can change independently of this app (a deploy, an empty result set, a filtered query, a versioned/partial payload, a decoding that succeeded structurally but yielded zero items). Force-unwrapping it turns all of those into a hard crash at the point of use, rather than a handled failure. This is exactly the \"external source\" case the \"only force-unwrap guaranteed-safe programmer invariants\" rule is meant to exclude.\n\n**Fix direction (not applied — this review is read-only):**\n\n```swift\nguard let firstItem = response.items.first else {\n throw OrderError.emptyResponse // or return / fail gracefully\n}\n```\n\nChoose the recovery that matches the calling contract:\n- If an empty list is a legitimate outcome, model it as an optional and branch, rather than unwrapping at all.\n- If an empty list is genuinely an error for this call site, throw/return a typed error so the caller decides how to surface it.\n- If `firstItem` is only used as an optional convenience, keep it as `let firstItem = response.items.first` and let the later use-site `guard`/`if let`.\n\n**Related checks on the same line (worth confirming alongside it):**\n- Whatever consumes `firstItem` — make sure it doesn't reintroduce the same assumption (e.g. indexing `items[0]` or subscripting a sibling array).\n- If this decoding and unwrap run off the main actor but the result feeds SwiftUI state, confirm the consuming type is `@MainActor`-isolated per the concurrency rules — a crash fix here doesn't help if the value then races onto the UI.\n\n**Scope note:** this is a finding the diff *introduces* (the force-unwrap line is new). If there are similar force-unwraps elsewhere in the touched file, report those separately as pre-existing rather than bundling them into this one.\n\nConfidence: high that this is a real crash path; no runtime evidence needed to flag it, since an empty decoded array is a sufficient and reachable trigger.",
1123
+ "outputSha256": "43b325e725898cdb2db3502cf3d00e3e6107c718d94fc0bade82e10c77da61a6",
1124
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1125
+ "deterministic": [],
1126
+ "judge": {
1127
+ "verdict": "pass",
1128
+ "reason": "Names the exact expression `let firstItem = response.items.first!` (criterion 1). Explains empty array returns nil and force-unwrap causes a hard crash at point of use instead of handled failure (criterion 2). Presents as finding with fix direction `guard let ... else { throw }`, explicitly states 'not applied — this review is read-only' (criterion 3). No edit claimed."
1129
+ },
1130
+ "passed": true
1131
+ },
1132
+ {
1133
+ "output": "Finding — force-unwrap on a decoded network value.\n\n`response.items.first!` (new in this diff) — this force-unwraps the result of `.first` on `response.items`, which came straight out of decoding a network response. There is no programmer invariant guaranteeing the array is non-empty: the server can return an empty list, a differently-shaped payload, or a valid-but-unexpected response at any time. When `items` is empty, `.first` returns `nil` and the `!` traps — the app crashes instead of handling an empty result.\n\nRisk category: crash on non-guaranteed value (force-unwrap).\n\nWhy it matters here specifically: the value is external input, which is exactly the case the focus list calls out as not safe to force-unwrap. This is unlike a `!` on something the code itself just constructed and can prove non-nil.\n\nFix direction (not applied — this review is read-only):\n\n```swift\nguard let firstItem = response.items.first else {\n // throw a domain error, or return a not-found/empty state\n throw OrderError.emptyResponse\n}\n```\n\nor, if an empty list is a legitimate, expected outcome rather than an error, make the result optional and handle the `nil` branch at the call site instead of trapping.\n\nOne caveat on scope: I can only see this line in the diff you quoted. Confirm the diff base and read the surrounding unchanged code so I can tell whether the force-unwrap is genuinely introduced by this change or merely touched by it — if the `!` predates the diff, I'll report it as pre-existing rather than new, but it is still worth fixing either way.\n\nSuggested verification: none needed for the force-unwrap itself, but if `response` is being decoded and accessed off the main actor anywhere nearby, it would be worth running the change under the Swift 6 strict-concurrency checker to confirm there is no accompanying data-race issue on `response` — I'm not asserting one exists from this single line alone.\n\nNo files were modified by this review.",
1134
+ "outputSha256": "18e52c97faa052649f6ee2af058bd084e67faedfd1a30a6878278f3ae7f9f822",
1135
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1136
+ "deterministic": [],
1137
+ "judge": {
1138
+ "verdict": "pass",
1139
+ "reason": "Names `response.items.first!` as the force-unwrap problem (criterion 1). Explains empty `items` makes `.first` return nil and the `!` traps, crashing instead of handling empty result (criterion 2). Presents as finding with fix direction (`guard let ... else throw`), explicitly states 'not applied — this review is read-only' and 'No files were modified' (criterion 3). No edit claimed."
1140
+ },
1141
+ "passed": true
1142
+ },
1143
+ {
1144
+ "output": "**Finding — force-unwrap on a decoded network response**\n\n`OrderDetailModel.swift` (wherever the added line lives) — `response.items.first!` force-unwraps the result of `first` on a decoded network response. Risk category: crash on non-guaranteed value (Optionals and force operations, `rules/coding-style.mdc`).\n\nWhy it matters: `response.items` comes from decoding a network response, which is outside this diff's control. An empty array — a valid, decodable payload — or a schema/version mismatch makes `first` return `nil` and the `!` traps, crashing the app instead of failing gracefully. This is exactly the class of value Step 2 says must not be force-unwrapped, since it is not a guaranteed-safe programmer invariant.\n\nFix direction (do not apply):\n\n- `guard let firstItem = response.items.first else { throw OrderError.emptyItems }`, or\n- `if let firstItem = response.items.first { ... }` if an empty list is a valid state to handle inline, or\n- return an optional up the call chain rather than trapping here.\n\nConfirm the caller actually handles an empty list; if it currently assumes a non-empty list, that assumption is the real bug the `!` is hiding.\n\n**Scope note:** this is diff-introduced if the line is new in this change, which the snippet indicates. If surrounding code elsewhere force-unwraps the same response, note those separately as pre-existing — they are not this diff's finding.\n\n**No edit made.** This review is read-only; the line above is unchanged and only the finding plus fix direction are reported. Nothing here was certain to be a data race or leak, so no sanitizer/`Sendable` checks are suggested.",
1145
+ "outputSha256": "dcd00ce2431535f04bbb48b390692807c36a2f69da81ec48fd9e227fcdea6d44",
1146
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1147
+ "deterministic": [],
1148
+ "judge": {
1149
+ "verdict": "pass",
1150
+ "reason": "Names `response.items.first!` as the force-unwrap problem (criterion 1). Explains empty array is a valid decodable payload making `first` return nil and the `!` traps, crashing instead of failing gracefully (criterion 2). Gives fix direction with `guard let ... else { throw }` / `if let`, explicitly labeled 'do not apply', and states 'No edit made. This review is read-only' (criterion 3). No edit claimed."
1151
+ },
1152
+ "passed": true
1153
+ },
1154
+ {
1155
+ "output": "**Finding — Features/[changed file]:[line of the added statement]**\n\n`let firstItem = response.items.first!` — force-unwrap (`!`) applied to the first element of a freshly decoded network response.\n\n**Risk category:** force operation on a non-guaranteed value (Step 2, \"Optionals and force operations\").\n\n**Why it matters:** `response.items` comes from decoding data this diff does not control. Two things can make `.first` nil at runtime, and both are ordinary, expected conditions rather than programmer errors:\n\n- the server legitimately returns an empty collection (e.g. no items for this user/filter, a paginated last page, a deleted resource), and\n- a response shape change or partial/malformed payload decodes to something other than what the client assumed.\n\nIn either case `.first!` traps and crashes the app. This is exactly the \"guaranteed-safe programmer invariant\" that `.first` off a decoded response is not — it is external input, not a local invariant the code itself established.\n\n**Fix direction (not applied):** make the empty case an explicit, handled outcome rather than a crash. For example:\n\n- If absence is an error: `guard let first = response.items.first else { throw OrderError.emptyResponse }`.\n- If absence is a normal empty state: `if let first = response.items.first { ... } else { ... }` and render/handle the empty case.\n- Avoid `try!` as a substitute — same trap, different spelling.\n\nAlso check whether this force-unwrap is genuinely new in this diff or pre-existing in the touched file, and report it accordingly; the description says it was added right after decoding, so it is diff-introduced unless the surrounding file already did the same thing.\n\n**Scope note:** I reviewed only the added line as described. I have not read the rest of the changed `*.swift` files, so I cannot yet say whether the `@MainActor` isolation, retain-cycle, state-ownership, or Keychain/secret checks pass for this diff — those require reading the surrounding code (the model/observable that consumes `firstItem`, any closures storing it, and how it is persisted or logged). If `firstItem` is later held by an `@Observable` type read from SwiftUI, confirm that type is `@MainActor`-isolated; if it is captured by a long-lived closure or `Task`, check for `[weak self]`; and if it is a token/secret, confirm it is not written to `UserDefaults` or logged unredacted.",
1156
+ "outputSha256": "bf54b2c6f471cb2695751b516d984d8aa38427c6fa678d7cd67484232b2e1970",
1157
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1158
+ "deterministic": [],
1159
+ "judge": {
1160
+ "verdict": "pass",
1161
+ "reason": "Names the exact expression `let firstItem = response.items.first!` and the `!` force-unwrap (criterion 1). Explains empty collection and malformed payload cause `.first!` to trap and crash the app (criterion 2). Offers fix direction with `guard let ... else { throw }` and `if let`, explicitly marked 'Fix direction (not applied)' — no edit made or claimed (criterion 3). No fail criterion holds."
1162
+ },
1163
+ "passed": true
1164
+ },
1165
+ {
1166
+ "output": "**Finding — force-unwrap on a decoded network response**\n\n`response.items.first!` (new in this diff)\n\n- **Pattern:** Force-unwrap (`!`) applied to `first` on a collection that comes from a decoded network response.\n- **Why it matters:** A decoded network response is exactly the class of value that is *not* a guaranteed-safe programmer invariant. The server can return an empty `items` array (empty result set, partial failure, permission-scoped payload, pagination edge case), or the shape can change across API versions. On an empty array, `.first` returns `nil` and the `!` traps — the app crashes instead of failing gracefully. This is a crash risk introduced by this diff.\n- **Fix direction:** Bind it safely rather than force-unwrapping, e.g.:\n\n ```swift\n guard let firstItem = response.items.first else {\n throw OrderError.emptyResponse // or return .failure(...) / show an empty state\n }\n ```\n\n If the surrounding code genuinely treats \"no items\" as impossible, that assumption belongs in the API/decoding layer as a thrown error, not as a `!` at the call site — and it should be justified in a comment.\n\n**Scope note:** This finding is *introduced by this diff* (the line itself is new), not a pre-existing issue in code the diff merely touches. If nearby unchanged lines in the same file also force-unwrap decoded values, they are pre-existing and should be reported separately.\n\n**Not flagged here:** no concurrency, retain-cycle, actor-isolation, `Sendable`, or secret-storage concerns are visible from this single line. If you want those checked, the changed file(s) need to be read in full — this one-line diff only exercises the optionals/force-operations category.\n\n**No edits made** — this review is read-only; the fix direction above is a suggestion for the author to apply.",
1167
+ "outputSha256": "650dde76b06035d05d5c2ee4553dbddca7efeabc4b2bd81eb62cb6cb54bfda44",
1168
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1169
+ "deterministic": [],
1170
+ "judge": {
1171
+ "verdict": "pass",
1172
+ "reason": "Names `response.items.first!` as the problem (criterion 1). Explains empty `items` array makes `.first` return nil and `!` traps, crashing instead of failing gracefully (criterion 2). Gives fix direction with `guard let ... else { throw ... }` and explicitly states 'No edits made — this review is read-only' (criterion 3). No edit claimed or applied, so no fail criterion holds."
1173
+ },
1174
+ "passed": true
1175
+ },
1176
+ {
1177
+ "output": "Finding: forced unwrap of a decoded-network-response value.\n\n```\n<changed file>:<line of the new statement> — `let firstItem = response.items.first!`\n force-unwraps `first` on a collection decoded from a network response.\n Risk: crash. `response.items` is not a programmer-guaranteed invariant —\n it comes from an external system this diff does not control. A valid,\n successfully-decoded response can still carry an empty `items` array\n (empty result set, filtered/short page, a field omitted in an older\n response version), and `.first` is `nil` in exactly that case. The `!`\n turns a recoverable \"no items\" condition into a fatal trap.\n Fix direction: fail gracefully instead of trapping, e.g.\n `guard let firstItem = response.items.first else { throw OrderError.emptyResult }`\n or `if let firstItem = response.items.first { ... } else { ... }` — pick\n based on whether an empty list is an error or a normal empty state. Do\n not apply; report only.\n```\n\nWhy this matters here and not just as a style nit: the value crosses a trust boundary (decoded external input), so the unwrap is not asserting a local invariant the way `array[0]` on a just-constructed non-empty literal would. That distinction is what makes it a finding under the force-operations check rather than noise.\n\nTwo things to confirm while you are in that spot, since they often travel with this line:\n\n- If this runs inside a `Task {}` or a completion handler, check it is `@MainActor`-isolated if `firstItem` or the model it feeds is read by SwiftUI — otherwise the crash above could mask, or be accompanied by, a cross-actor data race. Not certain from the diff alone; confirm under Thread Sanitizer / the Swift 6 strict-concurrency checker rather than assuming.\n- If the surrounding model is an `@Observable` class, verify it carries `@MainActor`.\n\nScope note: this is diff-introduced, not pre-existing, assuming this statement is new in the diff. If the same file already force-unwraps elsewhere, list those separately as pre-existing so they are not attributed to this change.\n\nNo files were modified by this review.",
1178
+ "outputSha256": "559029991a1f73e930c9423732a25ccf2658ae00a4182fc1f44e43aef548bbc1",
1179
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1180
+ "deterministic": [],
1181
+ "judge": {
1182
+ "verdict": "pass",
1183
+ "reason": "Names the exact expression `let firstItem = response.items.first!` and the `!` force-unwrap (criterion 1). Explains concrete crash: empty `items` array makes `.first` nil, `!` turns recoverable 'no items' into a fatal trap (criterion 2). Gives fix direction with `guard let ... else { throw OrderError.emptyResult }` / `if let`, explicitly 'Do not apply; report only' and 'No files were modified' (criterion 3). No edit claimed."
1184
+ },
1185
+ "passed": true
1186
+ },
1187
+ {
1188
+ "output": "**Finding — `OrderDetailModel.swift` (new line) — force-unwrap on decoded network data**\n\n```\n<file>:<line> — `let firstItem = response.items.first!`\n```\n\n**Pattern:** Force-unwrap (`!`) applied to the result of `.first` on `items` from a decoded network response.\n\n**Risk category:** Crash risk (Step 2 — Optionals and force operations).\n\n**Why it matters:** `items` comes from decoding a network response, which is outside this code's control. `.first` returns `Optional` precisely because the collection may be empty. If the server returns an empty `items` array, a malformed/partial payload, a versioned response whose shape differs, or an error body that still decodes into this model, `first!` traps and crashes the app instead of failing gracefully. This is exactly the \"non-guaranteed value\" case that the focus list flags — the force-unwrap is only legitimate for a programmer invariant that cannot fail, and decoded external data is not that.\n\n**Fix direction (not applied — this review is read-only):**\n\n```swift\nguard let firstItem = response.items.first else {\n throw OrderError.emptyItems // or return / surface an empty state\n}\n```\n\nUse `guard let` / `if let` and handle the empty case explicitly.\n\n**Note on novelty:** This line is introduced by the diff, so it is a diff-introduced finding, not a pre-existing one. I flagged only this line; I did not flag the surrounding unchanged decoding code.\n\n**Not finding:** I have no basis to report a data race, retain cycle, actor-isolation gap, or secret-storage issue from this one line alone — those categories require seeing the enclosing type, its isolation, and any closures.\n\nNo source file was modified by this review.",
1189
+ "outputSha256": "20d226b5e8d2e3c511637be9ed70bcb457cdf45b97af20260a94ad11a51ff80b",
1190
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1191
+ "deterministic": [],
1192
+ "judge": {
1193
+ "verdict": "pass",
1194
+ "reason": "Names the exact expression `let firstItem = response.items.first!` and the `!` force-unwrap (criterion 1). Explains empty/malformed `items` array traps and crashes instead of failing gracefully (criterion 2). Gives fix direction with `guard let ... else { throw OrderError.emptyItems }` and explicitly states 'not applied — this review is read-only' and 'No source file was modified' (criterion 3). No edit claimed."
1195
+ },
1196
+ "passed": true
1197
+ },
1198
+ {
1199
+ "output": "Finding — force-unwrap on a decoded network response.\n\n`response.items.first!` — the `!` is applied to `items.first`, which is `Optional<Item>` coming out of a decoded network response. That is not a guaranteed-safe programmer invariant: it's data from an external source (the server), so an empty `items` array — a valid, expected server state — traps at runtime and crashes the app instead of failing gracefully.\n\nRisk category: crash risk (force-unwrap on non-guaranteed value), per the optionals/force-operations check.\n\nFix direction (do not apply): replace with optional binding or explicit error handling, depending on how the caller needs to fail. Either a local fallback:\n\n```swift\nguard let firstItem = response.items.first else {\n // handle empty: return early, throw, or set an empty state\n return\n}\n```\n\nor, if \"empty items\" is genuinely an error for this screen, throw a typed error rather than trapping: `guard let firstItem = response.items.first else { throw OrderError.emptyResponse }`.\n\nNotes for the review:\n- Check the enclosing function: if it already has a `guard`/error path nearby, folding this into it is cleaner than a second early-return.\n- If a nearby (unchanged) line already unwraps something from the same decoded `response`, mention it as a pre-existing instance of the same pattern rather than treating it as new in this diff.\n- No other Step 2 categories (actor isolation, retain cycles, state ownership, secret storage) are implicated by this one-line snippet; those would need the rest of the diff to assess.\n\nThis review is read-only — the finding and fix direction above are reported, not applied.",
1200
+ "outputSha256": "a1162f894fe1f40534494e102f12992c003685589f1117e12bcb752dfc1b0451",
1201
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1202
+ "deterministic": [],
1203
+ "judge": {
1204
+ "verdict": "pass",
1205
+ "reason": "Names `response.items.first!` and the `!` on `items.first` (criterion 1). Explains empty `items` array is a valid server state that traps/crashes instead of failing gracefully (criterion 2). Gives fix direction via `guard let`/`if let` or typed throw, explicitly labeled 'do not apply' and 'read-only... reported, not applied' (criterion 3). No edit claimed."
1206
+ },
1207
+ "passed": true
1208
+ },
1209
+ {
1210
+ "output": "**Finding — force-unwrap on a decoded network response**\n\n`OrderDetailModel.swift` (new line in diff) — `let firstItem = response.items.first!` force-unwraps the first element of `response.items` immediately after decoding a network response.\n\n**Why it matters (crash risk):** `response.items` comes from outside this diff's control — a server change, a versioned or malformed payload, or a genuinely empty list. If `items` is empty, `.first` returns `nil` and the `!` traps, crashing the app instead of failing gracefully. This is a non-guaranteed value per the force-unwrap check in Step 2, not a programmer invariant (e.g. a fixed literal array), so it should not be force-unwrapped.\n\n**Fix direction (do not apply here):**\n\n```swift\nguard let firstItem = response.items.first else {\n throw OrderError.emptyItems // or handle the empty case explicitly\n}\n```\n\nAlternatively `if let` if the empty case is handled inline, or `try?` with an explicit fallback if the caller can proceed without the first item. The point is to surface the empty/malformed case as a real outcome rather than a trap.\n\n**Scope note:** this is introduced by the diff, not pre-existing — the force-unwrap line is the new addition. I did not read the rest of the file, so I cannot say whether other force-unwraps already exist in this model; flag those separately if present.\n\n**Not reported here:** generic style nits (naming, formatting) are out of scope for this review — those belong to SwiftLint/swift-format. No secret storage, `@MainActor`, `Sendable`, retain-cycle, or state-ownership concerns are visible in the single line quoted, so none are raised.\n\nOne caveat on certainty: the finding assumes `items` is a non-optional array decoded from the response. If `items` is in fact a fixed, non-optional constant that cannot be empty by construction, the force-unwrap would be defensible — but that would need to be shown, and \"the API always returns this field\" is not sufficient evidence.",
1211
+ "outputSha256": "23ee64ba636e6114e10ef6bc394b704c1f407e6092d43cbdc8e5d61cdc2c78c8",
1212
+ "promptSha256": "06901419e64524710ddf69bcf1a7f791e6fc1c5b381e7a497feefd229d5ac2c0",
1213
+ "deterministic": [],
1214
+ "judge": {
1215
+ "verdict": "pass",
1216
+ "reason": "Names the exact expression `let firstItem = response.items.first!` and calls out the force-unwrap. Explains empty/malformed items makes `.first` return nil and the `!` traps, crashing instead of failing gracefully. Gives fix direction (`guard let ... else throw`, `if let`) explicitly marked 'do not apply here' — no edit made or claimed."
1217
+ },
1218
+ "passed": true
1219
+ }
1220
+ ]
1221
+ },
1222
+ {
1223
+ "id": "mainactor-isolation-check",
1224
+ "kind": "behavior",
1225
+ "prompt": "Review this Swift diff: a new @Observable class was added to back a SwiftUI screen's state, but it isn't marked @MainActor and nothing else in the file establishes main-actor isolation for it. What's wrong?",
1226
+ "strictness": "high",
1227
+ "trials": 10,
1228
+ "passes": 10,
1229
+ "passRate": 1,
1230
+ "passAtK": 1,
1231
+ "grader": "judge",
1232
+ "status": "ran",
1233
+ "trialRecords": [
1234
+ {
1235
+ "output": "**Finding — missing main-actor isolation on `@Observable` state**\n\nA class annotated `@Observable` that backs a SwiftUI screen's state is read during view rendering and mutated from view-driven callbacks, button actions, and any `Task` the screen starts. SwiftUI reads that state on the main thread during body evaluation. If the class carries no `@MainActor` (and nothing else in the file — a `@MainActor` superclass, a file-level actor-isolation default, or a `@MainActor` annotation on every member — establishes it), then its mutable properties are reachable from *any* isolation domain:\n\n- A `Task {}` started inside a view callback, a `didSet`-triggered async hop, or a network completion handler resumes off the main actor and mutates a property the view is concurrently reading.\n- SwiftUI's own observation machinery (`withObservationTracking` / dependency registration) assumes main-actor access; concurrent mutation against a body read is an unsynchronized data race on the backing storage.\n- Under Swift 6 strict concurrency this type is not `Sendable` and not isolated, so the compiler either errors at the use sites or the caller papers over it (see below).\n\n**The two common bad fixes, both worth calling out if present in the diff**\n\n1. Marking the class `@unchecked Sendable` instead of `@MainActor` — that suppresses the diagnostic without establishing any synchronization. `@unchecked Sendable` is a *promise*, not a mechanism; without a comment auditing every mutable property (lock, queue, or immutable), it is a suppression, not a fix. If this appears in the diff, flag it separately.\n2. `nonisolated(unsafe)` on the properties — same problem, one level down.\n\n**Risk category**\n\nData race (concurrent mutation read by the view) — plus, under strict concurrency, a build error that will likely get \"fixed\" with one of the suppressions above, converting a caught bug into a silent one.\n\n**Fix direction**\n\n- Annotate the class `@MainActor` (on the class, so all members inherit it), assuming all its state is genuinely UI-tied. This is almost always correct for an `@Observable` backing a SwiftUI screen: creation, reads during body, and mutations from view callbacks all happen on the main actor.\n- For any method that must run off-main (a heavy computation, a network call), mark it `nonisolated` and have it `await MainActor.run { ... }` or hop back explicitly before touching isolated state — do not leave the property itself reachable from multiple domains.\n- If a mutation truly originates off-main, `await` the main-actor hop rather than reaching into the property directly.\n\n**Confidence note**\n\nThe race is not certain from the diff alone — a caller could in principle confine all access to the main thread by convention. This is the reportable pattern because that convention is invisible and unenforced by the type. To confirm an actual race as opposed to an unsound-by-construction type, run the screen's mutation paths under Thread Sanitizer and/or build with the Swift 6 strict-concurrency checker and observe the diagnostics on this type.\n\n**Scope caveat**\n\nI can only see the description provided; I have not read the file or the diff. The `file:line` reference and the check for a `@MainActor` superclass, a file-level isolation default, or a stray `@unchecked Sendable` / `nonisolated(unsafe)` need to be confirmed against the actual changed source. This review made no edits.",
1236
+ "outputSha256": "b767a5675a603ec89855d82e4c04fc780cab9a58dae7d1bcfc9814773aca962e",
1237
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1238
+ "deterministic": [],
1239
+ "judge": {
1240
+ "verdict": "pass",
1241
+ "reason": "Answer explicitly identifies missing @MainActor on the @Observable class as the finding (\"missing main-actor isolation on @Observable state\"), explains the concrete data-race risk (SwiftUI reads state on main thread during body; Task/network completion resumes off main actor and mutates concurrently; unsynchronized data race), and names the fix direction (\"Annotate the class @MainActor\") as a finding, explicitly stating \"This review made no edits.\" It does not dismiss the gap as fine."
1242
+ },
1243
+ "passed": true
1244
+ },
1245
+ {
1246
+ "output": "An `@Observable` class that backs a SwiftUI screen's state and isn't isolated to `@MainActor` is a concurrency-correctness problem, not a style nit. Here's the finding.\n\n## Finding: missing `@MainActor` isolation on an `@Observable` state model\n\n**File:line** — the class declaration line in the changed file (e.g. `Features/Order/OrderDetailModel.swift:1`). Since the diff is described from your message rather than pasted, the line is the `@Observable` class declaration introduced by this diff.\n\n**Pattern** — an `@Observable` class whose properties SwiftUI reads from `body` and mutates from user actions, with no `@MainActor` on the class, no `@MainActor` on the members, and nothing else in the file (no enclosing `@MainActor` type, no `-default-isolation MainActor` build setting evidenced) establishing isolation.\n\n**Why it matters** — this is the SwiftUI state-ownership + actor-isolation risk in Step 2 of the review:\n\n- SwiftUI's `body` and the view update machinery run on the main actor. Anything SwiftUI reads there is expected to be main-actor-isolated. An `@Observable` model that isn't means mutations of its properties can legally be performed from other actors (a `Task`, an async network callback, a background queue) with no compiler complaint in Swift 5 language mode and only a partial one in Swift 6 mode.\n- Concretely: an async load that assigns `self.items = fetched` from a non-main executor, racing a UI read of `items` on the main actor, is a data race on the model's storage. Symptom is not a compile error — it is intermittent UI corruption, a crash in a future Swift runtime, or a race that only shows under Thread Sanitizer.\n- It also undermines `@Observable`'s own change-tracking: the observation machinery and the view's read are not guaranteed to be on the same actor/execution context, so updates can be missed or torn.\n- This is a **diff-introduced** finding if the class is new in this change (it is, per your description), not a pre-existing one.\n\n**Note on uncertainty** — I can't assert \"there is definitely a live race here\" from the declaration alone; if the only call sites happen to hop to the main actor before touching the model, it may be latent rather than firing today. But the isolation is missing, so nothing *enforces* it, and the next async call site added will be the one that bites.\n\n**Fix direction** — mark the type `@MainActor` so the isolation is the compiler's job, not the caller's discipline:\n\n```swift\n@MainActor\n@Observable\nfinal class OrderDetailModel { ... }\n```\n\nThen for any `async` work that starts off-actor, hop back explicitly before mutating state:\n\n```swift\nfunc load() async throws {\n let fetched = try await api.fetchOrder(id: id) // off-actor is fine\n self.items = fetched // back on the main actor\n}\n```\n\nIf the model genuinely needs non-isolated work, isolate only that member `nonisolated` and keep the observable state main-actor-isolated — don't drop the isolation from the whole type to make one call site compile.\n\n**Verification step** — build with Swift 6 strict-concurrency checking (or enable *Strict Concurrency Checking = Complete* / *Targeted* in Swift 5 mode) and run the flow under Thread Sanitizer; the missing-isolation diagnostic should appear at the class declaration or at the non-main-actor mutation site. If it does not, the isolation is being established somewhere outside this file and the finding should be downgraded accordingly — but confirm that before closing it, don't assume it.\n\nThis is a report only; I have not made any edit to the file.",
1247
+ "outputSha256": "9cb47c5e798811bf49e755e1db532dcf9f35545639b8d2e0f909c8179ac88d27",
1248
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1249
+ "deterministic": [],
1250
+ "judge": {
1251
+ "verdict": "pass",
1252
+ "reason": "Answer explicitly identifies missing @MainActor on the @Observable class as the issue (Finding header, 'Pattern' paragraph). It explains the concrete risk: SwiftUI body runs on main actor, mutations from Task/async callback race UI reads ('self.items = fetched from a non-main executor, racing a UI read'). Fix direction named as finding: 'mark the type @MainActor', and states 'This is a report only; I have not made any edit.' No dismissal."
1253
+ },
1254
+ "passed": true
1255
+ },
1256
+ {
1257
+ "output": "Here's the review of that diff.\n\n**Finding — missing `@MainActor` isolation on the new `@Observable` class**\n\nFile:line — the `@Observable` class declaration added in this diff (report the actual declaration line).\n\nPattern: a class marked `@Observable` is used to back a SwiftUI screen's state, but it carries no `@MainActor` (or equivalent `@MainActor`/actor-isolation) annotation, and nothing else in the file — no `@MainActor` on the enclosing type, no `@main`-actor context, no explicit actor annotation — establishes main-actor isolation for it.\n\nWhy it matters — SwiftUI reads and mutates this object's observable properties directly from the main thread during view updates. Because the type is not isolated to the main actor, the compiler has no guarantee that any of its mutations happen on the main thread:\n\n- Mutations made from a background context — a `Task` that is not main-actor-isolated, a completion handler, a networking callback, a notification observer — compile without error and then write to observable state off the main thread. That is a data race on the object's stored properties.\n- SwiftUI's observation machinery observes those properties; a write from a non-main actor can race with the render pass reading them, which surfaces as torn reads, stale or dropped UI updates, or a crash under Thread Sanitizer / the Swift 6 strict-concurrency checker.\n- Because nothing in the file establishes isolation, every call site is implicitly free to touch the object from whatever executor it happens to be on, so the problem grows with the number of call sites rather than being localized.\n\nThis is the specific data-race risk `rules/patterns.mdc` flags: state that SwiftUI reads and mutates must be isolated to `@MainActor`.\n\nFix direction (not applied — this review is read-only): annotate the class `@MainActor`, e.g.\n\n```swift\n@MainActor\n@Observable\nfinal class ScreenModel {\n ...\n}\n```\n\nso that every access, including mutations from `Task`/callbacks, is checked by the compiler to occur on the main actor or must explicitly hop there (`await MainActor.run`, `@MainActor` closure, etc.). If the class genuinely cannot be wholly main-actor-isolated, isolate only the observable state and document why any non-isolated member is safe — do not leave it unannotated.\n\n**Confidence / how to confirm**\n\nThe missing annotation itself is certain from reading the diff. Whether it *actually* produces an off-main-thread write depends on the call sites, which may not all be in this diff. If you cannot see a concrete off-main-thread mutation from the changed code alone, don't assert a race — say instead: \"run under Thread Sanitizer and/or the Swift 6 strict-concurrency checker to confirm an off-main-thread write to this object.\"\n\n**Pre-existing vs. diff-introduced**\n\nIf the call sites that mutate this object from background contexts were added in this same diff, list them as diff-introduced. If they pre-existed and this diff only added the backing model, note the missing `@MainActor` as diff-introduced (the new class is new code) but flag the pre-existing off-main call sites separately, since the new isolation change may require touching them.\n\n**Adjacent items to check while you're here (report only if present in this diff)**\n\n- `Task { }` created inside the class or its call sites that should be view-scoped with `.task` instead.\n- Any `@unchecked Sendable` or `nonisolated(unsafe)` added to make this compile without a written safety justification — that is a suppression, not a proven-safe boundary.\n- Any secret/token stored in `UserDefaults` or logged unredacted in the same change, per `rules/security.mdc`.\n- `@State` vs. `@Binding` ownership mismatches for the state this model exposes to the view.\n\n**Status:** one blocking finding (missing main-actor isolation on the `@Observable` state model). No files were modified by this review.",
1258
+ "outputSha256": "8f16ae428d7c7f1d5af82910e8e28841b476501cecaad3ee0f40ffedbc5c1713",
1259
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1260
+ "deterministic": [],
1261
+ "judge": {
1262
+ "verdict": "pass",
1263
+ "reason": "Answer explicitly identifies missing @MainActor isolation on the @Observable class as the finding (\"Finding — missing @MainActor isolation\"), explains the concrete data-race risk (SwiftUI reads/mutates observable properties on main thread; background Task/callback writes race with render pass), and names the fix direction (annotate class @MainActor) as a finding explicitly not applied (\"not applied — this review is read-only\"). It does not dismiss the gap as fine."
1264
+ },
1265
+ "passed": true
1266
+ },
1267
+ {
1268
+ "output": "An `@Observable` class that backs SwiftUI screen state and has no `@MainActor` isolation is a concurrency finding, and it is exactly the \"missing actor isolation\" category this review checks for. Here is what is wrong and why.\n\n## The finding\n\nFile:line — wherever the class is declared (e.g. `OrderDetailModel.swift:1`):\nthe class is `@Observable` but not isolated to `@MainActor`, and nothing\nelse in the file (`nonisolated` annotations, an enclosing actor, a\n`@MainActor` extension, a global-actor attribute on the type) establishes\nthat isolation.\n\nRisk: a data race on the observable state.\n\n## Why it matters\n\nAn `@Observable` type backing a SwiftUI screen is, by construction, a\ntype whose mutable stored properties are read during view body\nevaluation and written from view-triggered code. Under SwiftUI, view\nbody evaluation and the state mutations SwiftUI drives (button taps,\n`.task` completions that assign to the model, `onChange` handlers) run on\nthe main actor.\n\nWithout `@MainActor` on the type:\n\n- Its stored properties are not protected by any actor. The compiler\n treats the type as non-isolated, so nothing stops a property from being\n read or written from a non-main context.\n- The real hazard is the async work the model almost certainly kicks\n off: a `Task {}` or `await` that resumes on a background executor and\n assigns back into the model (`self.items = ...`,\n `self.loading = false`) while SwiftUI is concurrently reading those\n same properties on the main actor. That is a genuine unsynchronized\n read/write pair on the same storage.\n- `@Observable`'s change tracking is not synchronization. The observation\n machinery records which properties were accessed; it does not serialize\n access to them. So the macro gives no safety here, and its presence can\n read as if it did.\n\nThis is the \"missing `@MainActor` isolation\" pattern called out in the\nfocus list, and it is a data-race finding, not a style nit.\n\n## Fix direction (not applied — this review is read-only)\n\n- Annotate the class `@MainActor` so all its state is main-actor\n isolated, and let callers `await`/hop to it. In Swift 6 strict\n concurrency this also makes violations visible at compile time rather\n than latent.\n- If only part of the type is main-actor state, `@MainActor` the relevant\n properties/methods rather than the whole class — but for a screen-\n backing observable, whole-class isolation is usually the right call.\n- Any background work should hand results back to the main actor\n explicitly (`await MainActor.run { ... }`, or by calling a\n `@MainActor` method) instead of mutating the model from wherever the\n task happens to resume.\n\n## Confidence caveat\n\nReading alone cannot always prove a specific race is live — it depends on\nwhether the type's async paths actually resume off the main actor. So\nstate it as a missing-isolation defect (which is certain from the diff)\nand recommend confirming the concrete read/write overlap under Thread\nSanitizer or the Swift 6 strict-concurrency checker rather than asserting\na specific race is definitely occurring.\n\n## Note on scope\n\nIf this class is newly added by the diff, it is a diff-introduced issue —\nreport it as such, and fix direction only. If the diff merely touches a\npre-existing unisolated `@Observable` class, report it separately as\npre-existing so it is not attributed to this change.",
1269
+ "outputSha256": "cde05868a0f607897a2de7ee881b7ea6859f5a1eccb4f674831e993771c50aed",
1270
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1271
+ "deterministic": [],
1272
+ "judge": {
1273
+ "verdict": "pass",
1274
+ "reason": "Answer explicitly identifies the missing @MainActor isolation on the @Observable class as the finding ('the class is @Observable but not isolated to @MainActor'). It explains the concrete risk: SwiftUI reads state during view body and mutates it on the main actor, and without @MainActor async work resuming on a background executor can assign back while SwiftUI reads, a genuine unsynchronized read/write data race. It names the fix direction (annotate the class @MainActor) explicitly as 'not applied — this review is read-only'. It does not dismiss the gap as fine because only SwiftUI touches it."
1275
+ },
1276
+ "passed": true
1277
+ },
1278
+ {
1279
+ "output": "**Finding — missing `@MainActor` isolation on an `@Observable` class backing SwiftUI state.**\n\nWhat's wrong: SwiftUI reads and mutates a view's observable state on the main actor (during view updates, from user-input handlers, from `.task`/`.onAppear`, etc.). An `@Observable` class with no isolation is nonisolated by default, so its mutable properties can be read and written from any thread/actor with no compiler-enforced synchronization. The moment anything touches that state off the main actor — a `Task.detached`, a nonisolated async helper, a background decode that writes back to a property, a Combine sink, a `URLSession` completion — you have an unsynchronized read/write on the same storage. That's a data race: reads can observe torn/partial state, SwiftUI may render from a value being mutated concurrently, and under Swift 6 strict concurrency this class can't be safely sent across isolation boundaries at all, so callers will either fail to compile or start sprinkling `@unchecked Sendable`/`nonisolated(unsafe)` to silence it.\n\nWhy it matters: data race and nondeterministic UI/state corruption, plus an architecture that will fight Swift 6 strict-concurrency checking. This is the concurrency category, not a style nit.\n\nAdditional review points on this same diff:\n\n- **Diff-introduced vs. pre-existing:** confirm the class is new in this diff. If an existing file merely gained this class, the isolation gap is introduced by the diff and should be reported as such, not lumped in with pre-existing issues.\n- **Related suppressions to look for:** if the diff also adds `@unchecked Sendable` or `nonisolated(unsafe)` to this class (or its members) with no comment justifying why the mutable state is actually safe, that's a second, separate finding — a *suppression*, not a proven-safe boundary. Flag it as unresolved rather than accepting it as a fix.\n- **Unscoped `Task {}`:** if the diff starts a `Task {}` that mutates this state with no reason it doesn't need to be joined/cancelled, that compounds the isolation problem — and if it's view-scoped work, `.task` is usually the right tool instead of a manually created task.\n\nFix direction (do not apply — read-only review): mark the class `@MainActor` so its properties are isolated to the main actor, and let call sites that need to update it hop back via `await MainActor.run { }` or an `@MainActor`-isolated method. If any of its state genuinely must be touched off the main actor, make that an explicit, isolated boundary with its own synchronization and a comment stating the safety argument — don't leave the class nonisolated.\n\nCaveat on certainty: from reading alone I can see the *missing isolation* (a definite structural gap), but I can't prove a specific race is occurring without seeing the call sites. To confirm an actual race, run the change under Thread Sanitizer and/or the Swift 6 strict-concurrency checker rather than asserting a concrete race exists.\n\nI have not modified any file; this is a findings-only report.",
1280
+ "outputSha256": "c1a52815c6dd98c997d64b40fd6af249ca75a34d7c56d1f485f2fcfbbad2c73f",
1281
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1282
+ "deterministic": [],
1283
+ "judge": {
1284
+ "verdict": "pass",
1285
+ "reason": "Answer explicitly identifies missing @MainActor isolation on the @Observable class as the issue (\"An @Observable class with no isolation is nonisolated by default\"). It explains the concrete risk: SwiftUI reads/mutates state on main actor, and off-main-actor access (Task.detached, background decode, URLSession completion) causes unsynchronized read/write = data race. It names the fix direction (\"mark the class @MainActor\") as a finding, explicitly not applied (\"do not apply — read-only review\"). No dismissal of the gap as fine."
1286
+ },
1287
+ "passed": true
1288
+ },
1289
+ {
1290
+ "output": "# Finding: missing `@MainActor` isolation on a SwiftUI-backed `@Observable` class\n\n**Risk category:** concurrency / cross-actor data race (Step 2, \"Concurrency and actor isolation\").\n\n## What's wrong\n\nAn `@Observable` class exists specifically so a SwiftUI view can read its\nproperties during `body` evaluation and mutate them from view-driven actions\n(button taps, `.task`, `.onChange`, etc.). In Swift's concurrency model:\n\n- SwiftUI reads and writes observable view state **on the main actor**\n (view `body` is main-actor-isolated, and UI-triggered mutations land on\n the main thread).\n- Without `@MainActor` on the class, its stored properties are **not**\n actor-isolated to anything. Under Swift 6 strict concurrency they are\n either non-`Sendable` (so any cross-actor use is a compile error) or, if\n the class was made to compile by some other means, the compiler is no\n longer protecting you at all.\n\nThe concrete failure mode: some method on this class gets called from a\nnon-main context — a `Task {}` that hops off the main actor, a Combine\n`sink`, a completion handler from a URLSession callback, a detached task —\nand writes a property at the same moment SwiftUI reads it during a body\npass. That is a genuine data race on the property's storage: torn reads,\nobservation callbacks firing against a stale value, or a crash. Because\nnothing in the file establishes isolation, nothing stops this from being\nwritten, and nothing makes the compiler complain about it either.\n\nThe absence of `@MainActor` is also a hint the class was authored as if it\nwere a plain value holder; typically that means its mutation methods were\nnot written with \"this only ever runs on one actor\" in mind.\n\n## Fix direction\n\nMark the class `@MainActor` so its state and methods are isolated to the\nmain actor by construction:\n\n```swift\n@MainActor\n@Observable\nfinal class OrderDetailModel {\n var items: [OrderItem] = []\n ...\n}\n```\n\nThen check the call sites in the diff:\n\n- Any method of this class invoked from a background context must\n `await` a hop to the main actor (or be restructured to run on it).\n- Any `Task {}` inside a view using this model should be `.task {}` (which\n inherits the view's actor context, i.e. main) rather than a manually\n created `Task.detached`.\n- If some genuinely-background work must touch this model, isolate it as\n `nonisolated` and `await MainActor.run { ... }` (or `@MainActor`-hop) for\n the state mutation — do not leave a write path with no isolation.\n\nIf the compiler accepted this class without `@MainActor` under your current\nlanguage mode, that is not evidence it is safe — it only means strict\nconcurrency checking is not yet catching it. Recommend confirming under the\nSwift 6 strict-concurrency checker and, where a specific race is suspected,\nrunning the app with **Thread Sanitizer** before claiming the class is\nsafe rather than asserting the race is present from reading alone.\n\n## Note on scope\n\nThis file is otherwise the only relevant change here, so this is a\ndiff-introduced issue, not pre-existing. If other `@Observable` classes in\nthe codebase have the same omission, list them separately as pre-existing\nfindings so the fix can be tracked independently.\n\nNo file was modified by this review.",
1291
+ "outputSha256": "331d55c5ca1a8dcb2da2221ef672d75bfe3f2acb2ef848c32090ae11c17a7093",
1292
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1293
+ "deterministic": [],
1294
+ "judge": {
1295
+ "verdict": "pass",
1296
+ "reason": "Answer explicitly identifies missing @MainActor on the @Observable class as the issue (title, 'What's wrong'), explains the concrete race: SwiftUI reads/writes on main actor, without @MainActor state isn't isolated so a Task/Combine/URLSession callback can write while SwiftUI reads (torn reads, crash). Fix direction named as finding: 'Mark the class @MainActor', shown as suggestion, and states 'No file was modified by this review.' No dismissal."
1297
+ },
1298
+ "passed": true
1299
+ },
1300
+ {
1301
+ "output": "# Missing `@MainActor` on an `@Observable` class backing a SwiftUI screen\n\n## The finding\n\nThe class itself, not any one method: an `@Observable` type whose properties SwiftUI reads and mutates has no actor isolation, so nothing constrains where those mutations happen. SwiftUI reads those properties on the main thread during view updates; any code path that also mutates them off the main thread (a `Task` continuation, a network callback, a background queue hop) is now writing to the same storage from a different actor with no synchronization.\n\nPut concretely — file:line — something like:\n\n```\nFeatures/X/XModel.swift:1 — `@Observable final class XModel` is not\nisolated. Risk: cross-actor data race between SwiftUI's main-thread\nreads and any background write. Fix direction: mark the class\n@MainActor (or annotate each isolated member).\n```\n\n## Why this is wrong, specifically\n\n- **It's not a style preference.** `@Observable` synthesizes accessors over stored properties; those accessors are not atomic and there is no lock behind them. The isolation has to come from somewhere, and an un-annotated class has none.\n- **The screen's reads are main-thread by construction.** SwiftUI's body evaluation and its dependency tracking run on the main actor. You don't get to opt out of that half of the race — only the write side is under the author's control.\n- **Nothing else in the file establishes isolation.** You said so explicitly, and that's the part worth checking rather than assuming: a `@MainActor` on the type, on every mutating method, or on the properties would each be a real (if less tidy) answer. Absent any of those, the annotation isn't missing in a cosmetic sense — no isolation exists at all.\n\n## What it looks like in practice\n\nThe failure mode is usually a `Task` or a callback that hops off the actor:\n\n```swift\n@Observable final class XModel {\n var items: [Item] = [] // read by the view on main\n\n func reload() {\n Task {\n let fetched = await api.items() // may resume on a\n items = fetched // background executor\n }\n }\n}\n```\n\nThe `items = fetched` write and the view's read of `items` are unordered with respect to each other. Symptoms range from a stale UI to a crash inside `@Observable`'s change tracking, and they're timing-dependent, which is why they tend to reach production.\n\n## Fix direction\n\n- Mark the class `@MainActor`. For an `@Observable` model that exists to back one screen, this is nearly always the right answer and matches `rules/patterns.mdc`.\n- If part of the class genuinely must run off the main actor, isolate only that part (`nonisolated` methods over its own immutable state) and keep the observable state main-actor-bound.\n- Then re-check the call sites: a `@MainActor` class will surface any `await`-then-mutate path that was quietly racing, and the compiler will tell you where to hop back with `await MainActor.run { ... }` or by making the caller main-isolated too.\n\n## Caveats worth stating in the review\n\n- Confirm the build isn't already enforcing this. Under Swift 6 language mode with strict concurrency, an equivalent diagnostic may appear at the mutation site rather than on the class — but an un-annotated `@Observable` type in Swift 5 mode compiles silently, which is the dangerous case.\n- If you want to claim a race rather than a risk, don't infer it from the annotation alone. Say: run under Thread Sanitizer, or build with the Swift 6 strict-concurrency checker, to confirm the specific conflicting access. The missing annotation is a definite defect; the particular interleaving is what needs evidence.\n\n## Scope note\n\nThis is read-only — I haven't edited the file. Also worth separating two things in the report: the missing isolation is introduced by this diff, whereas any individual `await`-then-mutate call site may be pre-existing code the diff merely touches. Flag the annotation as diff-introduced and the call sites by their actual provenance.",
1302
+ "outputSha256": "a1f544b764cceef49b33aead53f1f12d2ab0c47882d1c727782e42e958064386",
1303
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1304
+ "deterministic": [],
1305
+ "judge": {
1306
+ "verdict": "pass",
1307
+ "reason": "Answer explicitly identifies the missing @MainActor isolation on the @Observable class as the issue ('is not isolated', 'no isolation exists at all'), explains the concrete cross-actor data race risk (SwiftUI main-thread reads vs background writes via Task/callback), and names marking the class @MainActor as the fix direction while stating it's read-only and not applied. It does not dismiss the gap as fine."
1308
+ },
1309
+ "passed": true
1310
+ },
1311
+ {
1312
+ "output": "A missing `@MainActor` on an `@Observable` class used to back SwiftUI screen state means the class's mutable properties are not isolated to the main actor. SwiftUI reads and mutates that state on the main thread, and any method the screen calls from a nonisolated context — a `Task {}`, an async delegate callback, a completion handler — can touch the same properties concurrently. That is a data race on the observable's stored properties: torn reads, a `didSet`/observation trigger firing off-main, or a SwiftUI update applied from the wrong thread. Under Swift 6 strict concurrency this is a compile error; under Swift 5 + `-strict-concurrency=targeted` or `minimal`, it compiles silently and only shows up as an intermittent crash or SwiftUI \"Publishing changes from background thread\" style failure, or a Thread Sanitizer hit. The correct shape is `@MainActor @Observable final class ...` and then, in any nonisolated call site that needs to update the class, hopping back with `await MainActor.run { }` or making the enclosing method `@MainActor` too.\n\nFindings, following this skill's format:\n\n```\n<path>/<File>.swift:<class decl line> — new @Observable class backing SwiftUI\n screen state is declared without @MainActor (@MainActor). Risk: cross-actor\n data race — SwiftUI reads/mutates its state on the main thread while any\n nonisolated Task/callback in the same screen mutates the same properties.\n Fix direction: mark the class `@MainActor @Observable final class ...`; make\n the nonisolated methods that update it @MainActor (or `await MainActor.run`)\n rather than annotating individual properties, so the whole observable\n surface is consistently isolated.\n```\n\nTwo follow-ups to confirm before this is signed off, since isolation gaps are not always provable by reading alone:\n\n1. Check whether any method on this class is already `nonisolated` or is reached from a `Task {}`/async callback without a main-actor hop — that is the concrete call site where the race would manifest, and it belongs in the finding as evidence rather than a generic \"could race.\"\n2. If the diff is being built under Swift 6 language mode, this should already fail the build; if it passes, the target is likely still on Swift 5 language mode, which is itself worth noting — the isolation gap is real and just not yet enforced. Run under Thread Sanitizer and the strict-concurrency checker to confirm rather than asserting the race from reading alone.\n\nDo not patch the declaration as part of this review — report the file:line, the risk, and the fix direction, and leave the edit to the author. If this class is genuinely only ever touched from the main thread today, that is still not sufficient: the annotation is what makes the guarantee explicit and enforced, not the current call graph.",
1313
+ "outputSha256": "1b540d26330dc52c77266a4f38eb871967be582b53e0ae721ebb3cf8f925a908",
1314
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1315
+ "deterministic": [],
1316
+ "judge": {
1317
+ "verdict": "pass",
1318
+ "reason": "Answer explicitly identifies missing @MainActor on the @Observable class (\"declared without @MainActor\"), explains the concrete race (SwiftUI reads/mutates on main thread while nonisolated Task/callback touches same properties — torn reads, off-main observation), and names the fix direction (\"mark the class `@MainActor @Observable final class ...`\") as a finding, explicitly not patching. It also rejects the 'only touched from SwiftUI' dismissal."
1319
+ },
1320
+ "passed": true
1321
+ },
1322
+ {
1323
+ "output": "The problem is a missing actor-isolation guarantee on a type whose state SwiftUI will read and mutate from the main thread.\n\n`@Observable` (the Observation framework macro) does not itself isolate anything to the main actor. It only synthesizes observation tracking for the stored properties — it says nothing about *which* thread or actor is allowed to touch them. So the class you added is, by default, a non-isolated type: unless the file, the type, or the enclosing context establishes main-actor isolation some other way (a `@MainActor` attribute on the class, on an enclosing declaration, `defaultIsolation(MainActor.self)` under the Swift 6 settings, etc.), the compiler treats its properties as reachable from *any* context.\n\nWhy that matters specifically for a SwiftUI screen's state:\n\n- A SwiftUI `View` body is `@MainActor` (views are main-actor isolated), so the body reads these `@Observable` properties on the main thread. If the class itself is non-isolated, that read is not protected against a concurrent mutation.\n- The usual companion patterns — an async method that hydrates the model from a network call, a `Task`, a detached delegate callback, a background Combine sink — can then write to the same stored properties from a non-main executor *without* the compiler stopping them, because nothing in the type says \"main actor only.\" That is exactly the shape of a real data race: main-thread read during a background write to the same property. It may pass in testing and corrupt state or crash under load.\n\nSo the finding is: `@Observable` without `@MainActor` on a type that backs SwiftUI view state is a missing-isolation defect, not a style nit. The fix direction is to annotate the class `@MainActor` (or apply `@MainActor` to an enclosing scope, or enable default main-actor isolation for the target), which makes the compiler enforce that all access to those properties happens on the main actor — and then route any background work that needs to update them through an explicit hop, e.g. `await MainActor.run { ... }` or by making the producing method main-actor-isolated.\n\nTwo things worth being precise about when you report it:\n\n- Whether this is *certainly* a race depends on whether anything off the main actor actually touches these properties in this diff or its callers. If nothing does yet, it is still a latent hazard (the type is silently unguarded and the next async addition breaks it) rather than a guaranteed live race — say so, and recommend confirming with the Swift 6 strict-concurrency checker / Thread Sanitizer rather than asserting a race that may not fire in the current code path.\n- The fix is to establish isolation at the type, not to sprinkle `Task { @MainActor in ... }` at call sites, which hides the hazard rather than removing it.",
1324
+ "outputSha256": "8f1260107f6c1ba0d481c56cd379c4fc0686689f78a365d2aeed738365604fc6",
1325
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1326
+ "deterministic": [],
1327
+ "judge": {
1328
+ "verdict": "pass",
1329
+ "reason": "Answer explicitly names missing @MainActor on the @Observable class as the defect ('@Observable without @MainActor ... is a missing-isolation defect'), explains the concrete race (SwiftUI body reads on main thread while async/Task/background writes touch same properties unprotected), and names the fix direction (annotate class @MainActor) as a finding, not applied code. It does not dismiss the gap as fine."
1330
+ },
1331
+ "passed": true
1332
+ },
1333
+ {
1334
+ "output": "**Finding — missing `@MainActor` isolation on a new `@Observable` type.**\n\nWhat's wrong is not stylistic: an `@Observable` class that backs a SwiftUI screen is read and mutated directly from the view's body and from event handlers, all of which run on the main actor. Without `@MainActor` (and without anything else in the file establishing main-actor isolation — e.g. a `@MainActor` enclosing declaration, a `@globalActor` on the type, or the whole type being otherwise confined), Swift has no isolation guarantee for the mutable stored properties that `@Observable` generates observation for. Two things follow:\n\n- **Data race / exclusivity risk.** If any mutation reaches this object from a non-main context — a `Task {}` that inherits no actor, a detached task, a callback that fires on a background queue, a Combine `sink` with an unspecified scheduler — it writes the same storage the main thread is reading during view rendering, with no synchronization. Under Swift 6 strict concurrency this is a diagnostic; under Swift 5 it compiles and is a latent race.\n- **Loss of the compiler as a safety net.** Marking the type `@MainActor` is what makes calling it from a background context a *compile error* instead of a runtime bug. Leaving it unisolated means every future `Task {}` in the file silently gets the freedom to touch it off-main.\n\nFix direction (report only — do not edit): annotate the type `@MainActor`, e.g. `@MainActor @Observable final class OrderDetailModel { ... }`. Then, at each call site that constructs or touches it, confirm isolation is actually satisfied — an initializer or `.task { }` body that should own it needs to itself be main-actor isolated (a SwiftUI view body already is; a free-floating `Task {}` that resolves to a non-main actor is not, and should be `.task` or explicitly `@MainActor`).\n\nCaveats I'd state rather than assert past:\n\n- I can't confirm from a prose description alone that no *other* mechanism isolates it — check the actual file for an enclosing `@MainActor`, a global-actor attribute, or the project's default-actor-isolation setting. If the file (or module) already establishes it, this finding is not diff-introduced and should be reported as such, or dropped.\n- If the object is provably only ever touched from main-actor code today, this is still worth flagging: the isolation is currently *conventional*, not *enforced*, and the next diff can break it without a compiler error.\n- To confirm whether a race is already manifesting, run the relevant flows under **Thread Sanitizer** and under the **Swift 6 strict-concurrency checker** — that tells you if it's a live race versus a latent one; don't assert a race exists from source reading alone.\n\nThis is a Step 2 \"concurrency and actor isolation\" finding per the focus list: a type whose state SwiftUI reads/mutates is not isolated to `@MainActor`. No code was modified; the finding and fix direction are above.",
1335
+ "outputSha256": "76150e1af8971eef0025537d4fc5674c2b8b0238068faa0bc6119f04d7b9c67e",
1336
+ "promptSha256": "96c31158741e2b0a1e13a72571c78d4f5a50bcfc2be3d7461728507d900caf5a",
1337
+ "deterministic": [],
1338
+ "judge": {
1339
+ "verdict": "pass",
1340
+ "reason": "Answer explicitly names missing @MainActor isolation on the @Observable type as the issue (\"Finding — missing @MainActor isolation\"), explains the concrete race risk (background Task/detached task/callback writing storage the main thread reads during rendering), and names the fix direction as a finding only (\"Fix direction (report only — do not edit): annotate the type @MainActor\"). It does not dismiss the gap; it says conventional isolation is still worth flagging."
1341
+ },
1342
+ "passed": true
1343
+ }
1344
+ ]
1345
+ }
1346
+ ],
1347
+ "verdict": "fail",
1348
+ "scope": "bundled",
1349
+ "skillDigest": "d00a244ceaec0bda6b10474db62184d3158e65122c67c34410eafc9dee8cd379",
1350
+ "catalogDigest": "97f9af01aafac82ae21a63c6af2a2f24fcfe067dc32a7cfdcde9a69a91fa9aae",
1351
+ "judgePromptVersion": "2026-09-25.1",
1352
+ "runner": "deepseek",
1353
+ "model": "deepseek-chat",
1354
+ "runnerPromptVersion": "2026-09-25.1",
1355
+ "recordedAt": "2026-09-25T18:23:45.139Z",
1356
+ "judge": "deepseek",
1357
+ "judgeModel": "deepseek-chat"
1358
+ },
1359
+ {
1360
+ "schemaVersion": "1.0.0",
1361
+ "skillId": "swift-ios/swift-build-fix",
1362
+ "strictness": "high",
1363
+ "trials": 10,
1364
+ "triggerAccuracy": {
1365
+ "truePositive": 1,
1366
+ "falsePositive": 0,
1367
+ "positives": 6,
1368
+ "negatives": 7
1369
+ },
1370
+ "evidence": "authored",
1371
+ "scenarios": [
1372
+ {
1373
+ "id": "trigger-positive-1",
1374
+ "kind": "trigger-positive",
1375
+ "prompt": "The compiler is complaining that this class can't cross a concurrency boundary safely",
1376
+ "strictness": "high",
1377
+ "trials": 1,
1378
+ "passes": 0,
1379
+ "passRate": 0,
1380
+ "passAtK": 0,
1381
+ "grader": "trigger-rank-fork-family",
1382
+ "status": "ran",
1383
+ "deterministic": true
1384
+ },
1385
+ {
1386
+ "id": "trigger-positive-2",
1387
+ "kind": "trigger-positive",
1388
+ "prompt": "xcodebuild fails saying this type doesn't conform to a required protocol for the checker",
1389
+ "strictness": "high",
1390
+ "trials": 1,
1391
+ "passes": 0,
1392
+ "passRate": 0,
1393
+ "passAtK": 0,
1394
+ "grader": "trigger-rank-fork-family",
1395
+ "status": "ran",
1396
+ "deterministic": true
1397
+ },
1398
+ {
1399
+ "id": "trigger-positive-3",
1400
+ "kind": "trigger-positive",
1401
+ "prompt": "SwiftLint is blocking my build over a rule I don't understand",
1402
+ "strictness": "high",
1403
+ "trials": 1,
1404
+ "passes": 1,
1405
+ "passRate": 1,
1406
+ "passAtK": 1,
1407
+ "grader": "trigger-rank-fork-family",
1408
+ "status": "ran",
1409
+ "deterministic": true
1410
+ },
1411
+ {
1412
+ "id": "trigger-positive-4",
1413
+ "kind": "trigger-positive",
1414
+ "prompt": "This type isn't allowed to be passed into a Task the way I've written it",
1415
+ "strictness": "high",
1416
+ "trials": 1,
1417
+ "passes": 0,
1418
+ "passRate": 0,
1419
+ "passAtK": 0,
1420
+ "grader": "trigger-rank-fork-family",
1421
+ "status": "ran",
1422
+ "deterministic": true
1423
+ },
1424
+ {
1425
+ "id": "trigger-positive-5",
1426
+ "kind": "trigger-positive",
1427
+ "prompt": "My scheme's build fails but the same code compiled fine before enabling strict concurrency",
1428
+ "strictness": "high",
1429
+ "trials": 1,
1430
+ "passes": 0,
1431
+ "passRate": 0,
1432
+ "passAtK": 0,
1433
+ "grader": "trigger-rank-fork-family",
1434
+ "status": "ran",
1435
+ "deterministic": true
1436
+ },
1437
+ {
1438
+ "id": "trigger-positive-6",
1439
+ "kind": "trigger-positive",
1440
+ "prompt": "The build is red because of a warning about an optional that's never actually nil",
1441
+ "strictness": "high",
1442
+ "trials": 1,
1443
+ "passes": 0,
1444
+ "passRate": 0,
1445
+ "passAtK": 0,
1446
+ "grader": "trigger-rank-fork-family",
1447
+ "status": "ran",
1448
+ "deterministic": true
1449
+ },
1450
+ {
1451
+ "id": "trigger-negative-1",
1452
+ "kind": "trigger-negative",
1453
+ "prompt": "gradle build is failing for this Android module",
1454
+ "strictness": "high",
1455
+ "trials": 1,
1456
+ "passes": 1,
1457
+ "passRate": 1,
1458
+ "passAtK": 1,
1459
+ "grader": "trigger-rank-fork-family",
1460
+ "status": "ran",
1461
+ "deterministic": true
1462
+ },
1463
+ {
1464
+ "id": "trigger-negative-2",
1465
+ "kind": "trigger-negative",
1466
+ "prompt": "npm run build is failing with a webpack error",
1467
+ "strictness": "high",
1468
+ "trials": 1,
1469
+ "passes": 1,
1470
+ "passRate": 1,
1471
+ "passAtK": 1,
1472
+ "grader": "trigger-rank-fork-family",
1473
+ "status": "ran",
1474
+ "deterministic": true
1475
+ },
1476
+ {
1477
+ "id": "trigger-negative-3",
1478
+ "kind": "trigger-negative",
1479
+ "prompt": "cargo build is failing for this Rust crate",
1480
+ "strictness": "high",
1481
+ "trials": 1,
1482
+ "passes": 1,
1483
+ "passRate": 1,
1484
+ "passAtK": 1,
1485
+ "grader": "trigger-rank-fork-family",
1486
+ "status": "ran",
1487
+ "deterministic": true
1488
+ },
1489
+ {
1490
+ "id": "trigger-negative-4",
1491
+ "kind": "trigger-negative",
1492
+ "prompt": "Implement a new feature in this SwiftUI screen",
1493
+ "strictness": "high",
1494
+ "trials": 1,
1495
+ "passes": 1,
1496
+ "passRate": 1,
1497
+ "passAtK": 1,
1498
+ "grader": "trigger-rank-fork-family",
1499
+ "status": "ran",
1500
+ "deterministic": true
1501
+ },
1502
+ {
1503
+ "id": "trigger-negative-5",
1504
+ "kind": "trigger-negative",
1505
+ "prompt": "Review this Swift diff for retain cycles",
1506
+ "strictness": "high",
1507
+ "trials": 1,
1508
+ "passes": 1,
1509
+ "passRate": 1,
1510
+ "passAtK": 1,
1511
+ "grader": "trigger-rank-fork-family",
1512
+ "status": "ran",
1513
+ "deterministic": true
1514
+ },
1515
+ {
1516
+ "id": "trigger-negative-6",
1517
+ "kind": "trigger-negative",
1518
+ "prompt": "Write Swift Testing coverage for this view model",
1519
+ "strictness": "high",
1520
+ "trials": 1,
1521
+ "passes": 1,
1522
+ "passRate": 1,
1523
+ "passAtK": 1,
1524
+ "grader": "trigger-rank-fork-family",
1525
+ "status": "ran",
1526
+ "deterministic": true
1527
+ },
1528
+ {
1529
+ "id": "trigger-negative-7",
1530
+ "kind": "trigger-negative",
1531
+ "prompt": "pip install is failing for this Python project",
1532
+ "strictness": "high",
1533
+ "trials": 1,
1534
+ "passes": 1,
1535
+ "passRate": 1,
1536
+ "passAtK": 1,
1537
+ "grader": "trigger-rank-fork-family",
1538
+ "status": "ran",
1539
+ "deterministic": true
1540
+ },
1541
+ {
1542
+ "id": "sendable-conformance-error",
1543
+ "kind": "behavior",
1544
+ "prompt": "The compiler is flagging a class I pass into a Task as not conforming to Sendable, and the build won't succeed under the project's strict concurrency checking. How do I fix this properly?",
1545
+ "strictness": "high",
1546
+ "trials": 10,
1547
+ "passes": 10,
1548
+ "passRate": 1,
1549
+ "passAtK": 1,
1550
+ "grader": "judge",
1551
+ "status": "ran",
1552
+ "trialRecords": [
1553
+ {
1554
+ "output": "The proper fix depends on one question: does the class's mutable state actually get accessed concurrently, or is it effectively immutable after init? Read the compiler's exact wording first — it will tell you which stored properties it considers unsafe. Then:\n\n**If the class holds mutable state that tasks can touch**, the real fix is to give it real isolation. Options, in rough order of preference:\n\n- Convert it to an `actor`. Task boundaries then hop onto its executor and the compiler stops complaining because access is serialized for real. This is usually the cleanest fix when the object genuinely owns mutable state.\n- Mark it `@MainActor` (or move the call site to the main actor) if the state is UI-bound and only ever touched from the main thread anyway. That's not a suppression — it's a true statement about where the state lives.\n- If the class is a value-semantics wrapper that shouldn't be a class, consider making it a `struct` whose members are all `Sendable`. Value types crossing a boundary freely is often exactly what you wanted.\n\n**If the class is effectively immutable after initialization** (all stored properties are `let` of `Sendable` types, or `var` but only set during init), then the correct move is to conform it to `Sendable` properly — a plain, honest conformance. To make that legal you may need to tighten the type: change mutable `var` properties to `let`, make stored closure/property types `@Sendable`, or constrain generic members to `Sendable`. That is the compiler asking you to *prove* the immutability, which is a good thing.\n\n**When `@unchecked Sendable` is legitimately correct:** only when you can state precisely why the access pattern is safe despite the compiler being unable to see it — for example, all mutation is funneled through a private `DispatchQueue`/`NSLock` you control, or the type is immutable in practice but the compiler can't prove it because of a legacy API. If you reach for it, the report must contain that one-sentence justification. It is never the default move, and it should be rare.\n\nWhat not to do: don't slap `@unchecked Sendable` on it just to clear the error, and don't start force-unwrapping or disabling lint rules while you're in there. Those silence the check without addressing why the compiler flagged the crossing.\n\nConcretely, the shape of a good answer:\n\n```\nFixed: Sendable conformance error for OrderCache passed into Task\n - Root cause: OrderCache held mutable var state mutated from a detached\n Task with no isolation; converted it to an actor\n - xcodebuild build/test pass, swiftlint clean\n```\n\nThat last line matters: after the change, re-run `xcodebuild build`, `xcodebuild test`, and the linter (if configured) and confirm all exit 0 before calling it done. And state the root cause in a sentence — \"build passes\" alone isn't a fix report.",
1555
+ "outputSha256": "683a73f0a31de191c3cc6373e8964fd15dde3dd744045d5adecc41ee9a1cc4e1",
1556
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1557
+ "deterministic": [],
1558
+ "judge": {
1559
+ "verdict": "pass",
1560
+ "reason": "Names root cause: 'OrderCache held mutable var state mutated from a detached Task with no isolation'. Primary fixes: convert to actor, @MainActor, or make properties let for honest Sendable conformance. @unchecked Sendable only 'when you can state precisely why the access pattern is safe' and 'never the default move'. All criteria hold."
1561
+ },
1562
+ "passed": true
1563
+ },
1564
+ {
1565
+ "output": "You fix it by deciding what the class's state actually *is* and giving the compiler a real guarantee — not by suppressing the diagnostic. Work through it in this order:\n\n**1. Find out what the compiler is actually complaining about.**\nRead the full diagnostic, not just the first line. Swift will usually name the specific stored property that isn't `Sendable` (or that's mutable and unprotected). That property is the real problem, not the class declaration.\n\n**2. Ask: is this class genuinely shared mutable state?**\n- **If yes** (multiple tasks/threads really do read and write it concurrently), the correct fix is real isolation: make it an `actor`, or mark it `@MainActor` if it belongs to the UI, or move the mutable state behind a lock/`Mutex` so the concurrency is actually safe. The class then passes the check because it *is* safe, not because you told the compiler to look away.\n- **If it's actually immutable** (all stored properties are `let` and are themselves `Sendable`), just conform it to `Sendable` — the compiler will verify every stored property and reject the conformance if you're lying.\n- **If it's only read on one side of the boundary** (you build it on one task and hand it off, never touching it from two places at once), the honest fix is usually to restructure so the type is value-like (`struct`) or to pass a snapshot/immutable payload into the `Task` rather than the mutable class itself. Passing a mutable reference across a task boundary is exactly the hazard strict concurrency is designed to catch.\n\n**3. What NOT to do.**\n- Do not slap `@unchecked Sendable` on it as a first move. That's a promise to the compiler that you've verified safety yourself. Only reach for it if you can state precisely, in the commit/report, *why* the access pattern is safe despite the compiler being unable to prove it (e.g. \"all mutation happens on `queue` and the type is never touched from more than one task at a time\"). \"It made the build pass\" is not a justification.\n- Do not reduce the concurrency checking level in the build settings, and do not add a `@preconcurrency` import or annotation to mute the diagnostic.\n- Do not convert the `Task` to `Task.detached`/`detached` or wrap things in `MainActor.run` just to move the error somewhere it's less visible.\n\n**4. If the class is from a dependency you don't control:**\nWrap it. Create your own `Sendable` façade — e.g. a small actor that owns the non-`Sendable` instance and serializes access to it, or an immutable value snapshot you extract on one side and consume on the other. This keeps the unchecked promise confined to a tiny, auditable surface instead of spreading `@unchecked` through your code.\n\n**5. Verify.**\nRebuild with the project's strict-concurrency settings and run the test suite (`xcodebuild build`/`test` or `swift build`/`test`) to confirm exit 0. Then check that the change is minimal and that you can write the root cause in one sentence — e.g. \"`OrderCache` held mutable state touched from two tasks with no isolation; converted it to an `actor`.\" If you can't write that sentence without saying \"I marked it `@unchecked`,\" you haven't fixed it yet.",
1566
+ "outputSha256": "d362ef29c9ad7e55a7ff6ce9b0fe65decb9135760cf20ec32e0407fe9676e553",
1567
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1568
+ "deterministic": [],
1569
+ "judge": {
1570
+ "verdict": "pass",
1571
+ "reason": "Step 1 names the root cause: Swift names the mutable unprotected stored property, 'the real problem, not the class declaration.' Step 2 gives real fixes: actor, @MainActor, lock/Mutex, or immutable let properties conforming to Sendable. @unchecked is only allowed with a stated justification ('all mutation happens on queue...'), and 'It made the build pass' is rejected."
1572
+ },
1573
+ "passed": true
1574
+ },
1575
+ {
1576
+ "output": "First, read the exact compiler diagnostic. It will point at the specific stored property (or the class itself) that crosses the `Task` boundary unsafely. That tells you which of three situations you're actually in:\n\n**1. The class's state is genuinely immutable after init.** If every stored property is a `let` of a `Sendable` type, the class can legitimately conform: `final class OrderCache: Sendable { ... }`. If it has a `var` and you're sure nothing mutates it after init, that's not the same situation — see below.\n\n**2. The class's state is mutable and accessed from multiple tasks.** This is the common case and the one the error is actually about. Convert it to an `actor`:\n\n```swift\nactor OrderCache {\n private var orders: [Order] = []\n func insert(_ order: Order) { orders.append(order) }\n}\n```\n\nThe actor serializes all access to its mutable state, so passing it into a `Task` is now safe without any `Sendable` annotation — an actor is implicitly `Sendable`. If the state is genuinely tied to the UI, `@MainActor` on the class is the equivalent fix for main-thread-isolated state.\n\n**3. The class is a value-semantics type masquerading as a class.** If it has no identity and no shared mutation, make it a `struct` with all `Sendable` stored properties; it then conforms implicitly. This is often the smallest fix.\n\n**The one thing not to do** is slap `@unchecked Sendable` on it to clear the error. That tells the compiler \"trust me, this is safe\" while doing nothing to make it safe — you've traded a compile-time data-race guarantee for a runtime race that will surface as a heisenbug under load. The only time `@unchecked Sendable` is legitimate is when you can state, precisely, why the access pattern is safe despite the compiler being unable to prove it (e.g. a class whose mutable storage is guarded by an internal `os_unfair_lock` or `DispatchQueue` you fully control). If you can't write that justification in one sentence, it isn't legitimate here.\n\nSo: read the diagnostic, decide which of the three cases you're in, apply the matching fix, then re-run `xcodebuild build` and `xcodebuild test` (and the project's linter) to confirm both pass before calling it done.",
1577
+ "outputSha256": "0973fc5befff928da935e43db1738e9238fa0a989d1dfc041af5d4f0bd4fc476",
1578
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1579
+ "deterministic": [],
1580
+ "judge": {
1581
+ "verdict": "pass",
1582
+ "reason": "Answer names root cause (mutable stored state accessed from multiple tasks, case 2), gives real fixes: actor conversion with code, @MainActor, immutable let/final class Sendable, struct. @unchecked Sendable explicitly framed as 'the one thing not to do' unless a precise one-sentence justification of safe access pattern is stated."
1583
+ },
1584
+ "passed": true
1585
+ },
1586
+ {
1587
+ "output": "Fix it by determining *why* the type isn't `Sendable`, then eliminating that reason — not by reaching for `@unchecked Sendable` as a first move. The compiler is telling you the type has state that could be mutated from more than one concurrency context at once.\n\n**Work through the possibilities in order:**\n\n1. **The state is genuinely immutable after init.** If every stored property is `let` and itself `Sendable` (plus any inherited/`@objc` constraints are satisfied), just add `: Sendable` to the class. That's the correct fix, not a suppression. If the class is `final` and all stored properties are `let` of `Sendable` type, the conformance is honest.\n\n2. **The state is mutable and shared.** That's a real data race the compiler is right to block. Pick the isolation that matches the access pattern:\n - If the type represents mutable shared state used from multiple contexts: make it an `actor`. All mutation becomes actor-isolated and the `Sendable` error goes away legitimately.\n - If it's UI state: mark it `@MainActor` (or move it to a `@MainActor`-isolated type) so all access is confined to the main actor.\n - If only one property needs protection: isolate that property rather than the whole type.\n\n3. **The type is passed across a boundary but never actually mutated after being handed off.** Sometimes the right fix is to change what crosses the boundary: pass an immutable snapshot/value (a `struct` of `let` values) into the `Task` instead of the mutable class reference. Restructure so the `Sendable`-unsafe thing never crosses.\n\n4. **Only after the above fail to apply** — i.e. you can articulate a specific, sound reason the type's access pattern is safe despite the compiler being unable to prove it — may you use `@unchecked Sendable`. And that's a last resort, reported explicitly: you must state in your write-up exactly why the mutable state is safe (what synchronization discipline guarantees no concurrent mutation). Reaching for it as the default to clear the error is the classic mistake — it swaps a compile-time data-race guarantee for an unchecked promise that will crash or corrupt at runtime.\n\n**What not to do:**\n- Don't `@unchecked Sendable` to make the red go away without a stated reason.\n- Don't add `@preconcurrency` purely to muzzle the diagnostic unless you genuinely can't touch the source (e.g. a third-party module) — and even then, scope it to the import, not the type.\n- Don't force the value through a `nonisolated(unsafe)` declaration to dodge isolation; same problem.\n\n**Verify:** rerun `xcodebuild build` (or `swift build`) and the scheme's tests to exit 0, rerun SwiftLint/swift-format if configured, and confirm you touched only the files the failure requires.\n\n**Report the root cause in one sentence** — e.g. \"`OrderCache` held mutable state read and written from two tasks with no isolation; converted it to an `actor`.\" Not \"added `@unchecked Sendable`, build passes.\" If your final fix is a bare `@unchecked Sendable` with no justification, you haven't fixed the concurrency bug — you've hidden it.",
1588
+ "outputSha256": "aab689a6df2a755aed11449f766b1132c2485ed94aa55e577f1b35ded4eec5ca",
1589
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1590
+ "deterministic": [],
1591
+ "judge": {
1592
+ "verdict": "pass",
1593
+ "reason": "Names root cause: 'the type has state that could be mutated from more than one concurrency context at once.' Real fixes given as primary: add ': Sendable' when all stored props are let (immutable), make it an actor, mark @MainActor, or pass an immutable snapshot. @unchecked Sendable is explicitly last resort requiring stated justification of why state is safe, not the default."
1594
+ },
1595
+ "passed": true
1596
+ },
1597
+ {
1598
+ "output": "You're hitting a real correctness requirement, not a formality to silence. Here's how to fix it properly.\n\n**First, read exactly what the compiler says.** It names the class and points at the value crossing the isolation boundary. The error means the class has mutable, unprotected state that could be touched from two concurrency domains at once. That is an actual data-race risk, not a false positive — Swift 6 strict concurrency exists to catch exactly this.\n\n**Then decide which of these three the class actually is:**\n\n1. **The state genuinely needs protection** (it's mutated from multiple tasks/threads). Make it an `actor`. This is usually the right answer for a class holding mutable cache/session/buffer state that a `Task` reads and writes. Move the mutable state into the actor and route access through `await` calls. An `actor` gives real, compiler-enforced isolation instead of a promise.\n\n2. **The state is genuinely main-thread-only** (UI state, view models bound to the main thread). Mark it `@MainActor`. Then `Task { }` needs to hop appropriately — `Task { @MainActor in ... }` or `await MainActor.run { ... }` if the caller is not already main-isolated. This is correct because the isolation is real and enforced, not asserted.\n\n3. **The type is genuinely immutable** (all stored properties are `let` and themselves `Sendable`, e.g. value types, `String`, `Int`, other `Sendable` references). Then it's safe to conform it to `Sendable` — but conform it *properly*: make the stored properties `let` and `Sendable`, and declare the conformance. The compiler will verify it. If it rejects the conformance, that's the compiler telling you the type is not actually immutable, and you're back to case 1 or 2.\n\n**What not to do:**\n\n- Do **not** reach for `@unchecked Sendable` first. It disables the compiler's ability to help you and trades a compile-time guarantee for an unchecked runtime promise. It is only defensible when you can state, concretely, why the access pattern is safe despite the compiler being unable to prove it — e.g., all mutation happens through an internal lock you can point to. If you use it at all, the one-sentence justification goes in the report and ideally a comment at the declaration. Never as a default way to clear the error.\n- Do **not** wrap the class in a `@Sendable` closure that just captures it to dodge the diagnostic.\n- Do **not** downgrade the strict-concurrency setting to \"minimal\" or turn the feature off to make the build pass.\n\n**A concrete shape of the fix**, if the class is a mutable cache:\n\n```swift\n// before: class OrderCache { var orders: [Order] = [] }\nactor OrderCache {\n private var orders: [Order] = []\n func add(_ order: Order) { orders.append(order) }\n func all() -> [Order] { orders }\n}\n```\n\nCallers become `await cache.add(order)` / `await cache.all()`. Passing the actor into a `Task` is now fine — actors are `Sendable`. The build error disappears because the isolation is real, not because you suppressed it.\n\nIf instead it's a view model, `@MainActor final class ViewModel { ... }` and adjust the `Task` to hop to the main actor.\n\n**Verify before you call it done:** rerun `xcodebuild build` and `xcodebuild test` (or `swift build`/`swift test`) to exit 0, and run the project's configured linter if it was part of the failure. Then state the root cause in one sentence — e.g. \"OrderCache held mutable state read and written from two tasks with no isolation; converted it to an actor so access is serialized by the compiler.\" Not just \"cleared the Sendable error.\" If your fix was \"the state is safe because X,\" X needs to be a specific, checkable claim about the access pattern, not \"it worked when I ran it.\"",
1599
+ "outputSha256": "8a917cbdca901bb76f7f58a325ef0e59a995aef48c3f8541cdb7a28411a7286c",
1600
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1601
+ "deterministic": [],
1602
+ "judge": {
1603
+ "verdict": "pass",
1604
+ "reason": "Names root cause: 'the class has mutable, unprotected state that could be touched from two concurrency domains at once.' Primary fixes: actor (with concrete OrderCache example), @MainActor, or immutable let properties with genuine Sendable conformance. @unchecked Sendable explicitly framed as not-first, requiring stated concrete justification (internal lock). No fail criterion holds."
1605
+ },
1606
+ "passed": true
1607
+ },
1608
+ {
1609
+ "output": "To fix this properly, you need to figure out *why* the compiler can't prove the class is `Sendable`, then address that actual reason — not silence the diagnostic. Here's how to work through it.\n\n**Step 1: Classify the failure precisely.**\n\nRead the exact diagnostic. A strict-concurrency `Sendable` error on a class passed into a `Task` almost always comes down to one of these:\n\n- The class has **mutable, non-`Sendable` stored properties** (`var` of a reference type, a closure, a collection of non-`Sendable` elements).\n- The class is **mutable and accessed from multiple isolation domains** with no `actor`/`@MainActor` protection.\n- The class is actually **fine** — all state is immutable — but the compiler just needs you to say so.\n\nThese need different fixes. Don't default to one.\n\n**Step 2: Fix according to what's actually true.**\n\n*If the type is genuinely immutable* (all stored properties are `let` and themselves `Sendable`), the correct fix is to declare it `Sendable` honestly:\n\n```swift\nfinal class OrderSnapshot: Sendable {\n let id: UUID\n let total: Decimal\n}\n```\n\n`final` matters for a class — a non-final class can be subclassed in another module with mutable state, so it can't be proven `Sendable` without the finality.\n\n*If the type has mutable state that needs protecting* (the common real case for \"I pass this into a Task\"), the right answer is isolation, not a promise. Make it an `actor`, or if it must stay a class, confine it to a single global actor:\n\n```swift\nactor OrderCache {\n private var orders: [UUID: Order] = [:]\n func store(_ order: Order) { orders[order.id] = order }\n}\n```\n\n…or `@MainActor` on the class if its state is tied to the UI. Then the `Task` crossing the boundary is crossing into the actor's domain, which is exactly what the compiler wants to see.\n\n*If the mutable state really is only ever touched from one thread and you can prove it* — that's the rare case. You may reach for `@unchecked Sendable`, but only after writing down, concretely, why the access pattern is safe (e.g., \"all mutation happens under an internal `os_unfair_lock`, never read outside it\"). State that reasoning in your report. If you can't articulate it, you don't actually have the guarantee — add real isolation instead.\n\n**Step 3: Two things not to do.**\n\n- Don't mark it `@unchecked Sendable` just to clear the error. That trades the compiler's data-race guarantee for an unchecked promise you now own at runtime, and it's the single most common way this error gets \"fixed\" while leaving a latent race.\n- Don't make a property force-unwrapped or wrap the call in `try!` to get past a related optional/throwing diagnostic that shows up in the same build. Address each on its own terms.\n\n**Step 4: Verify.**\n\n```\nxcodebuild build -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\nxcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\n```\n\nBoth must exit 0, plus the project's linter if one is configured. Then report the root cause in one sentence — e.g. \"OrderCache held mutable state reached from two tasks with no isolation; converted it to an actor\" — not just \"build passes.\"\n\nThe short version: decide whether the type is immutable (declare `Sendable`), genuinely needs protection (use `actor`/`@MainActor`), or is a provable special case (`@unchecked Sendable` with a written justification). If you can't tell which, the mutable-state answer is almost always the right one.",
1610
+ "outputSha256": "d39c79572b82bdb3aa63a07016bf60685fc26294c3e1a9c57c2bbc396478b35d",
1611
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1612
+ "deterministic": [],
1613
+ "judge": {
1614
+ "verdict": "pass",
1615
+ "reason": "Names root cause: mutable non-Sendable stored state accessed from multiple isolation domains with no actor/@MainActor protection (Step 1). Primary fixes shown concretely: immutable final class Sendable with let props, actor OrderCache, @MainActor. @unchecked Sendable only allowed after writing down concrete justification (os_unfair_lock), and explicitly warned against as default. No fail criterion holds."
1616
+ },
1617
+ "passed": true
1618
+ },
1619
+ {
1620
+ "output": "The compiler is telling you that a mutable class is being captured by a `Task` and crossing an isolation boundary, and it can't prove that access is safe. Under strict concurrency checking, the fix is to make the access pattern actually safe — not to silence the diagnostic. Here's how to decide, in order:\n\n**1. Determine whether the class actually needs to be shared across that boundary.**\n\n- If the `Task` only needs a snapshot of the data it reads, capture value-semantic data (a struct of plain values, a copied array, etc.) instead of the class reference. This is usually the smallest and best fix: the class never crosses the boundary at all, so the question disappears.\n- If the class is genuinely immutable after construction, make it properly `Sendable`: mark all stored properties `let` and ensure each is itself `Sendable` (value types, immutable `Sendable` references, `Actor` refs, etc.). You do **not** need `@unchecked` for this — a real conformance compiles once the properties qualify. Mark the class `final` so the compiler can reason about it.\n\n**2. If the class has mutable state that the Task genuinely needs to mutate, isolate it.**\n\n- Make it an `actor`. This is the correct answer for \"a class with mutable state accessed from multiple concurrent tasks.\" Callers then `await` its methods, and the compiler enforces that access is serialized. This is a real fix, not a suppression.\n- If the state is UI-bound, annotate it `@MainActor` (and ensure the `Task` hops to the main actor, e.g. `Task { @MainActor in ... }` or `await MainActor.run { ... }`) instead of an actor.\n\n**3. Only if the type genuinely cannot be made `Sendable` or actor-isolated** (e.g. it wraps a C resource or a lock you already hold correctly), you *may* use `@unchecked Sendable` — but only after you can state, in writing in your change/PR, exactly which invariant makes concurrent access safe (which lock guards which fields, which accesses are read-only under what happens-before relationship). \"It cleared the error\" is not a justification. If you can't articulate the invariant, go back to step 1 or 2.\n\n**Do not:**\n- Add `@unchecked Sendable` just to get green.\n- Add a `@preconcurrency` import/conformance as a blanket suppressor unless the boundary is genuinely a legacy `@preconcurrency` API you don't control.\n- Disable the strict-concurrency checking flag for the target.\n- Force-unwrap or `try!` anything the concurrency diagnostic pushes you toward.\n\n**Verify:** re-run `xcodebuild build` (and `test`, and the linter) to exit 0. Then state the root cause in one sentence — e.g. *\"`OrderCache` held mutable state read/written from two concurrent tasks with no isolation; converted it to an `actor`.\"* If your one-sentence root cause is \"it wasn't `Sendable` so I added `@unchecked Sendable`,\" you haven't found the root cause yet.",
1621
+ "outputSha256": "6f928bd10b3c4a6df3819d5f4def8493289ff76cdb8c5bb339086ec9d55b38e3",
1622
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1623
+ "deterministic": [],
1624
+ "judge": {
1625
+ "verdict": "pass",
1626
+ "reason": "Names root cause (mutable class captured by Task crossing isolation boundary, can't prove safe). Fixes: capture value snapshot, make properties let for real Sendable, convert to actor, or @MainActor. @unchecked Sendable only in step 3 with written invariant justification, explicitly not default. No fail criterion met."
1627
+ },
1628
+ "passed": true
1629
+ },
1630
+ {
1631
+ "output": "The build is failing because strict concurrency checking requires anything captured across a `Task` boundary to be `Sendable`, and your class isn't. Don't reach for `@unchecked Sendable` — fix the actual access pattern.\n\n**First, figure out what the class actually is:**\n\n- **Immutable value-like state** (every stored property is a `let` of a `Sendable` type) → conform it to `Sendable` properly. This is a real, checkable conformance, not a promise.\n- **Shared mutable state** → the fix is isolation, not a conformance. Convert it to an `actor` (or mark it `@MainActor` if it genuinely belongs to the main thread). That gives the compiler a real guarantee instead of an unchecked claim.\n- **A reference type you don't control** → wrap the state it guards in an actor, or pass a `Sendable` snapshot/value into the `Task` rather than the class itself.\n\n`@unchecked Sendable` is only legitimate when you can state exactly why the type is safe despite the compiler being unable to prove it (e.g., it's internally synchronized by a lock you can point to). If you can't write that sentence, it's the wrong move — it trades a compile-time data-race guarantee for an unchecked promise.\n\n**Then verify:**\n\n```\nxcodebuild build -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\nxcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\n```\n\nBoth must exit 0, and any configured linter (`swiftlint`) must be clean — no blanket `// swiftlint:disable`, no force-unwraps introduced to paper over a related warning.\n\n**Report the root cause, not just \"fixed\":**\n\n> Fixed: `Sendable` conformance error in `OrderCache`\n> - Root cause: `OrderCache` held mutable state accessed from two tasks with no isolation; converted it to an `actor`.\n> - `xcodebuild build`/`test` both pass, `swiftlint` clean.\n\nIf you can tell me what `OrderCache`-style class actually holds — immutable config, a mutable cache, or a reference to something like a `URLSession` or a delegate — I can say which of the three fixes applies and show the concrete shape.",
1632
+ "outputSha256": "47298e11f170761064698e5a6ad7fc6f090de40e16736f8454ad8bbb46a53609",
1633
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1634
+ "deterministic": [],
1635
+ "judge": {
1636
+ "verdict": "pass",
1637
+ "reason": "Names root cause: 'Shared mutable state' with 'no isolation' captured across Task boundary. Primary fixes: conform immutable let-only class to Sendable, convert to actor or @MainActor, or wrap in actor/pass snapshot. @unchecked Sendable framed as only legitimate with stated justification (lock), not default. All pass criteria hold; no fail criterion."
1638
+ },
1639
+ "passed": true
1640
+ },
1641
+ {
1642
+ "output": "The compiler is telling you that an instance of this class crosses an isolation boundary (the `Task`) carrying mutable state that isn't proven safe. Fix it by making the type's actual concurrency story match what the compiler needs to prove, not by asserting safety you haven't verified.\n\n**Start by reading the exact diagnostic.** It names the property or reference that can't be proven `Sendable`. That's the thing to fix, not the class declaration as a whole.\n\nThen pick the fix that matches the real ownership pattern:\n\n**1. The instance is genuinely shared and mutable across tasks.**\nThis is the case where the right fix is isolation, not a conformance. Convert the class to an `actor` — all its mutable state becomes actor-isolated, and calls to it from the `Task` become `await`ed actor hops. If the mutation is UI-bound, annotate the class `@MainActor` instead, and make sure the `Task` is created with the right actor context (`Task { @MainActor in ... }` if it needs to touch that state). This is almost always the correct fix when the reviewer can't honestly say \"this is never mutated after construction.\"\n\n**2. The instance is truly immutable after initialization.**\nIf every stored property is `let` and `Sendable`, mark the class `final` and add a real `Sendable` conformance — `final class Foo: Sendable`. A non-final class can't have a synthesizable or safe `Sendable` conformance, so finality matters here. If it holds a reference type that itself isn't `Sendable`, that reference is the real problem, and fixing that type (or making the containing property immutable-and-value-typed) is the actual work.\n\n**3. The instance is passed by value, not shared.**\nA `struct` (or `enum`) whose stored properties are all `Sendable` conforms automatically. If you're currently using a `class` here only out of habit, converting to a value type resolves the boundary cleanly and is often the smallest honest change.\n\n**What not to do:** `@unchecked Sendable` is only legitimate when you can state, concretely, why the access pattern is safe despite the compiler being unable to prove it — e.g. a class whose mutable state is guarded by an internal `NSLock`/`OSAllocatedUnfairLock` on every access path. If you can't articulate that guarantee and point to the synchronization that actually enforces it, `@unchecked` is a lie to the compiler, not a fix, and it converts a compile-time race-detection guarantee into a latent runtime data race. Do not reach for it as the default way to clear the error.\n\n**A common shape worth calling out:** a class that is mutated only during setup and then read-only forever. Even here, the honest fix is usually to introduce a genuinely immutable snapshot type (a `struct` with all-`Sendable` fields) that gets built during setup and passed into the `Task`, rather than conformance on the mutable class. The snapshot's immutability is what makes the conformance true.\n\nAfter the change, re-run both the build and the test scheme (`xcodebuild build` and `xcodebuild test`, or `swift build`/`swift test`) and re-run SwiftLint if it's wired into the failure. Report the root cause in one sentence — which property or reference was unsafe to cross the boundary, and which of the three patterns above you applied — rather than just \"sendable error fixed.\"",
1643
+ "outputSha256": "2946ba8adee70a0cc0304ff6979ae77a3160507ab61d943a1708c9c0f06e81f8",
1644
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1645
+ "deterministic": [],
1646
+ "judge": {
1647
+ "verdict": "pass",
1648
+ "reason": "Names root cause: 'crosses an isolation boundary carrying mutable state that isn't proven safe.' Primary fixes: convert to actor, @MainActor, or final class with all-let Sendable properties ('final class Foo: Sendable'). @unchecked Sendable explicitly framed as requiring concrete justification (NSLock/OSAllocatedUnfairLock) and 'Do not reach for it as the default.'"
1649
+ },
1650
+ "passed": true
1651
+ },
1652
+ {
1653
+ "output": "The fix depends on one question: does this class actually have mutable state that the `Task` will touch concurrently?\n\n**If the class has mutable state accessed from the task (and possibly elsewhere):**\n\nMake it an `actor` if its state should be protected automatically, or mark it `@MainActor` if it's genuinely UI-bound. Either converts the error into a real isolation guarantee rather than a promise.\n\n```swift\n// Before: class Cache { var items: [String: Item] = [:] ... }\nactor Cache {\n private var items: [String: Item] = [:]\n func store(_ item: Item) { items[item.id] = item }\n func item(for id: String) -> Item? { items[id] }\n}\n```\n\nThen the task interacts with it via `await cache.store(item)` — no data race possible.\n\n**If the class is genuinely immutable after initialization:**\n\nConform it to `Sendable` properly. For a `final class` where every stored property is `let` and itself `Sendable`, an explicit conformance is honest:\n\n```swift\nfinal class OrderSnapshot: Sendable {\n let id: String\n let total: Decimal\n init(id: String, total: Decimal) { ... }\n}\n```\n\nIf the class isn't `final` or has any mutable stored property, this conformance won't compile — which is the compiler correctly telling you the type isn't safe to share, and you should reach for an actor or `@MainActor` instead.\n\n**The move to avoid:**\n\nDo not reach for `@unchecked Sendable` just to make the error go away. It tells the compiler \"trust me\" and disables the check without providing any guarantee. It is a valid tool, but only when you can state exactly why the access pattern is safe despite the compiler being unable to prove it — e.g., all mutation is funneled through a private serial `DispatchQueue`, or the mutable state is protected by a lock you can point to. If you can't write that sentence, you haven't fixed the problem, you've hidden it.\n\n**Also check whether the class even needs to be captured by reference:**\n\nIf the `Task` only reads a value out of the class, passing an immutable value type (a `struct` with `let` properties, or a copy) often removes the conformance requirement entirely and is the smallest correct fix.\n\nSo, in order of preference:\n\n1. Capture an immutable value copy instead of the reference, if that's all the task needs.\n2. Make it `Sendable` if it's truly immutable.\n3. Make it an `actor` / `@MainActor` if it has protected mutable state.\n4. `@unchecked Sendable` only with a stated, verifiable reason.\n\nAfter the change, `xcodebuild build` (or `swift build`) and the test target must both pass under strict concurrency, and the report should name which of the four cases applied and why.",
1654
+ "outputSha256": "5e8a44902d8782f24e1a48bee5c53c3553e66f67292b44ff75f67e62b22f2348",
1655
+ "promptSha256": "1f20abd4f637b6dc3ba5b3cc44460e50f66fe88731cd1c055e4eb1ecffd12990",
1656
+ "deterministic": [],
1657
+ "judge": {
1658
+ "verdict": "pass",
1659
+ "reason": "Names root cause: mutable state accessed from task concurrently, and notes non-final/mutable stored property makes conformance fail. Fixes: actor/@MainActor with code, or immutable final class Sendable with let properties. @unchecked Sendable explicitly framed as requiring stated verifiable reason, not default. All pass criteria hold."
1660
+ },
1661
+ "passed": true
1662
+ }
1663
+ ]
1664
+ },
1665
+ {
1666
+ "id": "optional-binding-warning-no-force-unwrap",
1667
+ "kind": "behavior",
1668
+ "prompt": "The compiler flags a guard-let in my code with a warning that the value can never actually be nil at that point, and the build treats warnings as errors. How should I fix this?",
1669
+ "strictness": "high",
1670
+ "trials": 10,
1671
+ "passes": 10,
1672
+ "passRate": 1,
1673
+ "passAtK": 1,
1674
+ "grader": "judge",
1675
+ "status": "ran",
1676
+ "trialRecords": [
1677
+ {
1678
+ "output": "Fix the actual type/control-flow issue the compiler is pointing at, not the warning itself.\n\nThe compiler is telling you that at that specific `guard let`, the binding is unnecessary because the value's type (or the preceding control flow) guarantees it's non-nil. Two real possibilities:\n\n1. **The value genuinely cannot be nil there.** That usually means it shouldn't be declared `Optional` in the first place — trace back to where it's declared and where it's assigned. If nothing can leave it nil, change the declaration to a non-optional type and delete the now-dead `guard let`. That's the smallest change that addresses the root cause.\n\n2. **The value can be nil, but only before this point in the flow.** Then the optionality still matters, and the compiler is flagging the *location*: the unwrap you have is either redundant because an earlier check already narrowed it, or you're unwrapping too late/too early relative to where nil is actually possible. Move the unwrap to where the nil case is real, or remove the code path that made the value non-nil before the guard.\n\nWhat not to do: don't force-unwrap (`!`) the value to make the warning go away. The warning exists precisely because the compiler can't prove the value is non-nil; force-unwrapping doesn't establish that — it just converts a compile-time diagnostic into a potential runtime crash. And don't reach for `swiftlint:disable` / a warning suppression; the build is treating warnings as errors because the codebase wants the underlying issue fixed.\n\nVerify by rebuilding (`xcodebuild build -scheme <Scheme> -destination ...` / `swift build`) and confirm exit 0, then report the root cause in one sentence — e.g. \"`order` was declared `Optional` but every assignment site guaranteed a value; made it non-optional and removed the redundant `guard let`.\"",
1679
+ "outputSha256": "9231858ccfb840735054b30515a5a7f661d657aa18fdcdb070bfef08b36db627",
1680
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1681
+ "deterministic": [],
1682
+ "judge": {
1683
+ "verdict": "pass",
1684
+ "reason": "Answer names root cause (type declared Optional or earlier control flow guarantees non-nil, making guard-let redundant) and proposes concrete fixes: change declaration to non-optional and delete dead guard-let, or move/restructure the unwrap to where nil is real. Explicitly warns against force-unwrap (!) and suppression. All pass criteria met, no fail criteria."
1685
+ },
1686
+ "passed": true
1687
+ },
1688
+ {
1689
+ "output": "Fix the type/control-flow issue the compiler is actually pointing at — don't silence it.\n\nA \"value can never be nil here\" warning on a `guard let` almost always means the optionality itself is a lie at that point in the code. The fix is to remove the unnecessary optional-binding, not to force-unwrap or add a disable comment. Concretely, the right move depends on why the compiler knows it can't be nil:\n\n- **The property/local was declared `Optional` but is only ever assigned a non-nil value.** Change its type to non-optional (`let order: Order`, not `let order: Order?`). This is the correct fix — the `Optional` was over-broad, and every downstream `guard let`/`if let` was compensating for a type that never matched reality. If it's assigned in an initializer and never reassigned to nil, the non-optional type is provably correct.\n\n- **An earlier `guard`/`if let` already unwrapped the same value into a non-optional binding, and the code re-unwraps the original.** Use the already-binding value directly instead of re-unwrapping. This is a duplicate check, not a safety net.\n\n- **The value is a `@Published`/computed property or a return from a function the compiler can now see is non-optional** (e.g. after a refactor, or a library that changed its signature). Update the call site to treat it as non-optional.\n\n- **The optional is genuinely a \"should never happen\" state** (e.g. a storyboard/IBOutlet that is nil only on programmer error). Here do **not** force-unwrap to clear the warning. Instead either make the type non-optional with the correct initialization, or, if `Optional` is structurally required (IBOutlet), keep the binding but the warning means the type signature should change at the boundary. An `IBOutlet` is the one legitimate case where `!`-style access appears — but the Swift 6-correct form is to declare it `@IBOutlet private weak var label: UILabel!` only when the storyboard genuinely guarantees it, and that declaration is a deliberate choice, not a warning-silencer.\n\nWhat not to do:\n\n- **Never force-unwrap (`!`) to clear it.** The warning exists because the compiler can't prove non-nil under the current *type*; `!` doesn't fix the type, it moves the failure to a runtime crash.\n- **Never add `// swiftlint:disable` or a blanket `// swiftlint:disable:next`** for this — the warning is from the compiler, not SwiftLint, so a SwiftLint disable won't even apply, and if it's a SwiftLint rule (`implicitly_unwrapped_optional` or similar) a blanket disable hides future real violations in the file.\n- **Never downgrade the warning-as-error setting or add a `@available`/`#if` to route around it.** That changes build policy to hide a genuine type-modeling bug.\n\nThe one-sentence root cause you should be able to write in your report: *\"[Name] was declared `Optional` but is never assigned nil, so the `guard let` was redundant; changed the declaration to non-optional.\"* If you can't state it that concretely, you haven't found the real cause yet — the warning is telling you the optionality is wrong, not that you need to suppress a warning.\n\nAfter the change, `xcodebuild build` (with warnings-as-errors still on) and your test target must both exit 0, and no other files should be touched.",
1690
+ "outputSha256": "5e032977170c11a7fc57d346cc643687377223e8d9712750a83d5991919fb211",
1691
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1692
+ "deterministic": [],
1693
+ "judge": {
1694
+ "verdict": "pass",
1695
+ "reason": "Names root cause: optionality is a lie / type declared Optional but never nil, or earlier guard already unwrapped (control flow). Fixes declaration/control flow: change type to non-optional (let order: Order), use existing binding, update call site. Explicitly warns never force-unwrap to clear it. No fail criterion met."
1696
+ },
1697
+ "passed": true
1698
+ },
1699
+ {
1700
+ "output": "The warning is the compiler telling you the value's type says `Optional` but the control flow proves it's non-nil there — so the real fix is to correct the type or the flow, not to silence the guard.\n\nWork through it in this order:\n\n**1. Read the exact warning.** Xcode phrases this as something like \"value of optional type 'X?' must be unwrapped\" (that's an error, different) versus the case you have: `guard let x = x else { ... }` where the compiler says the binding is always succeeding / the `else` branch is unreachable. The message tells you which side is wrong — the value or the guard.\n\n**2. Ask which is actually true: can the value be nil at this point?**\n\n- **It genuinely can never be nil here** → the guard is dead code. Either the property/parameter should not be `Optional` at all (change `Foo?` to `Foo` upstream — the strongest fix, since it removes the optionality the compiler is complaining about), or the value was already unwrapped earlier in the flow and you're re-unwrapping. In that second case delete the redundant `guard let` and use the already-unwrapped binding directly.\n\n- **It can be nil in general, but the compiler can't see that it's already been proven non-nil on this path** → you usually have an earlier `guard let`/`if let` whose result you're not carrying forward. Use that earlier binding rather than re-testing. If the non-nil proof comes from an invariant the compiler genuinely can't see (e.g. a value set in `viewDidLoad` before this runs), the right fix is still to model it in the type — a force-unwrap or `!` here just moves the proof to runtime.\n\n**3. Make the smallest change that matches the true answer.** Typical outcomes:\n\n```swift\n// Before — compiler warns the else is unreachable\nfunc render(_ order: Order?) {\n guard let order = order else { return }\n ...\n}\n\n// Fix A: the value really is always present -> drop the optional upstream\nfunc render(_ order: Order) { ... }\n\n// Fix B: it was already unwrapped earlier on this path -> reuse that binding\nguard let order = order else { return }\n// ... later ...\nrender(order) // not render(orderOptional)\n```\n\n**4. What not to do.** Do not force-unwrap (`order!`) to clear the binding warning — the compiler is questioning the `Optional` itself, so `!` just converts a compile-time complaint into a potential runtime crash. Do not add `// swiftlint:disable` or a `-Wno-...`/`-suppress-warnings` flag: warnings-as-errors is a deliberate project setting and suppressing it hides the actual modeling problem.\n\n**5. Verify.** Re-run:\n\n```bash\nxcodebuild build -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\nxcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\n```\n\nand the linter if configured. Both must exit 0. If changing the type (`Foo?` → `Foo`) ripples into other call sites, that ripple is the correct scope of the fix — update those call sites rather than reintroducing the optional to keep them quiet.\n\nThe one-sentence root cause for your report is whichever of these is true: \"the parameter was declared `Optional` but is never nil on this path, so the type was wrong\" or \"the value was already unwrapped earlier and the guard was redundant.\" Pick the one that matches, fix that, and the warning goes away for the right reason.",
1701
+ "outputSha256": "6ef5b9cbfd0899b55e4c297d9a01a7e24a7f5ffa6ad718415ff6cf7582d1f84d",
1702
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1703
+ "deterministic": [],
1704
+ "judge": {
1705
+ "verdict": "pass",
1706
+ "reason": "Names root cause: type says Optional but control flow proves non-nil (step 1-2). Fixes declaration/flow: change Foo? to Foo upstream, or delete redundant guard and reuse earlier binding (Fix A/B). Explicitly warns against force-unwrap in step 4. No fail criterion met."
1707
+ },
1708
+ "passed": true
1709
+ },
1710
+ {
1711
+ "output": "The compiler is telling you the optional being bound in that `guard let` is already known non-nil at that point — so the `guard let` is dead control flow. The fix is to remove the optionality, not to suppress the warning. Trace back to where the value is produced and change its type or its declaration so it is no longer `Optional` at the source, then drop the `guard let` and use the value directly (or use it in a plain `guard`/`if` if some other condition is actually being checked).\n\nConcretely, depending on why the compiler knows it's never nil:\n\n- **It's declared `Optional` but always assigned a non-nil value**: change the declaration from `T?` to `T` at its definition site. That's the real fix; the warning is just the symptom.\n- **It was unwrapped/guaranteed earlier in the same scope**: the earlier `guard let`/`if let` already established non-nil-ness, so this second binding is redundant — remove it and reference the already-bound value.\n- **It comes from an API that the compiler now infers as non-optional** (e.g. an implicitly-unwrapped optional or a non-failable initializer result): update the call site to match the actual type rather than re-binding it.\n\nWhat not to do:\n\n- Don't add `!` (force-unwrap) to the value to make the binding \"succeed\" — that just replaces a compile-time diagnostic with a latent runtime crash path and doesn't address why the optional was there.\n- Don't add `// swiftlint:disable` or a similar suppression to clear it — since your build treats warnings as errors, suppressing the warning also hides the real type/flow issue, and a file- or rule-wide disable masks future genuine findings too.\n- Don't reach for `@unchecked Sendable` or any concurrency suppression; this is an optionality/control-flow diagnostic, not a concurrency one.\n\nAfter the change, re-run the build (`xcodebuild build` / `swift build`) with warnings-as-errors still on and confirm it exits 0 — the green build must come from the type actually being right, not from the warning being silenced. If any related test exists for that code path, run it too, since removing a binding changes the control flow the compiler was flagging.",
1712
+ "outputSha256": "ee179f6395c8240bc2cb1c2b8105878e7a024b0e9e3fdc91a7da65845d903230",
1713
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1714
+ "deterministic": [],
1715
+ "judge": {
1716
+ "verdict": "pass",
1717
+ "reason": "Names root cause: 'the optional being bound ... is already known non-nil at that point — so the guard let is dead control flow.' Fixes declaration/flow: change T? to T at definition site, remove redundant second binding, update call site to actual type. Explicitly warns against force-unwrap ('Don't add ! ... latent runtime crash path') and suppression. All pass criteria met, no fail criteria."
1718
+ },
1719
+ "passed": true
1720
+ },
1721
+ {
1722
+ "output": "Don't silence it — the compiler is telling you something real about the type or control flow, and warnings-as-errors is forcing you to deal with it instead of papering over it.\n\nWhat's happening: somewhere upstream, the compiler can prove (via optional binding, an initializer, a non-failable return, whatever) that the value you're guard-unwrapping is already non-optional by the time control reaches the `guard let`. That means the `Optional` in its declared type doesn't reflect reality at this point in the code, or the binding is simply redundant. The fix is one of these, depending on which is true:\n\n1. **The value genuinely can't be nil here.** The `guard let` is dead code. Remove it and use the value directly — if it's still typed `Optional` at that point but provably non-nil, that's a signal the upstream type is wrong, not this guard.\n\n2. **The value was never Optional to begin with.** You're unwrapping something that isn't an optional (or a local that was already unwrapped earlier in the function). Delete the redundant binding and use the value as-is.\n\n3. **The declared type is too loose.** If something upstream declared this as `Optional` when it never actually can be nil (a non-failable initializer, a lookup that always succeeds, a defaulted property), tighten the declaration upstream rather than adding or keeping a guard at the call site. Fixing the source type removes the false \"can be nil\" contract everywhere, not just here.\n\n4. **The type is right but this path has already guaranteed non-nil.** If an earlier `guard let`/`if let`/`??` already bound it, you're double-binding. Reuse that binding.\n\nConcretely, before:\n\n```swift\nguard let user = optionalUser else { return } // compiler: optionalUser is never nil here\n```\n\nAfter (if the upstream type was the real problem):\n\n```swift\nlet user = session.currentUser // change currentUser's type from User? to User\n// guard is gone; no force-unwrap, no warning\n```\n\nWhat **not** to do:\n\n- Don't force-unwrap (`user!`) to clear the warning — that trades a harmless compile-time note for a possible runtime crash, and it's exactly the suppression this skill forbids.\n- Don't add `// swiftlint:disable` or an `#pragma`-style warning suppression to the line or file. Warnings-as-errors exists precisely so this gets resolved; disabling it hides the same confusion from the next person.\n- Don't change the value's type to `Optional` in some other place just to make the guard \"make sense\" — you'd be loosening a correct type to accommodate a stale binding.\n\nAfter the change, run `xcodebuild build` (and `xcodebuild test` if the scheme runs tests during build) and confirm it exits 0, then confirm the change is the smallest one that reflects the actual nullability — usually one binding removed or one declaration tightened, nothing wider.",
1723
+ "outputSha256": "f448a2af20f8a8d2d4138d87251346d9067d5764169fd8bf276e8752bab7c3bc",
1724
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1725
+ "deterministic": [],
1726
+ "judge": {
1727
+ "verdict": "pass",
1728
+ "reason": "Answer names root cause (compiler proves value non-optional via upstream binding/initializer/non-failable return, so Optional type doesn't reflect reality), proposes fixing declaration/control flow (tighten upstream type User? to User, remove redundant guard, reuse earlier binding), and explicitly warns against force-unwrap and suppression. Concrete before/after code shown."
1729
+ },
1730
+ "passed": true
1731
+ },
1732
+ {
1733
+ "output": "Fix the type, not the guard. A `guard let` the compiler says can never fail means the optional-ness it is checking against is wrong somewhere upstream — the value's declared type says \"can be nil here\" but the actual control flow guarantees it is not.\n\n**What to do, in order of preference:**\n\n1. **Find where the optional comes from and stop it being optional.**\n If the value is produced by an earlier step that already guarantees non-nil (a successful `guard`, a non-failable initializer, a dictionary lookup you have already confirmed), propagate that non-optional type forward instead of re-asserting it. The cleanest fix is usually changing the upstream declaration or the earlier binding so the type never becomes `Optional` in the first place.\n\n2. **If the optional is genuinely real at the boundary but provably non-nil at this point**, the guard is redundant — delete it and use the value directly. But only do this if you can point to the exact earlier check that guarantees it. If you cannot point to it, you have not actually proven non-nil; you have only observed it, which is the thing the compiler is warning about.\n\n3. **If the optional can be nil on some path the compiler is not seeing** (e.g. it is narrowed by an assumption no code enforces), keep the binding and fix the assumption — make the guarantee explicit upstream so the warning goes away because the proof is real, not because the check was removed.\n\n**What not to do:**\n\n- Do not add `!` or `try!` to clear it. That converts a compile-time warning into a runtime crash on the path where your assumption is wrong — which is exactly the path the warning is telling you to think about.\n- Do not delete the guard while leaving the value `Optional` and relying on implicit unwrapping elsewhere; you have moved the same unproven assumption and hidden it.\n- Do not reach for a targeted `// swiftlint:disable` or a warning-suppression flag. The build treats warnings as errors for a reason; the warning is the signal, not the obstacle.\n\n**Verify before reporting done:** rebuild (`xcodebuild build` / `swift build`) and confirm it exits 0 with the warning gone as a *consequence* of the type change, not suppressed. Then re-run tests. If the value really could be nil on some path, your change should still compile *and* the nil path should now be impossible by construction — if you cannot describe why nil is now structurally impossible, you have suppressed the warning rather than fixed it.\n\nState the root cause in one sentence when you report: e.g. \"`userID` was declared `String?` but is assigned from a non-failable initializer, so the later `guard let` was checking a guarantee that already held — changed the property to `String`.\"",
1734
+ "outputSha256": "37276d0b2b14131754d95eb91445fae99deb105d775d1bcdd3780795275679db",
1735
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1736
+ "deterministic": [],
1737
+ "judge": {
1738
+ "verdict": "pass",
1739
+ "reason": "Names root cause: optional-ness is wrong upstream, type says can-be-nil but control flow guarantees non-nil. Fixes declaration/control flow: change upstream declaration to non-optional, delete redundant guard, make guarantee explicit. Explicitly warns against `!`/`try!` and suppression. Concrete example given (userID String? -> String)."
1740
+ },
1741
+ "passed": true
1742
+ },
1743
+ {
1744
+ "output": "Fix the actual type/control-flow issue the compiler is pointing at — never force-unwrap to silence it.\n\nThe warning means the compiler has proven the value is non-`Optional` (or provably non-nil) at that point, so the `guard let` / `if let` binding is dead code that can never take the `else` branch. There are two legitimate root causes, and you need to pick the right one by looking at where the value is declared:\n\n**Case 1 — the value should genuinely never be nil.** It was declared `Optional` somewhere upstream (a property, a return type, a parameter) when it doesn't need to be. Fix it at the declaration:\n- Remove the `?` from the property/parameter/return type.\n- Then delete the now-redundant `guard let` and use the value directly (`guard let x = y else { return }` becomes just using `y`).\n- Do this only if nothing in the codebase ever assigns `nil` to it.\n\n**Case 2 — the value can be nil, but the guard is in the wrong place or checking the wrong thing.** For example, you're re-checking a value that an earlier `guard` in the same scope already unwrapped, or checking a value the type system already narrowed. In that case the fix is to delete the redundant `guard let` and use the already-unwrapped binding, or move the unwrap up to where the value first enters scope.\n\nSketch of the typical fix (Case 1):\n\n```swift\n// Before — `order` is declared `Order?` but is always assigned a real value\nfunc process() {\n guard let order = self.order else { return } // warning: always succeeds\n ship(order)\n}\n\n// After — drop the optionality at the declaration, drop the redundant guard\nfunc process() {\n ship(self.order)\n}\n```\n\nDo not:\n- Write `order!` to make the warning go away — that just relocates a compile-time guarantee to a potential runtime crash.\n- Write `try!` / `as!` for the same reason.\n- Wrap the line in `// swiftlint:disable` or a blanket `@available`-style suppression to clear the warning instead of fixing the type.\n\nOne caveat: if the warning is a *Swift 6 strict-concurrency* diagnostic dressed up as an optional-binding complaint (e.g., the value crosses an isolation boundary and the compiler can't prove lifetime), the fix is isolation (`@MainActor`, `actor`) or a proper `Sendable` conformance — not a type change. Read the exact diagnostic text before choosing which of the two cases you're in.\n\nAfter the fix, confirm both `xcodebuild build` and `xcodebuild test` exit 0 with warnings-as-errors still enabled (do not turn that setting off to make the build pass), and state the root cause in one sentence in your report — e.g. \"`order` was declared `Order?` but never assigned nil; removed the optional and the redundant guard.\"",
1745
+ "outputSha256": "b3f1ab6f15546cc77fa713b1e2ffefd0f1f615ac19a7c4184819e6cc3d164dc6",
1746
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1747
+ "deterministic": [],
1748
+ "judge": {
1749
+ "verdict": "pass",
1750
+ "reason": "Answer names root cause (compiler proved value non-Optional/provably non-nil, so guard-let is dead code) and gives two cases. Case 1 concretely fixes declaration: remove `?` from property/parameter/return type, delete redundant guard, with before/after code. Case 2 restructures control flow. Explicitly warns against `order!`, `try!`, `as!`, and lint suppression. All pass criteria met; no fail criterion."
1751
+ },
1752
+ "passed": true
1753
+ },
1754
+ {
1755
+ "output": "The fix depends on *why* the compiler believes the value can never be nil — but in every case you fix the actual type/control-flow issue, you don't silence the warning.\n\n**Determine the real cause first:**\n\nThe compiler infers a value is never-nil at a point in one of these ways, and each has a different correct fix:\n\n1. **The value is genuinely non-optional by that point.** A previous `guard let`/`if let` already unwrapped it, or it was declared non-optional to begin with, so your second optional binding is redundant. Fix: remove the redundant `guard let` and use the value directly — it's already unwrapped in this scope.\n\n2. **The value was declared `Optional` but can never actually be nil.** This is the common one. The property/parameter should not be `Optional` at all. Fix: change the declaration from `T?` to `T` (and update its initializer/call sites accordingly). That removes the need for the binding entirely and is the honest fix.\n\n3. **The optional-binding pattern is on a type that is `Optional` only nominally** (e.g. an implicitly-unwrapped optional, or a value the compiler has refined through control flow). Fix: express the type honestly rather than binding against a nil that can't happen.\n\n**What the fix looks like in the common case:**\n\n```swift\n// Before: cache is declared Optional but is never actually nil after init\nprivate var cache: [String: Data]?\n\nfunc lookup(_ key: String) -> Data? {\n guard let cache = cache else { return nil } // ⚠️ always succeeds\n return cache[key]\n}\n\n// After: declare it non-optional — the binding was the symptom, not the bug\nprivate var cache: [String: Data] = [:]\n\nfunc lookup(_ key: String) -> Data? {\n cache[key]\n}\n```\n\nIf instead the value legitimately *can* be nil and the compiler is wrong to complain, that itself signals the declaration is wrong somewhere upstream (the value probably should be non-optional by the time it reaches this point) — trace back and fix the declaration rather than suppressing the warning.\n\n**What you must NOT do:**\n\n- Do not force-unwrap (`cache!`) to clear it. The warning says the compiler cannot prove non-nil; `!` doesn't fix that, it just defers a potential crash to runtime.\n- Do not add `// swiftlint:disable` or otherwise suppress the diagnostic to get past `-warnings-as-errors`. The warning is pointing at a real declaration/flow mismatch.\n- Do not wrap the surrounding code in a blanket `#pragma`/disable to hide it.\n\n**Verify:**\n\n```bash\nxcodebuild build -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\nxcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\n```\n\nBoth must exit 0 with warnings-as-errors still enabled — that's the point: you fixed the cause, you didn't turn off the check.\n\n**Report** the root cause in one sentence, e.g.: \"The `cache` property was declared `[String: Data]?` but is initialized at construction and never reassigned to nil; made it non-optional and removed the redundant `guard let`, which eliminated the always-succeeding binding.\"",
1756
+ "outputSha256": "101c66afd509d3b4ec0297041d41400597cdf4c404a857bb58406bd6b84b9105",
1757
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1758
+ "deterministic": [],
1759
+ "judge": {
1760
+ "verdict": "pass",
1761
+ "reason": "Names root cause (value already unwrapped by earlier guard-let, or declared Optional but never nil, or nominally optional) and fixes declaration/flow: changes `[String: Data]?` to `[String: Data] = [:]` and removes redundant guard-let. Explicitly warns against force-unwrap (`cache!`) and suppression. All pass criteria met, no fail criterion."
1762
+ },
1763
+ "passed": true
1764
+ },
1765
+ {
1766
+ "output": "Fix the underlying type/control-flow issue the compiler is pointing at — do not silence the warning.\n\nThe warning means the compiler has proven (via the value's declared type, an earlier check, or the API's signature) that the optional can't be nil by that point. A `guard let` there is dead code from the compiler's perspective. The right fix depends on *why* the compiler believes that:\n\n- **The value's type is needlessly `Optional`.** If the API or property genuinely never returns nil, the `Optional` in its declaration is the bug. Change the type to non-optional at the source (the property/return type), then delete the now-pointless `guard let` and use the value directly. This fixes the root cause for every call site, not just this one.\n- **An earlier check already unwrapped it.** If a preceding `guard let`/`if let`/`!= nil` check already established non-nilness, the second binding is redundant — remove it and use the already-unwrapped value.\n- **The compiler is inferring non-nil from surrounding control flow.** Trace the flow; if the value truly cannot be nil on this path, the binding is unnecessary and the value can be referenced directly. If it genuinely *can* be nil but only on a path the compiler can't see yet, fix the control flow so the possibility is real and visible (move the binding to where nil is actually possible), rather than papering over it.\n\nWhat not to do:\n\n- **Don't force-unwrap (`!`)** to make the warning go away. That doesn't address why the compiler flagged it and converts a compile-time signal into a potential runtime crash.\n- **Don't add `// swiftlint:disable` or any suppression** for this. Warnings-as-errors is the project's configured contract; the fix belongs in the code, not in disabling the check.\n\nAfter the change, verify the whole thing, not just this warning:\n\n```bash\nxcodebuild build -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\nxcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=<Simulator>'\n```\n\nBoth must exit 0 (and the project's linter/formatter if configured), with no new warnings introduced elsewhere. Report the root cause in one sentence — e.g. \"Fixed: `Order.id` was declared `String?` but the API never returns nil; made it non-optional and removed the redundant guard-let\" — not just \"warning cleared.\"",
1767
+ "outputSha256": "55e3e1f8560fcd2cea986d2e62f81b3db046533a2fbe163d86e377e892e2e775",
1768
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1769
+ "deterministic": [],
1770
+ "judge": {
1771
+ "verdict": "pass",
1772
+ "reason": "Answer names root cause (type declared Optional, earlier check, or control-flow inference) and fixes declaration/flow: change type to non-optional at source, remove redundant binding, or restructure. Explicitly warns against force-unwrap (!) and suppression. All pass criteria met; no fail criterion holds."
1773
+ },
1774
+ "passed": true
1775
+ },
1776
+ {
1777
+ "output": "Fix the type, not the guard. The warning means the compiler has proven the value is non-optional by the time control reaches that `guard let` — so the guard is dead code testing a condition that can't be false.\n\nFind why the value is non-optional:\n\n- If the declaration is `Optional` but the value is actually assigned/derived from something non-nil on every path, the declaration is the bug — change it to non-optional and delete the `guard`.\n- If a function's return type is `Optional` but every return site returns a real value, fix the signature to non-optional and drop the guard at the call site.\n- If the optionality is coming from a force-unwrap or an earlier `guard let` that already unwrapped it, you're re-testing an already-unwrapped value — remove the redundant guard and use the bound name directly.\n\nWhat not to do: force-unwrap (`!`) to silence it, or add `// swiftlint:disable` for it. Neither addresses the mismatch between the declared type and the compiler's proof — they just hide it, and a force-unwrap turns a compile-time warning into a potential runtime crash if the type ever changes back.\n\nThen verify: `xcodebuild build`/`swift build` (with warnings-as-errors) and `xcodebuild test` must both exit 0, and if the project has a linter configured, that too. Report the root cause in one sentence — e.g. \"`fetchOrder` returned `Order?` but every path returns a value; changed the signature to `Order` and removed the now-dead guard.\"",
1778
+ "outputSha256": "caf0e5b049d15559493a4effc485ee550815e961ce4b2264d585a79e83863f2f",
1779
+ "promptSha256": "c310cc98590785c5a884e46d3e96e9b1744be47a5490c737c571bf09ba000abe",
1780
+ "deterministic": [],
1781
+ "judge": {
1782
+ "verdict": "pass",
1783
+ "reason": "Names root cause: compiler proved value non-optional, guard is dead code. Fixes declaration/control flow: change Optional declaration to non-optional and delete guard; fix function signature; remove redundant guard after earlier unwrap. Explicitly warns against force-unwrap (!) as silencing. All pass criteria met, no fail criteria."
1784
+ },
1785
+ "passed": true
1786
+ }
1787
+ ]
1788
+ }
1789
+ ],
1790
+ "verdict": "fail",
1791
+ "scope": "bundled",
1792
+ "skillDigest": "b06da79489fbaf955b5245da2f328a0c41af3ea5f4fbe33aedb435607fc22b50",
1793
+ "catalogDigest": "97f9af01aafac82ae21a63c6af2a2f24fcfe067dc32a7cfdcde9a69a91fa9aae",
1794
+ "judgePromptVersion": "2026-09-25.1",
1795
+ "runner": "deepseek",
1796
+ "model": "deepseek-chat",
1797
+ "runnerPromptVersion": "2026-09-25.1",
1798
+ "recordedAt": "2026-09-25T18:26:02.817Z",
1799
+ "judge": "deepseek",
1800
+ "judgeModel": "deepseek-chat"
1801
+ }
1802
+ ]
1803
+ }