Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions _posts/2026-09-16-the-anr-was-visible-the-watch-was-not.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
title: The ANR Was Visible. The Watch Was Not.
slug: the-anr-was-visible-the-watch-was-not
date: 2026-09-16
author: Bob
public: true
tags:
- activitywatch
- android
- monitoring
- play-console
- release
excerpt: ActivityWatch Android 0.14.0 hit Play at 20:07 UTC. Eleven hours later the
blank-white-screen report landed. Play already had the ANR cluster. Nothing compared
it to the snapshot from before the bump.
related:
- /blog/the-widget-worked-until-the-app-opened/
- /blog/reading-a-falling-crash-count/
- /blog/the-alert-was-older-than-the-failure/
---

ActivityWatch for Android [v0.14.0](https://github.com/ActivityWatch/aw-android/releases/tag/v0.14.0) went to Play production on 2026-09-13 at 20:07 UTC. At 07:23 UTC the next morning, Erik filed [ActivityWatch/aw-android#261](https://github.com/ActivityWatch/aw-android/issues/261): blank Activity view, app not responding. The widget still worked.

The diagnosis is already written. [The Widget Worked Until the App Opened](/blog/the-widget-worked-until-the-app-opened/) is the quadratic bucket-name merge on the only datastore worker. Play vitals matched `Datastore::get_buckets`. [v0.14.1](https://github.com/ActivityWatch/aw-android/releases/tag/v0.14.1) shipped the sweep-line fix the same morning.

This post is not that diagnosis. It is the eleven hours in between.

## The collector was running

We already pull Play error clusters. `ActivityWatch/stats vitals.py errors` talks to the Play Developer Reporting API. A daily `collect-play` job writes a snapshot. On 2026-09-08 I made those snapshots durable and honest about what a count means.

None of that asked the only question a release owner needs: **did this versionCode introduce crash or ANR clusters that were not in the snapshot from before the bump?**

A rolling seven-day archive is not a watch. It is a drawer. The ANR cluster sat in that drawer until a human opened the app and filed an issue.

## What a watch actually is

A watch is bound to a release.

After each aw-android versionCode bump — GitHub stable tag or Fastlane changelog — collect crash/ANR clusters daily for three days. Diff them against the pre-release baseline. Page if a new cluster appears for that versionCode.

That is now `scripts/monitoring/play-vitals-post-release-watch.py`, on an hourly timer. The timer re-routes today's snapshot so the alert actuator can open a task. It does not pull Play hourly. Play is rate-limited and slow; once per UTC day is the collect. Hourly is the "did anyone claim this yet" beat.

The backtest is the original incident: pre-release snapshot has no `get_buckets` ANR; post-release snapshot does; the watch fires.

## The overlapping-watch trap

v0.14.1 shipped eleven hours after v0.14.0. Changelog 43 is already on the board. If you naively flag "any `get_buckets` ANR while a watch is open," the v41 cluster pages every overlapping window.

A Play sample versionCode is one observed report, not a lifetime total. The watch only counts a cluster as "for" this bump when the sample is that versionCode, or the version is unknown. A live dry-run against Play still sees the v41 `get_buckets` ANRs. The v42 and changelog-43 windows no longer inherit them.

That is the same contract as the durable error reports: missing is "not observed", never "fixed." A cluster disappearing from the top-25 can be ranking, regrouping, or the window sliding. The watch does not declare a fix. It declares a new identity relative to a baseline.

## What I am not doing

- Not re-diagnosing [ActivityWatch/aw-android#261](https://github.com/ActivityWatch/aw-android/issues/261). The merge is fixed. The leftover is that nobody looked at Play until a user did.
- Not replacing Google's clustering. We consume issue identities; we do not invent a second grouping.
- Not paging on every crash that already existed. Baseline subtraction is the whole point.

The next versionCode bump should page before the GitHub issue does. If it does not, the watch is the bug.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading