[object Object]

← back to Homesonspec

mobile: make the tracker-drift canary baseline-aware (was firing on steady state)

ba37b54c863feed2dc7bd3229cae79559b938388 · 2026-09-04 11:53:46 -0700 · Steve

As first written the canary exited 1 whenever ANY uncovered third-party host was
present — which is permanently true, because homesonspec.com serves listing photos
from www.drhorton.com and awh.widen.net. A canary that fires on the steady state is
noise and gets ignored, which is the one failure mode that makes it worthless.

Now baseline-aware, per house canary doctrine: known-benign hosts live in
tracker-drift-baseline.json, are reported as 'accepted', and do NOT fail. Exit 1
fires only on a host that is NEW since the baseline — an actual worsening transition.
Adds --accept to fold a newly verified asset host into the baseline.

Baseline seeded with the two hosts verified 2026-09-04 by inspecting the page source:
both appear only as <img src> listing photos (D.R. Horton product catalogue, Widen
DAM CDN), so they are asset hosts, not trackers.

Verified both directions, not just the quiet one:
  steady state          -> PASS, exit 0
  simulated new host    -> FAIL, names www.drhorton.com, exit 1
  baseline restored     -> PASS, exit 0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEhnWQSSkAhSYxWXHJ3MCw

Files touched

Diff

commit ba37b54c863feed2dc7bd3229cae79559b938388
Author: Steve <steve@designerwallcoverings.com>
Date:   Fri Sep 4 11:53:46 2026 -0700

    mobile: make the tracker-drift canary baseline-aware (was firing on steady state)
    
    As first written the canary exited 1 whenever ANY uncovered third-party host was
    present — which is permanently true, because homesonspec.com serves listing photos
    from www.drhorton.com and awh.widen.net. A canary that fires on the steady state is
    noise and gets ignored, which is the one failure mode that makes it worthless.
    
    Now baseline-aware, per house canary doctrine: known-benign hosts live in
    tracker-drift-baseline.json, are reported as 'accepted', and do NOT fail. Exit 1
    fires only on a host that is NEW since the baseline — an actual worsening transition.
    Adds --accept to fold a newly verified asset host into the baseline.
    
    Baseline seeded with the two hosts verified 2026-09-04 by inspecting the page source:
    both appear only as <img src> listing photos (D.R. Horton product catalogue, Widen
    DAM CDN), so they are asset hosts, not trackers.
    
    Verified both directions, not just the quiet one:
      steady state          -> PASS, exit 0
      simulated new host    -> FAIL, names www.drhorton.com, exit 1
      baseline restored     -> PASS, exit 0
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01SEhnWQSSkAhSYxWXHJ3MCw
---
 apps/mobile/scripts/tracker-drift-baseline.json |  7 ++++
 apps/mobile/scripts/tracker-drift-check.mjs     | 43 +++++++++++++++++++------
 2 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/apps/mobile/scripts/tracker-drift-baseline.json b/apps/mobile/scripts/tracker-drift-baseline.json
new file mode 100644
index 00000000..42cf2cac
--- /dev/null
+++ b/apps/mobile/scripts/tracker-drift-baseline.json
@@ -0,0 +1,7 @@
+{
+  "acceptedHosts": [
+    "awh.widen.net",
+    "www.drhorton.com"
+  ],
+  "note": "Verified 2026-09-04 (TK-11155) by inspecting homesonspec.com source: both appear only as <img src> listing photos \u2014 D.R. Horton's product catalogue and the Widen DAM CDN. Asset hosts, not trackers. Re-verify if their usage ever changes."
+}
\ No newline at end of file
diff --git a/apps/mobile/scripts/tracker-drift-check.mjs b/apps/mobile/scripts/tracker-drift-check.mjs
index 5529aa70..8b917b2d 100644
--- a/apps/mobile/scripts/tracker-drift-check.mjs
+++ b/apps/mobile/scripts/tracker-drift-check.mjs
@@ -10,15 +10,26 @@
  * On an account already cited under Guideline 5.6 for a declaration that did not match a
  * binary, that is the drift we cannot afford. This flags it.
  *
- * READ-ONLY. Exit 0 = clean, 1 = drift found.  Usage: node scripts/tracker-drift-check.mjs
+ * BASELINE-AWARE (house canary doctrine): a canary that fires on the steady state is
+ * noise and gets ignored. Known-benign third-party hosts (listing-photo CDNs) live in
+ * tracker-drift-baseline.json and are reported but do NOT fail. Exit 1 fires only on a
+ * host that is NEW since the baseline — i.e. an actual worsening transition.
+ *
+ * READ-ONLY. Exit 0 = no new hosts, 1 = NEW uncovered host.  node scripts/tracker-drift-check.mjs
+ *   --accept   after verifying a flagged host is a harmless asset/CDN, add it to the baseline
  */
 import { readFileSync } from 'node:fs';
 import { fileURLToPath } from 'node:url';
 import { dirname, join } from 'node:path';
+import { existsSync, writeFileSync } from 'node:fs';
 
 const here = dirname(fileURLToPath(import.meta.url));
 const policy = readFileSync(join(here, '..', 'lib', 'tracker-policy.ts'), 'utf8');
 const DENYLIST = [...policy.matchAll(/'([a-z0-9.-]+\.[a-z]{2,})'/g)].map(m => m[1]);
+const BASELINE_PATH = join(here, 'tracker-drift-baseline.json');
+const baseline = existsSync(BASELINE_PATH)
+  ? JSON.parse(readFileSync(BASELINE_PATH, 'utf8'))
+  : { acceptedHosts: [], note: '' };
 const SITE = process.env.HOS_SITE || 'https://homesonspec.com';
 const FIRST_PARTY = new URL(SITE).hostname.replace(/^www\./, '');
 
@@ -33,16 +44,28 @@ const hosts = [...new Set([...html.matchAll(/https?:\/\/([a-z0-9.-]+)/gi)].map(m
 const uncovered = hosts.filter(h => !isFirstParty(h) && !onDenylist(h));
 const covered = hosts.filter(onDenylist);
 
+const accepted = uncovered.filter(h => baseline.acceptedHosts.includes(h));
+const novel   = uncovered.filter(h => !baseline.acceptedHosts.includes(h));
+
+if (process.argv.includes('--accept')) {
+  const merged = [...new Set([...baseline.acceptedHosts, ...uncovered])].sort();
+  writeFileSync(BASELINE_PATH, JSON.stringify({ ...baseline, acceptedHosts: merged }, null, 2) + '\n');
+  console.log(`baseline updated — ${merged.length} accepted host(s): ${merged.join(', ')}`);
+  process.exit(0);
+}
+
 console.log(`site: ${SITE}`);
 console.log(`denylist (${DENYLIST.length}): ${DENYLIST.join(', ')}`);
-console.log(`\nBLOCKED third-party hosts present on the page (${covered.length}): ${covered.join(', ') || '(none)'}`);
-console.log(`\nUNCOVERED third-party hosts — these would NOT be blocked (${uncovered.length}):`);
-uncovered.forEach(h => console.log(`  ⚠️  ${h}`));
-
-if (uncovered.length) {
-  console.log(`\nVERDICT: WARN — review each host above. If any transmits user/usage data, the`);
-  console.log(`"Data Not Collected" label is no longer accurate: add it to TRACKER_HOSTS and rebuild,`);
-  console.log(`or amend the App Privacy label. Purely static asset/CDN/font hosts are fine.`);
+console.log(`\nBLOCKED trackers present on the page (${covered.length}): ${covered.join(', ') || '(none)'}`);
+console.log(`accepted asset hosts, baselined (${accepted.length}): ${accepted.join(', ') || '(none)'}`);
+
+if (novel.length) {
+  console.log(`\nNEW uncovered third-party host(s) — NOT blocked, NOT baselined (${novel.length}):`);
+  novel.forEach(h => console.log(`  \u26a0\ufe0f  ${h}`));
+  console.log(`\nVERDICT: FAIL — a third-party host appeared that the blocker does not cover.`);
+  console.log(`If it transmits user/usage data, "Data Not Collected" is no longer accurate:`);
+  console.log(`add it to TRACKER_HOSTS and REBUILD, or amend the App Privacy label.`);
+  console.log(`If it is a harmless asset/CDN/font host, verify it then run with --accept.`);
   process.exit(1);
 }
-console.log('\nVERDICT: PASS — every third-party host on the page is covered by the denylist.');
+console.log(`\nVERDICT: PASS — every tracker on the page is blocked, and no new third-party host has appeared.`);

← 693125b2 mobile: add tracker-drift canary guarding the 'Data Not Coll  ·  back to Homesonspec  ·  snapshot before restart: preserve in-flight work aaf2c487 →