Audit Application Layer
Statically scans Flutter application-layer source files against bundled Riverpod v3 notifier rules and async-mutation patterns. Emits a violations table, then offers targeted fixes.
Rule source
Rules are bundled locally in skills/audit-application-layer/rules/.
This skill does not delegate to ai_toolkit/ — it is self-contained.
Phase 0 — Resolve input
Read the user's request and extract one of:
- Single file: a path ending in
.dart - Feature folder: a path that contains an
application/directory
If neither is clear, ask exactly one question:
"Provide a
.dartfile path underapplication/, or a feature folder path containing anapplication/directory."
Do not proceed until a path is confirmed.
Phase 1 — Load rule catalog
Read skills/audit-application-layer/rules/CATALOG.md in full before scanning.
Do not read individual rule doc files yet — the catalog contains all heuristics needed for Phase 3. Open a specific rule doc only if you need to clarify a borderline case or produce a more detailed fix explanation.
Phase 2 — Discover files
Single-file mode
Target file = the provided .dart path.
Classify it as application-file.
If the provided file is NOT under application/, classify as non-application and apply
only APP-DEP-01 (framework import check) if it is not under presentation/ either.
Folder mode
Spawn an Explore subagent:
Agent(
subagent_type="Explore",
prompt="List all .dart files (excluding .g.dart, .freezed.dart) recursively
under <input_path>/application/ (or under <input_path> if it is already an application/ dir).
For each file report:
- Relative path
- Whether it appears to be a notifier (class name ends in Notifier or contains AsyncNotifier/Notifier)
- Line count (approximate)
Report as a plain table."
)
Classify each file as application-file.
Phase 3 — Scan
For each application-file:
- Read the full file contents.
- Apply every heuristic in
rules/CATALOG.md. - For each match: record
{file, line_number, rule_id, severity, message, fix_hint, autofix_safe}.
Heuristic application notes:
- APP-DEP-01: flag any
import 'package:flutter/widgets.dart'orimport 'package:flutter/material.dart'orimport 'package:flutter/cupertino.dart'in files underapplication/. Riverpod imports (package:riverpod_annotation,package:riverpod,package:flutter_riverpod) are allowed and must NOT be flagged. - APP-NOTIF-02: flag
try {blocks inside a class that extends or mixes inAsyncNotifier,Notifier,StreamNotifier,AutoDisposeAsyncNotifier,AutoDisposeNotifier, or any class whose name ends inNotifier. The key signal is manualtry/catcharoundawaitexpressions for error reporting — theAsyncErrorLoggerand Riverpod's single-error-channel via state assignment already handle this. Do NOT flagtry/catchthat converts an infra exception to a domain exception (which is data-layer work and valid if present for a specific reason). - APP-NOTIF-01: flag public async methods (not
build) inside notifier classes that declare a return type other thanFuture<void>orvoid. Specifically flagFuture<T> methodName(whereTis notvoid. Mutation methods must surface errors via state (single error channel) and returnFuture<void>. - APP-STATE-01: flag provider annotations (
@riverpod) where the inferred or declared state type isdynamic,Object?(as a state type, not a param), orMapwithout type parameters. Specifically look forAsyncValue<dynamic>,AsyncValue<Map>,StateProvider<dynamic>,StateProvider<Map>, or class-levelstate =assignments where the assigned value is typeddynamic. - APP-COUPLE-01: in files under
application/, flagimportlines whose path containsdatasource/data_source, and usages of types ending inDatasource/DataSource(constructor calls,ref.read(xxxDatasourceProvider), type annotations). - APP-COUPLE-02: in files under
application/, flagimportlines whose path contains/presentation/. - APP-COUPLE-03: in notifier classes, flag assignments matching
=\s*\w*(Repository(Impl)?|Data[Ss]ource)\(— manual construction of repository/datasource implementations instead of provider resolution. Skip test files. - APP-COHESION-01: count public (non-
_, non-build) method declarations per notifier class; flag the class line when > 7. Also flag application files > 300 lines as a secondary signal.
Phase 4 — Report
Emit the violations grouped by file:
## Audit Results — Application Layer
### lib/.../auth/application/auth_notifier.dart
| Line | Rule ID | Severity | Message |
|------|---------|----------|---------|
| 8 | APP-DEP-01 | error | import 'package:flutter/material.dart' — application layer must stay framework-free (Riverpod core is OK) |
| 34 | APP-NOTIF-02 | error | Manual try/catch in AsyncNotifier.signIn() — error is already handled via state; remove try/catch or convert to domain exception in the data layer |
| 52 | APP-NOTIF-01 | warning | Future<AppUser?> signIn() returns a value — mutation should return Future<void> and surface result via state |
| 71 | APP-STATE-01 | warning | StateProvider<dynamic> — constrain state type to a specific model or AsyncValue<T> |
---
**Summary**: 4 violations across 1 file (2 errors, 2 warnings, 0 info)
If no violations are found, say so explicitly:
No violations found in <path>. All checked rules pass.
Phase 5 — Fix prompt
After the report, ask:
Apply fixes for which rule IDs? (comma-separated list, "all", or "none")
Auto-fix safe: (none)
Requires judgment: APP-DEP-01, APP-NOTIF-02, APP-NOTIF-01, APP-STATE-01,
APP-COUPLE-01, APP-COUPLE-02, APP-COUPLE-03, APP-COHESION-01
On response:
- "none" or no response: done.
- "all" or specific IDs:
- For each violation matching the selected IDs:
- If
autofix_safe: true: apply the edit directly, show diff. - If
autofix_safe: false: show the specific change needed and ask the user to confirm before editing. Provide the exact code transformation.
- If
- After all edits, re-run Phase 3 on touched files only.
- Confirm which violations were resolved.
- For each violation matching the selected IDs:
Never edit files that were not explicitly approved by the user.
Usage examples
audit the application layer of features/authaudit this notifier: lib/src/features/auth/application/auth_notifier.dartfind application violations in features/booking/application//audit-application-layer lib/src/features/auth/application//audit-application-layer lib/src/features/booking/
Notes
- Paths are relative to the project root — always resolve from there.
- This skill does not shell out to
dart analyze; it reads files directly. - It does not overlap with
riverpod-reviewer(which auditsref.watch/ref.readplacement in widgets) oraudit-domain-layer/audit-data-layer. - The single-error-channel pattern is documented in
skills/audit-application-layer/rules/patterns/async-notifier-command-api.md. - To add or modify rules, edit
skills/audit-application-layer/rules/CATALOG.mdonly.