| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| provenance:programming:crawler:openwpm [2026/09/05 13:59] – Add section 14: second generic (fable) review pass, 2026-09-05 — 19 findings accepted, 3 rejected, with the corrected FIREFOX_STATED map and its rejected residue; correct four earlier overstatements in sections 7, 10, 11.5 and 12 (verbatim quote that was karel.kubicek.claude | provenance:programming:crawler:openwpm [2026/09/21 13:36] (current) – Quote-check refresh 2026-09-21: re-ran quote_check.mjs --tools open[ -]?wpm with the pypdf fallback; 12 below threshold -> 10 rescued + 2 below in both; new provenance section. Authored by Claude karel.kubicek.claude |
|---|
| ==== 3.3 The version-lag column, and its limits ==== | ==== 3.3 The version-lag column, and its limits ==== |
| |
| ''RELEASED'' in ''report_openwpm.mjs'' is the tag→date map from ''git for-each-ref --sort=creatordate refs/tags'' in the OpenWPM repository. ''FIREFOX_OF'' is the bundled-Firefox map, read by checking out each ''v*'' tag and grepping ''scripts/install-firefox.sh'' for its ''FIREFOX_<major>_<minor>_RELEASE'' comment. | ''RELEASED'' in ''report_openwpm.mjs'' is the tag→date map from ''git for-each-ref %%--sort%%=creatordate refs/tags'' in the OpenWPM repository. ''FIREFOX_OF'' is the bundled-Firefox map, read by checking out each ''v*'' tag and grepping ''scripts/install-firefox.sh'' for its ''FIREFOX_<major>_<minor>_RELEASE'' comment. |
| |
| Three caveats, all of which are on the page in weaker form: | Three caveats, all of which are on the page in weaker form: |
| * **Tag date ≠ release-publication date.** GitHub's releases API gives v0.30.0 as 2024-10-06 and v0.29.0 as 2024-07-20, where the tags are 2024-10-02 and 2024-07-15. The page uses **tag creatordate** throughout, consistently. Nothing on the page turns on a difference of days. | * **Tag date ≠ release-publication date.** GitHub's releases API gives v0.30.0 as 2024-10-06 and v0.29.0 as 2024-07-20, where the tags are 2024-10-02 and 2024-07-15. The page uses **tag creatordate** throughout, consistently. Nothing on the page turns on a difference of days. |
| * **"Releases behind" uses 1 January of the venue year** as the reference point, not the submission date, which is unknown. It is therefore an upper bound on how out of date the authors were when they crawled. The page says this. | * **"Releases behind" uses 1 January of the venue year** as the reference point, not the submission date, which is unknown. It is therefore an upper bound on how out of date the authors were when they crawled. The page says this. |
| * **The bundled-Firefox column is nominal, and a review pass caught the page treating it as actual.** OpenWPM launches whatever ''FIREFOX_BINARY'' points at, so the pin is a default. The first draft wrote that a 2024 paper "crawled with the Firefox 90 of mid-2021"; that paper {[shaoor2024purl]} in fact states "We use OpenWPM (v0.17.0) [11] and Firefox (v102) [64] for crawling", and so does {[shaoor2023cookiegraph]} for the same OpenWPM version. Both were read in the source. ''report_openwpm.mjs'' now carries a **hand map** (''FIREFOX_STATED'') of the papers that state a crawl browser version, each with the sentence that decided it — except the {[ahmad2020_apophanies]} entry, whose value comes from the extraction's own version string rather than from a sentence read in the paper, and which is marked as such, because a regex cannot do it: ''/Firefox v?\d+/'' over the same 15 papers returns 6 papers, and the three extra are citation-marker splices and Firefox versions discussed in related work. 3 of 15 state it; 2 of those 3 ran a **newer** browser than their release ships. | * **The bundled-Firefox column is nominal, and a review pass caught the page treating it as actual.** OpenWPM launches whatever ''FIREFOX_BINARY'' points at, so the pin is a default. The first draft wrote that a 2024 paper "crawled with the Firefox 90 of mid-2021"; that paper {[shaoor2024purl]} in fact states "We use OpenWPM (v0.17.0) [11] and Firefox (v102) [64] for crawling", and so does {[shaoor2023cookiegraph]} for the same OpenWPM version. Both were read in the source. ''report_openwpm.mjs'' now carries a **hand map** (''FIREFOX_STATED'') of the papers that state a crawl browser version, each with the sentence that decided it. **The figures in this paragraph were 3 of 15 and 2 mismatches until 2026-09-05; they are now 9 of 15 and 3 mismatches** — see §14.1, and read that entry before trusting any count of this shape, because the seed probe was wrong twice for two different reasons. Current: 9 of the 15 state a crawl browser. 2 used a pre-0.10 release with no pin to compare against; of the remaining 7, **4 ran the Firefox their release pins and 3 did not**. |
| * **Three stated versions have no tag** (''0.1.0'', ''0.9.0'', ''0.13''), so their rows carry "—" rather than a guess. ''0.1.0'' predates the first tag (v0.2.0, 2014-08-12); ''0.9.0'' was never tagged (the sequence goes 0.8.0 → 0.10.0); ''0.13'' is presumably 0.13.0 but the paper did not write it that way and the report does not correct papers. | * **Three stated versions have no tag** (''0.1.0'', ''0.9.0'', ''0.13''), so their rows carry "—" rather than a guess. ''0.1.0'' predates the first tag (v0.2.0, 2014-08-12); ''0.9.0'' was never tagged (the sequence goes 0.8.0 → 0.10.0); ''0.13'' is presumably 0.13.0 but the paper did not write it that way and the report does not correct papers. |
| |
| ) | ) |
| ); | ); |
| // Does the paper also say which BROWSER it ran? This is a hand map, each entry | // Does the paper also say which BROWSER it ran? Hand map, each entry carrying |
| // carrying the deciding sentence, read against paper.cols.txt. | // the sentence that decided it, read against paper.cols.txt. |
| // | // |
| // The width of the probe that seeds this map decides the number the page | // THE WIDTH AND THE POPULATION OF THE SEED PROBE BOTH DECIDE THE PUBLISHED |
| // publishes, and the first version of it was too narrow. /Firefox v?\d+/ was | // NUMBER, and this map got each wrong once: |
| // used on 2026-08-14; it matches "Firefox (v102)" but NOT "Firefox version 88", | // 2026-08-14 seeded with /Firefox v?\d+/ -> 3 papers. Misses "Firefox |
| // "the Firefox browser (v100.0", or "which uses Firefox v121.0" once a column | // version 88", "the Firefox browser (v100.0", and a "Fire-|fox |
| // splice cuts "Fire-|fox". It found 3 papers, and the page published "3 of 15 | // v121.0" cut by a column splice. Published as "3 of 15" for |
| // state a browser" for three weeks. A generic review pass on 2026-09-05 re-swept | // three weeks, on a page that quoted one of the missed papers |
| // with a wide probe over whitespace-collapsed text and found 7. The wide probe | // three paragraphs later as its best-documented row. |
| // is run below and its REJECTED hits are printed, so the part of the sweep this | // 2026-09-05a re-swept wide, but only over slugs a reviewer had named -> 7. |
| // map throws away stays visible instead of vanishing. | // Still missed fouad2022_cookie (a setup TABLE: "Firefox version |
| | // 68.0 45.0.1" sits far from "OpenWPM ver-|sion v0.9.0 v0.7.0") |
| | // and demir2023_similarity ("the most recent stable Firefox |
| | // version available ... (v95.0 ...)"). |
| | // 2026-09-05b re-swept wide over ALL 15 version-stating papers -> 9. |
| | // The sweep is run below over the whole population and its REJECTED hits are |
| | // printed with reasons, so the map can be audited against its own residue. |
| const FIREFOX_STATED = { | const FIREFOX_STATED = { |
| 'apophanies-or-epiphanies-how-crawlers-impact-our-understanding-of-the-web': { | 'apophanies-or-epiphanies-how-crawlers-impact-our-understanding-of-the-web': { |
| firefox: '52.9', | firefox: '52.9', |
| quote: 'version string recorded by the extraction as "0.8; Firefox 52.9"; consistent with the firefox-52 era pin (NOT a sentence read in the paper — the only entry here that is not)', | quote: 'at the time of our experiments Open-WPM was unable to drive Firefox versions later than v52.9, while Selenium drove Firefox v66.0 (and Table 3: "OpenWPM [28] 0.8 | Selenium v3.6, Firefox v52.9")', |
| | }, |
| | 'my-cookie-is-a-phoenix-detection-measurement-and-lawfulness-of-cookie-respawning': { |
| | firefox: '68.0 (machine A); 45.0.1 (machine B)', |
| | quote: 'setup table: "Firefox version 68.0 45.0.1 ... OpenWPM ver[splice]sion v0.9.0 v0.7.0"', |
| }, | }, |
| 'reproducibility-and-replicability-of-web-measurement-studies': { | 'reproducibility-and-replicability-of-web-measurement-studies': { |
| firefox: '102', | firefox: '102', |
| quote: 'We use OpenWPM (v0.17.0) and Firefox (v102) [52] to crawl a sample of 20K out of the top-million websites', | quote: 'We use OpenWPM (v0.17.0) and Firefox (v102) [52] to crawl a sample of 20K out of the top-million websites', |
| | }, |
| | 'on-the-similarity-of-web-measurements-under-different-experimental-setups': { |
| | firefox: '95.0 and 86.0.1', |
| | note: 'ran two browsers deliberately, as an experimental variable; v95.0 is the one v0.18.0 pins', |
| | quote: 'we used the most recent stable Firefox version available when we started the experiment (v95.0; release date 12/2021) and a version that is roughly one year older (v86.0.1; 02/2021)', |
| }, | }, |
| 'a-large-scale-study-of-cookie-banner-interaction-tools-and-their-impact-on-users': { | 'a-large-scale-study-of-cookie-banner-interaction-tools-and-their-impact-on-users': { |
| }, | }, |
| }; | }; |
| // Papers the wide probe hits that are NOT in the map, with the reason. Printed | // Wide-probe hits NOT in the map, with the reason. A rejection nobody can see |
| // as residue: a rejection nobody can see is a rejection nobody can check. | // is a rejection nobody can check. |
| const FIREFOX_REJECTED = { | const FIREFOX_REJECTED = { |
| 'evaluating-practical-quic-website-fingerprinting-defenses-for-the-masses': | 'evaluating-practical-quic-website-fingerprinting-defenses-for-the-masses': |
| 'names the crawl browser without a version ("crawling the pages in MAIN with OpenWPM (v0.17.0) [1] using Firefox five consecutive times"); the "Firefox 88.0"/"Firefox 98.0" hits elsewhere are website-fingerprinting client comparisons, not the OpenWPM crawl', | 'names the crawl browser without a version ("crawling the pages in MAIN with OpenWPM (v0.17.0) [1] using Firefox five consecutive times"); the "Firefox 88.0"/"98.0" hits are website-fingerprinting client comparisons (MAIN/TIME/LARGE/FIREFOX/HET), not the crawl', |
| | 'automating-cookie-consent-and-gdpr-violation-detection': |
| | 'the only "Firefox 86" in the paper is a BIBLIOGRAPHY TITLE ("Firefox 86 introduces total cookie protection"); the methodology says only "the OpenWPM framework, version 0.12.0 [16, 35], which runs multiple concurrent Firefox browser instances"', |
| }; | }; |
| | const major = (s) => String(s).split('.')[0]; |
| | const stateCount = Object.keys(FIREFOX_STATED).length; |
| | p(''); |
| | p(`Of those ${statedPapers.size} papers, ${stateCount} also state which Firefox the crawl ran. Hand-read from a wide`); |
| | p(`sweep over all ${statedPapers.size}; the hits the map rejects are listed after the table.`); |
| p(''); | p(''); |
| p(`Of those ${statedPapers.size} papers, ${Object.keys(FIREFOX_STATED).length} also state which Firefox the crawl ran (hand-read;`); | let ffMatch = 0, ffDiffer = 0, ffNoPin = 0; |
| p(`the wide probe's rejected hits are listed after the table). The other`); | |
| p(`${statedPapers.size - Object.keys(FIREFOX_STATED).length} leave the browser to be inferred from the pin:`); | |
| let ffMatch = 0; | |
| let ffMismatch = 0; | |
| for (const [slug, v] of Object.entries(FIREFOX_STATED)) { | for (const [slug, v] of Object.entries(FIREFOX_STATED)) { |
| const paper = OPENWPM.find((x) => x.slug === slug); | const paper = OPENWPM.find((x) => x.slug === slug); |
| const ow = openwpmTuples(paper).map((t) => t.version).filter(Boolean)[0]; | const ow = openwpmTuples(paper).map((t) => t.version).filter(Boolean)[0]; |
| const nominal = FIREFOX_OF[normalise(ow ?? '')] ?? '?'; | const nominal = FIREFOX_OF[normalise(ow ?? '')] ?? '?'; |
| // Compare on the major version only: papers write 100, 100.0 and 121.0. | // The paper may state more than one browser; compare on any major it states. |
| const major = (s) => String(s).split('.')[0]; | const stated = String(v.firefox).match(/\d+(?:\.\d+)*/g) ?? []; |
| let verdict; | let verdict; |
| if (nominal === '?') verdict = 'no pin to compare (pre-0.10 release)'; | if (nominal === '?') { verdict = 'NO PIN to compare (pre-0.10 release)'; ffNoPin++; } |
| else if (major(nominal) === major(v.firefox)) { verdict = 'MATCHES the pin'; ffMatch++; } | else if (stated.some((s) => major(s) === major(nominal))) { verdict = 'MATCHES the pin'; ffMatch++; } |
| else { verdict = `DIFFERS from the pin (${nominal})`; ffMismatch++; } | else { verdict = `DIFFERS from the pin (${nominal})`; ffDiffer++; } |
| p(` ${paper.year} ${paper.venue}/${slug}`); | p(` ${paper.year} ${paper.venue}/${slug}`); |
| p(` OpenWPM ${ow} (ships Firefox ${nominal}) — paper states Firefox ${v.firefox} — ${verdict}`); | p(` OpenWPM ${ow} (ships Firefox ${nominal}) — paper states Firefox ${v.firefox} — ${verdict}`); |
| | if (v.note) p(` note: ${v.note}`); |
| p(` "${v.quote}"`); | p(` "${v.quote}"`); |
| } | } |
| } | } |
| p(''); | p(''); |
| p(`${ffMismatch} of the ${Object.keys(FIREFOX_STATED).length} ran a DIFFERENT browser from the one their OpenWPM release`); | p(`Split of the ${stateCount}: ${ffMatch} ran the Firefox their release pins, ${ffDiffer} ran a different one,`); |
| p(`ships and ${ffMatch} match it, so the bundled-Firefox column is nominal: OpenWPM launches whatever FIREFOX_BINARY`); | p(`${ffNoPin} used a pre-0.10 release that has no pin to compare against. So of the ${ffMatch + ffDiffer}`); |
| p(`points at. ${statedPapers.size - Object.keys(FIREFOX_STATED).length} of the ${statedPapers.size} do not say, and cannot be checked.`); | p(`that can be checked against a pin, ${ffDiffer} do not match it, and the bundled-Firefox column`); |
| | p('is nominal: OpenWPM launches whatever FIREFOX_BINARY points at.'); |
| | p(`${statedPapers.size - stateCount} of the ${statedPapers.size} do not say which browser they ran, and cannot be checked.`); |
| p(''); | p(''); |
| p('"Releases behind" counts tagged releases between the version the paper used'); | p('"Releases behind" counts tagged releases between the version the paper used'); |
| 0.36.0 2026-08-24 Firefox 154 | 0.36.0 2026-08-24 Firefox 154 |
| |
| Of those 15 papers, 7 also state which Firefox the crawl ran (hand-read; | Of those 15 papers, 9 also state which Firefox the crawl ran. Hand-read from a wide |
| the wide probe's rejected hits are listed after the table). The other | sweep over all 15; the hits the map rejects are listed after the table. |
| 8 leave the browser to be inferred from the pin: | |
| 2020 WWW/apophanies-or-epiphanies-how-crawlers-impact-our-understanding-of-the-web | 2020 WWW/apophanies-or-epiphanies-how-crawlers-impact-our-understanding-of-the-web |
| OpenWPM 0.8; Firefox 52.9 (ships Firefox ?) — paper states Firefox 52.9 — no pin to compare (pre-0.10 release) | OpenWPM 0.8; Firefox 52.9 (ships Firefox ?) — paper states Firefox 52.9 — NO PIN to compare (pre-0.10 release) |
| "version string recorded by the extraction as "0.8; Firefox 52.9"; consistent with the firefox-52 era pin (NOT a sentence read in the paper — the only entry here that is not)" | "at the time of our experiments Open-WPM was unable to drive Firefox versions later than v52.9, while Selenium drove Firefox v66.0 (and Table 3: "OpenWPM [28] 0.8 | Selenium v3.6, Firefox v52.9")" |
| | 2022 PETS/my-cookie-is-a-phoenix-detection-measurement-and-lawfulness-of-cookie-respawning |
| | OpenWPM 0.9.0 (machine A); 0.7.0 (machine B) (ships Firefox ?) — paper states Firefox 68.0 (machine A); 45.0.1 (machine B) — NO PIN to compare (pre-0.10 release) |
| | "setup table: "Firefox version 68.0 45.0.1 ... OpenWPM ver[splice]sion v0.9.0 v0.7.0"" |
| 2022 WWW/reproducibility-and-replicability-of-web-measurement-studies | 2022 WWW/reproducibility-and-replicability-of-web-measurement-studies |
| OpenWPM v0.15.0 (ships Firefox 88) — paper states Firefox 88 — MATCHES the pin | OpenWPM v0.15.0 (ships Firefox 88) — paper states Firefox 88 — MATCHES the pin |
| OpenWPM 0.17.0 (ships Firefox 90) — paper states Firefox 102 — DIFFERS from the pin (90) | OpenWPM 0.17.0 (ships Firefox 90) — paper states Firefox 102 — DIFFERS from the pin (90) |
| "We use OpenWPM (v0.17.0) and Firefox (v102) [52] to crawl a sample of 20K out of the top-million websites" | "We use OpenWPM (v0.17.0) and Firefox (v102) [52] to crawl a sample of 20K out of the top-million websites" |
| | 2023 IMC/on-the-similarity-of-web-measurements-under-different-experimental-setups |
| | OpenWPM v0.18.0 (ships Firefox 95) — paper states Firefox 95.0 and 86.0.1 — MATCHES the pin |
| | note: ran two browsers deliberately, as an experimental variable; v95.0 is the one v0.18.0 pins |
| | "we used the most recent stable Firefox version available when we started the experiment (v95.0; release date 12/2021) and a version that is roughly one year older (v86.0.1; 02/2021)" |
| 2024 PETS/a-large-scale-study-of-cookie-banner-interaction-tools-and-their-impact-on-users | 2024 PETS/a-large-scale-study-of-cookie-banner-interaction-tools-and-their-impact-on-users |
| OpenWPM 0.20.0 (ships Firefox 100) — paper states Firefox 100 — MATCHES the pin | OpenWPM 0.20.0 (ships Firefox 100) — paper states Firefox 100 — MATCHES the pin |
| Wide-probe hits REJECTED from the map: | Wide-probe hits REJECTED from the map: |
| evaluating-practical-quic-website-fingerprinting-defenses-for-the-masses | evaluating-practical-quic-website-fingerprinting-defenses-for-the-masses |
| names the crawl browser without a version ("crawling the pages in MAIN with OpenWPM (v0.17.0) [1] using Firefox five consecutive times"); the "Firefox 88.0"/"Firefox 98.0" hits elsewhere are website-fingerprinting client comparisons, not the OpenWPM crawl | names the crawl browser without a version ("crawling the pages in MAIN with OpenWPM (v0.17.0) [1] using Firefox five consecutive times"); the "Firefox 88.0"/"98.0" hits are website-fingerprinting client comparisons (MAIN/TIME/LARGE/FIREFOX/HET), not the crawl |
| | automating-cookie-consent-and-gdpr-violation-detection |
| | the only "Firefox 86" in the paper is a BIBLIOGRAPHY TITLE ("Firefox 86 introduces total cookie protection"); the methodology says only "the OpenWPM framework, version 0.12.0 [16, 35], which runs multiple concurrent Firefox browser instances" |
| |
| 3 of the 7 ran a DIFFERENT browser from the one their OpenWPM release | Split of the 9: 4 ran the Firefox their release pins, 3 ran a different one, |
| ships and 3 match it, so the bundled-Firefox column is nominal: OpenWPM launches whatever FIREFOX_BINARY | 2 used a pre-0.10 release that has no pin to compare against. So of the 7 |
| points at. 8 of the 15 do not say, and cannot be checked. | that can be checked against a pin, 3 do not match it, and the bundled-Firefox column |
| | is nominal: OpenWPM launches whatever FIREFOX_BINARY points at. |
| | 6 of the 15 do not say which browser they ran, and cannot be checked. |
| |
| "Releases behind" counts tagged releases between the version the paper used | "Releases behind" counts tagged releases between the version the paper used |
| All **65** evidence quotes attached to an OpenWPM ''tools[]'' tuple anywhere in the corpus were checked, twice, by two different methods. | All **65** evidence quotes attached to an OpenWPM ''tools[]'' tuple anywhere in the corpus were checked, twice, by two different methods. |
| |
| **First pass, ''scripts/quote_check.mjs --tools "open[ -]?wpm"'':** 34 exact, 19 partial (≥60% of five-word windows), 12 below threshold, 0 with no full text on disk. | **First pass, ''scripts/quote_check.mjs %%--tools%% "open[ -]?wpm"'', re-run 2026-09-21 with the PDF fallback:** 34 exact, 19 partial (≥60% of five-word windows), **10 rescued from the PDF**, **2 below threshold in both renderings**, 0 with no full text on disk. See //Quote-check refresh, 2026-09-21// at the foot of this page. |
| |
| **The 12 below threshold are not fabrications, and the method was the problem.** Hand-checking with whitespace normalisation found 3 of them immediately; the rest failed because the repaired two-column text splices the other column into the middle of a sentence. With punctuation and spaces stripped, PETS 2025 ''intractable-cookie-crumbs-…'' reads: | **The old figure was 12 below threshold, and the script now agrees with what this page worked out by hand.** 10 of the 12 are located in an independent ''pypdf'' rendering of the same ''paper.pdf'' — the stored text is what was wrong — and only **2** are below threshold in both, which is 3.1% of the 65. ''exact'' (34) and ''partial'' (19) did not move. |
| | |
| | **The 12 below threshold were not fabrications, and the method was the problem.** Hand-checking with whitespace normalisation found 3 of them immediately; the rest failed because the repaired two-column text splices the other column into the middle of a sentence. With punctuation and spaces stripped, PETS 2025 ''intractable-cookie-crumbs-…'' reads: |
| |
| <code> | <code> |
| </code> | </code> |
| |
| "Firefox v121.0" //is// in the paper; the word ''firefox'' is cut in half. A whole-quote containment test scores that quote as absent. | "Firefox v121.0" //is// in the paper; the word ''firefox'' is cut in half. A whole-quote containment test scores that quote as absent. **That quote is one of the 10 the PDF fallback now rescues**: 46% of its five-word windows in the stored rendering, 62% in ''pypdf'''s. The two still below threshold in both are ''PETS/2022/my-cookie-is-a-phoenix…'' (50%) and ''USENIX/2022/automating-cookie-consent-and-gdpr-violation-detection'' (58%), and in both the mismatch is inside the extraction's own string — a dropped citation marker — which no rendering of the PDF can repair. |
| |
| **Second pass, ''scripts/openwpm_quotecheck.py'', written for this page.** Skeletonise (lowercase, drop everything that is not a letter or digit), cut each quote into overlapping 4-word windows, and report the share of the quote's **word positions** covered by a present window. Coverage, not window count: one splice in a twelve-word quote kills up to six windows but only one word position. An earlier version of this script counted windows and reported 19 quotes below 60%, all of them short quotes with a single splice — a metric artefact, and it is recorded here because the first draft of this page nearly published it. | **Second pass, ''scripts/openwpm_quotecheck.py'', written for this page.** Skeletonise (lowercase, drop everything that is not a letter or digit), cut each quote into overlapping 4-word windows, and report the share of the quote's **word positions** covered by a present window. Coverage, not window count: one splice in a twelve-word quote kills up to six windows but only one word position. An earlier version of this script counted windows and reported 19 quotes below 60%, all of them short quotes with a single splice — a metric artefact, and it is recorded here because the first draft of this page nearly published it. |
| - **The "both" statefulness label was doubted, and the doubt was wrong.** Five OPENWPM papers have ''crawlConfig.statefulness == "both"''. The first draft of the content page dismissed two of the five: it read {[englehardt2016online]}'s //stateful (cookie-based) and stateless (fingerprinting-based) tracking// — a real homograph, in that paper's abstract — as the only basis for its label, and it read the persona paper {[agarwal2020_stop]}'s "A HPW crawl with a loaded persona is stateless" as contradicting it. The **citations review pass** checked both against the papers and both objections fail: {[englehardt2016online]}'s configuration table lists //Default Stateless 1 Million// (917,261 sites) beside //Default Stateful 100,000// (94,144), and it says of its own platform "it supports both stateful and stateless measurements"; {[agarwal2020_stop]} says "We visit all websites in a persona-specific list as a stateful crawl that stores the user history in a browser" and //then// crawls statelessly with the dumped state. The label is sound in at least three of the five, so the page now describes the three designs instead of warning about the label — while keeping the homograph as a reading trap, which is what it is. **Recorded as an error caught in review:** the first draft would have told readers to distrust a correct extraction, on the strength of one grep. | - **The "both" statefulness label was doubted, and the doubt was wrong.** Five OPENWPM papers have ''crawlConfig.statefulness == "both"''. The first draft of the content page dismissed two of the five: it read {[englehardt2016online]}'s //stateful (cookie-based) and stateless (fingerprinting-based) tracking// — a real homograph, in that paper's abstract — as the only basis for its label, and it read the persona paper {[agarwal2020_stop]}'s "A HPW crawl with a loaded persona is stateless" as contradicting it. The **citations review pass** checked both against the papers and both objections fail: {[englehardt2016online]}'s configuration table lists //Default Stateless 1 Million// (917,261 sites) beside //Default Stateful 100,000// (94,144), and it says of its own platform "it supports both stateful and stateless measurements"; {[agarwal2020_stop]} says "We visit all websites in a persona-specific list as a stateful crawl that stores the user history in a browser" and //then// crawls statelessly with the dumped state. The label is sound in at least three of the five, so the page now describes the three designs instead of warning about the label — while keeping the homograph as a reading trap, which is what it is. **Recorded as an error caught in review:** the first draft would have told readers to distrust a correct extraction, on the strength of one grep. |
| - **No causal claim about the ARM extension failure.** With a branded Firefox Nightly the extension loads and its privileged startup then fails. The obvious explanation is that a branded build does not grant ''experiment_apis'' to an unsigned add-on, and the obvious explanation is not evidence: installing the same ''.xpi'' by hand into the same Nightly succeeds (''INSTALL OK id= openwpm@mozilla.org''), which shows loading is not the problem but does not identify what is. Three probes were run and none settled it: a patched ''.xpi'' with ''experiment_apis'' removed was built and **not** used, because the extension cannot start without those APIs, so the comparison would have isolated nothing; installing the real ''.xpi'' with Firefox's own log captured showed no privilege error (but also no ''browser_params.json'' in the profile, so the extension's startup would have failed anyway, differently); and asking Firefox directly, in chrome context, whether it granted the add-on privileged status failed twice — ''WebExtensionPolicy'' is not defined in Marionette's chrome sandbox, and the asynchronous ''AddonManager.getAddonByID'' form timed out. The page reports the failure and says the cause was not isolated. | - **No causal claim about the ARM extension failure.** With a branded Firefox Nightly the extension loads and its privileged startup then fails. The obvious explanation is that a branded build does not grant ''experiment_apis'' to an unsigned add-on, and the obvious explanation is not evidence: installing the same ''.xpi'' by hand into the same Nightly succeeds (''INSTALL OK id= openwpm@mozilla.org''), which shows loading is not the problem but does not identify what is. Three probes were run and none settled it: a patched ''.xpi'' with ''experiment_apis'' removed was built and **not** used, because the extension cannot start without those APIs, so the comparison would have isolated nothing; installing the real ''.xpi'' with Firefox's own log captured showed no privilege error (but also no ''browser_params.json'' in the profile, so the extension's startup would have failed anyway, differently); and asking Firefox directly, in chrome context, whether it granted the add-on privileged status failed twice — ''WebExtensionPolicy'' is not defined in Marionette's chrome sandbox, and the asynchronous ''AddonManager.getAddonByID'' form timed out. The page reports the failure and says the cause was not isolated. |
| - **The geckodriver A/B is reported as causal**, because it is: same Firefox binary, same Selenium 4.45.0, same OpenWPM commit, only the driver changed, and the error names the argument OpenWPM passes. Attempt 1 (0.37.1) failed at ''NEW_SESSION'' with ''InvalidArgumentException: Argument --remote-allow-system-access can't be set via capabilities''; attempt 2 (0.37.0) got past that point and failed later and differently. | - **The geckodriver A/B is reported as causal**, because it is: same Firefox binary, same Selenium 4.45.0, same OpenWPM commit, only the driver changed, and the error names the argument OpenWPM passes. Attempt 1 (0.37.1) failed at ''NEW_SESSION'' with ''InvalidArgumentException: Argument %%--remote-allow-system-access%% can't be set via capabilities''; attempt 2 (0.37.0) got past that point and failed later and differently. |
| - **''cookie_instrument'' being the only default is reported from execution, not from the docs**, because the docs do not say it. Verified by constructing ''BrowserParams()'' and printing every instrument field. | - **''cookie_instrument'' being the only default is reported from execution, not from the docs**, because the docs do not say it. Verified by constructing ''BrowserParams()'' and printing every instrument field. |
| - **The default-JS-collection gaps are reported per object, not by substring search.** An earlier draft of ''openwpm_defaults.py'' searched the settings blob for "webrtc" and "battery" and reported both ABSENT. Both are wrong: WebRTC is ''RTCPeerConnection'', which //is// instrumented, and ''navigator.getBattery'' is covered by instrumenting ''window.navigator''. The published script checks object and property names, and the page states the real gap: WebGL, ''document.fonts'', ''screen'' beyond two properties, most of ''window'', and calls on objects returned by instrumented properties. | - **The default-JS-collection gaps are reported per object, not by substring search.** An earlier draft of ''openwpm_defaults.py'' searched the settings blob for "webrtc" and "battery" and reported both ABSENT. Both are wrong: WebRTC is ''RTCPeerConnection'', which //is// instrumented, and ''navigator.getBattery'' is covered by instrumenting ''window.navigator''. The published script checks object and property names, and the page states the real gap: WebGL, ''document.fonts'', ''screen'' beyond two properties, most of ''window'', and calls on objects returned by instrumented properties. |
| | "Use a versioned release" / "Include the OpenWPM version number" | ''README.md'', //Advice for Measurement Researchers//, quoted verbatim on the page | | | "Use a versioned release" / "Include the OpenWPM version number" | ''README.md'', //Advice for Measurement Researchers//, quoted verbatim on the page | |
| | ''docs/Papers.rst'' lists 76 studies, none later than 2021 | counted from the file; ''git log -1'' on it gives 2023-09-19 | | | ''docs/Papers.rst'' lists 76 studies, none later than 2021 | counted from the file; ''git log -1'' on it gives 2023-09-19 | |
| | the fingerprinting collection has not changed since 2020-07-08 | ''git log --follow'' on ''openwpm/js_instrumentation_collections/fingerprinting.json'': two commits, the later one a module rename (''502cd83'', 2020-11-14) | | | the fingerprinting collection has not changed since 2020-07-08 | ''git log %%--follow%%'' on ''openwpm/js_instrumentation_collections/fingerprinting.json'': two commits, the later one a module rename (''502cd83'', 2020-11-14) | |
| | commits per year, 63 contributors, 72 of 73 2026 commits by one author | ''git log'' on a full (unshallowed) clone | | | commits per year, 63 contributors, 72 of 73 2026 commits by one author | ''git log'' on a full (unshallowed) clone | |
| |
| Host: aarch64 Linux container, x86-64 binaries not executable (no ''/lib64/ld-linux-x86-64.so.2''), no conda, no Docker, no Firefox, Python 3.11, Node 22. | Host: aarch64 Linux container, x86-64 binaries not executable (no ''/lib64/ld-linux-x86-64.so.2''), no conda, no Docker, no Firefox, Python 3.11, Node 22. |
| |
| Everything below was run against the repository at ''b9dd4c3'' **unmodified**: after all of it, ''git status --porcelain'' reports only untracked additions — the two test scripts copied in from ''pages/'', the downloaded copy of the published one, and the crawl output directory. No tracked file was touched, so no claim here is about a patched OpenWPM. | Everything below was run against the repository at ''b9dd4c3'' **unmodified**: after all of it, ''git status %%--porcelain%%'' reports only untracked additions — the two test scripts copied in from ''pages/'', the downloaded copy of the published one, and the crawl output directory. No tracked file was touched, so no claim here is about a patched OpenWPM. |
| |
| ^ # ^ Command ^ Result ^ | ^ # ^ Command ^ Result ^ |
| | 1 | ''git clone https://github.com/openwpm/OpenWPM'' (then ''git fetch --unshallow'') | ok, commit ''b9dd4c3'', ''VERSION'' 0.35.0 | | | 1 | ''git clone https://github.com/openwpm/OpenWPM'' (then ''git fetch %%--unshallow%%'') | ok, commit ''b9dd4c3'', ''VERSION'' 0.35.0 | |
| | 2 | ''micromamba env create -f environment.yaml'' | **failed to solve** — 3 packages have no linux-aarch64 build (output below) | | | 2 | ''micromamba env create -f environment.yaml'' | **failed to solve** — 3 packages have no linux-aarch64 build (output below) | |
| | 3 | ''micromamba create -n owpm python=3.12 pip leveldb'' then ''pip install'' the imports of ''openwpm/'' | ok; ''pillow'' had to be added after a ''ModuleNotFoundError: PIL'' on import of ''openwpm.commands.browser_commands'' | | | 3 | ''micromamba create -n owpm python=3.12 pip leveldb'' then ''pip install'' the imports of ''openwpm/'' | ok; ''pillow'' had to be added after a ''ModuleNotFoundError: PIL'' on import of ''openwpm.commands.browser_commands'' | |
| | 7 | download the pinned unbranded Firefox for ''linux64-aarch64'' | **404** — the build does not exist (probe §1) | | | 7 | download the pinned unbranded Firefox for ''linux64-aarch64'' | **404** — the build does not exist (probe §1) | |
| | 8 | download Firefox Nightly ''linux64-aarch64'' + geckodriver 0.37.1 for aarch64 | ok — Firefox 156.0a1, geckodriver 0.37.1 | | | 8 | download Firefox Nightly ''linux64-aarch64'' + geckodriver 0.37.1 for aarch64 | ok — Firefox 156.0a1, geckodriver 0.37.1 | |
| | 9 | ''openwpm_smoke.py'' with geckodriver **0.37.1** | **failed at ''NEW_SESSION''**: ''InvalidArgumentException: Argument --remote-allow-system-access can't be set via capabilities'' | | | 9 | ''openwpm_smoke.py'' with geckodriver **0.37.1** | **failed at ''NEW_SESSION''**: ''InvalidArgumentException: Argument %%--remote-allow-system-access%% can't be set via capabilities'' | |
| | 10 | same with geckodriver **0.37.0** (the pinned version) | got further: Firefox exited status 1, ''Could not find profile folder.'' | | | 10 | same with geckodriver **0.37.0** (the pinned version) | got further: Firefox exited status 1, ''Could not find profile folder.'' | |
| | 11 | run Firefox directly with ''--headless --screenshot'' | reproduced the same error with ''HOME=/home/dev''; **succeeded** with ''HOME=/tmp/fh''. A container quirk, not an OpenWPM property, and not reported on the page | | | 11 | run Firefox directly with ''%%--headless%% %%--screenshot%%'' | reproduced the same error with ''HOME=/home/dev''; **succeeded** with ''HOME=/tmp/fh''. A container quirk, not an OpenWPM property, and not reported on the page | |
| | 12 | ''openwpm_smoke.py'' with geckodriver 0.37.0 and ''HOME=/tmp/fh'' | browser launched, **extension loaded**, then ''FileNotFoundError: …/extension_port.txt''; spawn unsuccessful, retried to the failure limit | | | 12 | ''openwpm_smoke.py'' with geckodriver 0.37.0 and ''HOME=/tmp/fh'' | browser launched, **extension loaded**, then ''FileNotFoundError: …/extension_port.txt''; spawn unsuccessful, retried to the failure limit | |
| | 13 | install the same ''.xpi'' into the same Nightly by hand via Selenium | ''INSTALL OK id= openwpm@mozilla.org'' | | | 13 | install the same ''.xpi'' into the same Nightly by hand via Selenium | ''INSTALL OK id= openwpm@mozilla.org'' | |
| | S8 | The three identifier-sweep hits were read; one of them ({[agarwal2020_stop]}) is the worked example the page was asking for and was not being used | **accepted**, added with a new bibliography entry | | | S8 | The three identifier-sweep hits were read; one of them ({[agarwal2020_stop]}) is the worked example the page was asking for and was not being used | **accepted**, added with a new bibliography entry | |
| |
| ==== 11.2 Figures against the script (''sonnet'') ==== | ==== 11.2 Figures against the script (sonnet) ==== |
| |
| Re-ran ''report_openwpm.mjs'', ''openwpm_quotecheck.py'' and ''openwpm_defaults.py'' (the last inside a live OpenWPM checkout) and confirmed all three reproduce the committed output byte for byte; checked the byte sizes, the 14 tables at 0 rows, every table in //Use in Publications//, and both ''check_page_numbers.mjs'' invocations. | Re-ran ''report_openwpm.mjs'', ''openwpm_quotecheck.py'' and ''openwpm_defaults.py'' (the last inside a live OpenWPM checkout) and confirmed all three reproduce the committed output byte for byte; checked the byte sizes, the 14 tables at 0 rows, every table in //Use in Publications//, and both ''check_page_numbers.mjs'' invocations. |
| | 2 | "no year above 12% and none below 3%" is falsified by the 2026 row (1.4%) in the table immediately above | **accepted**, now scoped to the eleven complete years 2015–2024, with the two provisional years named | | | 2 | "no year above 12% and none below 3%" is falsified by the 2026 row (1.4%) in the table immediately above | **accepted**, now scoped to the eleven complete years 2015–2024, with the two provisional years named | |
| | 3 | The version column paraphrased "0.9.0 (machine A); 0.7.0 (machine B)" as "0.9.0 and 0.7.0, one per machine", on a page that promises verbatim version strings | **accepted**, verbatim string restored | | | 3 | The version column paraphrased "0.9.0 (machine A); 0.7.0 (machine B)" as "0.9.0 and 0.7.0, one per machine", on a page that promises verbatim version strings | **accepted**, verbatim string restored | |
| | 4 | ''check_page_numbers.mjs --code'' exited 1 on ''62'' (a ''print()'' column width in the published script), so "both guards pass" was not true as invoked | **accepted**; the report's ''Z'' block now carries it with that reason, and both invocations pass | | | 4 | ''check_page_numbers.mjs %%--code%%'' exited 1 on ''62'' (a ''print()'' column width in the published script), so "both guards pass" was not true as invoked | **accepted**; the report's ''Z'' block now carries it with that reason, and both invocations pass | |
| | 5 | The new semver handling in ''check_page_numbers.mjs'' used ''report.includes(v)'', looser than the boundary-checked ''present()'' every other number goes through | **accepted**, now uses ''present()''. The reviewer confirmed it does not currently misfire; the point is that it could | | | 5 | The new semver handling in ''check_page_numbers.mjs'' used ''report.includes(v)'', looser than the boundary-checked ''present()'' every other number goes through | **accepted**, now uses ''present()''. The reviewer confirmed it does not currently misfire; the point is that it could | |
| | 6 | The guard scores "21" as accounted-for because "21" appears incidentally in the report (a citation marker, "21 crawls/harvests") — a presence-anywhere weakness of the guard, not introduced here | **accepted in part**: the figure is now attributed to ''report_crawler.mjs'' in the ''Z'' block. The general weakness is real and is left as a known limitation of the guard | | | 6 | The guard scores "21" as accounted-for because "21" appears incidentally in the report (a citation marker, "21 crawls/harvests") — a presence-anywhere weakness of the guard, not introduced here | **accepted in part**: the figure is now attributed to ''report_crawler.mjs'' in the ''Z'' block. The general weakness is real and is left as a known limitation of the guard | |
| | 10 | The quoted log collapses runs of spaces, which was not disclosed | **accepted**, disclosure extended | | | 10 | The quoted log collapses runs of spaces, which was not disclosed | **accepted**, disclosure extended | |
| |
| ==== 11.3 Citations and quotes (''sonnet'') ==== | ==== 11.3 Citations and quotes (sonnet) ==== |
| |
| Checked all 23 citekeys, the new BibTeX entries against Crossref and the PoPETs landing pages, every quoted sentence against ''paper.cols.txt'' with punctuation stripped, and every repository and issue quote against the sources. | Checked all 23 citekeys, the new BibTeX entries against Crossref and the PoPETs landing pages, every quoted sentence against ''paper.cols.txt'' with punctuation stripped, and every repository and issue quote against the sources. |
| | — | Everything else — the README block quote, the ''docs/'' quotes, all four GitHub issues, Bugzilla 634073, the ''fingerprinting.json'' history, the 14-object list, Manifest V2 and the three ''experiment_apis'', the Krumnow characterisation, the OpenWPM-Mobile and "No boundaries" claims, and every other version string in the table — verified against the source | no change | | | — | Everything else — the README block quote, the ''docs/'' quotes, all four GitHub issues, Bugzilla 634073, the ''fingerprinting.json'' history, the 14-object list, Manifest V2 and the three ''experiment_apis'', the Krumnow characterisation, the OpenWPM-Mobile and "No boundaries" claims, and every other version string in the table — verified against the source | no change | |
| |
| ==== 11.4 External currency (''sonnet'') ==== | ==== 11.4 External currency (sonnet) ==== |
| |
| Every external fact re-fetched today. The whole maintenance table reproduced exactly, all four cited issues still open, Bugzilla 634073 still ''NEW'', no PyPI package, Docker Hub still amd64-only, conda-forge still zero ''linux-aarch64'' builds for the three pins, geckodriver still 0.37.1 with its own ''CHANGES.md'' confirming the capabilities change, and — the check that mattered most — **the current** latest ''mozilla-release'' build also has no ''linux64-aarch64-add-on-devel'' task, so the ARM conclusion needs no caveat. Manifest V2 has no announced Firefox end-of-support date. | Every external fact re-fetched today. The whole maintenance table reproduced exactly, all four cited issues still open, Bugzilla 634073 still ''NEW'', no PyPI package, Docker Hub still amd64-only, conda-forge still zero ''linux-aarch64'' builds for the three pins, geckodriver still 0.37.1 with its own ''CHANGES.md'' confirming the capabilities change, and — the check that mattered most — **the current** latest ''mozilla-release'' build also has no ''linux64-aarch64-add-on-devel'' task, so the ARM conclusion needs no caveat. Manifest V2 has no announced Firefox end-of-support date. |
| | — | Noted, not used: Firefox is now 153.0 and Selenium 4.47.0. The pages claim neither as current | no change | | | — | Noted, not used: Firefox is now 153.0 and Selenium 4.47.0. The pages claim neither as current | no change | |
| |
| ==== 11.5 Generic pass (''fable'') ==== | ==== 11.5 Generic pass (fable) ==== |
| |
| It returned late, after the pages were already published, and it justified its slot: **fifteen findings on a page three focused passes had cleared**, including a data-loss bug in code the page tells readers to copy. Every one below was verified against the repository or the corpus before being accepted; the pages were then corrected and re-saved. | It returned late, after the pages were already published, and it justified its slot: **fifteen findings on a page three focused passes had cleared**, including a data-loss bug in code the page tells readers to copy. Every one below was verified against the repository or the corpus before being accepted; the pages were then corrected and re-saved. |
| | ALSAcnc imports rather than forks | ''git clone https://github.com/bouhoula/alsacnc''; ''grep -rn "from openwpm"'' | Imports ''openwpm.config'', ''openwpm.task_manager'', ''openwpm.commands.types'', ''openwpm.storage.sql_provider''; OpenWPM itself is cloned at a tag by ''docker/crawler/Dockerfile'', never vendored | | | ALSAcnc imports rather than forks | ''git clone https://github.com/bouhoula/alsacnc''; ''grep -rn "from openwpm"'' | Imports ''openwpm.config'', ''openwpm.task_manager'', ''openwpm.commands.types'', ''openwpm.storage.sql_provider''; OpenWPM itself is cloned at a tag by ''docker/crawler/Dockerfile'', never vendored | |
| | Monkey-patch layer | ''wc -l cookie_crawler/utils/monkey_patches/*.py'' | 5 files, **583 lines**: ''__init__.py'' 23, ''browser_manager.py'' 130, ''browser_manager_handle.py'' 194, ''command_sequence.py'' 199, ''shutdown.py'' 37. Applied at ''run_crawler.py:94'' and '':186'' | | | Monkey-patch layer | ''wc -l cookie_crawler/utils/monkey_patches/*.py'' | 5 files, **583 lines**: ''__init__.py'' 23, ''browser_manager.py'' 130, ''browser_manager_handle.py'' 194, ''command_sequence.py'' 199, ''shutdown.py'' 37. Applied at ''run_crawler.py:94'' and '':186'' | |
| | Upgrade history | ''git log --all -- docker/crawler/Dockerfile'', then ''git show <c>:docker/crawler/Dockerfile'' | **Four** pins, on two branches: ''235a510'' 2024-06-22 → v0.23.0, ''d5c449a'' 2024-09-24 → v0.29.0, ''3c6cfd1'' 2025-01-29 → v0.31.0 on ''main''; ''4acb3fd'' 2026-07-10 → **v0.34.0** on branch ''cnil''. The 2026-08-14 check ran ''git log'' without ''--all'' and saw only ''main'', so it found three and the page said three; a review pass found the fourth on 2026-09-05. The patch layer is byte-identical on both branches (23/130/194/199/37 lines), which is the stronger form of the claim: one 583-line layer across eleven OpenWPM releases | | | Upgrade history | ''git log %%--all%% -- docker/crawler/Dockerfile'', then ''git show <c>:docker/crawler/Dockerfile'' | **Four** pins, on two branches: ''235a510'' 2024-06-22 → v0.23.0, ''d5c449a'' 2024-09-24 → v0.29.0, ''3c6cfd1'' 2025-01-29 → v0.31.0 on ''main''; ''4acb3fd'' 2026-07-10 → **v0.34.0** on branch ''cnil''. The 2026-08-14 check ran ''git log'' without ''%%--all%%'' and saw only ''main'', so it found three and the page said three; a review pass found the fourth on 2026-09-05. The patch layer is byte-identical on both branches (23/130/194/199/37 lines), which is the stronger form of the claim: one 583-line layer across eleven OpenWPM releases | |
| | Upstream agrees | [[https://github.com/openwpm/OpenWPM/issues/964|issue #964]], comment by ''vringar'' 2021-12-16 | **Was not verbatim, and this row said it was.** Re-fetched 2026-09-05 via ''gh api repos/openwpm/OpenWPM/issues/964/comments'': the source reads "build on top of it **(as you apparently have done)** and never upgrade.\\ We should provide a better story here." The page had dropped the parenthetical with no ellipsis, and inserted an "[…]" between two consecutive sentences where nothing was cut. Both fixed. The dropped words are the ones that make the remark personal to the issue's author — the same non-independence this section discloses two paragraphs down, removed from the quote that shows it. Also corrected: #743 is an **issue**, not a PR (''pulls/743'' → 404, ''issues/743'' → "Refactor commands to actually follow the Command pattern"); #753 is a PR. The maintainer wrote "#743 and #753" without calling either a PR | | | Upstream agrees | [[https://github.com/openwpm/OpenWPM/issues/964|issue #964]], comment by ''vringar'' 2021-12-16 | **Was not verbatim, and this row said it was.** Re-fetched 2026-09-05 via ''gh api repos/openwpm/OpenWPM/issues/964/comments'': the source reads "build on top of it **(as you apparently have done)** and never upgrade.\\ We should provide a better story here." The page had dropped the parenthetical with no ellipsis, and inserted an "[…]" between two consecutive sentences where nothing was cut. Both fixed. The dropped words are the ones that make the remark personal to the issue's author — the same non-independence this section discloses two paragraphs down, removed from the quote that shows it. Also corrected: #743 is an **issue**, not a PR (''pulls/743'' → 404, ''issues/743'' → "Refactor commands to actually follow the Command pattern"); #753 is a PR. The maintainer wrote "#743 and #753" without calling either a PR | |
| |
| |
| ^ # ^ Finding ^ Action ^ | ^ # ^ Finding ^ Action ^ |
| | 1 | **The page said 3 of the 15 version-stating papers also state a browser. Seven do.** The hand map ''FIREFOX_STATED'' was seeded with ''/Firefox v?\d+/'', which matches "Firefox (v102)" but not "Firefox version 88" ({[demir2022_reproducibility]}), "the Firefox browser (v100.0" ({[demir2024_bannertools]}), "the Firefox browser (Version 123.0)" ({[bottger2025_regional]}), or a "Fire-[splice]fox v121.0" cut by a column splice ({[rasaii2025_crumbs]}) | **accepted**, all four read in ''paper.cols.txt'' and added. The consequences are larger than the count: pin mismatches go from 2 to **3** — {[bottger2025_regional]} ran Firefox 123 on v0.27.0, which ships 122 — and the split is now 3 matching the pin, 3 differing, 1 with no pin to compare. The page also contradicted itself, quoting {[rasaii2025_crumbs]} as "the best-documented row … states the OpenWPM version //and// the Firefox version" three paragraphs after saying only three papers state a browser. The report now runs a **wide** probe and prints the hits it rejects with the reason, so the map is auditable instead of asserted | | | 1 | **The page said 3 of the 15 version-stating papers also state a browser. Nine do.** The hand map ''FIREFOX_STATED'' was seeded with ''/Firefox v?\d+/'', which matches "Firefox (v102)" but not "Firefox version 88" ({[demir2022_reproducibility]}), "the Firefox browser (v100.0" ({[demir2024_bannertools]}), "the Firefox browser (Version 123.0)" ({[bottger2025_regional]}), or a "Fire-[splice]fox v121.0" cut by a column splice ({[rasaii2025_crumbs]}) | **accepted**, and then **got wrong a second time** — see §14.8. The first re-sweep was wide but ran only over slugs the reviewer had named, giving 7; swept over all 15 it gives **9**, adding {[fouad2022_cookie]} and {[demir2023_similarity]}. Final: 9 state a browser, 2 of them on a pre-0.10 release with no pin, and of the 7 checkable **3 do not match the pin** (was 2) — {[bottger2025_regional]} ran Firefox 123 on a release that ships 122. The page had also contradicted itself, quoting {[rasaii2025_crumbs]} as "the best-documented row … states the OpenWPM version //and// the Firefox version" three paragraphs after saying only three papers state a browser. The report now sweeps the **whole population** and prints the hits it rejects with reasons | |
| | 2 | **The Open Question "no paper we found reports ''num_browsers'' alongside a stateful claim" is false.** {[englehardt2018_email]} writes "We configure OpenWPM to run 15 measurement instances in parallel" and is one of the five ''both'' papers; {[englehardt2016online]} runs 20 | **accepted**, both read. Rewritten to the question that survives: papers do report the instance count, but none treats the resulting //N// cookie jars as a property of the measurement. An absence asserted from the papers that happened to be read, rather than from a query, is the characteristic way an Open Question goes wrong | | | 2 | **The Open Question "no paper we found reports ''num_browsers'' alongside a stateful claim" is false.** {[englehardt2018_email]} writes "We configure OpenWPM to run 15 measurement instances in parallel" and is one of the five ''both'' papers; {[englehardt2016online]} runs 20 | **accepted**, both read. Rewritten to the question that survives: papers do report the instance count, but none treats the resulting //N// cookie jars as a property of the measurement. An absence asserted from the papers that happened to be read, rather than from a query, is the characteristic way an Open Question goes wrong | |
| |
| ^ # ^ Finding ^ Action ^ | ^ # ^ Finding ^ Action ^ |
| | 3 | v0.36.0 (Firefox 154) exists; "Latest release 0.35.0", "four releases in 2026 … 148→152", "all 29 releases", "only the four 2026 releases (148–152)", and the two ''0.35.0 (Firefox 152)'' model sentences are all stale | **accepted**, probe re-run, whole table refreshed to 2026-09-05, version table gains a 0.36.0 row, 29→30 releases, four→five | | | 3 | v0.36.0 (Firefox 154) exists; "Latest release 0.35.0", "four releases in 2026 … 148→152", "all 29 releases", "only the four 2026 releases (148–152)", and the two ''0.35.0 (Firefox 152)'' model sentences are all stale | **accepted**, probe re-run, whole table refreshed to 2026-09-05, version table gains a 0.36.0 row, 29→30 releases, four→five | |
| | 4 | **The geckodriver pitfall describes a bug that upstream has fixed.** v0.36.0 pins ''geckodriver=0.37.1'' and requests the privilege through geckodriver's ''--allow-system-access'' flag instead of Firefox's ''-remote-allow-system-access'' | **accepted**, verified in ''deploy_firefox.py'' at ''61d285f'' and the CHANGELOG. The bullet is now scoped to v0.35.0 and earlier and says v0.36.0 fixes it. Our A/B measurement stands for the releases it was made on | | | 4 | **The geckodriver pitfall describes a bug that upstream has fixed.** v0.36.0 pins ''geckodriver=0.37.1'' and requests the privilege through geckodriver's ''%%--allow-system-access%%'' flag instead of Firefox's ''-remote-allow-system-access'' | **accepted**, verified in ''deploy_firefox.py'' at ''61d285f'' and the CHANGELOG. The bullet is now scoped to v0.35.0 and earlier and says v0.36.0 fixes it. Our A/B measurement stands for the releases it was made on | |
| | 5 | "Firefox reached 147" during 2025 — 147 shipped 2026-01-13; Firefox reached **146** in 2025 | **accepted**, ''product-details.mozilla.org/1.0/firefox_history_major_releases.json'' | | | 5 | "Firefox reached 147" during 2025 — 147 shipped 2026-01-13; Firefox reached **146** in 2025 | **accepted**, ''product-details.mozilla.org/1.0/firefox_history_major_releases.json'' | |
| | 6 | "180 open issues" is GitHub's ''open_issues_count'', which counts pull requests as issues | **accepted**: 141 issues + 39 PRs, from two ''search/issues'' queries, with the trap footnoted | | | 6 | "180 open issues" is GitHub's ''open_issues_count'', which counts pull requests as issues | **accepted**: 141 issues + 39 PRs, from two ''search/issues'' queries, with the trap footnoted | |
| | 8 | **The ''vringar'' quote is not verbatim and §12.1 said it was** — "(as you apparently have done)" dropped with no ellipsis, and an "[…]" inserted between two consecutive sentences | **accepted**, re-fetched and restored. See the corrected §12.1 row | | | 8 | **The ''vringar'' quote is not verbatim and §12.1 said it was** — "(as you apparently have done)" dropped with no ellipsis, and an "[…]" inserted between two consecutive sentences | **accepted**, re-fetched and restored. See the corrected §12.1 row | |
| | 9 | #743 is an **issue**, not a pull request | **accepted**, ''pulls/743'' → 404 | | | 9 | #743 is an **issue**, not a pull request | **accepted**, ''pulls/743'' → 404 | |
| | 10 | **ALSAcnc has a fourth public pin**, v0.34.0 (''4acb3fd'', 2026-07-10) on branch ''cnil'' — the 2026-08-14 check ran ''git log'' without ''--all'' | **accepted**, and it improves the page: the patch layer is byte-identical on both branches, so one 583-line layer carried the project across eleven OpenWPM releases, and its current pin is one of the five whose Firefox still downloads | | | 10 | **ALSAcnc has a fourth public pin**, v0.34.0 (''4acb3fd'', 2026-07-10) on branch ''cnil'' — the 2026-08-14 check ran ''git log'' without ''%%--all%%'' | **accepted**, and it improves the page. The "byte-identical patch layer" wording that first went with it was **wrong** and is corrected in §14.8: four of the five files are byte-identical across all four pins, and ''browser_manager.py'' is not. Its current pin is one of the five whose Firefox still downloads | |
| | 11 | **"a fork of any of those releases would by now be unbuildable" draws a contrast that does not exist** — ALSAcnc's ''main'' pins v0.31.0, whose Firefox 404s, so a fresh clone of it fails exactly as a fork would | **accepted**, and it was the sharpest finding of the pass. The bullet conflated two things. Rewritten so the contrast is **upgradability, not buildability**: the library-shaped project could move to a live release and did; a fork stops at the release it was cut from | | | 11 | **"a fork of any of those releases would by now be unbuildable" draws a contrast that does not exist** — ALSAcnc's ''main'' pins v0.31.0, whose Firefox 404s, so a fresh clone of it fails exactly as a fork would | **accepted**, and it was the sharpest finding of the pass. The bullet conflated two things. Rewritten so the contrast is **upgradability, not buildability**: the library-shaped project could move to a live release and did; a fork stops at the release it was cut from | |
| | 12 | **"Docker tags go back to 0.15.0" is wrong** — the four oldest images are ''v''-prefixed (''v0.10.0''–''v0.13.0''), plus ''0.14.1''; only ''0.14.0'' was never published | **accepted**. The 2026-08-14 probe tested one naming convention and read its absence as the artefact's absence. This one failed //against// the page's interest: a reader with a 2020–2021 artefact was told no image existed for it | | | 12 | **"Docker tags go back to 0.15.0" is wrong** — the four oldest images are ''v''-prefixed (''v0.10.0''–''v0.13.0''), plus ''0.14.1''; only ''0.14.0'' was never published | **accepted**. The 2026-08-14 probe tested one naming convention and read its absence as the artefact's absence. This one failed //against// the page's interest: a reader with a 2020–2021 artefact was told no image existed for it | |
| | 15 | §10 says "Six entries were added"; ''bib_additions_openwpm.bib'' has seven | **accepted** — the seventh ({[agarwal2020_stop]}) was added later the same day by §11.1 S8 and the count was not updated | | | 15 | §10 says "Six entries were added"; ''bib_additions_openwpm.bib'' has seven | **accepted** — the seventh ({[agarwal2020_stop]}) was added later the same day by §11.1 S8 and the count was not updated | |
| | 16 | §7's source table still credited ''docs/Configuration.md'' with "''save_content'' MD5 de-duplication" after §11.5 #2 corrected the page to SHA-256 | **accepted** — the same carry-over defect, one section apart | | | 16 | §7's source table still credited ''docs/Configuration.md'' with "''save_content'' MD5 de-duplication" after §11.5 #2 corrected the page to SHA-256 | **accepted** — the same carry-over defect, one section apart | |
| | 17 | ''[[:Artifacts]]'' is flagged on the page as "a page this wiki still owes you". It exists, with real content | **accepted**, flag removed. Verified from the rendered DOM: the link is ''wikilink1''. The identical stale caveat on [[:programming:crawler]] is **out of this item's scope** and was filed as a work item rather than edited | | | 17 | ''[[:Artifacts]]'' is flagged on the page as "a page this wiki still owes you". It exists, with real content | **accepted**, flag removed. Verified from the rendered DOM: the link is ''wikilink1''. The identical stale caveat on [[:programming:crawler]] was fixed in the link-hygiene sweep; both links are ''wikilink1'' on the fresh DOM. | |
| | 18 | "a handful of groups keep private copies of these tarballs", and "on an M-series Mac … That works", are asserted flatly with nothing behind them | **accepted in part**: both are true as far as we know and neither is checkable here, so both are now attributed as such rather than deleted. No Mac was available to this run | | | 18 | "a handful of groups keep private copies of these tarballs", and "on an M-series Mac … That works", are asserted flatly with nothing behind them | **accepted in part**: both are true as far as we know and neither is checkable here, so both are now attributed as such rather than deleted. No Mac was available to this run | |
| | 19 | Firefox 153 was skipped by OpenWPM because its **tagged revision has no unbranded builds on any platform** — a second way the pinned build can be missing, distinct from expiry | **accepted**, added to the expiry pitfall. Found in the v0.36.0 CHANGELOG by the adversarial pass while checking something else | | | 19 | Firefox 153 was skipped by OpenWPM because its **tagged revision has no unbranded builds on any platform** — a second way the pinned build can be missing, distinct from expiry | **accepted**, added to the expiry pitfall. Found in the v0.36.0 CHANGELOG by the adversarial pass while checking something else | |
| |
| Neither of these two tool bugs was found by an agent. Both turned up because the guards were actually run against the live pages rather than assumed to have been run when the pages were written — which is the argument for §14 existing at all. | Neither of these two tool bugs was found by an agent. Both turned up because the guards were actually run against the live pages rather than assumed to have been run when the pages were written — which is the argument for §14 existing at all. |
| | |
| | |
| | ==== 14.8 The verification pass, which found five defects in the corrections above ==== |
| | |
| | Per the workflow's own rule — re-run any reviewer whose findings you acted on — a ''sonnet'' pass was given the **corrected, published** pages and told to assume the corrections were wrong. It was right five times, and two of those were in the very finding §14.1 records as fixed. Everything below was re-verified by hand before being applied. |
| | |
| | ^ # ^ What the correction got wrong ^ Now ^ |
| | | A | **The corrected Firefox count was still short.** {[fouad2022_cookie]} states its browsers in a setup table — "Firefox version 68.0 45.0.1 … OpenWPM ver[splice]sion v0.9.0 v0.7.0" — and was in neither the map nor its rejected list | **accepted.** Re-swept over all 15 rather than over reviewer-named slugs, which also found {[demir2023_similarity]} ("the most recent stable Firefox version available … (v95.0 …) and a version that is roughly one year older (v86.0.1 …)"). **9, not 7.** Split 4 match / 3 differ / 2 no-pin; 6 say nothing. Also rejected on the same sweep: {[bollinger2022automating]}, whose only "Firefox 86" is a bibliography title | |
| | | B | **"the patch layer is byte-identical across all four" is false.** ''browser_manager.py'' differs on ''cnil'' | **accepted**, and the truth is a better argument: four of five files are untouched, and the fifth changed by one rebinding — ''BrowserManager.run'' → ''run_impl'' — because upstream renamed the method. That //is// what a monkey-patch upgrade costs, shown rather than asserted | |
| | | C | **"eleven OpenWPM releases" is twelve.** v0.23.0…v0.34.0 inclusive is 12 tags | **accepted**, reworded to "the twelve releases v0.23.0 to v0.34.0" | |
| | | D | **§3.3 still carried the pre-correction "3 of 15 … 2 of those 3".** The 2026-09-05 pass fixed §14 and the content page and left an earlier section of //this// page asserting the old numbers | **accepted.** This is the carry-over defect this page has now committed three times (§7's MD5 row, §11.5 #14's phantom annotation, and now §3.3): a figure is corrected where it is loudest and survives where it is quiet. Both counts in §3.3 replaced, with a pointer to §14.1 | |
| | | E | **The report script's own header sentence was backwards** — it announced "The other 8 leave the browser to be inferred from the pin:" and then printed the papers that //do// state it | **accepted**, and it mattered because that raw output is published verbatim in §4. Rewritten | |
| | | F | The ''ahmad2020_apophanies'' entry was footnoted "NOT a sentence read in the paper — the only entry here that is not". The paper does contain one: "at the time of our experiments Open-WPM was unable to drive Firefox versions later than v52.9, while Selenium drove Firefox v66.0", plus a table row | **accepted**, the quote is now the paper's own sentence and the disclaimer is gone | |
| | |
| | **What this pass says about the one before it.** The generic passes found the original error; the verification pass found that the fix was itself incomplete, and incomplete *in the same way* — a probe run over too small a population instead of too narrow a pattern. A correction is not self-verifying, and "we widened the regex" is not the same claim as "we swept the population". The report now does the sweep in code, over ''statedPapers'' itself, so the next person to widen it cannot quietly narrow the population at the same time. |
| |
| ===== Amendment, 2026-09-04: citekey consolidation ===== | ===== Amendment, 2026-09-04: citekey consolidation ===== |
| does not is worse than either convention applied consistently. */ | does not is worse than either convention applied consistently. */ |
| ~~DISCUSSION~~ | ~~DISCUSSION~~ |
| | |
| | ===== Markup sweep, 2026-09-17 ===== |
| | |
| | Mechanical rendering repair only: a fresh live raw/XHTML export of 188 pages was checked with ''check_wrap.mjs'' and ''check_typography.mjs''. Affected plugin tags, CLI flags and heading markup were repaired; no figures or substantive prose were changed. The resulting source and rendered DOM were re-checked after saving. |
| | |
| | ===== Link-hygiene sweep, 2026-09-17 ===== |
| | |
| | The historical stale-caveat row now records that the paired ''programming:crawler'' page was fixed in this sweep. The fresh rendered DOM confirmed both ''Artifacts'' links are live; no figures or citations changed. |
| | |
| | ===== Currency re-check, 2026-09-17 ===== |
| | |
| | The stale illustrative release/browser sentence on [[programming:crawler:openwpm]] |
| | was already corrected when this item was read: the page says ''OpenWPM 0.36.0 |
| | (Firefox 154)''. No content edit was made. The release pin and moving stable |
| | channel were re-fetched with these commands: |
| | |
| | <code> |
| | curl -sS 'https://product-details.mozilla.org/1.0/firefox_versions.json' | python3 -c 'import json,sys; d=json.load(sys.stdin); print(json.dumps({k:d.get(k) for k in ("LATEST_FIREFOX_VERSION","LATEST_FIREFOX_DEVEL_VERSION","FIREFOX_ESR","FIREFOX_ESR_VERSION")}, sort_keys=True))' |
| | curl -sS 'https://raw.githubusercontent.com/openwpm/OpenWPM/v0.35.0/environment.yaml' | rg -n -i 'firefox|geckodriver' |
| | curl -sS 'https://raw.githubusercontent.com/openwpm/OpenWPM/v0.35.0/scripts/install-firefox.sh' | rg -n '^(TAG|TARGET_SUFFIX)|FIREFOX_|firefox-ci|taskcluster' |
| | bash scripts/openwpm_firefox_availability.sh |
| | </code> |
| | |
| | Mozilla's product-details API returned ''LATEST_FIREFOX_VERSION=156.0''. The |
| | v0.35.0 installer returned ''FIREFOX_152_0_RELEASE'' and its environment pins |
| | ''geckodriver=0.37.0''; the availability checker returned ''v0.35.0 ... |
| | FIREFOX_152_0_ .tar.xz HTTP=200'' and ''v0.36.0 ... FIREFOX_154_0_ .tar.xz |
| | HTTP=200''. The content page's 0.36.0/154 example therefore names that release's |
| | own pin, not the moving stable channel. |
| | |
| | ===== Review layer, 2026-09-17 ===== |
| | |
| | One shared ''model: sonnet'' external-currency pass ran after publication and |
| | re-ran ''bash scripts/openwpm_firefox_availability.sh''. It **passed** the |
| | existing ''OpenWPM 0.36.0 (Firefox 154)'' example and found no correction needed; |
| | the v0.35.0 and v0.36.0 pins returned HTTP 200 from their resolved Mozilla build |
| | URLs. |
| | |
| | ===== Quote-check refresh, 2026-09-21 ===== |
| | |
| | The 2026-09-04 ''cols''-vs-PDF audit on [[:provenance:literature:corpus]] showed that 73.1% of evidence quotes that cannot be located in ''paper.cols.txt'' **are** present in an independent ''pypdf'' rendering of the same ''paper.pdf''. ''scripts/quote_check.mjs'' was patched the same day to re-check everything below threshold against that second rendering and report a fourth verdict, **RESCUED**. §5's first-pass figure predates the patch. Re-run, unedited first line: |
| | |
| | <code> |
| | $ node scripts/quote_check.mjs --tools 'open[ -]?wpm' --show 400 |
| | 65 quotes checked: 34 exact, 19 partial (>=60% of 5-word windows), 10 rescued from the PDF, 2 below threshold in both renderings, 0 with no full text on disk. |
| | </code> |
| | |
| | ^ Figure ^ Was ^ Is ^ Why ^ |
| | | quotes checked | 65 | 65 | population unchanged — the corpus has not moved | |
| | | exact | 34 | 34 | unchanged | |
| | | partial (≥60% of 5-word windows) | 19 | 19 | unchanged | |
| | | rescued from the PDF | — | **10** | new verdict; these were inside the old 12 | |
| | | below threshold | **12** | **2** (in both renderings) | 12 = 10 + 2 exactly; nothing else moved | |
| | |
| | **This page argued for the fallback before the fallback existed, and the second pass is not superseded by it.** §5's ''openwpm_quotecheck.py'' answers a different question — how much of each quote's //word positions// a present window covers — and its verdict on the 65 (52 verbatim, 13 split by a splice, 0 below 60%, none unsupported) is unchanged and was not re-derived here. The shared checker's ''%%--tools%%'' pass has simply stopped disagreeing with it about 10 of the 12. |
| | |
| | **Scope of this edit.** §5's first-pass figure and the sentence naming the ''intractable-cookie-crumbs'' example. ''openwpm_quotecheck.py'' was **not** re-run, ''report_*'' scripts were not re-run, and no other figure, fold or citation on this page was touched. |
| | |
| | ^ Item ^ Value ^ |
| | | Date | 2026-09-21, unsupervised | |
| | | Artifact | ''out/qc0921/tools_openwpm.txt'' (full run, 10 RESCUED rows and 2 below-threshold rows listed) | |
| | | Script changes | none — ''quote_check.mjs'' was already patched on 2026-09-04 | |
| | | Reviewers | one ''sonnet'' figures-vs-script pass | |
| | | Pages saved | this page only — [[:programming:crawler:openwpm]] carries no quote-check figure | |
| |