# Changelog of App Store Review & Rating Monitor (`al_mansouri/app-review-monitor`) Actor

- **URL**: https://apify.com/al_mansouri/app-review-monitor/changelog.md
- **Full Actor documentation**: https://apify.com/al_mansouri/app-review-monitor.md

## Changelog

All notable changes to the App Store Review & Rating Monitor.

### \[0.1.0] - 2026-08-27

First release.

#### Added

- Per-app, per-storefront monitoring of App Store ratings, rating counts and versions, with a
  cross-run baseline in a named key-value store on the customer's own account.
- Derived star value for newly arrived ratings, recovered from Apple's published average and
  count, with a computed error margin and a hard refusal above `MAX_DERIVED_STAR_ERROR` (0.5).
- Change kinds `baseline`, `ratings-added`, `ratings-removed`, `negative-review`, `rating-rose`,
  `rating-fell`, `version-changed`.
- Two charge events, `app-checked` and `reviews-changed`, defined but not priced. A row whose only
  change is a new release is charged as a check, not an alert.
- `versionReleasedAt` on every row, so a rating move can be read against the release that plausibly
  caused it.
- `scripts/run_false_alert_sweep.py`, the measuring instrument behind the listing's central claim.

#### Measured

- **42 checks across 14 apps and 3 storefronts, 90 seconds apart: zero reported movement**
  (2026-08-27). Apple serves the lookup endpoint from a CDN, so the risk was that two reads
  seconds apart disagree and every scheduled run invents a change; they do not.
- The star value of `k` new ratings resolves on any app under roughly **50,000 x k** ratings. That
  boundary is not chosen — it falls out of Apple publishing five decimals and this Actor refusing a
  margin above half a star — and `tests/test_derive.py` holds the README to it.

#### Fixed

- **A run whose baseline store cannot be opened no longer dies.** It used to call `Actor.fail()`,
  so the customer saw a failed run with no output at all. It now degrades: every app is published
  as a first sighting, every row carries the new `STATE_STORE_UNAVAILABLE` warning, and the run
  status message says plainly that nothing in the run is a change. This is why the Actor was
  flagged under maintenance — two of two runs by people other than the author failed outright,
  while every run on the author's own account succeeded.
  It falls back to the run's own key-value store, the same remedy the Website Change Monitor uses,
  spelled the same way so the four monitors do not each invent their own vocabulary for it.
  `STATE_UNAVAILABLE` is now raised only when the named store *and* the run's own store both
  refuse, which leaves no honest degraded mode.

- **A first run now produces rows.** With `onlyReportChanges` on — the default — a first sighting
  was treated as "nothing changed" and nothing was pushed, so a customer's first run ended with an
  empty dataset. That contradicted this README ("every app is a `baseline` row") and the charge
  tiering, which prices a baseline as a check because "the customer got a starting point out of
  it". Caught by running the deployed Actor against the listing's own example input, which
  reported 4 requested and 0 rows. A first sighting is now published; a genuinely quiet check
  still publishes nothing.

#### Deliberately not included

- **The customer-review feed.** Apple's `robots.txt` carries `Disallow: /*/rss/*`, which covers
  `/<cc>/rss/customerreviews/...`. This Actor reads only the lookup endpoint, which no rule there
  covers, and derives what it would otherwise have scraped. Do not add the feed.
- **Google Play.** The record model and the `stores/` package are platform-neutral so an Android
  reader can land without altering a published field, but the Play listing is embedded JSON in a
  1.3 MB HTML page rather than an official endpoint, and it is deferred rather than dropped.
