SITEMAP FIX — run this in your browser console on any primaryguard.com page.
It downloads a corrected sitemap.xml which you then paste over public/sitemap.xml on GitHub.

Nothing is changed on the server. It only reads the current sitemap, rewrites it
in memory, and saves a file to your Downloads folder.

=====================================================================
PASTE THIS INTO THE CONSOLE
=====================================================================

(async () => {
  const xml = await (await fetch('/sitemap.xml', {cache:'no-store'})).text();
  const TODAY = '2026-08-17';

  // --- edr-siem: npro is gone, splunk replaces it -------------------
  const EDR_OUT = ['npro-vs-sophos','crowdstrike-vs-npro','npro-vs-sentinelone','huntress-vs-npro',
    'defender-vs-npro','npro-vs-threatdown','cynet-vs-npro','npro-vs-stellar','eset-vs-npro',
    'bitdefender-vs-npro','npro-vs-trendmicro','arcticwolf-vs-npro','npro-vs-paloalto','elastic-vs-npro'];
  const EDR_IN = ['arcticwolf-vs-splunk','bitdefender-vs-splunk','crowdstrike-vs-splunk','cynet-vs-splunk',
    'defender-vs-splunk','elastic-vs-splunk','eset-vs-splunk','huntress-vs-splunk','paloalto-vs-splunk',
    'sentinelone-vs-splunk','sophos-vs-splunk','splunk-vs-stellar','splunk-vs-threatdown','splunk-vs-trendmicro'];

  // --- web-security-cdn: barracuda is gone, bunny replaces it -------
  const WAF_OUT = ['barracuda-vs-cloudflare','akamai-vs-barracuda','barracuda-vs-imperva','barracuda-vs-radware',
    'awswaf-vs-barracuda','barracuda-vs-f5','barracuda-vs-fortiweb','barracuda-vs-tencent','azurewaf-vs-barracuda',
    'barracuda-vs-fastly','barracuda-vs-paloaltowaf','barracuda-vs-sucuri','barracuda-vs-gcarmor','barracuda-vs-zscaler'];
  const WAF_IN = ['akamai-vs-bunny','awswaf-vs-bunny','azurewaf-vs-bunny','bunny-vs-cloudflare','bunny-vs-f5',
    'bunny-vs-fastly','bunny-vs-fortiweb','bunny-vs-gcarmor','bunny-vs-imperva','bunny-vs-paloaltowaf',
    'bunny-vs-radware','bunny-vs-sucuri','bunny-vs-tencent','bunny-vs-zscaler'];

  const dead = new Set([
    ...EDR_OUT.map(s => '/battlecards/edr-siem/' + s),
    ...WAF_OUT.map(s => '/battlecards/web-security-cdn/' + s),
  ]);

  // split into <url> blocks, drop the dead ones
  const blocks = xml.split(/(?=<url>)/);
  let removed = 0;
  const kept = blocks.filter(b => {
    const m = b.match(/<loc>([^<]+)<\/loc>/);
    if (!m) return true;
    const path = m[1].replace('https://primaryguard.com', '');
    if (dead.has(path)) { removed++; return false; }
    return true;
  });

  const entry = (pillar, slug) =>
    `  <url>\n    <loc>https://primaryguard.com/battlecards/${pillar}/${slug}</loc>\n` +
    `    <lastmod>${TODAY}</lastmod>\n    <priority>0.7</priority>\n  </url>\n`;

  const added = [
    ...EDR_IN.map(s => entry('edr-siem', s)),
    ...WAF_IN.map(s => entry('web-security-cdn', s)),
  ].join('');

  let out = kept.join('');
  out = out.replace('</urlset>', added + '</urlset>');

  const total = (out.match(/<loc>/g) || []).length;
  console.log('removed:', removed, '(expected 28)');
  console.log('added:  ', EDR_IN.length + WAF_IN.length, '(expected 28)');
  console.log('total URLs now:', total, '(expected 1501)');
  console.log('npro left:', (out.match(/edr-siem\/[a-z0-9-]*npro/g) || []).length, '(expected 0)');
  console.log('barracuda left:', (out.match(/web-security-cdn\/[a-z0-9-]*barracuda/g) || []).length, '(expected 0)');
  console.log('barracudangfw untouched:', (out.match(/barracudangfw/g) || []).length, '(expected 14 — network-infrastructure, leave alone)');

  const a = document.createElement('a');
  a.href = URL.createObjectURL(new Blob([out], {type:'application/xml'}));
  a.download = 'sitemap.xml';
  a.click();
  console.log('%cDownloaded sitemap.xml — check the numbers above before committing.', 'color:green;font-weight:bold');
})();

=====================================================================
EXPECTED OUTPUT
=====================================================================
  removed: 28 (expected 28)
  added:   28 (expected 28)
  total URLs now: 1501 (expected 1501)
  npro left: 0 (expected 0)
  barracuda left: 0 (expected 0)
  barracudangfw untouched: 14 (expected 14 - network-infrastructure, leave alone)

If any number differs, STOP and send me the output. Do not commit.

=====================================================================
THEN
=====================================================================
1. Open the downloaded sitemap.xml in a text editor
2. GitHub -> public/sitemap.xml -> edit -> select all -> paste -> commit
   Commit message: Fix sitemap - npro to splunk, barracuda to bunny

3. Separately, in src/data/battlecardVendors.ts, inside "web-security-cdn":
   FIND:     { id: "barracuda", nm: "Barracuda WAF" },
   REPLACE:  { id: "bunny", nm: "bunny.net Shield" },
   (leave "barracudangfw" in network-infrastructure alone - different product)

=====================================================================
WHY THIS KEEPS HAPPENING
=====================================================================
sitemap.xml is a hand-maintained static file in public/. It is NOT generated
from battlecardVendors.ts. You can see the drift in the file itself - blocks
dated 2026-06-26, 06-29 and 07-01, then hand-added one-line entries at the
bottom in a different format with no lastmod.

So edr-siem vendor names now live in FIVE places:
  1. public/sitemap.xml                      (hand-maintained)
  2. src/data/battlecardVendors.ts
  3. src/components/EDRSIEMBattlecard.tsx
  4. src/pages/EDRComparisonPage.tsx
  5. src/pages/BattlecardPage.tsx            (header copy)

Until the sitemap is generated at build time from battlecardVendors.ts, this
will drift again on the next vendor change. That is the real fix and it is a
separate piece of work - a small Node script run at build, in the same style
as inject-battlecard-meta.mjs.
