Screen history for a mobile app (Codex)
This repo turns a Revyl Atlas map into a review workflow. Atlas stores a
screenshot of every screen for every build; atlas-review adds diffing,
provenance, blame, approvals and alerting.
The deliverable is one self-contained HTML file: atlas-review report
inlines the raw frames and runs the detector in the browser, so any build pair
can be compared in either direction with adjustable thresholds. $REPO = this
cloned repo's path.
Prerequisites — check first, stop clearly if missing
revyl CLI installed and authenticated. revyl atlas apps lists apps with
their Atlas app ids (UUIDs, not names).
- At least two mapped builds:
revyl build list --app <id> --json. A build
enters Atlas only after something ran against it. An unmapped build is not
"no change" — check emits build_not_mapped. Fix by running a suite:
revyl workflow run <suite> --build <id>.
- Python 3.9+. Dependencies: Pillow, numpy.
Setup
cd $REPO
pip install -e .
atlas-review init --app <app-id> # writes .atlas-review.json
atlas-review builds # verify: #N labels, commit, author, time
atlas-review screens
Run commands from the directory holding .atlas-review.json, or pass
--config. Builds are addressable as #N, a version string, a UUID, or
latest.
Common tasks
atlas-review report --open # the screen-history report
atlas-review report --builds 12 # cap a long history
atlas-review changes --markdown # PR table of what moved
atlas-review diff checkout --from "#2" --to "#5" --mode overlay -o diff.png
atlas-review blame checkout --region 0.8,0.15,0.2,0.8 --method bisect
atlas-review serve # approvals write to review.json
atlas-review check --markdown # CI gate; non-zero at --fail-on
Policy (in .atlas-review.json)
compare_against: "approved" (default) beats comparing to the previous
build — otherwise an unreviewed change becomes the new normal after one build.
- Approving a screen at a build downgrades its alerts to INFO, so an intentional
redesign does not keep CI red.
"ignore_approval": true on a watch region
opts out.
watch boxes are [x, y, w, h] as fractions of the frame; the threshold is a
fraction of the box's own area.
diff.ignore takes status_bar (default), ios_home_indicator,
android_nav_bar, plus arbitrary ignore_boxes.
Gotchas
- Blame answers "when did these pixels change", not "when did this widget
appear" — in a reflowing list a fixed band changes whenever content above it
grows.
- Frames of one screen arrive at different widths from different devices; all
are normalised to one width before measuring.
size_changed means the aspect
changed (rotation / device shape).
- The detector exists twice —
src/atlas_review/diff.py and
src/atlas_review/assets/report.js. Change one, change both, and extend the
JsPythonParity tests. Frames are embedded byte-for-byte; never re-encode.
- Coverage bounds the answer: a screen no test or exploration reaches has no
frames to compare.
Tests
python3 -m unittest discover -s tests # 65 tests, no network, no revyl CLI
1---2name: screenhistory-23description: Set up and drive atlas-review (screenhistory) against a Revyl app: see every past iteration of every screen, diff any two builds in the browser, find the build where something first changed, approve screens, and gate CI on unexpected visual change. Trigger on "show me past versions of this screen", "what changed between these builds", "screen history", "visual review", "visual regression", "when did this button move", or "set up atlas-review".4---56# Screen history for a mobile app (Codex)78This repo turns a Revyl Atlas map into a review workflow. Atlas stores a9screenshot of every screen for every build; `atlas-review` adds diffing,10provenance, blame, approvals and alerting.1112The deliverable is **one self-contained HTML file**: `atlas-review report`13inlines the raw frames and runs the detector in the browser, so any build pair14can be compared in either direction with adjustable thresholds. `$REPO` = this15cloned repo's path.1617## Prerequisites — check first, stop clearly if missing1819- `revyl` CLI installed and authenticated. `revyl atlas apps` lists apps with20 their Atlas app **ids** (UUIDs, not names).21- At least two *mapped* builds: `revyl build list --app <id> --json`. A build22 enters Atlas only after something ran against it. An unmapped build is not23 "no change" — `check` emits `build_not_mapped`. Fix by running a suite:24 `revyl workflow run <suite> --build <id>`.25- Python 3.9+. Dependencies: Pillow, numpy.2627## Setup2829```bash30cd $REPO31pip install -e .32atlas-review init --app <app-id> # writes .atlas-review.json33atlas-review builds # verify: #N labels, commit, author, time34atlas-review screens35```3637Run commands from the directory holding `.atlas-review.json`, or pass38`--config`. Builds are addressable as `#N`, a version string, a UUID, or39`latest`.4041## Common tasks4243```bash44atlas-review report --open # the screen-history report45atlas-review report --builds 12 # cap a long history46atlas-review changes --markdown # PR table of what moved47atlas-review diff checkout --from "#2" --to "#5" --mode overlay -o diff.png48atlas-review blame checkout --region 0.8,0.15,0.2,0.8 --method bisect49atlas-review serve # approvals write to review.json50atlas-review check --markdown # CI gate; non-zero at --fail-on51```5253## Policy (in `.atlas-review.json`)5455- `compare_against: "approved"` (default) beats comparing to the previous56 build — otherwise an unreviewed change becomes the new normal after one build.57- Approving a screen at a build downgrades its alerts to INFO, so an intentional58 redesign does not keep CI red. `"ignore_approval": true` on a watch region59 opts out.60- `watch` boxes are `[x, y, w, h]` as fractions of the frame; the threshold is a61 fraction of the box's own area.62- `diff.ignore` takes `status_bar` (default), `ios_home_indicator`,63 `android_nav_bar`, plus arbitrary `ignore_boxes`.6465## Gotchas6667- Blame answers "when did these pixels change", not "when did this widget68 appear" — in a reflowing list a fixed band changes whenever content above it69 grows.70- Frames of one screen arrive at different widths from different devices; all71 are normalised to one width before measuring. `size_changed` means the aspect72 changed (rotation / device shape).73- The detector exists twice — `src/atlas_review/diff.py` and74 `src/atlas_review/assets/report.js`. Change one, change both, and extend the75 `JsPythonParity` tests. Frames are embedded byte-for-byte; never re-encode.76- Coverage bounds the answer: a screen no test or exploration reaches has no77 frames to compare.7879## Tests8081```bash82python3 -m unittest discover -s tests # 65 tests, no network, no revyl CLI83```