Render Runbook

Purpose: Store renders, compute diffs, and manage retention.


First Diagnostic Question

Is the delta wrong? (false positives, missed changes, reordering noise)

If yes, investigate render and diff logic before summarization.


Inputs

  • Latest section_hashes from tracker
  • Previous render (if any)

Process Steps

1. Render Record

  • Create a lightweight render entry (hashes + timestamps)

2. Diffing

  • Compare section hashes by ID
  • Classify: added / removed / changed / reordered

3. Summarizable Delta

  • Extract only changed sections' normalized snippets (bounded)

4. Retention

  • Keep last N renders (policy-based)
  • Prune older renders without affecting audits

Diagnostic Decision Tree

Render/Diff issue suspected
    │
    ├─ False positives? (changes reported but nothing meaningful changed)
    │   ├─ Reordering detected as change → Section ID stability issue
    │   ├─ Cosmetic changes surfaced → Tracker normalization issue (go to tracker)
    │   └─ Same content, different hash → Hash determinism issue
    │
    ├─ Missed changes? (known changes not detected)
    │   ├─ Change between checks but same hash → Content was reverted
    │   ├─ Section not tracked → New section not captured
    │   └─ Change too small → Below diff threshold
    │
    ├─ Diff inconsistent?
    │   ├─ Same inputs, different output → Non-deterministic comparison
    │   └─ Section ordering affects results → ID-based comparison broken
    │
    └─ Storage issues?
        ├─ Renders not persisting → Database write failure
        ├─ Historical data missing → Retention policy too aggressive
        └─ Corruption suspected → Data integrity check needed

Common Failure Scenarios

False Positives (Noise)

Symptoms:

  • Users receive alerts for trivial or cosmetic changes
  • Reordering triggers change detection
  • Frequent churn on same section

Actions:

  1. Verify against the meaningful change spec
  2. Inspect section hashes for instability (may be tracker issue)
  3. Check if reordering should be suppressed
  4. Increase suppression thresholds if needed

Principle: Silence is preferable to noise.

Missed Changes

Symptoms:

  • Known page changes not surfaced
  • User reports change not detected

Actions:

  1. Confirm change persisted between checks (wasn't reverted)
  2. Review if change fell below detection threshold
  3. Check if section was newly added (baseline issue)
  4. Verify cadence alignment - change may have happened between checks

Diff Non-Determinism

Symptoms:

  • Same URL produces different diffs on re-run
  • Inconsistent delta output

Actions:

  1. Check section ID generation stability
  2. Verify hash comparison is order-independent where appropriate
  3. Review any caching that might affect results
  4. Test with known-stable input

Storage/Retention Issues

Symptoms:

  • Historical renders missing
  • Unable to compute diff (no baseline)
  • Audit trail gaps

Actions:

  1. Check retention policy settings
  2. Verify database writes are succeeding
  3. Review storage quotas
  4. Restore from backup if corruption suspected

Stop Conditions

Hard Stop

Trigger immediately if any are true:

  • Diff output is inconsistent or non-deterministic
  • Render persistence risks corrupting historical state

Action: Treat affected URLs as baseline and halt diff emission.

Degrade Mode

  • Skip diffing and mark run as baseline
  • Preserve raw hashes for later reprocessing

Resume once diff stability is verified.


Signals to Watch

SignalIndicates
Reordering without content changeSection ID instability
Frequent churn in single sectionDynamic content not filtered
Diff output varianceNon-deterministic comparison
Missing historical rendersRetention or storage issue

Database Queries

Check render history for a URL

SELECT id, url_id, section_count, created_at
FROM url_renders
WHERE url_id = '<url_id>'
ORDER BY created_at DESC
LIMIT 10;

Find URLs with high diff frequency

SELECT url_id, COUNT(*) as diff_count
FROM url_changes
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY url_id
ORDER BY diff_count DESC
LIMIT 20;

Check for potential false positives (high churn)

SELECT url_id, COUNT(*) as changes,
       COUNT(DISTINCT DATE(created_at)) as days_with_changes
FROM url_changes
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY url_id
HAVING COUNT(*) > 5
ORDER BY changes DESC;