.agents/skills/android-ui-visual-review/references/analysis-playbook.md
Use this reference to turn a code diff into a minimal but complete screenshot matrix.
For a PR, “before” is the merge-base of the fetched PR head and its configured
base branch. It is not necessarily the PR's current baseRefOid, the local
main, or the commit immediately preceding the head.
For a branch or commit, confirm the intended base. Compute the merge-base after fetching both sides.
Record both SHAs before any checkout. Build each SHA rather than attempting to reverse selected files on a single build.
Start broad:
git diff --stat "$BEFORE_SHA" "$AFTER_SHA"
git diff --name-status "$BEFORE_SHA" "$AFTER_SHA"
git diff "$BEFORE_SHA" "$AFTER_SHA" -- app/src/main app/src/debug
Then classify changed files.
| Diff area | Likely visual impact |
|---|---|
ui/*.kt, composables, modifiers, layouts | Direct screen/layout change |
ui/theme/*, colors, shapes, typography | Cross-screen theme change |
res/values*, drawables, mipmaps | Text, locale, icon, launcher, or palette |
| Manifest locale/theme/activity metadata | System or activity presentation |
DataManager, preferences, defaults | Fresh-install/default-state change |
AppStateStore, ViewModel/state flows | UI changes only after specific state |
| Service/transport/backend only | Usually no static UI delta; trace exposed state |
src/debug or Android tests | Fixture/test mechanism, not production UI |
Do not stop at filenames. Search every changed public symbol and resource:
rg -n "<ChangedSymbol|resource_name>" app/src
Trace in both directions:
These are orientation points, not a substitute for inspecting the current revision:
| Surface | Starting points |
|---|---|
| App launch/navigation/permissions | MainActivity.kt, ui/ChatScreen.kt |
| Top bar, nickname, peer/channel/location controls | ui/ChatHeader.kt |
| Message rows, bubbles, timestamps, media | ui/MessageComponents.kt |
| App state consumed by Compose | services/AppStateStore.kt, ViewModels |
| Default nickname/preferences | ui/DataManager.kt |
| About and Settings | ui/AboutSheet.kt |
| Location/geohash/channel controls | ui/LocationChannelsSheet.kt |
| Hotspot UI | hotspot/HotspotActivity.kt |
| Dynamic/fallback colors and shapes | ui/theme/Theme.kt, ThemePreference.kt |
| Debug ADB hooks | src/debug/.../testhook/TestHookReceiver.kt, TestHookDriver.kt |
Files and packages can move. Use rg --files and symbol search to re-establish
the current map at the target commits.
Some visual changes appear far away from the edited function:
Write these as explicit hypotheses before capture. Each hypothesis needs either a matrix row or a documented reason it cannot be shown statically.
Keep the matrix small enough to review but large enough to hit every changed branch.
| Field | What to record |
|---|---|
| Surface | Human-readable screen/component |
| Entry path | Actions from launch to the target |
| Fixture | Messages, peer, channel, setting, or empty state |
| Platform | Android API feature needed, such as dynamic color |
| Width | Logical dp breakpoint |
| Theme | System/light/dark |
| Locale | System/default or selected locale |
| Expected before | Specific visual contract |
| Expected after | Specific visual contract |
| Control | State expected not to change, when useful |
Examples:
A static screenshot can prove rendering, layout, labels, selected state, and visible recreation. It cannot prove:
Name those limitations. Use relevant unit/instrumented tests or the repository's Mesh Lab workflow separately.
Treat these as expected noise unless the PR changes them:
Stabilize or disclose the noise. Never describe it as a PR effect.