@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0

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 (326) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +328 -329
  5. package/package.json +2 -2
  6. package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
  7. package/pipeline/scripts/_notices.mjs +12 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +1 -1
  9. package/pipeline/skills/.skill-manifest.json +106 -106
  10. package/pipeline/skills/shared/README.md +71 -71
  11. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
  16. package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
  17. package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
  18. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  19. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  20. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  21. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  22. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  23. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  24. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  25. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  26. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  27. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  28. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  29. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  30. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  31. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  32. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  33. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  34. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  35. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  37. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  38. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  39. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  40. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  41. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  42. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  43. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  44. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  45. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  46. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  47. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  48. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  49. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  50. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  51. package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
  52. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  53. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  54. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  55. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
  56. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  57. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  58. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  59. package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
  60. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
  61. package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
  62. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  63. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  64. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  65. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  66. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  67. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  68. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  69. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  70. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  71. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  72. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  73. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  74. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  75. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  76. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  77. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  78. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  79. package/pipeline/skills/shared/external/council/SKILL.md +1 -0
  80. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  81. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  82. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  83. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
  84. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
  85. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  86. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  87. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  88. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  89. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  90. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  91. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  92. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  93. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  94. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  95. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  96. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  97. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  98. package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
  99. package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
  100. package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
  101. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  102. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  103. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  104. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  105. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  106. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  107. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
  108. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
  109. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  110. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  111. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  112. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  113. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  114. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
  115. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  116. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  117. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  118. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  119. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
  120. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  121. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  122. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  123. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  124. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  125. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  126. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  127. package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
  128. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  129. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  130. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  131. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  132. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  133. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  134. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
  135. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
  136. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
  137. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
  138. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
  139. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
  140. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
  141. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
  142. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
  143. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
  144. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
  145. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
  146. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
  147. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
  148. package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
  149. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
  150. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  151. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  152. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  153. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  154. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  155. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  156. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  157. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  158. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  159. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  160. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  161. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  162. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  163. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
  164. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  165. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  166. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  167. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  168. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  169. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  170. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  171. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  172. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  173. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  174. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  175. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  176. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  177. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  178. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  179. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  180. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  181. package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  183. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  184. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  185. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  186. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
  187. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
  188. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  189. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  190. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  191. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
  192. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
  193. package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
  194. package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
  195. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  196. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  197. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  198. package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
  199. package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
  200. package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
  201. package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
  202. package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
  203. package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
  204. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
  205. package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
  206. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  207. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  208. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  209. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  210. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  211. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  212. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  213. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  214. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  215. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  216. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  217. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  218. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  219. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  220. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  221. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  222. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  223. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  224. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  225. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  226. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  227. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  228. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  229. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  230. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  231. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  232. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  233. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  234. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  235. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  236. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  237. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  238. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  239. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  240. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  241. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  242. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  243. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  244. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  245. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  246. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  247. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  248. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  249. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  250. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  251. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  252. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  253. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  254. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  255. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  256. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  257. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  258. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  259. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  260. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  261. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  262. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  263. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  264. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  265. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  266. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  267. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  268. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  269. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  270. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  271. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  272. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  273. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  274. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  275. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  276. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  277. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  278. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  279. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  280. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  281. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  282. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  283. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  284. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  285. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  286. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  287. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  288. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  289. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  290. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  291. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  292. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  293. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  294. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  295. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  296. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  297. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  298. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  299. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  300. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  301. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  302. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  303. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  304. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  305. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  306. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  307. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  308. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  309. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  310. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
  311. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
  312. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  313. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  314. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
  315. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  316. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  317. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  318. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
  319. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  320. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  321. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
  322. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
  323. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
  324. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  325. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  326. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,398 +1,452 @@
1
- # Accessibility Patterns Reference
1
+ # Accessibility Code Patterns
2
+
3
+ Back to [SKILL.md](../SKILL.md).
2
4
 
3
5
  ## Contents
4
- - Labels, Values, and Hints
5
- - Traits and Element Grouping
6
- - Custom Controls and Adjustable Actions
7
- - Focus Management Patterns
8
- - Dynamic Type and Layout
9
- - Custom Rotors
10
- - System Accessibility Preferences
11
- - UIKit Accessibility Patterns
12
- - AppKit Accessibility Patterns
13
- - Common Mistakes Checklist
14
- - Voice Control Patterns
15
- - Switch Control Patterns
16
- - Full Keyboard Access Patterns
17
- - Automated Accessibility Testing
18
-
19
- ## Labels, Values, and Hints
6
+
7
+ - [Labels, values, hints](#labels-values-hints)
8
+ - [Traits and grouping](#traits-and-grouping)
9
+ - [Custom and adjustable controls](#custom-and-adjustable-controls)
10
+ - [Focus patterns](#focus-patterns)
11
+ - [Dynamic Type and layout](#dynamic-type-and-layout)
12
+ - [Custom rotors](#custom-rotors)
13
+ - [System preference values](#system-preference-values)
14
+ - [UIKit](#uikit)
15
+ - [AppKit](#appkit)
16
+ - [Mistakes to catch in review](#mistakes-to-catch-in-review)
17
+ - [Voice Control](#voice-control)
18
+ - [Switch Control](#switch-control)
19
+ - [Full Keyboard Access](#full-keyboard-access)
20
+ - [Automated checks with XCTest](#automated-checks-with-xctest)
21
+
22
+ ## Labels, values, hints
20
23
 
21
24
  ```swift
22
- Button(action: { }) {
23
- Image(systemName: "heart.fill")
25
+ // Icon-only button: the label is what VoiceOver and Voice Control use.
26
+ Button { bookmark(article) } label: {
27
+ Image(systemName: article.isSaved ? "bookmark.fill" : "bookmark")
24
28
  }
25
- .accessibilityLabel("Favorite")
29
+ .accessibilityLabel("Bookmark")
26
30
 
27
- Slider(value: $volume, in: 0...100)
28
- .accessibilityValue("\(Int(volume)) percent")
31
+ // Value: speak the number people care about, not the raw slider position.
32
+ Slider(value: $brightness) // 0.0 ... 1.0
33
+ .accessibilityLabel("Brightness")
34
+ .accessibilityValue("\(Int(brightness * 100)) percent")
29
35
 
30
- Button("Submit")
31
- .accessibilityHint("Submits the form and sends your feedback")
36
+ // Hint: what happens when activated, read last and only after a pause.
37
+ Button("Archive", action: archiveThread)
38
+ .accessibilityHint("Moves this conversation out of the inbox")
32
39
  ```
33
40
 
34
- ## Traits and Element Grouping
41
+ ## Traits and grouping
42
+
43
+ `.accessibilityAddTraits` adds to the element's existing traits rather than
44
+ replacing them:
35
45
 
36
46
  ```swift
37
- // Add traits without overwriting defaults
38
- Button("Go") { }
47
+ Text(departureCountdown)
39
48
  .accessibilityAddTraits(.updatesFrequently)
49
+ ```
50
+
51
+ Merge a row so it is one stop instead of three:
40
52
 
41
- // Group children into a single accessibility element
53
+ ```swift
42
54
  HStack {
43
- Image(systemName: "person.circle")
44
- VStack {
45
- Text("John Doe")
46
- Text("Engineer")
55
+ Image(driver.photoName)
56
+ VStack(alignment: .leading) {
57
+ Text(driver.name)
58
+ Text(driver.vehicle)
47
59
  }
48
60
  }
49
61
  .accessibilityElement(children: .combine)
62
+ ```
50
63
 
51
- // Binary custom control: prefer Toggle when possible; otherwise expose toggle state
52
- HStack {
53
- Image(systemName: isFavorite ? "heart.fill" : "heart")
54
- Text(product.name)
64
+ ### Two-state custom control
65
+
66
+ First choice is a real `Toggle`. When the design forces a custom view, expose
67
+ it as a toggle yourself:
68
+
69
+ ```swift
70
+ struct PinChip: View {
71
+ let noteTitle: String
72
+ @Binding var isPinned: Bool
73
+
74
+ var body: some View {
75
+ HStack(spacing: 6) {
76
+ Image(systemName: isPinned ? "pin.fill" : "pin")
77
+ Text(noteTitle)
78
+ }
79
+ .onTapGesture { isPinned.toggle() }
80
+ .accessibilityElement()
81
+ .accessibilityLabel("Pin \(noteTitle)")
82
+ .accessibilityValue(isPinned ? "On" : "Off")
83
+ .accessibilityAddTraits(.isToggle) // iOS 17+
84
+ .accessibilityAction { isPinned.toggle() } // default activate action
85
+ }
55
86
  }
56
- .onTapGesture { isFavorite.toggle() }
57
- .accessibilityElement()
58
- .accessibilityLabel("Favorite \(product.name)")
59
- .accessibilityValue(isFavorite ? "On" : "Off")
60
- .accessibilityAddTraits(.isToggle)
61
- .accessibilityAction { isFavorite.toggle() }
62
87
  ```
63
88
 
64
- ## Custom Controls and Adjustable Actions
89
+ ## Custom and adjustable controls
90
+
91
+ For quantities, steppers, ratings, sliders and any other adjustable value,
92
+ start from the native control (`Stepper`, `Slider`, `Picker`). Only a truly
93
+ custom control needs the work below: in SwiftUI
94
+ `.accessibilityAdjustableAction`, in UIKit
95
+ `accessibilityTraits.insert(.adjustable)` plus `accessibilityIncrement()` /
96
+ `accessibilityDecrement()`.
65
97
 
66
98
  ```swift
67
- HStack { /* custom star rating UI */ }
68
- .accessibilityElement()
69
- .accessibilityLabel("Rating")
70
- .accessibilityValue("\(rating) out of 5 stars")
71
- .accessibilityAdjustableAction { direction in
72
- switch direction {
73
- case .increment: if rating < 5 { rating += 1 }
74
- case .decrement: if rating > 1 { rating -= 1 }
75
- @unknown default: break
99
+ struct SpiceLevelPicker: View {
100
+ @Binding var level: Int // 1...4
101
+ private let range = 1...4
102
+
103
+ var body: some View {
104
+ HStack {
105
+ ForEach(range, id: \.self) { value in
106
+ Image(systemName: value <= level ? "flame.fill" : "flame")
107
+ .onTapGesture { level = value }
108
+ }
109
+ }
110
+ .accessibilityElement()
111
+ .accessibilityLabel("Spice level")
112
+ .accessibilityValue("\(level) of \(range.upperBound)")
113
+ .accessibilityAdjustableAction { change in
114
+ switch change {
115
+ case .increment: level = min(level + 1, range.upperBound)
116
+ case .decrement: level = max(level - 1, range.lowerBound)
117
+ @unknown default: break
118
+ }
76
119
  }
77
120
  }
121
+ }
78
122
  ```
79
123
 
80
- For custom quantity controls, steppers, ratings, sliders, or other adjustable values, prefer the native control first. If the control is custom, SwiftUI needs `.accessibilityAdjustableAction`; UIKit custom controls also need `accessibilityTraits.insert(.adjustable)`.
124
+ ## Focus patterns
81
125
 
82
- ## Focus Management Patterns
126
+ Returning focus after a sheet, with a `Bool`:
83
127
 
84
128
  ```swift
85
- @AccessibilityFocusState private var focusOnTrigger: Bool
86
-
87
- Button("Open Settings") { showSheet = true }
88
- .accessibilityFocused($focusOnTrigger)
89
- .sheet(isPresented: $showSheet) {
90
- SettingsSheet()
91
- .onDisappear {
92
- Task { @MainActor in
93
- try? await Task.sleep(for: .milliseconds(100))
94
- focusOnTrigger = true
95
- }
129
+ struct InvoiceHeader: View {
130
+ @State private var editing = false
131
+ @AccessibilityFocusState private var editButtonFocused: Bool
132
+
133
+ var body: some View {
134
+ Button("Edit invoice", systemImage: "pencil") { editing = true }
135
+ .accessibilityFocused($editButtonFocused)
136
+ .sheet(isPresented: $editing) {
137
+ InvoiceEditor()
138
+ .onDisappear {
139
+ Task { @MainActor in
140
+ try? await Task.sleep(nanoseconds: 100_000_000)
141
+ editButtonFocused = true
142
+ }
143
+ }
96
144
  }
97
145
  }
146
+ }
98
147
  ```
99
148
 
149
+ Several targets, with an optional enum:
150
+
100
151
  ```swift
101
- enum A11yFocus: Hashable { case nameField, emailField, submitButton }
102
- @AccessibilityFocusState private var focus: A11yFocus?
152
+ enum AddressFocus: Hashable { case street, city, postcode }
153
+
154
+ @AccessibilityFocusState private var addressFocus: AddressFocus?
155
+ // TextField("Street", text: $street).accessibilityFocused($addressFocus, equals: .street)
156
+ // On a bad postcode: addressFocus = .postcode
103
157
  ```
104
158
 
105
- ## Dynamic Type and Layout
159
+ ## Dynamic Type and layout
106
160
 
107
161
  ```swift
108
- @ScaledMetric(relativeTo: .title) private var iconSize: CGFloat = 24
109
- @ScaledMetric(relativeTo: .body) private var rowSpacing: CGFloat = 12
110
- @ScaledMetric(relativeTo: .body) private var controlHeight: CGFloat = 44
111
- @Environment(\.dynamicTypeSize) var dynamicTypeSize
112
-
113
- var body: some View {
114
- Group {
115
- if dynamicTypeSize.isAccessibilitySize {
116
- VStack(alignment: .leading) { icon; textContent }
117
- } else {
118
- HStack { icon; textContent }
162
+ struct TransferRow: View {
163
+ @Environment(\.dynamicTypeSize) private var typeSize
164
+ @ScaledMetric(relativeTo: .body) private var rowHeight: CGFloat = 44
165
+ @ScaledMetric(relativeTo: .body) private var gap: CGFloat = 12
166
+ @ScaledMetric(relativeTo: .title) private var glyphSize: CGFloat = 24
167
+
168
+ let transfer: Transfer
169
+
170
+ var body: some View {
171
+ let layout = typeSize.isAccessibilitySize
172
+ ? AnyLayout(VStackLayout(alignment: .leading, spacing: gap))
173
+ : AnyLayout(HStackLayout(spacing: gap))
174
+
175
+ layout {
176
+ Image(systemName: "arrow.up.arrow.down")
177
+ .font(.system(size: glyphSize))
178
+ Text(transfer.counterparty).font(.body)
179
+ Text(transfer.amountText).font(.headline)
119
180
  }
181
+ .frame(minHeight: rowHeight)
120
182
  }
121
- .frame(minHeight: controlHeight)
122
183
  }
123
184
  ```
124
185
 
125
- Use `@ScaledMetric(relativeTo:)` for non-text dimensions that need to track text size, including icon sizes, spacing, control heights, and custom hit-region dimensions.
186
+ - `@ScaledMetric(relativeTo:)` is for custom hit regions, control heights,
187
+ spacing and glyph sizes that should keep pace with the text.
188
+ - `dynamicTypeSize.isAccessibilitySize` is the usual switch point from a
189
+ horizontal row to a leading-aligned vertical stack.
126
190
 
127
- ## Custom Rotors
191
+ ## Custom rotors
128
192
 
129
193
  ```swift
130
- List(items) { item in ItemRow(item: item) }
131
- .accessibilityRotor("Unread") {
132
- ForEach(items.filter { !$0.isRead }) { item in
133
- AccessibilityRotorEntry(item.title, id: item.id)
134
- }
194
+ List(inbox) { item in
195
+ MessageRow(message: item)
196
+ }
197
+ .accessibilityRotor("Flagged") {
198
+ ForEach(inbox.filter(\.isFlagged)) { item in
199
+ AccessibilityRotorEntry(item.subject, id: item.id)
135
200
  }
201
+ }
136
202
  ```
137
203
 
138
- ## System Accessibility Preferences
204
+ ## System preference values
139
205
 
140
- ```swift
141
- @Environment(\.accessibilityReduceMotion) var reduceMotion
142
- @Environment(\.accessibilityReduceTransparency) var reduceTransparency
143
- @Environment(\.colorSchemeContrast) var contrast
144
- @Environment(\.legibilityWeight) var legibilityWeight
145
- ```
206
+ The four environment values to read are `\.accessibilityReduceMotion`,
207
+ `\.accessibilityReduceTransparency`, `\.colorSchemeContrast` and
208
+ `\.legibilityWeight`. Usage is in [SKILL.md](../SKILL.md#system-preferences).
146
209
 
147
- ## UIKit Accessibility Patterns
210
+ ## UIKit
148
211
 
149
212
  ```swift
150
- customButton.accessibilityTraits.insert(.button)
151
- customButton.accessibilityTraits.remove(.staticText)
213
+ final class StatusPill: UIView {
214
+ func configureAccessibility(title: String) {
215
+ isAccessibilityElement = true
216
+ accessibilityLabel = title
217
+ accessibilityTraits.insert(.button)
218
+ accessibilityTraits.remove(.staticText)
219
+ }
220
+ }
152
221
 
153
- UIAccessibility.post(notification: .announcement, argument: "Upload complete")
154
- UIAccessibility.post(notification: .layoutChanged, argument: targetView)
155
- UIAccessibility.post(notification: .screenChanged, argument: newScreenView)
222
+ // Status, partial update, full screen change:
223
+ UIAccessibility.post(notification: .announcement, argument: "3 files uploaded")
224
+ UIAccessibility.post(notification: .layoutChanged, argument: resultsTable)
225
+ UIAccessibility.post(notification: .screenChanged, argument: onboardingTitle)
156
226
  ```
157
227
 
158
- ## AppKit Accessibility Patterns
228
+ ## AppKit
159
229
 
160
- AppKit accessibility centers on `NSAccessibilityProtocol`. Use standard AppKit controls when possible, then override or add accessibility behavior only where the default metadata is wrong or incomplete.
230
+ Everything flows through `NSAccessibilityProtocol`. Customize only the pieces
231
+ AppKit gets wrong or leaves out.
161
232
 
162
- ### Custom NSView with role, label, value, and action
233
+ ### Custom view: role, label, value, action
163
234
 
164
235
  ```swift
165
- final class FavoriteToggleView: NSView {
166
- var isFavorite = false {
236
+ final class LockToggleView: NSView {
237
+ private(set) var isLocked = false {
167
238
  didSet {
168
239
  NSAccessibility.post(element: self, notification: .valueChanged)
240
+ needsDisplay = true
169
241
  }
170
242
  }
171
243
 
244
+ override func accessibilityLabel() -> String? { "Lock layer" }
245
+ override func accessibilityValue() -> Any? { isLocked ? "Locked" : "Unlocked" }
172
246
  override func isAccessibilityElement() -> Bool { true }
173
- override func accessibilityRole() -> NSAccessibility.Role? { .button }
174
- override func accessibilityLabel() -> String? { "Favorite" }
175
- override func accessibilityValue() -> Any? { isFavorite ? "On" : "Off" }
176
-
177
247
  override func accessibilityPerformPress() -> Bool {
178
- isFavorite.toggle()
248
+ isLocked.toggle()
179
249
  return true
180
250
  }
251
+ override func accessibilityRole() -> NSAccessibility.Role? { .button }
181
252
  }
182
253
  ```
183
254
 
184
- ### NSAccessibilityElement for non-view items
255
+ ### Elements with no view
185
256
 
186
- Use `NSAccessibilityElement` when an accessible item has no backing `NSView`, such as a virtual data point in a chart or a drawn annotation.
257
+ For things that are drawn rather than backed by an `NSView`, such as one bar
258
+ in a chart or an annotation painted on a canvas, create an
259
+ `NSAccessibilityElement`:
187
260
 
188
261
  ```swift
189
- let pointElement = NSAccessibilityElement.element(
262
+ let barElement = NSAccessibilityElement.element(
190
263
  withRole: .button,
191
- frame: pointFrame,
192
- label: "March revenue",
264
+ frame: barFrameInScreenCoordinates,
265
+ label: "March revenue, 42 thousand",
193
266
  parent: chartView
194
267
  )
195
268
  ```
196
269
 
197
- ### AppKit announcements and notifications
270
+ ### Notifications
198
271
 
199
272
  ```swift
200
- NSAccessibility.post(element: saveStatusLabel, notification: .valueChanged)
273
+ // The accessible value changed.
274
+ NSAccessibility.post(element: sliderView, notification: .valueChanged)
201
275
 
276
+ // A passing status message.
202
277
  NSAccessibility.post(
203
- element: self,
278
+ element: exportPanelView,
204
279
  notification: .announcementRequested,
205
- userInfo: [
206
- .announcement: "Export complete"
207
- ]
280
+ userInfo: [.announcement: "Backup finished"]
208
281
  )
209
282
  ```
210
283
 
211
- Use `.announcementRequested` when assistive apps need to announce transient status. Use state-specific notifications such as `.valueChanged` when the accessible value changed.
212
-
213
- ## Common Mistakes Checklist
214
-
215
- - Direct trait assignment instead of `.accessibilityAddTraits`
216
- - Missing focus restoration after dismissing sheets
217
- - Ungrouped list rows creating excessive swipe stops
218
- - Icon-only buttons missing labels
219
- - Ignoring Reduce Motion, Reduce Transparency, or Increase Contrast
220
- - Fixed font sizes that break Dynamic Type
221
- - Tap targets smaller than 44x44 points
284
+ Pick `.announcementRequested` for transient status and the specific
285
+ notification (such as `.valueChanged`) when the element's accessible value
286
+ actually changed.
222
287
 
223
- ## Voice Control Patterns
288
+ ## Mistakes to catch in review
224
289
 
225
- Voice Control generates tap targets from accessibility labels. Labels must be speakable and unique within the visible screen.
290
+ - Tap targets below 44x44 pt.
291
+ - Traits assigned directly instead of through `.accessibilityAddTraits`.
292
+ - Hard-coded font sizes, so Dynamic Type has no effect.
293
+ - Focus not restored after a sheet closes.
294
+ - Icon-only buttons with no label.
295
+ - Increase Contrast, Reduce Transparency or Reduce Motion settings ignored.
296
+ - List rows left ungrouped, each producing several swipe stops.
226
297
 
227
- ### accessibilityInputLabels (iOS 14+)
298
+ ## Voice Control
228
299
 
229
- Provide shorter spoken alternatives when the primary label is long, awkward, repeated, localized, acronym-heavy, or commonly shortened in speech:
300
+ Voice Control builds its tap targets from accessibility labels, so every label
301
+ must be something a person can say, and unique among what is visible.
302
+ `accessibilityInputLabels` (iOS 14+) supplies shorter spoken alternatives when
303
+ the main label is long, clumsy, repeated, localized, acronym-heavy, or
304
+ normally shortened in speech.
230
305
 
231
306
  ```swift
232
- // Primary label is descriptive but long to speak
233
- Button(action: { startWorkout() }) {
234
- VStack {
235
- Image(systemName: "figure.run")
236
- Text("Start Outdoor Running Workout")
237
- }
238
- }
239
- .accessibilityLabel("Start Outdoor Running Workout")
240
- .accessibilityInputLabels(["Start Run", "Run", "Start Workout"])
241
- ```
307
+ Button("Start 45-minute progressive endurance ride") { startRide() }
308
+ .accessibilityLabel("Start 45-minute progressive endurance ride")
309
+ .accessibilityInputLabels(["Start ride", "Endurance ride", "Ride"])
242
310
 
243
- ```swift
244
- // Navigation link with verbose label
245
- NavigationLink {
246
- AccountSettingsView()
247
- } label: {
248
- Label("Account and Privacy Settings", systemImage: "person.circle")
311
+ NavigationLink(value: Route.notifications) {
312
+ Label("Notification and alert preferences", systemImage: "bell.badge")
249
313
  }
250
- .accessibilityInputLabels(["Account", "Settings", "Privacy"])
314
+ .accessibilityInputLabels(["Notifications", "Alerts"])
251
315
  ```
252
316
 
253
- Also consider input labels for repeated row actions, quantity controls, media controls, and product-name labels where Voice Control users are likely to speak a shorter command than the visible text.
317
+ Also worth input labels: labels built from product names, playback controls,
318
+ steppers for quantities, and the same action repeated on every row.
254
319
 
255
- ### Speakable Label Guidelines
320
+ ### Speakable labels
256
321
 
257
322
  ```swift
258
- // Bad: emoji-only, unspeakable
259
- Button("❤️") { toggleFavorite() }
323
+ // Bad: nothing to say.
324
+ Button("\u{1F5D1}") { remove(entry) } // a wastebasket emoji
260
325
 
261
- // Good: speakable label
262
- Button(action: { toggleFavorite() }) {
263
- Image(systemName: "heart.fill")
264
- }
265
- .accessibilityLabel("Favorite")
326
+ // Good: symbol on screen, words for speech.
327
+ Button { remove(entry) } label: { Image(systemName: "trash") }
328
+ .accessibilityLabel("Delete")
266
329
 
267
- // Bad: duplicate labels on same screen
268
- ForEach(items) { item in
269
- Button("Edit") { edit(item) } // Voice Control can't distinguish
330
+ // Bad: ten identical "Rename" buttons; Voice Control cannot tell them apart.
331
+ ForEach(playlists) { playlist in
332
+ Button("Rename") { rename(playlist) }
270
333
  }
271
334
 
272
- // Good: unique labels
273
- ForEach(items) { item in
274
- Button("Edit") { edit(item) }
275
- .accessibilityLabel("Edit \(item.name)")
335
+ // Good: keep the visible word, make the spoken name unique.
336
+ ForEach(playlists) { playlist in
337
+ Button("Rename") { rename(playlist) }
338
+ .accessibilityLabel("Rename \(playlist.name)")
276
339
  }
277
340
  ```
278
341
 
279
- ## Switch Control Patterns
280
-
281
- Switch Control scans elements sequentially. Reduce scan stops with grouping and provide custom actions for gesture-based interactions.
342
+ ## Switch Control
282
343
 
283
- ### Custom Actions for Gesture Alternatives
344
+ Switch Control scans element by element, so group to cut stops and add custom
345
+ actions for anything gesture-driven.
284
346
 
285
347
  ```swift
286
- // Swipe-to-delete row: Switch Control can't swipe
348
+ // Swipe actions also exposed as named actions.
287
349
  TaskRow(task: task)
288
- .accessibilityAction(named: "Complete") { completeTask(task) }
289
- .accessibilityAction(named: "Delete") { deleteTask(task) }
290
- .accessibilityAction(named: "Reschedule") { rescheduleTask(task) }
291
- ```
292
-
293
- ```swift
294
- // Long-press context menu: expose actions directly
295
- PhotoThumbnail(photo: photo)
296
- .contextMenu { /* ... */ }
297
- .accessibilityAction(named: "Share") { sharePhoto(photo) }
350
+ .swipeActions {
351
+ Button("Delete", role: .destructive) { delete(task) }
352
+ }
353
+ .accessibilityAction(named: "Mark done") { complete(task) }
354
+ .accessibilityAction(named: "Delete") { delete(task) }
355
+ .accessibilityAction(named: "Snooze until tomorrow") { snooze(task) }
356
+
357
+ // Context-menu operations reachable without a long press.
358
+ PhotoTile(photo: photo)
359
+ .contextMenu {
360
+ Button("Share") { share(photo) }
361
+ Button("Add to Album") { addToAlbum(photo) }
362
+ Button("Delete", role: .destructive) { delete(photo) }
363
+ }
364
+ .accessibilityAction(named: "Delete") { delete(photo) }
365
+ .accessibilityAction(named: "Share") { share(photo) }
298
366
  .accessibilityAction(named: "Add to Album") { addToAlbum(photo) }
299
- .accessibilityAction(named: "Delete") { deletePhoto(photo) }
300
367
  ```
301
368
 
302
- ### Grouping for Scan Efficiency
369
+ Grouping in numbers: this attachment row is five scan stops as written (icon,
370
+ name, date, size, chevron). With `.combine` it becomes one.
303
371
 
304
372
  ```swift
305
- // Bad: 5 scan stops per row
306
- HStack {
307
- Image(systemName: "doc")
308
- VStack {
309
- Text(document.title)
310
- Text(document.date.formatted())
311
- }
312
- Spacer()
313
- Text(document.size)
314
- Image(systemName: "chevron.right")
315
- }
316
-
317
- // Good: 1 scan stop per row
318
373
  HStack {
319
- Image(systemName: "doc")
320
- VStack {
321
- Text(document.title)
322
- Text(document.date.formatted())
323
- }
324
- Spacer()
325
- Text(document.size)
374
+ Image(systemName: "paperclip")
375
+ Text(file.name)
376
+ Text(file.modified, style: .date)
377
+ Text(file.sizeText)
326
378
  Image(systemName: "chevron.right")
327
379
  }
328
380
  .accessibilityElement(children: .combine)
329
381
  ```
330
382
 
331
- ## Full Keyboard Access Patterns
332
-
333
- Full Keyboard Access review checks whether keyboard users can complete the same common tasks without touch. Keep the implementation mechanics in the `focus-engine` skill when the fix requires Tab-order wiring, skipped custom cards, `.focusable()`, SwiftUI keyboard focus state, focus sections, directional movement, tvOS focus, or `UIFocusGuide`.
383
+ VoiceOver users benefit from the same change: one swipe per attachment instead
384
+ of five.
334
385
 
335
- - Every interactive control is reachable by keyboard.
336
- - Activation works with expected keyboard input.
337
- - Focus indicators are visible and not hidden by custom styling.
338
- - Focus traversal is logical and does not trap users in a region.
339
- - Gesture-only interactions have keyboard-operable alternatives.
340
- - App shortcuts do not override system shortcuts.
341
- - Custom controls skipped by Tab should be filed as keyboard focus implementation issues and routed to `focus-engine`; keep the accessibility finding here.
342
- - Explicitly assess traversal impact: accessibility element order and grouping affect VoiceOver swipe order, Switch Control scan order, Voice Control overlay targeting, and Full Keyboard Access reachability review.
386
+ ## Full Keyboard Access
343
387
 
344
- ## Automated Accessibility Testing
388
+ The question a review asks: can someone using only a keyboard complete the
389
+ same common tasks as someone using touch? The mechanics (`UIFocusGuide`, tvOS
390
+ focus, arrow-key movement, focus sections, SwiftUI keyboard focus state,
391
+ `.focusable()`, cards that Tab skips, Tab order wiring) are `hig-inputs`
392
+ work.
345
393
 
346
- Use `XCUIElement` attributes to verify accessibility properties in UI tests.
394
+ Check:
347
395
 
348
- ### Verifying Labels and Identifiers
396
+ - every interactive control can be reached from the keyboard;
397
+ - it activates with the keys people expect (Space, Return);
398
+ - the focus ring is visible and no custom style hides it;
399
+ - traversal is logical and never gets stuck in one region;
400
+ - gesture-only interactions have a keyboard alternative;
401
+ - the app's shortcuts do not shadow system shortcuts.
349
402
 
350
- ```swift
351
- func testAccessibilityLabels() throws {
352
- let app = XCUIApplication()
353
- app.launch()
354
-
355
- // Verify buttons have meaningful labels
356
- let settingsButton = app.buttons["Settings"]
357
- XCTAssertTrue(settingsButton.exists, "Settings button must exist")
358
- XCTAssertTrue(settingsButton.isEnabled, "Settings button must be enabled")
359
-
360
- // Verify a cell groups content correctly
361
- let productCell = app.cells.element(boundBy: 0)
362
- XCTAssertFalse(productCell.label.isEmpty, "Product cell must have a combined label")
363
- }
364
- ```
403
+ A custom control that Tab skips is filed as a keyboard-focus implementation
404
+ issue for `hig-inputs`, while the accessibility finding is recorded here.
405
+ Whatever the bug, write down what the current ordering and grouping do to the
406
+ four traversal paths: VoiceOver swipes, switch scanning, Voice Control
407
+ overlays and keyboard reach.
365
408
 
366
- ### Testing Focus and Selection State
409
+ ## Automated checks with XCTest
367
410
 
368
411
  ```swift
369
- func testTabNavigationOrder() throws {
370
- let app = XCUIApplication()
371
- app.launch()
372
-
373
- let usernameField = app.textFields["Username"]
374
- let passwordField = app.secureTextFields["Password"]
375
-
376
- usernameField.tap()
377
- XCTAssertTrue(usernameField.hasFocus)
378
-
379
- // Tab to next field
380
- usernameField.typeText("\t")
381
- XCTAssertTrue(passwordField.hasFocus)
382
- }
383
- ```
412
+ @MainActor
413
+ final class AccountScreenAccessibilityTests: XCTestCase {
414
+ private func launchedApp() -> XCUIApplication {
415
+ let app = XCUIApplication()
416
+ app.launch()
417
+ return app
418
+ }
384
419
 
385
- ### Testing Custom Actions
420
+ func testControlsExposeLabels() {
421
+ let app = launchedApp()
422
+ let logout = app.buttons["Sign out"]
423
+ XCTAssertTrue(logout.exists, "Sign out button should be exposed")
424
+ XCTAssertTrue(logout.isEnabled, "Sign out button should be enabled")
386
425
 
387
- ```swift
388
- func testSwipeToDeleteAlternative() throws {
389
- let app = XCUIApplication()
390
- app.launch()
426
+ let firstRow = app.cells.element(boundBy: 0)
427
+ XCTAssertTrue(firstRow.exists)
428
+ XCTAssertTrue(firstRow.buttons["Remove device"].exists)
429
+ XCTAssertFalse(firstRow.label.isEmpty, "Grouped row should read as one label")
430
+ }
391
431
 
392
- let cell = app.cells["task-buy-groceries"]
393
- XCTAssertTrue(cell.exists)
432
+ func testTabMovesBetweenFields() {
433
+ let app = launchedApp()
434
+ let email = app.textFields["Email"]
435
+ let password = app.secureTextFields["Password"]
436
+ email.tap()
437
+ XCTAssertTrue(email.hasFocus)
438
+ email.typeText("\t")
439
+ XCTAssertTrue(password.hasFocus)
440
+ }
394
441
 
395
- // Verify accessibility identifier is set for test targeting
396
- XCTAssertEqual(cell.identifier, "task-buy-groceries")
442
+ func testRowKeepsItsIdentifier() {
443
+ let app = launchedApp()
444
+ let row = app.cells["device-row-primary"]
445
+ XCTAssertTrue(row.exists)
446
+ XCTAssertEqual(row.identifier, "device-row-primary")
447
+ }
397
448
  }
398
449
  ```
450
+
451
+ The identifier check matters because UI tests and custom-action tests target
452
+ rows by accessibility identifier.