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 you are about to hand off any change to a screen or component on a mobile repository - the size, text-scale and dark-mode matrix, the exact tool calls to see your own build, and the checklist that decides whether the screen is done.
The English summary is being prepared. Showing the original description.
See how to installReview the instructions the agent will receive before you install.
A green build and a passing widget test say the code compiles and the tree is what the test asserted. Neither says the screen looks right on a 360 phone at 200% text, on a tablet, in landscape, or in dark mode. Default assumption: the change is NOT done until you've looked at it rendered — be the skeptic here, not the advocate.
Core principle: two layers, always both. A matrix test in the suite catches overflow mechanically on every future change; looking at the rendered screen catches what a test assertion can't (a placeholder glyph, a clipped icon, invisible text in dark mode).
360×640 (phone) · 430×932 (large phone) · 640×360 landscape · 768×1024 (tablet) — each at text scale 1.0 and 2.0, and in dark mode.
Flutter (verified, Flutter 3.41.6 — 11/11 green after the fix below):
const sizes = <String, Size>{
'phone 360x640': Size(360, 640),
'large phone 430x932': Size(430, 932),
'landscape 640x360': Size(640, 360),
'tablet 768x1024': Size(768, 1024),
};
for (final e in sizes.entries) {
for (final scale in [1.0, 2.0]) {
testWidgets('PriceRow at ${e.key}, text x$scale, dark', (tester) async {
tester.view.physicalSize = e.value * 3;
tester.view.devicePixelRatio = 3;
tester.platformDispatcher.textScaleFactorTestValue = scale;
addTearDown(tester.view.reset);
addTearDown(tester.platformDispatcher.clearAllTestValues);
final handle = tester.ensureSemantics();
await tester.pumpWidget(host(PriceRow(title: longRealisticTitle, price: '1.299,00 TL', onAdd: () {}),
brightness: Brightness.dark));
expect(tester.takeException(), isNull); // overflow = FlutterError here
await expectLater(tester, meetsGuideline(androidTapTargetGuideline));
await expectLater(tester, meetsGuideline(iOSTapTargetGuideline));
await expectLater(tester, meetsGuideline(labeledTapTargetGuideline));
handle.dispose();
});
}
}
Verified result: Row[Expanded(title), price, IconButton] passes every case at text 1.0. At text 2.0 it fails — "A RenderFlex overflowed by 82 pixels on the right" at 360 (122 at 320, 12 at 430). The fix that passes all cases: wrap in LayoutBuilder; if constraints.maxWidth < 280 * MediaQuery.textScalerOf(context).scale(1), render Column[title, Row[Expanded(price), IconButton]] instead of the single Row. This is the ❌/✅ worked example for both this skill and mobile-ui-ux.
Compose: DeviceConfigurationOverride(ForcedSize(DpSize(360.dp, 640.dp)) then FontScale(2f) then DarkMode(true)) { ... } around the composable under test, repeated per matrix cell.
SwiftUI: #Preview with .environment(\.dynamicTypeSize, .accessibility3), .preferredColorScheme(.dark) and traits: .landscapeLeft (typechecks against the iOS 18 simulator SDK — verified) — plus snapshot tests if the repo already has them.
Pick the first path that applies:
(a) Host-local emulator/simulator — your own build.
mobile_launch_app {repository_id} — this takes the device lease and installs the build registered on the deploy target (the stage build), not your branch.flutter build apk --debug
adb devices
adb -s <serial> uninstall <pkg> # only needed on INSTALL_FAILED_UPDATE_INCOMPATIBLE
adb -s <serial> install build/app/outputs/flutter-apk/app-debug.apk
adb -s <serial> shell monkey -p <pkg> -c android.intent.category.LAUNCHER 1
Native Android: ANDROID_SERIAL=<serial> ./gradlew installDebug.flutter build ios --simulator --debug
xcrun simctl install <udid> build/ios/iphonesimulator/Runner.app
xcrun simctl launch <udid> <bundle-id>
Native iOS: xcodebuild -scheme <S> -destination 'id=<udid>' -derivedDataPath build build, then simctl install the .app.mobile_wait_for the new element → mobile_screenshot → mobile_rotate {orientation: landscape} → mobile_screenshot → mobile_rotate {orientation: portrait}.adb shell settings put system font_scale 2.0 and adb shell cmd uimode night yes; reset with font_scale 1.0 and night no.xcrun simctl ui <udid> content_size accessibility-extra-extra-extra-large and xcrun simctl ui <udid> appearance dark (simctl options verified). Reset with content_size large and appearance light.mobile_read_ui {filter: "clickable=\"true\""} — see below.mobile_release_device as your last mobile step.(b) Remote/shared phone with no local install path. It shows the stage build only — use (c) or (d) to see your own change; say so in the closing message.
(c) Flutter widget previewer (no device needed, verified). Add @Preview(name: 'phone dark 2x', size: Size(360, 640), brightness: Brightness.dark, textScaleFactor: 2.0) beside the widget (import 'package:flutter/widget_previews.dart'). Run mkdir -p /tmp/tt-<task key> && flutter widget-preview start --web-server > /tmp/tt-<task key>/preview.log 2>&1 &. The log prints lib/main.dart is being served at http://localhost:<port>; then browser_navigate → browser_screenshot. The previewer runs on the web: a widget touching dart:io or a plugin needs a fake in the preview.
(d) Native screenshots over loopback. Start a loopback server over the screenshot directory, e.g. mkdir -p /tmp/tt-<task key> && python3 -m http.server 8799 --bind 127.0.0.1 -d <dir> > /tmp/tt-<task key>/shots.log 2>&1 & (py -3 instead of python3 on Windows). Then browser_navigate http://127.0.0.1:8799/<file>.png → browser_screenshot. file:// is refused by the browser guard; loopback http is allowed by default.
If a device call reports the device busy, stop: the task is parked and resumes by itself — do not retry in a loop.
mobile_read_ui {filter: "clickable=\"true\""}. Every line needs a non-empty text or content-desc; bounds ≥48dp × (dpi/160) px on Android, ≥44pt on iOS. Verify the line-per-node shape on first use — the exact field names can differ by platform.
Collect every finding from every matrix cell before touching code. Fix everything from the batch in one pass, then re-run the full matrix once. At most two rounds total — whatever is still open after round two goes into the closing message, honestly, rather than triggering a third silent pass.
Name the render path used (device-own-build / device-stage-only / previewer / simulator) and, for each matrix size checked, what you saw. A known gap reported honestly is not a failure; an unverified claim of "done" is.
mobile_launch_app (with no own-build install) as proof of your change — it's the stage build.--update-goldens or regenerating a snapshot to make a red matrix test green.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.