name: improve-code
description: Use when refactoring or improving a Coffee Quest screen, widget, or feature for testability, structure, and convention-consistency — extracting controllers and pure helpers out of widgets, removing magic numbers, adding unit tests, organizing per-screen folders, wiring debug toggles, or fixing accessibility — all without changing user-visible behavior. Invoke as /improve-code <path-or-feature>; defaults to the open file / current selection when no target is given.
Improve Code Skill
Apply Coffee Quest's refactoring + testability playbook to a screen, widget, or feature. Goal: clearer, more testable, convention-consistent code with no change to user-visible behavior.
Target: the path/feature passed as the argument; otherwise the open file or current selection.
Operating rules
- Run all commands from
coffee_quest/. After each step runflutter analyze(expect "No issues found!") andflutter test(expect green). Do not continue on red. - Work in small, individually-verifiable steps. For large or structural changes, propose a short plan first; track progress with a todo list.
- Refactors must be behavior-preserving. When extracting numeric constants keep the
exact literal values — do NOT derive them (
1 - 0.85 != 0.15in IEEE-754). Let tests prove parity. - Reuse existing helpers/widgets/providers before writing new code.
- Report honestly: if a test fails or a step is skipped, say so with the output.
- If a Flutter tooling crash hits a stale SwiftPM symlink (
PathExistsExceptiononios/Flutter/ephemeral/),rm -rf ios/Flutter/ephemeraland retry. Note: the Bash working directory can flap — prefer absolute paths.
Review lens — look for
- Magic numbers — bare literals in
build()/ math. Only0/1may be inline. - Logic trapped in the widget — timers, state machines, sequencing, or async
orchestration living inside a
State. - Side-effects that can't be unit-tested — persistence/navigation called inline instead of injected.
- Oversized files — soft cap ~250 lines; multiple
State/widget classes, or UI mixed with logic, in one file. - Accessibility gaps — loading/empty/error states without
Semanticslabels, or animations that ignore reduced motion. - Unsafe debug toggles — hand-flipped
constflags instead of compile-time off. - Weak names — single-letter identifiers (except loop
i),t/pfor animation values instead of intent names. - Hardcoded navigation — path strings or gate→destination logic duplicated in screens instead of the router.
- Organization — single-use widgets not collocated with their screen; widgets shared by 2+ screens buried in one screen's folder.
- Docs drift — how-to instructions duplicated across code comments and docs.
Refactor playbook
- Pure helpers: move animation math / mappings / derivations into a sibling
pure-Dart file (e.g.
*_animation.dart) as named top-level functions; unit-test them directly, no widget pumping. - Controller: pull orchestration/state/timers into a plain
ChangeNotifiernamed*Controller, with dependencies injected as callbacks (e.g.onSubmit,onFinished,isGateResolved). Test withfake_async+ fake callbacks. Reserve the name Notifier for Riverpod@riverpodclasses; a widget-localChangeNotifieris a Controller (mirrors Flutter'sTextEditingController/AnimationController). - Thin the widget: the screen becomes a view that creates the controller in
initState/didChangeDependencies, listens, rebuilds, and disposes it. - Test views without a DB: wrap in
ProviderScope(overrides: [repoProvider.overrideWithValue(fake)]); test notifiers viaProviderContainer. Do not introduce a BLoC-style Page/View split — this is a Riverpod app, so provider overrides are the isolation seam. - Folders: per-screen subfolder; collocate single-use widgets in
<screen>/widgets/, keep widgets shared by 2+ screens in the feature'spresentation/widgets/. Verify usage by grep, not assumption. Move files withgit mvso history is preserved. - Debug toggles:
static const X = bool.fromEnvironment('X')(default off, safe by construction); add it to the README "Run-time flags" table and point to it from the code comment. - Accessibility: loading/empty/error states get
Semanticslabels and respectMediaQuery.disableAnimations(reduced motion).
Conventions
package:coffee_quest/…imports insidelib/(never relative../).- TSDoc only for complex logic / third-party integrations; skip self-evident code.
- Single source of truth for how-to docs (README); code comments point to it.
- Navigate by route
name(context.goNamed(...)), never hardcoded paths; gate→destination policy lives in the router. - Regenerate after model/provider/table changes:
dart run build_runner build. - Keep
CLAUDE.mdandAGENTS.mdin sync when editing either.
Deliverable
Report findings → changes made → verification (analyze result + test counts, before/after). Call out anything intentionally left, risky, or out of scope.