Review checklist
This is the checklist to run down — by eye, on any diff, yours or an AI’s — after the tools in Verification Tools have run and come back clean. It fits on one printed page on purpose: a checklist nobody actually opens during a review is worthless. Every line links the catalog entry that explains why, so this page stays a list, not a re-run of the course. The groups follow the same order as How to read Flutter code you did not write, plus a final Tooling group covering how each of the other eight actually gets verified.
flowchart LR A["State & lifecycle"] --> R["Needs a real dispose/rebuild sequence<br/>to surface at all"] W["Widget tree & keys"] --> T["Mostly human review<br/>(renders correctly either way)"] L["Layout"] --> T2["Framework catches it loudly --<br/>but only the exact arrangement that overflows"] As["Async & isolates"] --> R N["Navigation"] --> T P["Platform"] --> D["Needs the actual platform/runtime --<br/>compiles and analyzes clean otherwise"] Pf["Performance"] --> M["Silent cost, not a crash --<br/>needs reading RenderObject properties directly"] Tl["Tooling & release"] --> M2["Analyzer/lint catches SOME --<br/>only if the rule is actually enabled"]
pubspec & SDK constraints
Section titled “pubspec & SDK constraints”- Does
environment: sdk:inpubspec.yamlactually admit the Dart/Flutter version this project targets, not one copied from an older tutorial? - Does any Riverpod code call
StateProvider/StateNotifierProvider/ChangeNotifierProvidervia the mainflutter_riverpod.dartimport, instead of the requiredlegacy.dartimport in Riverpod 3? See the AI Bug Catalog, entry 5, proven with a realundefined_functiondiagnostic. - If
custom_lint/riverpod_lintare both pinned, do they actually resolve together at those versions? See Verification Tools for a real, current version-conflict finding.
State & lifecycle
Section titled “State & lifecycle”- Is there a
ProviderScopeabove the firstConsumerWidget/ref.watchcall? See the AI Bug Catalog, entry 1, proven with a realBad state: No ProviderScope found. - Does every
setStatereachable from.then(), anawaitcontinuation, aTimer, or aStreamlistener checkmountedfirst? See entry 2, proven with a realsetState() called after dispose(). - Does any widget’s
build()callsetStateon a different, still-mid-build widget synchronously? See entry 3, proven with a realsetState() or markNeedsBuild() called during build. - Is a
latefield ever read on a path where the method assigning it might not have run yet? See entry 4, proven with a realLateInitializationError.
Widget tree & keys
Section titled “Widget tree & keys”- Does a list of stateful widgets built with
for/.map()have akeyat all, when its order can change? See the AI Bug Catalog, entry 6, proven with a real reorder test. - Is the same
GlobalKeyconstant reused across sibling widgets instead ofUniqueKey()/aValueKeyper item? See entry 7, proven with a realDuplicate keys found. - Does
Scaffold.of(context)ever get called with the exact samecontextthe enclosingScaffoldwas built with, instead of aBuilder-descendant context? See entry 8, proven with a realScaffold.of() called with a context that does not contain a Scaffold.
Layout
Section titled “Layout”- Is a
ListView/GridView/other scrollable placed directly inside aColumn/Rowwith nothing bounding its main-axis size? See the AI Bug Catalog, entry 9, proven with a realVertical viewport was given unbounded height— and confirm the REVERSE case (aColumninside aListView) was not “fixed” unnecessarily. - Is
Expanded/Flexibleever used as a child of something that is not aRow/Column/Flex? See entry 10, proven with a realIncorrect use of ParentDataWidget. - Does a
Row/Columnof fixed-size children have noExpanded/Flexible/scrolling escape hatch for content that can exceed the viewport? See entry 11, proven with a realRenderFlex overflowed.
Async & isolates
Section titled “Async & isolates”- Does an async function get called directly inside
build()instead of once inState(initState/alate finalfield)? See the AI Bug Catalog, entry 12, proven with a real rebuild-refetch count. - Does a
compute()closure capture aBuildContext, aZone, or anything else reachable from this isolate’s own binding? See entry 13, proven with a realIllegal argument in isolate message: object is unsendable. - Is a
StreamControllerleft at its single-subscription default while more than one independent.listen()call exists on it? See entry 14, proven with a realBad state: Stream has already been listened to.
Navigation
Section titled “Navigation”- Is a parameterized
go_routerroute (/pets/:id) declared before a more specific static route at the same segment level (/pets/new)? See the AI Bug Catalog, entry 15, proven with a real misroute test. - Is
context.go()/router.go()used where the user needs to be able to press back (drill-down navigation), rather thanpush()? See entry 16, proven with a real route-stack-depth comparison. - Does a
redirectcallback read external state (an auth flag) withoutrefreshListenablepointed at whatever notifies when that state changes? See entry 17, proven with a real stuck-on-login test. - Does any code still use
WillPopScope(deprecated, no predictive-back support), or referencePredictiveBackPageTransitionBuilder(missing the “s”)? See entry 18, proven with a real deprecationinfoand a realundefined_functionerror.
Platform
Section titled “Platform”- Does
dart:io/Platform.isIOS/Fileget used unconditionally in code that also has to build for web? See the AI Bug Catalog, entry 19, proven with a real, cleanflutter build web --releasethat hides the bug until actual runtime. - Does a
MethodChannel.invokeMethodcall assume a native handler is registered on every platform the app ships to (and does every test that exercises it mock the channel)? See entry 20, proven with a realMissingPluginException. - Is
FlutterError.onErrortreated as complete error coverage, with norunZonedGuarded/PlatformDispatcher.onErrorfor errors thrown outside the framework’s own build/layout/paint? See entry 21, proven with a real bare-Futureerror that onlyrunZonedGuardedcatches.
Performance
Section titled “Performance”- Does every
AnimationControllercreated withSingleTickerProviderStateMixin/TickerProviderStateMixinget.dispose()d in theState’s owndispose()? See the AI Bug Catalog, entry 22, proven with a realwas disposed with an active Ticker. - Is
Opacity(opacity: 1.0)used where the value never actually varies, instead of returning the child directly? See entry 23, proven by reading a liveRenderOpacity’s ownisRepaintBoundary/alwaysNeedsCompositingproperties. - Does any code still pass a bare number to
cacheExtentinstead ofscrollCacheExtent: ScrollCacheExtent.pixels(...)? See entry 24, proven with a real deprecationinfoand a realdart fix --dry-runsuggestion.
Tooling & release
Section titled “Tooling & release”- Is
constassumed to be enforced by “the linter,” when this course’s pinnedflutter_lints6.0.0 only shipsprefer_const_constructors_in_immutables, not the general rule? See the AI Bug Catalog, entry 25, proven with a real before/afterflutter analyzediff. - Is any
print()call assumed to be stripped from a release build? See entry 26, proven with a real string found verbatim inside a releasemain.dart.js. - Does a
switchover asealed classskip a subtype, relying on habit instead of the analyzer’s own exhaustiveness check? See entry 27, proven with a realnon_exhaustive_switch_expressionerror. - Does any named parameter or method name look plausible but not actually exist on the class in question? See entry 28, proven with real
undefined_named_parameter/undefined_methoderrors — the cheapest, most mechanical check on this whole page. - Does CI run
flutter analyzeANDflutter test(not just one), knowing analyze proves types/syntax only, never runtime behavior? See Verification Tools. - Is
flutter build web --wasmever exercised as a portability gate, or only the default JS-compiled build? See Verification Tools, proven with a real, clean--wasmbuild. - Does this course’s own harness (
npm run verify,--test <module>/<lesson>) run against every fence, not just a human skim? See Verification Tools.