The workflow
- 01Why review before accepting a change?
- 02What source did the reviewer inspect?
- 03Which findings were returned?
- 04What change was made?
Run a focused concurrency review on the proposed changes, inspect each finding in its isolation context, and then use the compiler and behavior tests to verify the repair. A synthetic Swift model produced two real findings in this walkthrough; a narrower, main-actor-isolated version produced none, which is evidence about the review tool rather than proof of race freedom.
Why review before accepting a change?
Agent-generated code can combine patterns from different examples. A model might use observation for UI state while also starting detached work that writes the same state. The important review question is who owns the mutable value and which execution context may access it. Counting occurrences of async does not answer that question.
The repository documents a focused tool called review_swift_concurrency. It returns file locations, rule identifiers, severities, explanations, and suggested changes. That structure makes a finding easier to investigate than a broad request to improve concurrency. The tool is still heuristic: it reads source patterns rather than constructing the compiler's full isolation model.
Swift's concurrency migration guide is the primary reference for language-level diagnosis. The experiment below measures this project's reviewer. It is not a survey establishing which mistakes coding agents make most often.
What source did the reviewer inspect?
I created an intentionally small, synthetic fixture called FeedModel.swift. It contains no user app code, networking, or persistence:
import Observation
@Observable
final class FeedModel {
var title = ""
func refresh() {
Task.detached { self.title = "Updated" }
}
}
The detached operation has no independent computation to perform. It exists only to assign a string. That makes the example suitable for discussing ownership without pretending that moving expensive work onto the main actor is a general performance solution.
I connected an MCP client to the published 2.7.0 server and called review_swift_concurrency with the fixture directory as its absolute path argument. This was a real tool call, not an illustration of what a response might look like. The complete response is preserved in the before record.
Which findings were returned?
The response reported one blocker and one serious finding across one Swift file:
| Location | Rule | Reported severity |
|---|---|---|
FeedModel.swift:3 |
observable-without-mainactor |
blocker |
FeedModel.swift:7 |
task-detached |
serious |
Those are the reviewer's classifications. Do not confuse them with compiler diagnostic levels. In particular, observation alone does not establish that every observable type must have an explicit main-actor annotation. Actual ownership, callers, and project isolation settings matter. A reviewer that uses text patterns cannot infer every one of those conditions.
The second finding points to an operation whose detached execution is unnecessary in this fixture. The repair should preserve the program's intended behavior, not merely remove a keyword until the count turns green. In a real application, identify the work that should run independently, the values it returns, and the isolated state that consumes them.
What change was made?
For this UI-state example I made ownership explicit and removed the unnecessary task:
import Observation
@MainActor
@Observable
final class FeedModel {
var title = ""
func refresh() {
title = "Updated"
}
}
The change does not introduce another asynchronous wrapper. Callers now have to respect the model's actor isolation. If a real refresh loads data, keep the loading contract explicit and update the model through its isolation boundary; this tiny example does not implement that service.
I called the same reviewer against the second fixture. The after record reports zero findings across one file. Both source fixtures are included with the draft so the line references and change can be inspected. There is no hidden rewrite, model scoring step, or manually adjusted result.
How should I use the result in an app?
Start with the changed model and its callers. Determine whether isolation is explicit on the type, inherited through context, or selected by build settings. Then decide whether the suggested annotation describes the intended ownership. A correct fix in one model may be unnecessary or misleading in another.
Next compile using the application's real Swift language mode and deployment settings. The fixture's successful review does not establish that a view initializer, service, or test can call the repaired model correctly. Those dependencies are precisely where a compiler adds information that the text reviewer lacks.
Finally exercise the behavior that motivated the edit. A feed refresh should show loading, success, failure, and cancellation states as required by the app. A clean review cannot demonstrate any of them. Keep review output beside build and test results so the acceptance report does not flatten several different checks into a single pass.
Limits
This experiment did not run a coding model, compile these fixtures, or measure runtime races. It does not establish an agent error rate or a token-saving advantage. The published reviewer's explanatory wording is stronger than the evidence its pattern matching can prove; interpret findings as investigation leads. A file-level annotation can also conceal a problem in another type in the same file. Zero findings means no matching rule fired, not that all concurrency behavior is correct.
Last verified
September 16, 2026, local time. Published ios-agent-mcp 2.7.0, Node.js 24.15.0, actual stdio tool calls. Repository sources: docs/mcp/tools.md, docs/mcp/examples.md, and docs/evidence-and-scope.md.
Example project: ios-agent-skill.
