refactor: decouple from site-specific CDN references #5

Merged
kfj001 merged 11 commits from feature/no_mention_of_pornhub into master 2026-08-30 17:07:52 -07:00
3 changed files with 333 additions and 42 deletions
Showing only changes of commit e3b904783f - Show all commits

No files matched your search

+239
View File
@@ -0,0 +1,239 @@
/**
* referer_proxy.test.mjs — coverage for the background worker's per-CDN-host
* referer capture + DNR proxy-host learning, added in PR #5.
*
* The background worker is not itself a module, so the test transpiles it into
* one (wrapping + top-level-statement `async function` transpile) under a mocked
* `chrome` + `fetch`/`btoa` environment, then exercises the captured listeners
* and the message handler directly.
*
* Covers the three gaps robot flagged:
* (a) closing a tab must NOT wipe the host-keyed `goon_referers` global store,
* (b) two hosts proxied concurrently must each keep their OWN referer (no race
* that leaves host B's referer live for host A -> 412),
* (c) the new referer-capture / proxy-host-learning / onRemoved paths run.
*/
import { describe, it } from './runner.mjs';
import { readFileSync, writeFileSync } from 'node:fs';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { dirname, join } from 'node:path';
import { tmpdir } from 'node:os';
const __dirname = dirname(fileURLToPath(import.meta.url));
const backgroundSource = readFileSync(join(__dirname, '../src/background/background.js'), 'utf8');
// Transpile the top-level-statement worker into an ES module. Wrapping in an
// async IIFE makes its top-level `async function` declarations + `await`-using
// nested functions legal inside a module.
function buildModule(code) {
return `(async () => {\n${code}\n})();\n`;
}
// A fresh mock of the chrome APIs the worker touches. `onBeforeSendHeaders`,
// `onBeforeRequest`, and `tabs.onRemoved` capture their listener so the test can
// drive them; `declarativeNetRequest.updateSessionRules` records the live rules.
function makeChromeEnv() {
const storage = {};
const handlers = { onMessage: [] };
let sessionRules = {};
const webRequest = {
onBeforeSendHeaders: { addListener: (cb) => { handlers.onBeforeSendHeaders = cb; } },
onBeforeRequest: { addListener: (cb) => { handlers.onBeforeRequest = cb; } },
};
const chrome = {
storage: {
local: {
get: async (keys) => {
const out = {};
const arr = Array.isArray(keys) ? keys : (keys === undefined ? Object.keys(storage) : [keys]);
for (const k of arr) if (k in storage) out[k] = storage[k];
return out;
},
set: async (data) => {
for (const [k, v] of Object.entries(data)) storage[k] = v;
},
remove: async (keys) => {
const arr = Array.isArray(keys) ? keys : [keys];
for (const k of arr) delete storage[k];
},
},
},
webRequest,
tabs: {
onRemoved: { addListener: (cb) => { handlers.onRemoved = cb; } },
},
runtime: { onMessage: { addListener: (cb) => { handlers.onMessage.push(cb); } } },
declarativeNetRequest: {
updateSessionRules: async ({ removeRuleIds = [], addRules = [] } = {}) => {
const rm = new Set(removeRuleIds);
sessionRules = Object.fromEntries(
Object.entries(sessionRules).filter(([id]) => !rm.has(id))
);
for (const r of addRules) sessionRules[r.id] = r;
},
},
};
return { chrome, handlers, storage, getSessionRules: () => sessionRules };
}
// Load the worker into a fresh environment. `data:` URLs are cached by Node, so
// the module body (listener registration) would only run once; instead we write
// a uniquely-named temp file per load so each call registers into its own env.
let loadCounter = 0;
async function loadBackground(env) {
global.chrome = env.chrome;
const file = join(tmpdir(), `goon_bg_${process.pid}_${loadCounter++}.mjs`);
writeFileSync(file, buildModule(backgroundSource));
const module = await import(pathToFileURL(file).href);
await module.default;
return module;
}
function videoDetails(tabId, url, referer) {
return {
tabId,
url,
requestHeaders: referer ? [{ name: 'Referer', value: referer }] : [],
};
}
describe('PR#5: per-host referer capture + proxy race', () => {
// (a) Blocking fix: a host-keyed `goon_referers` entry must outlive the close
// of ANY tab — including a different tab.
it('closing a tab does not wipe goon_referers captured for another host', async () => {
const env = makeChromeEnv();
global.chrome = env.chrome;
await loadBackground(env);
// A live source tab captures the provider referer for its CDN host.
const cap = env.handlers.onBeforeSendHeaders;
if (!cap) throw new Error('onBeforeSendHeaders listener was not registered');
await cap(videoDetails(11, 'https://cdnA.example.com/hls/live/seg-1.ts', 'https://pageA.example.com/watch'));
const rA = env.storage['goon_referers']?.['cdna.example.com'];
if (!rA) throw new Error('referer was not captured for cdnA');
if (rA.referer !== 'https://pageA.example.com/watch') {
throw new Error('captured referer wrong: ' + JSON.stringify(rA));
}
// A DIFFERENT tab closes. The per-tab cleanup must NOT remove goon_referers.
await env.handlers.onRemoved(22);
const after = env.storage['goon_referers'];
if (!after || !after['cdna.example.com']) {
throw new Error('closing tab 22 wiped goon_referers — host A referer lost');
}
if (after['cdna.example.com'].referer !== 'https://pageA.example.com/watch') {
throw new Error('closing tab 22 corrupted the host A referer: ' + JSON.stringify(after));
}
});
it('closing the capturing tab itself preserves the referer for later proxy use', async () => {
const env = makeChromeEnv();
global.chrome = env.chrome;
await loadBackground(env);
await env.handlers.onBeforeSendHeaders(
videoDetails(11, 'https://cdnB.example.com/video/x/master.m3u8', 'https://pageB.example.com/v')
);
// The very tab that captured the referer now closes.
await env.handlers.onRemoved(11);
const after = env.storage['goon_referers']?.['cdnb.example.com'];
if (!after) throw new Error('goon_referers for the capturing host was wiped on its own tab close');
if (after.referer !== 'https://pageB.example.com/v') {
throw new Error('capturing-tab close corrupted referer: ' + JSON.stringify(after));
}
});
// (b) Should-fix + coverage: two hosts proxied concurrently must each keep
// their own referer. With a shared rule id + non-atomic install this regressed;
// per-host rule ids + the per-host lock keep them distinct.
it('concurrent proxy fetches for two hosts keep distinct per-host referer rules', async () => {
const env = makeChromeEnv();
let fetchCalls = 0;
global.chrome = env.chrome;
global.fetch = async (url) => {
fetchCalls++;
return {
ok: true,
status: 200,
headers: { get: () => 'application/vnd.apple.mpegurl' },
arrayBuffer: async () => new Uint8Array([0]).buffer,
};
};
await loadBackground(env);
// Two GOON_PROXY_FETCH messages for different CDN hosts, fired together.
const handler = env.handlers.onMessage[env.handlers.onMessage.length - 1];
let respA, respB;
handler({ type: 'GOON_PROXY_FETCH', url: 'https://cdnA.example.com/hls/live/seg-1.ts', referer: 'https://pageA.example.com/watch' }, {}, (r) => { respA = r; });
handler({ type: 'GOON_PROXY_FETCH', url: 'https://cdnB.example.com/hls/live/seg-1.ts', referer: 'https://pageB.example.com/watch' }, {}, (r) => { respB = r; });
await new Promise(r => setTimeout(r, 30)); // let async sends + installs flush
if (!respA || !respA.ok) throw new Error('proxy A failed: ' + JSON.stringify(respA));
if (!respB || !respB.ok) throw new Error('proxy B failed: ' + JSON.stringify(respB));
if (fetchCalls < 2) throw new Error('expected both proxy fetches to run, got ' + fetchCalls);
// Each host must have its OWN installed DNR rule with its OWN referer —
// host A must NOT be served host B's referer (the 412 regression).
const rules = env.getSessionRules();
const ruleA = Object.values(rules).find(r => r.condition?.requestDomains?.includes('cdna.example.com'));
const ruleB = Object.values(rules).find(r => r.condition?.requestDomains?.includes('cdnb.example.com'));
if (!ruleA) throw new Error('no DNR rule installed for cdna; rules=' + JSON.stringify(rules));
if (!ruleB) throw new Error('no DNR rule installed for cdnb; rules=' + JSON.stringify(rules));
if (ruleA.id === ruleB.id) {
throw new Error('cdnA and cdnB shared a DNR rule id -> concurrent race possible');
}
const refA = ruleA.action.requestHeaders?.find(h => h.header.toLowerCase() === 'referer')?.value;
const refB = ruleB.action.requestHeaders?.find(h => h.header.toLowerCase() === 'referer')?.value;
if (refA !== 'https://pageA.example.com/watch') {
throw new Error('cdnA served wrong referer: ' + refA);
}
if (refB !== 'https://pageB.example.com/watch') {
throw new Error('cdnB served wrong referer: ' + refB);
}
if (refA === refB) throw new Error('both hosts got the same referer — cross-host bleed');
});
it('repeated proxy for the same host is idempotent (one rule, one install)', async () => {
const env = makeChromeEnv();
let installs = 0;
env.chrome.declarativeNetRequest.updateSessionRules = async ({ addRules = [] } = {}) => {
for (const r of addRules) installs++;
};
global.chrome = env.chrome;
global.fetch = async () => ({
ok: true, status: 200,
headers: { get: () => 'application/vnd.apple.mpegurl' },
arrayBuffer: async () => new Uint8Array([0]).buffer,
});
await loadBackground(env);
const handler = env.handlers.onMessage[env.handlers.onMessage.length - 1];
const run = async (n) => {
handler(
{ type: 'GOON_PROXY_FETCH', url: 'https://cdnA.example.com/hls/live/seg-1.ts', referer: 'https://pageA.example.com/watch' },
{},
() => {}
);
await new Promise(r => setTimeout(r, 5));
};
await run(1);
const installsAfterFirst = installs;
await run(2);
await run(3);
// Same host + same referer should not re-add the rule on repeat fetches.
if (installs !== installsAfterFirst) {
throw new Error(`expected idempotent install, but re-added rule ${installs - installsAfterFirst} extra time(s)`);
}
});
});
+1
View File
@@ -7,6 +7,7 @@ import './data_flow.test.mjs';
import './viewer_integration.test.mjs';
import './config_validation.test.mjs';
import './hls_qa.test.mjs';
import './referer_proxy.test.mjs';
import { run } from './runner.mjs';
const result = await run();
+93 -42
View File
@@ -257,13 +257,17 @@ chrome.webRequest.onBeforeRequest.addListener(
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
{ urls: ['<all_urls>'] }
);
// Clean up stale entries when tabs are closed
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Clean up stale PER-TAB entries when tabs are closed. NOTE: 'goon_referers' is
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// a host-keyed GLOBAL store — it must outlive its capture tab so a proxy fetch
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// for that host still finds its referer after the source tab is closed. It is
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// therefore NOT removed here (only the per-tab vr_requests_/wr_manifests_ keys
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// are). Stale referers are pruned opportunistically in persistReferer.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
chrome.tabs.onRemoved.addListener(async (tabId) => {
const keys = ['wr_manifests_' + tabId, 'vr_requests_' + tabId, 'goon_referers'];
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const keys = ['wr_manifests_' + tabId, 'vr_requests_' + tabId];
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
try {
await chrome.storage.local.remove(keys);
} catch { /* ignore */ }
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
});
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
} catch { /* ignore */ }
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
});
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// === Capture the provider-origin Referer per CDN host (CDN-agnostic) ===
// Some media CDNs reject requests whose `Referer` is not the provider page's
@@ -282,7 +286,21 @@ chrome.tabs.onRemoved.addListener(async (tabId) => {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// GOON_PROXY_FETCH handler then installs a DNR rule that re-inserts that
// captured referer for just that host, so the proxy's fetch() is accepted.
// This requires no knowledge of any particular site.
const REFERER_RULE_ID = 9001;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
//
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Each CDN host gets its OWN declarativeNetRequest rule id so that concurrent
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// proxy fetches for different hosts can't clobber each other's rule (a single
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// shared id + a remove-then-add lets two hosts interleave and leave the wrong
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// host's referer live). The id is derived from the host via a monotonic counter
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// keyed by host, so it is stable for a given host across installs.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
let nextRefererRuleId = 9001;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const refererRuleIds = new Map();
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
function refererRuleIdFor(host) {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const existing = refererRuleIds.get(host);
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
if (existing !== undefined) return existing;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const id = nextRefererRuleId++;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
refererRuleIds.set(host, id);
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
return id;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// host of a URL (CDN host, lowercased); '' when the URL is malformed.
function hostOf(url) {
@@ -306,31 +324,49 @@ function readReferer(headers) {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
return '';
}
// How long a captured referer is trusted before it is pruned on the next
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// persist. Referers are short-lived session tokens; this keeps the per-host
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// global store from accumulating stale entries without tying cleanup to tab
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// close (a still-open source tab's referer must survive other tabs closing).
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const REFERER_TTL_MS = 30 * 60 * 1000;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Persist the captured referer per CDN host so the proxy can re-use it even
// after this capture tab closes. Keyed by host so a proxy for that host can
// look its referer up without knowing the source tab.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// look its referer up without knowing the source tab. Each entry is stamped
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// with a capture time; entries older than the TTL are pruned opportunistically
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// here (never on tab close).
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
async function persistReferer(host, referer) {
if (!host || !referer) return;
try {
const stored = await chrome.storage.local.get('goon_referers');
const map = stored['goon_referers'] || {};
if (map[host] === referer) return;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
map[host] = referer;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const now = Date.now();
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Opportunistic per-host prune: drop entries older than the TTL.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
for (const [h, entry] of Object.entries(map)) {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
if (h !== host && (!entry || !entry.at || now - entry.at > REFERER_TTL_MS)) {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
delete map[h];
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const current = map[host];
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
if (current && current.referer === referer) return;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
map[host] = { referer, at: now };
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
await chrome.storage.local.set({ goon_referers: map });
} catch (e) {
console.warn('[goon-bg] persistReferer failed:', e && e.message ? e.message : e);
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
// Look up the referer captured for a host. '' when none has been captured.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Look up the referer captured for a host. '' when none has been captured
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// (or the stored entry is malformed).
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
async function getReferer(host) {
if (!host) return '';
try {
const stored = await chrome.storage.local.get('goon_referers');
return (stored['goon_referers'] || {})[host] || '';
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
} catch {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const entry = (stored['goon_referers'] || {})[host];
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
return entry && entry.referer ? entry.referer : '';
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
} catch {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
return '';
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
// Capture the referer the real page sends for its video requests.
@@ -356,47 +392,62 @@ chrome.webRequest.onBeforeSendHeaders.addListener(
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// CDN host. The value comes from capture (or a fallback origin), never a
// hardcoded site. Scoped to the requested host so only proxy fetches for that
// host get the rewritten header.
//
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Each host gets its own rule id (refererRuleIdFor) so that concurrent proxy
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// fetches for DIFFERENT hosts never interleave: host A's rule and host B's rule
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// are distinct DNR ids and one install can't remove the other. Within a single
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// host, a per-host async lock (refererRuleLocks) serializes the idempotency
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// check + updateSessionRules so the install-and-record pair is atomic — no two
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// installs for the same host can interleave their check/update.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const refererRuleInstalled = new Map();
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const refererRuleLocks = new Map();
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
async function ensureRefererRule(host, referer) {
if (!host || !referer) return;
const api = chrome.declarativeNetRequest;
if (!api || typeof api.updateSessionRules !== 'function') {
console.warn('[goon-bg] declarativeNetRequest unavailable; skipping referer rule');
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
return;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
if (refererRuleInstalled.has(host) && refererRuleInstalled.get(host) === referer) {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
console.warn('[goon-bg] declarativeNetRequest unavailable; skipping referer rule');
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
return;
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Serialize per host so the idempotency check + updateSessionRules is atomic.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const run = (async () => {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
if (refererRuleInstalled.has(host) && refererRuleInstalled.get(host) === referer) {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
return;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const ruleId = refererRuleIdFor(host);
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
try {
await api.updateSessionRules({
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
removeRuleIds: [REFERER_RULE_ID],
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
addRules: [{
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
id: REFERER_RULE_ID,
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
priority: 1,
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
action: {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
type: 'modifyHeaders',
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Remove only THIS host's own rule id, then add it back scoped to the host.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
await api.updateSessionRules({
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
removeRuleIds: [ruleId],
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
addRules: [{
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
id: ruleId,
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
priority: 1,
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
action: {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
type: 'modifyHeaders',
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// `set` is allowed for any request header (only `append` is restricted
// to a fixed allowlist). `referer` is the header the CDN checks.
requestHeaders: [
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
{ header: 'referer', operation: 'set', value: referer },
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
],
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
},
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
condition: {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
requestHeaders: [
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
{ header: 'referer', operation: 'set', value: referer },
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
],
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
},
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
condition: {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Host + subdomains ONLY, so only proxy fetches for this host get the
// rewritten referer; the source page's own requests keep theirs.
requestDomains: [host],
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
},
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}],
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
});
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
refererRuleInstalled.set(host, referer);
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
console.log('[goon-bg] DNR referer rule installed for', host);
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
} catch (e) {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
requestDomains: [host],
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
},
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}],
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
});
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
refererRuleInstalled.set(host, referer);
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
console.log('[goon-bg] DNR referer rule installed for', host, '(' + ruleId + ')');
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
} catch (e) {
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
console.warn('[goon-bg] ensureRefererRule failed:', e && e.message ? e.message : e);
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
})().finally(() => { refererRuleLocks.set(host, null); });
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
refererRuleLocks.set(host, run);
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
return run;
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
}
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// Track which host's referer is currently installed so repeated proxy fetches
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// for the same host don't reinstall the same rule.
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
const refererRuleInstalled = new Map();
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
// === Message handlers for popup/data consumers ===
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.

Blocking: 'goon_referers' is a host-keyed GLOBAL store meant to outlive its capture tab (see the docstring just above and the PR body: "persist it per CDN host ... even after this capture tab closes"). Adding it to the per-tab onRemoved cleanup means closing ANY tab wipes referers captured by other still-open source tabs, so the next proxy fetch for those hosts loses its referer and 412s. Remove 'goon_referers' from this array (keep the per-tab vr_requests_ / wr_manifests_ keys). If you want cleanup, key it per host with an expiry instead of on every tab removal.
Review

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).

Concurrent-proxy race: REFERER_RULE_ID is a single shared id and the idempotency check + updateSessionRules({removeRuleIds, addRules}) are not atomic. Two hosts proxied in parallel (common in the multi-panel grid) can interleave so the live rule ends up host B's while refererRuleInstalled records host A as installed -> host A's fetches get host B's referer -> 412. Now that the rule is per-host, use a distinct rule id per host (or add all hosts' rules in one updateSessionRules call) and make the install+record atomic (per-host async lock / queue).
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.
Review

[SHOULD-FIX] F2
Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The extraHeaders permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism.
Suggested fix: Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.

[SHOULD-FIX] F2 Documentation/behavior mismatch. The PR body, commit 66c6218 message, and the code comments at :311 (:311 'via chrome.webRequest.onBeforeSendHeaders, which sees the request headers') describe an onBeforeSendHeaders + extraHeaders header-reading capture. The actual code uses onBeforeRequest (cannot read request headers) and derives the referer from the source TAB's URL instead (chrome.tabs.get). The `extraHeaders` permission is not declared in manifest.json (permissions: storage, tabs, scripting, webRequest, declarativeNetRequest). The commit message for :245-248 ('extraInfoSpec ... is rejected by some Chromium builds and fails the whole service worker') explains why, but the PR body / high-level comments were never updated to match, so a reviewer is misled about the mechanism. **Suggested fix:** Reword the PR body and the :311/:308-314 comments to say the referer is derived from the source tab URL (via onBeforeRequest + chrome.tabs.get) rather than 'read from request headers via onBeforeSendHeaders'. The actual mechanism is sound and arguably safer than reading real headers; the mismatch is a documentation issue, not a correctness one.