Skip to content

Structure Drift Detection

Vendors sometimes change their changelog page structure or feed format without notice. A heading selector that worked last month might break. An RSS feed might switch to Atom.

Watch Changelog computes a cheap hash of the feed or page shape and compares it to the last known structure. When the hash changes, we flag the source for investigation.

For each source, we compute a SHA-256 hash of:

  • adapterType: rss, atom, github, or html
  • contentType: HTTP Content-Type header (if available)
  • itemKeys: A stable sorted list of feed field names or HTML selectors

Example for an RSS feed:

{
"adapter": "rss",
"content": "application/rss+xml",
"keys": ["description", "link", "pubDate", "title"]
}

Example for an HTML changelog:

{
"adapter": "html",
"content": "text/html",
"keys": [".changelog-entry h3", ".changelog-entry .date", ".changelog-entry a"]
}

The hash is stored in ChangelogSource.structureHash.

When we fetch a source and the computed hash differs from structureHash:

  1. We set structureChangedAt to the current timestamp
  2. We store the new hash
  3. The source is flagged for manual review

This does not automatically mark the source as degraded. It is a signal that the adapter might need updates.

model ChangelogSource {
// ...
structureHash String? // SHA-256 hex of structure shape
structureChangedAt DateTime? // When we detected the hash changed
// ...
}

The structure hash helper is in lib/changelog/structure-hash.ts:

computeStructureHash({
adapterType: "rss",
contentType: "application/rss+xml",
itemKeys: ["title", "link", "pubDate", "description"]
})
// Returns: "a3f8b2..." (SHA-256 hex)

The fetch job (not in this pass) will call this helper and compare the result to the stored hash.

Learn about Health and Billing to understand how degraded sources are handled.