Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
The English summary is being prepared. Showing the original description.
Use when building native iOS with SwiftUI - small composable views, observable state models, atomic components, Swift 6.2+ concurrency, and system styling over hardcoded values
The English summary is being prepared. Showing the original description.
See how to installReview the instructions the agent will receive before you install.
Native iOS (SwiftUI) is chosen when a task needs deep Apple-platform integration or the app is already native (see native-vs-flutter-decision). Same discipline as Flutter: small composed views, state out of the view, reusable atomic components.
Core principle: Views are a function of state. Data and business logic live in an observable model, not in the View.
View types (not @ViewBuilder funcs) so each has its own body and preview.@State for local ephemeral UI only (and it is always private); app/business state in an @MainActor @Observable model injected via init/@Environment. Views send intents to the model; the model owns the logic and the networking.Color semantic roles, spacing/typography from a tokens file (see mobile-design-system-foundation) — not scattered magic numbers. Support Dynamic Type and dark mode.#Preview every reusable view in its key states (loading/data/error), and in the matrix: Dynamic Type .accessibility3, dark, traits: .landscapeLeft.struct) for models and view state; reference types only where identity is needed.Task — it shadows _Concurrency.Task, which every async/.task {} call site needs; a rename (BoardItem, WorkItem, …) is a five-minute fix versus a confusing compile error later.@MainActor isolation, so a view model that touches UI state should be @MainActor @Observable explicitly rather than relying on inference holding across Swift versions.DispatchQueue.main.async, etc.) in new code — async/await, Task { }, Task.sleep(for:)..task { } on the view, not onAppear + a detached Task.struct BoardItem: Identifiable, Sendable { let id: Int; let title: String } // never name a model `Task`
enum LoadState<T> { case loading, empty, data(T), failed(String) }
@MainActor @Observable final class ItemListModel {
private(set) var state: LoadState<[BoardItem]> = .loading
private let repo: any BoardItemRepository
init(repo: any BoardItemRepository) { self.repo = repo }
func load() async {
state = .loading
do { let items = try await repo.list(); state = items.isEmpty ? .empty : .data(items) }
catch { state = .failed(error.localizedDescription) }
}
}
struct ItemListScreen: View {
@State private var model: ItemListModel
init(model: ItemListModel) { _model = State(initialValue: model) }
var body: some View {
Group {
switch model.state {
case .loading: AppSpinner()
case .empty: ContentUnavailableView("No items yet", systemImage: "tray")
case .failed(let message):
ContentUnavailableView {
Label("Couldn't load items", systemImage: "exclamationmark.triangle")
} description: { Text(message) } actions: {
Button("Try again") { Task { await model.load() } }
}
case .data(let items): ItemList(items: items)
}
}
.task { await model.load() }
}
}
Typechecks with swiftc -swift-version 6 (verified). The original example's domain struct Task shadowed _Concurrency.Task, giving error: missing argument for parameter 'title' in call at every Task { } call site — renamed to BoardItem here. Note the explicit .empty case rendered with ContentUnavailableView and a retry action on .failed, and the init that seeds State(initialValue:) so the model can be injected.
Previews at the matrix (typechecked against the iOS 18 simulator SDK):
#Preview("Phone, AX3, dark") { ItemListScreen(model: .preview).environment(\.dynamicTypeSize, .accessibility3).preferredColorScheme(.dark) }
#Preview("Landscape", traits: .landscapeLeft) { ItemListScreen(model: .preview) }
For a layout that must switch at large accessibility sizes: typeSize.isAccessibilitySize ? AnyLayout(VStackLayout()) : AnyLayout(HStackLayout()). For an icon-only control: Button("Add to cart", systemImage: "cart.badge.plus", action:) with .labelStyle(.iconOnly) and .frame(minWidth: 44, minHeight: 44) (see mobile-accessibility).
@Observable model with a mocked repository (no UI).import Testing, @Test, #expect) where the target already uses Xcode 16+; XCTest stays for existing UI tests and app.performAccessibilityAudit(). Test-first.foregroundStyle (not foregroundColor), .clipShape(.rect(cornerRadius:)) (not .cornerRadius), the Tab API for tab bars, the two-parameter onChange(of:) { old, new in }, .topBarTrailing placement, containerRelativeFrame instead of GeometryReader when it covers the case, never UIScreen.main.bounds.Color.withValues is not a thing in SwiftUI (that's the Flutter equivalent) — use asset-catalog colours or Color(.sRGB, ...)/.opacity() as the repo already does..glassEffect only on custom floating controls, and only when the task asks for it.UIDesignRequiresCompatibility is ignored when building with the iOS 27 SDK — don't rely on it to opt back out of the new look.body / View.@ViewBuilder helper funcs instead of real subviews.Task.async/await.View with a URLSession call in it.Color(red:...) and paddings sprinkled across views.body.Task anywhere in the diff.No reviews yet. Tell others what you thought.
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
The English summary is being prepared. Showing the original description.
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
The English summary is being prepared. Showing the original description.
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
The English summary is being prepared. Showing the original description.
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
The English summary is being prepared. Showing the original description.
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
The English summary is being prepared. Showing the original description.
Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
The English summary is being prepared. Showing the original description.