The failure mode of every watcher ever built is that it quietly stops watching. The page moves, the selector breaks, the fetch starts returning a cookie banner, and the system reports no changes for eighteen months because it is reading nothing. This post is mostly about that.
Key takeaways
Anchor on the label, not the markup. “Standard rate” survives a redesign; a CSS path does not.
Every fetch stores a snapshot, so a change can be evidenced eighteen months later.
A source that becomes unreadable raises an alarm. Silence is the dangerous outcome.
PDFs are read the same way as pages, through Textract, and change less often.
The model reads the page; the comparison is plain equality on a number.
How a page gets read
Fig 1. How one source is read on a schedule. The digest check means the model is only involved on the rare days a page actually changes, and a missing label is an alarm rather than an assumption.
Storage
App integration
Machine learning
Management
Analytics
Outside AWS
Anchoring on the label
The naive approach is a CSS selector or an XPath, and it breaks on the first redesign, which for a government site is roughly annual. The robust approach is to describe what you are looking for in words — “the standard rate percentage” — and ask the model to find it in the page text.
That survives a redesign, a table becoming a list, and a value moving between paragraphs. What it does not survive is the label itself changing, which is exactly right: if a page stops describing something as the standard rate, that is a real event and a human should look at it. So a missing label is an alarm, not a silent zero.
Why the snapshot is kept
Two reasons, and the second is the one people do not anticipate. The first is audit: when somebody asks in eighteen months why a rate was applied from a particular date, the answer should be a stored copy of the page as it read on that date, not a memory and a link to a page that has since changed.
The second is debugging the watcher itself. When a source starts producing a value that looks wrong, having the last thirty snapshots means you can see exactly when the page changed shape. Content-addressed storage means thirty daily snapshots of an unchanged page cost one object, not thirty.
The failure mode that matters
Fig 2. The five ways a watcher stops working, and why the last one needs a separate mechanism. Nothing inside a system that is not running can report that it is not running.
Networking
Security & identity
Management
Analytics
The last one deserves the emphasis. Every other failure produces a message from inside the system; a system that is not running produces nothing, which is indistinguishable from a quiet month. So the register carries a last_checked timestamp per row, and a separate scheduled job — a different rule, in a different function — alarms if any row has not been checked in three days.
That is a small amount of duplication and it is the difference between a watcher and the appearance of one.
PDFs
A good proportion of authoritative rate schedules are PDFs, often several hundred pages of them. They are handled the same way: fetch, digest, and only if the bytes changed do they go through Textract and the same label-anchored read. PDFs change less often than pages, which makes the digest short-circuit even more effective, and when they do change it is usually a whole new document with a new URL — which the redirect and link-following logic has to handle.
Next: what the differ does with a change, and why the effective date matters more than the value.