Detection is arithmetic.
Judgement is a person.
Nothing about whether your list changed is decided by a model. We fetch, strip, hash and compare — and where that produces something ambiguous, a named reviewer resolves it before it reaches you. This page explains exactly how, because a compliance record you cannot check is worth very little.
Four steps, and none of them guess.
The same sequence runs against your own stack and against every vendor in the register. It is deliberately boring, because boring is what makes a record defensible a year later.
The page is retrieved politely, with the response code, byte count and timestamp recorded whether it succeeds or not.
Everything that is not the list is removed by a versioned normaliser, so presentation churn can never look like a change.
Two hashes per check — one for the page, one for the set of named entities. Only the second one can raise an alarm.
Added, removed, relocated, renamed, repurposed — or held for review. Every outcome is dated and written to the ledger.
Most of a page is noise.
A vendor edits their sub-processor page constantly without touching the list: a new cookie banner, a rebuilt template, a refreshed “last updated” date, rows reordered alphabetically. All of it is discarded before anything is compared.
This is why the alert you get means something. A watcher that fires on every edit gets muted inside a week, and then it protects nobody.
- Navigation, headers and footers
- Cookie and consent banners
- Class names, inline styles, markup churn
- “Last updated” stamps and CSRF nonces
- Whitespace, non-breaking spaces, punctuation
- Row order — the entity set is sorted before hashing
- Duplicate rows for the same entity
Two hashes, and only one of them can wake you up.
Page hash
never alertsCovers the whole cleaned document. It moves whenever anything on the page moves, which is often and usually meaningless.
page changed · list did not
Kept because it tells us the vendor is still maintaining the page at all. Used for nothing else.
Entity hash
the only triggerCovers the sorted set of named entities and their stated values. Order-independent by construction, so reshuffling rows changes nothing.
list changed · 28 → 29 entities
If this hash is unchanged, nothing is published, no matter how much of the page was rewritten.
We attack our own detector, on real pages.
Twenty real vendor pages, eight kinds of harmless edit applied to each, and a rule that none of them may produce a published change. Then five kinds of real movement, which all must be caught with the correct class.
Our own measurements, run against live vendor pages. The harness and its numbers are re-run on every change to the detector.
- Whitespace and indentation changes
- A cookie banner injected
- Class and style attribute churn
- The “last updated” date refreshed
- An analytics tag added
- A CSRF nonce rotated
- Rows reordered
- Non-breaking space padding
- An entity added
- An entity removed
- A country changed
- An entity renamed — matched, not reported as one in and one out
- A mass removal — quarantined rather than published
Four things the arithmetic cannot settle.
These are the cases that make an automated feed untrustworthy, and they are the reason a named reviewer sits between the detector and you.
“Amazon Web Services, Inc.”, “AWS” and “Amazon Web Services EMEA SARL” are one relationship or three, depending on the contract. A machine cannot tell which.
A vendor moves to a new template and eighteen entities appear at once. That is not eighteen new sub-processors, and publishing it as such would be the most damaging thing we could do.
A marketing tag on a website is not a sub-processor under your DPA. Deciding what actually touches customer data inside a product is a judgement, and we record who made it.
A vendor is bought and every entity is renamed on the same day. Rename matching catches most of it; a person confirms the rest before anyone is told their supply chain changed.
Verify us rather than trust us.
Every check, change and decision is appended to a hash-chained ledger as it happens. Each row carries the hash of the row before it, so an entry cannot be altered or back-dated without breaking every row that follows.
The verification endpoint is public and unauthenticated. Anyone — you, your auditor, a customer of yours — can check a record without an account.
A single ledger row
publicprev c7a4e1b09d33
at 2026-08-17T06:12:04Z
kind change.published
subject atlassian.com
payload sha256:8e12721fbc…
row_hash = sha256(prev_hash || timestamp || kind || subject || payload)
We publish our own gaps.
A register that only reports its wins is not a register. Every page states how we read that business, and where we cannot, it says so rather than showing you something stale.
| How the list is published | Share | What we do | Status |
|---|---|---|---|
| HTML table | 72% | Read and compared entity by entity, daily | full coverage |
| HTML list or prose | 12% | Read with a confidence score shown on the page | full coverage |
| PDF document | 9% | Parsed on the same pipeline | rolling out |
| Trust centre needing a browser | 5% | Flagged on the page; forward the vendor’s notice and the record stays complete | in progress |
| Behind a customer login | 2% | Marked no longer public, with the last public capture kept and dated | by design |
What we will never tell you.
This product could be built as an accusation engine. It is deliberately not.
- That you are compliantWe publish observations and dated records. Whether they satisfy your obligations is a question for you and your counsel.
- That a vendor is in breachWe do not write “undisclosed” and we do not infer intent. A page changed, on a date, and here is the evidence.
- That a deadline is runningUnless it comes from a contract you gave us. Anything else is labelled as a standard-clause illustration.
- Anything a model decidedModels may suggest a candidate page or draft a summary, both labelled. None can create, alter or suppress a record.
Now let us run it against your stack.
Free discovery, a named reviewer, and nothing published until you approve it.