# Changelog of Website Change Monitor with Smart Diff (`al_mansouri/verified-website-change-monitor`) Actor

- **URL**: https://apify.com/al\_mansouri/verified-website-change-monitor/changelog.md
- **Full Actor documentation**: https://apify.com/al\_mansouri/verified-website-change-monitor.md

## Changelog

All notable changes to this Actor are recorded here. Versions follow the `ACTOR_VERSION` constant
in `src/change_monitor/constants.py`.

### 0.1.0 - unreleased

First working version. Free; charge events are declared but no prices are set.

#### Added

- A run whose saved baseline store cannot be opened now continues instead of failing. It records
  each page fresh in the run's own storage and publishes every row with a
  `STATE_STORE_UNAVAILABLE` warning, and the terminal status message leads with the fact that
  nothing was compared. No page is ever reported as unchanged on such a run, because nothing was
  there to compare it against — the rows are all first sightings, which is what they say.
  Previously the whole run failed, which protected no customer data and cost the listing three
  days of "under maintenance" when Apify's automated quality tests hit it on their own account.
  If the run's own storage is unavailable too, the run still fails: there is no honest degraded
  mode left.
- Checks a list of public URLs and reports `baseline`, `page-checked`, or `change-detected` per
  page per run.
- A noise filter that removes cookie and consent banners, carousels and sliders, ad slots, live
  regions, and rendered timestamps before anything is compared, so a page whose only difference is
  a rotating promo comes back 100% similar.
- Price, percentage, and stock-phrase detection. A change to any of them is reported at every
  sensitivity, however small, and named in `changedSignals`.
- `sensitivity`, `ignoreSelectors`, and `watchSelectors` for narrowing what counts. Changing either
  selector list starts a fresh baseline, because the old capture is no longer comparable.
- Baselines persist between runs in a named key-value store on the customer's own account,
  configurable through `stateStoreName`.
- Guards that report doubt rather than a change: a non-2xx response, a page that collapsed to a
  fraction of its previous size, a watch selector that stopped matching, and a truncated read.
- Three charge events (`page-checked`, `change-detected`, `ai-summary-generated`) wired through
  the shared commit protocol, so monetising later is a price change rather than a redesign.
- `useBrowser` renders pages in Chromium for sites that build their content in JavaScript. Off by
  default, because it costs several times more per page. The destination policy is applied to
  every request the page makes, not just the one asked for, and service workers are blocked so
  they cannot route around it. A failed render falls back to the plain HTML and marks the row
  `warning` rather than failing the check.
- `notifyWebhookUrl` POSTs each change record to an address the customer supplies. Validated
  through the same destination policy as a watched page, on every send rather than once, and
  redirects are refused rather than followed — a redirect is a second destination that nothing
  validated. Only changes are delivered, never the quiet checks.
- `aiApiKey`, `aiModel`, and `aiSummaryLanguage` add a one-sentence summary to detected changes,
  on the customer's own Anthropic or OpenAI key and their own bill. The provider is read from the
  key prefix. Only the diff is sent, never the page, and only on a real change.

#### Notes

- The baseline is advanced only after the row has been published. If that write then fails the next
  run may report the same change again; the run's status message says so. The alternative order
  would lose an alert silently, which is worse.
- A summary that fails is a `AI_SUMMARY_FAILED` warning on a row that still publishes, still
  carries its diff, and is still charged at the change tier rather than the summary tier — billed
  for what it actually carries.
- A webhook that fails is deliberately *not* a warning on the row. The check was fine; only the
  delivery was not, and degrading `status` for a customer's endpoint being down would drain that
  field of the meaning it exists to carry. It is counted in the run's status message instead,
  which is the one failure a webhook cannot report through itself.
