| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| provenance:programming:crawler:webxray [2026/09/17 06:26] – C3.9 fixes from review: mutation-harness count was 14, is 24; note that the re-run command no longer reproduces the NOTFOUND; fontawesome.com is no longer a bytes-pass failure; state the post-requote residue. Authored by Claude karel.kubicek.claude | provenance:programming:crawler:webxray [2026/09/22 04:23] (current) – Escape the literal {[citekey]} in the 2026-09-22 scope note: ''..'' monospace does not escape the bibtex plugin, so it rendered as a live unresolved citation marker. Authored by Claude karel.kubicek.claude |
|---|
| | A8 | Per-year and per-venue shape | year/venue of the 15 | 15 | last use of crawler-or-list: **2022** | | | A8 | Per-year and per-venue shape | year/venue of the 15 | 15 | last use of crawler-or-list: **2022** | |
| | A9 | Which ownership resources does the corpus name at all? | six full-text sweeps | 5,859 | PSL 101, Disconnect-as-a-list 74, Tracker Radar 32, WhoTracks.me 23, Crunchbase 23, webXray 15 | | | A9 | Which ownership resources does the corpus name at all? | six full-text sweeps | 5,859 | PSL 101, Disconnect-as-a-list 74, Tracker Radar 32, WhoTracks.me 23, Crunchbase 23, webXray 15 | |
| | A10 | Union of the five owner databases | union of A9 rows minus the PSL row | 5,859 / 1,120 crawled | **136** (2.3% / 12.1%) | | | A10 | Union of the five owner databases | union of A9 rows minus the PSL row | 5,859 / 1,120 crawled | **136** (2.3% of the corpus); **107** of them are among the 1,120 that crawled (**9.6%** of that population) | |
| | A11 | Which Tracker Radar artefact did each of the 32 use? | ''TR_ROLE'' hand map | 32 | ownership 11, tracker/category 9, Collector crawler 9, citation 2, compared 1 | | | A11 | Which Tracker Radar artefact did each of the 32 use? | ''TR_ROLE'' hand map | 32 | ownership 11, tracker/category 9, Collector crawler 9, citation 2, compared 1 | |
| | A12 | Ownership use of Tracker Radar over time | year of the 11 | — | 2021:1, 2023:2, 2024:1, 2025:4, 2026:3 | | | A12 | Ownership use of Tracker Radar over time | year of the 11 | — | 2021:1, 2023:2, 2024:1, 2025:4, 2026:3 | |
| ==== A.16 Evidence quotes spot-checked ==== | ==== A.16 Evidence quotes spot-checked ==== |
| |
| The 16 ''evidence.quote'' values behind the webXray tool and classification tuples, checked by 4-word-window coverage against ''paper.cols.txt'': **4 exact, 11 partial (≥60% of windows), 1 below threshold.** Full list in section H of the report output. | The 16 ''evidence.quote'' values behind the webXray tool and classification tuples, checked by 4-word-window coverage against ''paper.cols.txt'', with a ''pypdf'' rendering of the same ''paper.pdf'' consulted for anything below threshold: **4 exact, 11 partial (≥60% of windows), 0 rescued from the PDF, 1 below threshold in both renderings.** Full list in section H of the report output. |
| |
| The one below threshold is {[musa2022_atom]} at 58%: "We used external data sources including WHOIS records, TLS certificates, and WebXray [61] to identify the parent organizations of each identified tracker." Read by hand in the source: **present and verbatim**; the ''.cols'' rendering splices an adjacent column through it. Below-threshold is not "unsupported". | The one below threshold is {[musa2022_atom]} at 58%: "We used external data sources including WHOIS records, TLS certificates, and WebXray [61] to identify the parent organizations of each identified tracker." Read by hand in the source: **present and verbatim**; the ''.cols'' rendering splices an adjacent column through it. Below-threshold is not "unsupported". |
| ^ ^ ^ | ^ ^ ^ |
| | Frame | the **32,337** registrable domains in Tracker Radar's ''domain_summary.json'' as fetched on **2026-09-05**, folded with the **ICANN section only** of the Public Suffix List and resolved by parent-label lookup. ''owner_sample.py'' imports ''owner_dbs.py'' and uses its universe function, so the frame is built by the same code as the first sitting's | | | Frame | the **32,337** registrable domains in Tracker Radar's ''domain_summary.json'' as fetched on **2026-09-05**, folded with the **ICANN section only** of the Public Suffix List and resolved by parent-label lookup. ''owner_sample.py'' imports ''owner_dbs.py'' and uses its universe function, so the frame is built by the same code as the first sitting's | |
| | …but it is **not the same snapshot** | the first sitting's frame, on 2026-08-17, was **32,369** domains. Tracker Radar's ''domain_summary.json'' and the Public Suffix List both changed between the two dates (see the run table above), and the frame moved by 32 domains. Per-list coverage moved with it: webXray 669→664, Tracker Radar 5,581→5,566, Disconnect 2,268→2,264, and webXray's prevalence mass 58.6%→57.9%. The coverage **shares** are unchanged to one decimal (2.1% / 17.2% / 7.0%), which is why the two sets of figures can sit on one page without looking inconsistent — and is exactly why the difference is stated here. Verify with ''python3 scripts/owner_sample.py --cache out/webxray/cache'' against ''--cache out/owner_cache'' | | | …but it is **not the same snapshot** | the first sitting's frame, on 2026-08-17, was **32,369** domains. Tracker Radar's ''domain_summary.json'' and the Public Suffix List both changed between the two dates (see the run table above), and the frame moved by 32 domains. Per-list coverage moved with it: webXray 669→664, Tracker Radar 5,581→5,566, Disconnect 2,268→2,264, and webXray's prevalence mass 58.6%→57.9%. The coverage **shares** are unchanged to one decimal (2.1% / 17.2% / 7.0%), which is why the two sets of figures can sit on one page without looking inconsistent — and is exactly why the difference is stated here. Verify with ''python3 scripts/owner_sample.py %%--cache%% out/webxray/cache'' against ''%%--cache%% out/owner_cache'' | |
| | Which figures use which | every **accuracy** figure and the coverage counts in the random-sample section use the 2026-09-05 frame (32,337). Every figure in the earlier coverage and agreement sections, and all 30 rows of the hand adjudication, use the 2026-08-17 frame (32,369) and are **not** re-derived: they are pinned to the snapshot the adjudication was done against, and re-running them would orphan that work | | | Which figures use which | every **accuracy** figure and the coverage counts in the random-sample section use the 2026-09-05 frame (32,337). Every figure in the earlier coverage and agreement sections, and all 30 rows of the hand adjudication, use the 2026-08-17 frame (32,369) and are **not** re-derived: they are pinned to the snapshot the adjudication was done against, and re-running them would orphan that work | |
| | What that is | **Tracker Radar's view of the third-party surface**, not a neutral census of the web. Every figure inherits it | | | What that is | **Tracker Radar's view of the third-party surface**, not a neutral census of the web. Every figure inherits it | |
| | ''owner_verify_sources.py'' | re-fetch the URL with ''curl''-grade HTTP, or redo the TLS handshake for a ''tls://'' source; match the quote after normalising whitespace, quote characters and hyphenation | 121 OK of the 136 rows that carried a source at that point; 13 NOTFOUND, 2 FETCHFAIL | | | ''owner_verify_sources.py'' | re-fetch the URL with ''curl''-grade HTTP, or redo the TLS handshake for a ''tls://'' source; match the quote after normalising whitespace, quote characters and hyphenation | 121 OK of the 136 rows that carried a source at that point; 13 NOTFOUND, 2 FETCHFAIL | |
| | ''owner_verify_rendered.mjs'' | re-check the failures in a real browser (Playwright), because footers and Impressum text are frequently client-rendered | rescued **5**: ''fontawesome.com'', ''flashtalking.com'', ''force.com'', ''conviva.com'', ''cartfulsolutions.com'' | | | ''owner_verify_rendered.mjs'' | re-check the failures in a real browser (Playwright), because footers and Impressum text are frequently client-rendered | rescued **5**: ''fontawesome.com'', ''flashtalking.com'', ''force.com'', ''conviva.com'', ''cartfulsolutions.com'' | |
| | ''owner_corrections.py'' | by hand, for the 10 that survived both, plus 1 added on 2026-09-17 when the fixed checker was re-run over all 175 rows ([[#C3.9 The fixed checker re-run over the first sitting (2026-09-17)|C3.9]]) | 5 ''requote'', 5 ''resource'', 1 ''demote'' | | | ''owner_corrections.py'' | by hand, for the 10 that survived both, plus 1 applied on 2026-09-17 from the 2026-09-11 re-run of the fixed checker ([[#C3.9 The 2026-09-11 re-run, applied (2026-09-17)|C3.9]]) | 5 ''requote'', 5 ''resource'', 1 ''demote'' | |
| |
| The 5 **requotes** are the finding worth keeping: in 5 of 175 rows the "quote" | The **requotes** are the finding worth keeping: in **4** of 175 rows the "quote" |
| was a re-ordering, a summary or a splice of the page's own words, despite a brief | was a re-ordering or a summary of the page's own words, despite a brief that said |
| that said verbatim. The claim held in all five and the source stayed; the quote | verbatim. The claim held in all four and the source stayed; the quote was |
| was replaced with text copied out of the fetched page. Four were found on | replaced with text copied out of the fetched page. A **fifth** requote, |
| 2026-09-05; the fifth, ''compass-fit.jp'', only on 2026-09-17, because the | ''compass-fit.jp'', is counted with them in the table above because the remedy is |
| checker that would have caught it was itself broken for non-Latin text until | identical, but it is a different defect: **one dropped character**, not a |
| 2026-09-11 — see [[#C3.9 The fixed checker re-run over the first sitting (2026-09-17)|C3.9]]. That is the argument for | paraphrase. It was found on 2026-09-11 and applied on 2026-09-17, because the |
| | checker that would have caught it in the first place was itself blind to |
| | non-Latin text until then — see [[#C3.9 The 2026-09-11 re-run, applied (2026-09-17)|C3.9]]. That is the argument for |
| verifying every citation by machine rather than trusting the adjudicator, and it | verifying every citation by machine rather than trusting the adjudicator, and it |
| is the same defect a WebFetch summary produces. | is the same defect a WebFetch summary produces. |
| **Where every row's citation ended up** (''owner_citation_audit.py''): | **Where every row's citation ended up** (''owner_citation_audit.py''): |
| |
| ^ State ^ Rows ^ | All four columns below are **as of 2026-09-05**, and two of the numbers have |
| | since moved for reasons that are not about the citations — |
| | [[#C3.9 The 2026-09-11 re-run, applied (2026-09-17)|C3.9]] has the arithmetic. |
| | |
| | ^ State (2026-09-05) ^ Rows ^ |
| | cited, confirmed in the fetched bytes | 132 — of which **119 are the whole quote**, 8 matched as fragments either side of an ellipsis, and 5 matched only on a 60-character window of a long quote | | | cited, confirmed in the fetched bytes | 132 — of which **119 are the whole quote**, 8 matched as fragments either side of an ellipsis, and 5 matched only on a 60-character window of a long quote | |
| | cited, confirmed only in a rendered browser | 3 | | | cited, confirmed only in a rendered browser | 3 | |
| ''force.com''. A bytes-only audit re-run **on 2026-09-05** reported all three as | ''force.com''. A bytes-only audit re-run **on 2026-09-05** reported all three as |
| failures — ''fontawesome.com'' no longer, since the ''OK-MARKUP'' status of | failures — ''fontawesome.com'' no longer, since the ''OK-MARKUP'' status of |
| 2026-09-11 lets the bytes pass see the markup its quote is ([[#C3.9 The fixed checker re-run over the first sitting (2026-09-17)|C3.9]]) — | 2026-09-11 lets the bytes pass see the markup its quote is ([[#C3.9 The 2026-09-11 re-run, applied (2026-09-17)|C3.9]]) — |
| which is why the audit script exists: the answer to "so are three figures | which is why the audit script exists: the answer to "so are three figures |
| uncited?" otherwise lives in three separate JSON files. | uncited?" otherwise lives in three separate JSON files. |
| //root// rather than its entry (''addthiscdn.com'', ''tqlkg.com''; both are in | //root// rather than its entry (''addthiscdn.com'', ''tqlkg.com''; both are in |
| ''owner_verdict_fixes.py'' with the reasoning), and 1 from the ''cnevids.com'' | ''owner_verdict_fixes.py'' with the reasoning), and 1 from the ''cnevids.com'' |
| demotion. Separately, **10 of 175 rows had their source or quote replaced**, and | demotion. Separately, **11 of 175 rows had their source or quote replaced**, and |
| 9 of those 10 left the verdicts untouched. | 10 of those 11 left the verdicts untouched. |
| |
| ==== C3.5a A page-destroying DokuWiki defect, found before publication ==== | ==== C3.5a A page-destroying DokuWiki defect, found before publication ==== |
| === Three defects this pass found in the instruments === | === Three defects this pass found in the instruments === |
| |
| * **''owner_verify_sources.py'' was deleting every non-Latin character.** Its ''norm()'' ended in ''%re.sub(r"[^a-z0-9]+", " ", s)%'', so a Cyrillic, Greek, Hebrew or CJK quote was checked only on whatever Latin substring it happened to contain — and a wholly non-Latin quote normalised to the empty string and was reported ''NOQUOTE'', a status that reads like "the row has no quote" rather than "I could not check this quote". ''owner_verify_rendered.mjs'' has always used ''%[^a-z0-9À-]+%'', so the browser pass and the bytes pass disagreed about what a character is. Found because rater 2 cited a wholly Chinese sentence for ''qbox.me''. The Python class is now the JavaScript one. **Consequence for the first sitting:** re-running the fixed script over all 175 rows moves three statuses, and only one of them is this fix biting — ''compass-fit.jp'', whose Japanese quote was previously verified on the six letters ''COMPASS-FIT'' alone and is **not** verbatim on the cited page. The mismatch is **one character**: the page's body reads ''台湾国内での、ネイティブ型広告配信サービス…'' and the row's quote drops the full-width comma after ''台湾国内での''. Everything else, including the ''致しました。'' ending, is on the page. So this is a transcription slip rather than a paraphrase, and the row's //claim// is unaffected — MicroAd's own newsroom page carries the partnership, the service name and Taiwan — so no published rate moves. The row needed a ''requote'' in ''owner_corrections.py''; that was **done on 2026-09-17** and is recorded in [[#C3.9 The fixed checker re-run over the first sitting (2026-09-17)|C3.9]]. //A first draft of this bullet said the page's headline ends ''の提供を開始'' and implied the ''致しました。'' ending appears nowhere; a reviewer found the full sentence in the body and the real one-comma difference.// ''tns-counter.ru'', the other non-Latin row, verifies clean under the fix. | * **''owner_verify_sources.py'' was deleting every non-Latin character.** Its ''norm()'' ended in ''%re.sub(r"[^a-z0-9]+", " ", s)%'', so a Cyrillic, Greek, Hebrew or CJK quote was checked only on whatever Latin substring it happened to contain — and a wholly non-Latin quote normalised to the empty string and was reported ''NOQUOTE'', a status that reads like "the row has no quote" rather than "I could not check this quote". ''owner_verify_rendered.mjs'' has always used ''%[^a-z0-9À-]+%'', so the browser pass and the bytes pass disagreed about what a character is. Found because rater 2 cited a wholly Chinese sentence for ''qbox.me''. The Python class is now the JavaScript one. **Consequence for the first sitting:** re-running the fixed script over all 175 rows moves three statuses, and only one of them is this fix biting — ''compass-fit.jp'', whose Japanese quote was previously verified on the six letters ''COMPASS-FIT'' alone and is **not** verbatim on the cited page. The mismatch is **one character**: the page's body reads ''台湾国内での、ネイティブ型広告配信サービス…'' and the row's quote drops the full-width comma after ''台湾国内での''. Everything else, including the ''致しました。'' ending, is on the page. So this is a transcription slip rather than a paraphrase, and the row's //claim// is unaffected — MicroAd's own newsroom page carries the partnership, the service name and Taiwan — so no published rate moves. The row needed a ''requote'' in ''owner_corrections.py''; that was **done on 2026-09-17** and is recorded in [[#C3.9 The 2026-09-11 re-run, applied (2026-09-17)|C3.9]]. //A first draft of this bullet said the page's headline ends ''の提供を開始'' and implied the ''致しました。'' ending appears nowhere; a reviewer found the full sentence in the body and the real one-comma difference.// Three rows in the 175 carry a non-Latin quote, not two: ''compass-fit.jp'', ''tns-counter.ru'' (Russian) and ''bilibili.com'' (a certificate subject, ''%%O = 上海幻电信息科技有限公司%%'', which the broken class reduced to "o cn bilibili com"). The other two verify clean under the fix. **The fix is not symmetric, and that is worth stating:** the character class keeps everything in U+00C0–U+FFFF, which includes CJK punctuation, while ASCII punctuation is still normalised to whitespace. So ''%%norm("Brightcove Inc, describes") == norm("Brightcove Inc describes")%%'' is true and the same comparison over ''%%国内での、ネイティブ%%'' versus ''%%国内でのネイティブ%%'' is false. A Latin quote missing a comma passes; a Japanese one does not. That asymmetry is why ''compass-fit.jp'' failed on one character, and closing it would mean stripping U+3000–U+303F and U+FF00–U+FF65 as well. |
| * **Neither citation check can see a quote that is markup.** ''owner_verify_sources.norm()'' strips ''%<...>%'' before searching, which is right for a prose quote and fatal for a citation to a ''%<script src>%'', a ''%<link>%'' or an attribute; ''owner_verify_rendered.mjs'' reads ''document.body.innerText'', which excludes script elements for the same reason. So the two passes, which exist to catch each other's blind spots, share this one — and a **false** NOTFOUND from both was acted on. The bytes pass now also searches an un-stripped copy and reports ''OK-MARKUP'' when that is where the quote lives. Re-running the fixed script over the **first** sitting's 175 rows moves ''fontawesome.com'' from NOTFOUND to OK-MARKUP; that row was already rescued by the browser pass in ''owner_citation_audit.py'', so the published "0 uncited rows" is unchanged and now has two independent routes rather than one. | * **Neither citation check can see a quote that is markup.** ''owner_verify_sources.norm()'' strips ''%<...>%'' before searching, which is right for a prose quote and fatal for a citation to a ''%<script src>%'', a ''%<link>%'' or an attribute; ''owner_verify_rendered.mjs'' reads ''document.body.innerText'', which excludes script elements for the same reason. So the two passes, which exist to catch each other's blind spots, share this one — and a **false** NOTFOUND from both was acted on. The bytes pass now also searches an un-stripped copy and reports ''OK-MARKUP'' when that is where the quote lives. Re-running the fixed script over the **first** sitting's 175 rows moves ''fontawesome.com'' from NOTFOUND to OK-MARKUP; that row was already rescued by the browser pass in ''owner_citation_audit.py'', so the published "0 uncited rows" is unchanged and now has two independent routes rather than one. |
| * **The citation check is time-sensitive, and by a measurable amount.** The same 175 rows re-verified six days later move **3 statuses of 175** (and a fourth, ''fontawesome.com'', is rescued ''NOTFOUND'' → ''OK-MARKUP'' by the status added in the bullet above, which is a change of instrument rather than of evidence), two of them for reasons that are purely the web moving: ''cartfulsolutions.com'' went ''OK'' → ''OK-WINDOW'', and ''brightcove.net'' went ''OK-WINDOW'' → ''FETCHFAIL'' on one run and back to ''OK-WINDOW'' on the next, which is a host being briefly unreachable rather than a citation changing. A "zero uncited rows" claim is therefore a claim about a date, and this page should be read as saying the citations verified on 2026-09-05, 2026-09-11 and — for the three rows below — 2026-09-17 rather than that they verify. Re-fetched again on 2026-09-17: ''brightcove.net'' is ''OK-WINDOW'' (806,613 bytes; the page now reads %%The Brightcove Privacy Policies ("Privacy Policies") describe Brightcove Inc.%%, an inserted parenthetical inside the quoted span), and ''cartfulsolutions.com'' is still ''OK-WINDOW'' (23,044 bytes; the footer was restructured so the "© 2026" and the trademark sentence are no longer adjacent). Both name the same entity they did, neither was requoted, and ''OK-WINDOW'' is a passing status by design. | * **The citation check is time-sensitive, but less of what moves is the web than it looks.** Re-verifying the same 175 rows on 2026-09-11 moves **3 statuses of 175**: ''compass-fit.jp'' ''OK'' → ''NOTFOUND'' (the non-Latin fix biting), ''cartfulsolutions.com'' ''OK'' → ''OK-WINDOW'' (the web moving: the footer was restructured and the page grew from 15,933 to 23,044 bytes), and ''fontawesome.com'' ''NOTFOUND'' → ''OK-MARKUP'' (the instrument changing, per the bullet above). ''brightcove.net'' is ''OK-WINDOW'' in **both** retained artefacts; it FETCHFAILed on one execution of the script and answered on the next, which is a host briefly unreachable and not a status that moved. Its quote elides about 20 characters the page has carried since 2026-09-05, so it is an adjudicator elision of the same class as ''compass-fit.jp'' — rescued only because a long quote gets the 60-character window fallback and a 40-character one does not. A "zero uncited rows" claim is therefore a claim about a date, and about a quote length; this page should be read as saying the citations verified on 2026-09-05, on 2026-09-11 and — for three named rows — on 2026-09-17, rather than that they verify. |
| |
| === What this section does and does not license === | === What this section does and does not license === |
| * **Six days separate the two ratings.** Corporate ownership rarely moves in six days, and the frozen probe removes the mechanical part of the drift, but a page that changed in that window is indistinguishable from a rater that read it differently. | * **Six days separate the two ratings.** Corporate ownership rarely moves in six days, and the frozen probe removes the mechanical part of the drift, but a page that changed in that window is indistinguishable from a rater that read it differently. |
| |
| ==== C3.9 The fixed checker re-run over the first sitting (2026-09-17) ==== | ==== C3.9 The 2026-09-11 re-run, applied (2026-09-17) ==== |
| |
| The ''norm()'' fix of 2026-09-11 ([[#C3.8 Inter-rater agreement: a second model on a random fifth (2026-09-11)|C3.8]]) was made while auditing the //second// rater's rows. It also invalidates the first sitting's pass over every row whose quote is not Latin script, because the broken checker had reported those rows OK on whatever Latin substring they happened to contain. This section is the re-run, and what it changed. | The ''norm()'' fix of 2026-09-11 ([[#C3.8 Inter-rater agreement: a second model on a random fifth (2026-09-11)|C3.8]]) was made while auditing the //second// rater's rows. It also invalidates the first sitting's pass over every row whose quote is not Latin script, because the broken checker had reported those rows OK on whatever Latin substring they happened to contain. The re-run over all 175 first-sitting rows was made on **2026-09-11** and its consequence recorded as open work. This section is where that work was done, on **2026-09-17**. |
| |
| === What was run === | === What was run, and when === |
| | |
| | The 175-row re-run is **not** today's work. It was run on 2026-09-11, against an empty cache, as: |
| |
| <code> | <code> |
| </code> | </code> |
| |
| 175 rows, an empty cache, so every source was fetched again. **That command no longer reproduces the result below**: ''out/adj_rows_scored.json'' now carries the corrected quote, so ''compass-fit.jp'' comes back ''OK''. ''out/irr/verify_s1_refix.json'' is the 2026-09-11 run against the rows as they then were. Compared against ''out/verify_final.json'' (2026-09-05), **three statuses move**: | Its artefacts — ''out/irr/verify_s1_refix.json'' and the 133 cached bodies under ''out/irr/verify_cache_s1_refix/'' — all carry 2026-09-11 timestamps, and **that command no longer reproduces the result below**: ''out/adj_rows_scored.json'' now carries the corrected quote, so ''compass-fit.jp'' comes back ''OK''. What was done on 2026-09-17 is the correction, the chain re-run, and a **three-row** live re-fetch of ''compass-fit.jp'', ''brightcove.net'' and ''cartfulsolutions.com'' — not a fourth pass over 175 sources. Compared against ''out/verify_final.json'' (2026-09-05), the 2026-09-11 run moves **three statuses**: |
| |
| ^ Domain ^ 2026-09-05 ^ re-run ^ Which of the two is it? ^ | ^ Domain ^ 2026-09-05 ^ 2026-09-11 ^ Which of the three is it? ^ |
| | ''compass-fit.jp'' | ''OK'' | ''NOTFOUND'' | **the fix biting.** Its quote is Japanese; the broken ''norm()'' had checked it on the six Latin letters ''COMPASS-FIT'' | | | ''compass-fit.jp'' | ''OK'' | ''NOTFOUND'' | **the fix biting.** Its quote is Japanese; the broken ''norm()'' had checked it on the six Latin letters ''COMPASS-FIT'' | |
| | ''cartfulsolutions.com'' | ''OK'' | ''OK-WINDOW'' | the web moving. The footer was restructured; the quote still matches on a 60-character window | | | ''cartfulsolutions.com'' | ''OK'' | ''OK-WINDOW'' | the web moving. The footer was restructured and the page grew from 15,933 to 23,044 bytes; the quote still matches on a 60-character window | |
| | ''fontawesome.com'' | ''NOTFOUND'' | ''OK-MARKUP'' | the instrument changing. ''OK-MARKUP'' did not exist on 2026-09-05; the row was rescued by the browser pass then, and by the bytes pass now | | | ''fontawesome.com'' | ''NOTFOUND'' | ''OK-MARKUP'' | the instrument changing. ''OK-MARKUP'' did not exist on 2026-09-05; the row was rescued by the browser pass then, and by the bytes pass now | |
| |
| ''brightcove.net'' is ''OK-WINDOW'' in **both** files. C3.8's bullet records it as ''OK-WINDOW'' → ''FETCHFAIL''; that was an earlier execution of the same script, whose JSON was overwritten by the retained one. The host was briefly unreachable, which is the bullet's point, but the retained artefact does not show it and this page should not be read as if it did. | ''brightcove.net'' is ''OK-WINDOW'' in **both** files, so it is not a fourth mover. C3.8's bullet recorded it as ''OK-WINDOW'' → ''FETCHFAIL''; that was an earlier execution of the same script, whose JSON was overwritten by the retained one. The host was briefly unreachable, which is the bullet's point, but the retained artefact does not show it. |
| |
| === What was done about each === | === What was done about each === |
| |
| * ''compass-fit.jp'' — **requoted** in ''scripts/owner_corrections.py'' (the eleventh correction; see C3.5). The replacement is the body sentence in full, ''%%株式会社マイクロアド…開始致しました。%%'', copied out of the fetched page: the shortest contiguous span on it that names both MicroAd and COMPASS-FIT, where the old quote named only the service. It verifies ''OK'' against a live fetch of 2026-09-17 (39,110 bytes). The row's claim — MicroAd, Inc. — is carried by the same page and never rested on the missing character. | * ''compass-fit.jp'' — **requoted** in ''scripts/owner_corrections.py'' (the eleventh correction; see [[#C3.5 Every citation re-fetched, and the eleven fixed by hand|C3.5]]). The replacement is the body sentence in full, ''%%株式会社マイクロアド…開始致しました。%%'', copied out of the fetched page. It is not the //shortest// span on the page naming a MicroAd entity and the service — the page title is 71 normalised characters and names both — it is the one that carries the **parent and the operating subsidiary together**, which is what ''owner_today = MicroAd, Inc.'' rests on where the old quote named only the service. It verifies ''OK'' against a live fetch of 2026-09-17 (39,110 bytes). |
| * ''cartfulsolutions.com'' and ''brightcove.net'' — **nothing.** ''OK-WINDOW'' is a passing status by design: a long quote gets spliced by boilerplate, and requiring the literal string would fail every such row. Both were re-fetched on 2026-09-17 and both still name the entity the row claims. Requoting them would chase the web rather than fix an error, and would have to be redone the next time either footer is edited. | * ''cartfulsolutions.com'' — **nothing.** ''OK-WINDOW'' is a passing status by design: a long quote gets spliced by boilerplate, and requiring the literal string would fail every such row. Re-fetched 2026-09-17 (23,044 bytes) and it still names Cartful Solutions, Inc. Requoting it would chase the web and have to be redone the next time the footer is edited. |
| | * ''brightcove.net'' — **nothing, but not for the reason it first looks.** Re-fetched 2026-09-17 (806,613 bytes) and still ''OK-WINDOW''. Its quote is **not** a victim of the page changing: the parenthetical it elides, ''%%The Brightcove Privacy Policies ("Privacy Policies") describe Brightcove Inc.%%'', is byte-identical in the 2026-09-05, 2026-09-11 and 2026-09-17 bodies. The row is an adjudicator elision of the **same class** as ''compass-fit.jp'', and the only reason one was requoted and the other was not is **quote length**: at ~110 characters brightcove's clears the 60-character window fallback, and at ~40 compass-fit's cannot. That is the honest line, and it is a property of the checker rather than of the evidence. |
| * ''fontawesome.com'' — **nothing.** The row was already cited and already counted as cited; what changed is that the bytes pass can now see the evidence the browser pass saw on 2026-09-05. | * ''fontawesome.com'' — **nothing.** The row was already cited and already counted as cited; what changed is that the bytes pass can now see the evidence the browser pass saw on 2026-09-05. |
| |
| | ''owner_random_sample.py'' (2026-09-11 rows) | **byte-identical** — the estimates the pages actually publish | | | ''owner_random_sample.py'' (2026-09-11 rows) | **byte-identical** — the estimates the pages actually publish | |
| | ''report_tail_pass.py'' | byte-identical | | | ''report_tail_pass.py'' | byte-identical | |
| | | ''owner_citation_audit.py'' | byte-identical — but see below, it reads the 2026-09-05 artefacts and cannot see any of this | |
| | ''check_tail_figures.py'' against [[design:ownership_resolution]] | 80 figures, all present and matching | | | ''check_tail_figures.py'' against [[design:ownership_resolution]] | 80 figures, all present and matching | |
| | ''check_tail_figures_mutations.sh'' | identical output, 24 of 24 caught | | | ''check_tail_figures_mutations.sh'' | identical output, 24 of 24 caught | |
| Two ''wrote …'' lines in the published output blocks change from ''/tmp/discard_rows.json'' and ''/tmp/discard2.json'' to the paths the documented commands name. The committed blocks had been produced by a verification re-run that deliberately wrote to ''/tmp'' so as not to clobber; the published command line said otherwise. The re-run writes where the command says, so block and command now agree. | Two ''wrote …'' lines in the published output blocks change from ''/tmp/discard_rows.json'' and ''/tmp/discard2.json'' to the paths the documented commands name. The committed blocks had been produced by a verification re-run that deliberately wrote to ''/tmp'' so as not to clobber; the published command line said otherwise. The re-run writes where the command says, so block and command now agree. |
| |
| After the requote, the only rows the bytes pass still fails in that re-run are ''force.com'' and ''flashtalking.com'' — both already carried by the browser pass and both counted as cited in C3.5's table. No row is uncited. | === What the citation audit still says, and what it would say === |
| |
| ''check_owner_sample_figures.py'' still reports 16 mismatches against ''design:ownership_resolution'' — as it did before this change, and for a reason that has nothing to do with it: that page publishes the **second pass's** estimates, and this guard checks the 2026-09-05 ones. Its mutation harness runs against ''pages/wx_new.txt'', the 2026-09-05 snapshot, and passes. The guard for the current page is ''check_tail_figures.py''. | ''owner_citation_audit.py'' reads ''out/verify.json'' and ''out/verify_final.json'', both 2026-09-05 artefacts. Re-running it today therefore reproduces its old output byte-for-byte and **cannot see** either the fixed checker or this requote. C3.5's table is labelled 2026-09-05 for that reason. Recomputed against the 2026-09-11 statuses **with the requote applied**, the split would be: |
| | |
| | ^ State ^ 2026-09-05 (published) ^ with the fix and the requote ^ |
| | | whole quote | 119 | 118 | |
| | | ellipsis fragments | 8 | 8 | |
| | | 60-character window | 5 | 6 | |
| | | markup only | — | 1 | |
| | | cited in the bytes, total | 132 | **133** | |
| | | cited only in a rendered browser | 3 | 2 | |
| | | uncited | **0** | **0** | |
| | |
| | The movement is ''cartfulsolutions.com'' whole → window and ''fontawesome.com'' browser → markup. The only rows the bytes pass still fails are ''force.com'' and ''flashtalking.com'', both carried by the browser pass on 2026-09-05. **No row is uncited under either reading**, which is why the published table was dated rather than replaced: replacing it would mix a 2026-09-05 census with a 2026-09-11 one. |
| |
| === Judgement calls === | === Judgement calls === |
| |
| * **The correction was appended last in ''CORRECTIONS'', after the ''demote''.** The dict's order is the printed order, and this correction is eleven days younger than the other ten. Grouping it with the other ''requote'' entries would have read as if it had been found with them, which is the one thing about it worth knowing. | * **The correction was appended last in ''CORRECTIONS'', after the ''demote''.** The dict's order is the printed order, and this correction is eleven days younger than the other ten. Grouping it with the other ''requote'' entries would have read as if it had been found with them, which is the one thing about it worth knowing. |
| | * **It is counted as a requote but described as a transcription slip.** The remedy is identical to the other four; the defect is not. C3.5 now says four paraphrases and one dropped character rather than five of one thing. |
| | * **''brightcove.net'' was left alone on a rule the checker enforces, not on a judgement about the evidence.** Requoting every row whose quote is an elision would mean requoting rows the checker passes, which is a different and much larger piece of work; it is recorded here as a known, quantified gap rather than done. |
| * **The section-G heading on the appendix is now computed** from ''len(CORRECTIONS)'' rather than typed. It said "the ten citations fixed by hand" and would have been wrong the moment this correction landed. | * **The section-G heading on the appendix is now computed** from ''len(CORRECTIONS)'' rather than typed. It said "the ten citations fixed by hand" and would have been wrong the moment this correction landed. |
| * **The reviewer's confirmation in [[#Reviewers, second sitting (2026-09-05)|the 2026-09-05 reviewer log]] still says "10 corrections".** It is left as written: it is a dated record of what that reviewer verified on that day, and editing it would make the log agree with a state it never saw. | * **The reviewer's confirmation in [[#Reviewers, second sitting (2026-09-05)|the 2026-09-05 reviewer log]] still says "10 corrections".** It is left as written: it is a dated record of what that reviewer verified on that day, and editing it would make the log agree with a state it never saw. |
| * **Regenerating the appendix also publishes an unrelated fix.** ''owner_verify_sources.py'' gained a WHOIS retry on 2026-09-11 that the appendix was never regenerated for, so its published block was 524 bytes behind the file. It is current now, and the manifest hash for section E moves with it. | * **Regenerating the appendix also publishes an unrelated fix.** ''owner_verify_sources.py'' gained a WHOIS retry on 2026-09-11 that the appendix was never regenerated for, so its published block was 524 bytes behind the file. It is current now, and the manifest hash for section E moves with it. |
| | |
| | === Reviewers (2026-09-17) === |
| | |
| | ^ Finding ^ Decision ^ |
| | | **The published mutation count is wrong: "14 of 14 caught" for ''check_tail_figures_mutations.sh''; the harness catches 24** | **ACCEPTED.** Reproduced: the committed output ends ''mutations caught: 24; survived or broken: 0'' and has 24 ''caught'' lines. A transcription error introduced by this sitting — there was never a 14-mutation version. Fixed | |
| | | **C3.9 dated the 175-row re-run to 2026-09-17; it ran on 2026-09-11** | **ACCEPTED, and the most useful finding.** Verified from mtimes: ''verify_s1_refix.json'' and all 133 cache bodies are 2026-09-11. Only three rows were fetched on 2026-09-17. The heading and the "What was run" block are rewritten; C3.5's table row is too | |
| | | **The ''brightcove.net'' rationale is factually wrong.** The elided parenthetical is in the 2026-09-05 body, so it is an adjudicator elision, not the web moving | **ACCEPTED.** Verified against all three cached bodies: byte-identical. The real distinction is quote length against the 60-character window, and both C3.8 and C3.9 now say so | |
| | | **The fix introduced a Latin/CJK asymmetry the page does not disclose**: ASCII punctuation normalises to whitespace, CJK punctuation does not | **ACCEPTED.** Reproduced against the committed module. Disclosed in C3.8's first bullet, with what closing it would take | |
| | | **"''tns-counter.ru'', the other non-Latin row" is false**: ''bilibili.com'' is a third | **ACCEPTED.** Three rows in the 175 carry non-Latin text. Both others verify clean under the fix, so no status moved, but the sentence claimed a census it had not done | |
| | | **"the shortest contiguous span naming both MicroAd and COMPASS-FIT" is false** | **ACCEPTED.** The page title is 71 normalised characters and names both. The real reason for the body sentence is that it names parent and subsidiary together. Fixed in the script's note and here | |
| | | **C3.5's "10 of 175 rows had their source or quote replaced, 9 of those 10" is stale** | **ACCEPTED.** 11 and 10 of 11 | |
| | | **Section F still listed the requote as work this sitting did not apply** | **ACCEPTED.** Closed with a pointer here | |
| | | **The citation-audit table is an undated 2026-09-05 figure that the fix moves** | **ACCEPTED.** Dated, and the recomputed split published above rather than substituted for it | |
| | | **''check_owner_sample_figures.py'' fails 16 figures against ''design:ownership_resolution''** | **Not a defect, and confirmed pre-existing** by re-running it against the pre-change output. That page publishes the second pass's estimates; this guard checks the 2026-09-05 ones, and its own mutation harness runs against ''pages/wx_new.txt'' and passes | |
| | | Probe artefacts live in ''out/rq/'' rather than a documented path | **Noted, not fixed.** They are a three-row scratch check, not an artefact any figure rests on; the figure they support (39,110 bytes, ''OK'') is reproducible from the command in this section | |
| |
| ===== D. External sources: verified, and rejected ===== | ===== D. External sources: verified, and rejected ===== |
| * **Publishing the uncorrected comparison as the headline.** Rater 2's one disqualified citation (''kameleoon.io'') is demoted in a sensitivity line rather than in the headline table, because rater 1's headline rows are pre-correction too and the symmetric comparison is the honest one. The corrected variant moves the pooled figure from +0.400 to +0.400 and is printed beside it. | * **Publishing the uncorrected comparison as the headline.** Rater 2's one disqualified citation (''kameleoon.io'') is demoted in a sensitivity line rather than in the headline table, because rater 1's headline rows are pre-correction too and the symmetric comparison is the honest one. The corrected variant moves the pooled figure from +0.400 to +0.400 and is printed beside it. |
| * **Not re-estimating the accuracy rates from rater 2's verdicts.** It would have been one line of code and it would have been meaningless: 35 rows is not the sample design, the stratum weights do not apply to it, and substituting 35 of 175 rows produces a hybrid that is neither rater's reading. What is published instead is the unweighted ''current'' share per rater, labelled as a direction and not a rate. | * **Not re-estimating the accuracy rates from rater 2's verdicts.** It would have been one line of code and it would have been meaningless: 35 rows is not the sample design, the stratum weights do not apply to it, and substituting 35 of 175 rows produces a hybrid that is neither rater's reading. What is published instead is the unweighted ''current'' share per rater, labelled as a direction and not a rate. |
| * **Fixing ''owner_verify_sources.py'' rather than only recording its defect.** The script is published, its hash is on the appendix manifest, and changing it means the appendix regenerates. The alternative — a note saying the check is blind to non-Latin quotes, beside a check that stays blind — would have left the next reader with an instrument the page knows is broken. The consequence for the first sitting's rows is stated in C3.8 and one row now needs a requote that this sitting did **not** apply. | * **Fixing ''owner_verify_sources.py'' rather than only recording its defect.** The script is published, its hash is on the appendix manifest, and changing it means the appendix regenerates. The alternative — a note saying the check is blind to non-Latin quotes, beside a check that stays blind — would have left the next reader with an instrument the page knows is broken. The consequence for the first sitting's rows is stated in C3.8, and the one row that needed a requote got it on **2026-09-17** ([[#C3.9 The 2026-09-11 re-run, applied (2026-09-17)|C3.9]]). |
| * **No ''~~DISCUSSION~~'' on this provenance page.** Following the convention set by the earlier provenance pages: comments belong on the content page. | * **No ''~~DISCUSSION~~'' on this provenance page.** Following the convention set by the earlier provenance pages: comments belong on the content page. |
| |
| |
| ^ Finding ^ Decision ^ | ^ Finding ^ Decision ^ |
| | **"the same universe ''owner_dbs.py'' uses, so the two sittings' figures are on one denominator" is false.** The first sitting's frame is **32,369** domains, the second's **32,337** | **ACCEPTED, blocking, and the most valuable finding of the run.** Reproduced by running ''owner_sample.py --cache out/webxray/cache'' (32,369; 669 / 5,581 / 2,268) against ''--cache out/owner_cache'' (32,337; 664 / 5,566 / 2,264). Both are real. The coverage **shares** round to the same 2.1% / 17.2% / 7.0%, which is precisely why two different frames could sit on one page unnoticed. [[#C3.1 The frame, and what it excludes|C3.1]] now carries three rows on it, and the content page carries a ''%%<WRAP tip>%%'' next to the figures themselves | | | **"the same universe ''owner_dbs.py'' uses, so the two sittings' figures are on one denominator" is false.** The first sitting's frame is **32,369** domains, the second's **32,337** | **ACCEPTED, blocking, and the most valuable finding of the run.** Reproduced by running ''owner_sample.py %%--cache%% out/webxray/cache'' (32,369; 669 / 5,581 / 2,268) against ''%%--cache%% out/owner_cache'' (32,337; 664 / 5,566 / 2,264). Both are real. The coverage **shares** round to the same 2.1% / 17.2% / 7.0%, which is precisely why two different frames could sit on one page unnoticed. [[#C3.1 The frame, and what it excludes|C3.1]] now carries three rows on it, and the content page carries a ''%%<WRAP tip>%%'' next to the figures themselves | |
| | **The run table's hash list is false.** It claimed all six input files were unchanged between the sittings; ''tr_domain_summary'' went ''7a303228d812a41c'' → ''19f7a5a6a839ec87'' (16,310,837 → 16,347,575 bytes) and the Public Suffix List went ''155b43d46932e933'' → ''aef8fb81d63232da'' | **ACCEPTED, blocking.** Verified against ''out/webxray/owner_dbs-output.txt''. This was written from the second sitting's hashes without checking them against the first sitting's — an assumption stated as a measurement, which is the exact failure the page spends a section warning about. The row now lists the four that are unchanged and the two that moved, and says so | | | **The run table's hash list is false.** It claimed all six input files were unchanged between the sittings; ''tr_domain_summary'' went ''7a303228d812a41c'' → ''19f7a5a6a839ec87'' (16,310,837 → 16,347,575 bytes) and the Public Suffix List went ''155b43d46932e933'' → ''aef8fb81d63232da'' | **ACCEPTED, blocking.** Verified against ''out/webxray/owner_dbs-output.txt''. This was written from the second sitting's hashes without checking them against the first sitting's — an assumption stated as a measurement, which is the exact failure the page spends a section warning about. The row now lists the four that are unchanged and the two that moved, and says so | |
| | **The appendix's manifest hash for ''out/probe_all.txt'' matches no file.** Published ''7d2ca1e722836803''; the file hashes ''3def89e0d3fc8a14'' | **ACCEPTED, blocking.** Root cause found on verification: ''probe_all.txt'' contains **one lone CR**, inside a copyright line scraped from a live site, and Python's text mode silently translates it to LF — so the builder hashed a string that was not the file. Fixed at the root: the builder now reads bytes, hashes the file on disk, discloses newline normalisation **per file** in a new manifest column, and **self-checks** every row and block before writing. The self-check was mutation-tested by reintroducing the original bug, which it rejects. All 23 manifest rows now verify independently | | | **The appendix's manifest hash for ''out/probe_all.txt'' matches no file.** Published ''7d2ca1e722836803''; the file hashes ''3def89e0d3fc8a14'' | **ACCEPTED, blocking.** Root cause found on verification: ''probe_all.txt'' contains **one lone CR**, inside a copyright line scraped from a live site, and Python's text mode silently translates it to LF — so the builder hashed a string that was not the file. Fixed at the root: the builder now reads bytes, hashes the file on disk, discloses newline normalisation **per file** in a new manifest column, and **self-checks** every row and block before writing. The self-check was mutation-tested by reintroducing the original bug, which it rejects. All 23 manifest rows now verify independently | |
| |
| | **Three findings from the figures-versus-script pass, none of them a wrong number on the page today.** (a) ''owner_irr_kappa.py'' documented NAMED as "neither rater is forced to ''absent''" while the code selected with ''or''; the two are equivalent only because both raters' ''absent'' cells happen to coincide, which is empirical luck rather than an invariant. (b) The JSON artefact was not byte-stable: ''pe'' summed over a ''set()'', whose iteration order is hash-seed randomised, so the 15th–16th decimal moved between runs. (c) The page pointed at appendix section **AE** for the subsample domain list; AE is a mutation harness and the list is in **AF** | **ALL THREE ACCEPTED.** (a) ''assert_absent_agrees()'' now raises before any population is built, and prints that ''absent'' agrees on all 105 cells; the docstring now says what the code does and why the equivalence is checked rather than assumed. (b) ''sorted(set(...))'', verified byte-stable over three runs under a randomised hash seed. (c) Fixed to AF. The reviewer also noted that the **pooled** bootstrap rows resample cells rather than domain blocks — which the page already discloses, and the estimator's docstring now does too | | | **Three findings from the figures-versus-script pass, none of them a wrong number on the page today.** (a) ''owner_irr_kappa.py'' documented NAMED as "neither rater is forced to ''absent''" while the code selected with ''or''; the two are equivalent only because both raters' ''absent'' cells happen to coincide, which is empirical luck rather than an invariant. (b) The JSON artefact was not byte-stable: ''pe'' summed over a ''set()'', whose iteration order is hash-seed randomised, so the 15th–16th decimal moved between runs. (c) The page pointed at appendix section **AE** for the subsample domain list; AE is a mutation harness and the list is in **AF** | **ALL THREE ACCEPTED.** (a) ''assert_absent_agrees()'' now raises before any population is built, and prints that ''absent'' agrees on all 105 cells; the docstring now says what the code does and why the equivalence is checked rather than assumed. (b) ''sorted(set(...))'', verified byte-stable over three runs under a randomised hash seed. (c) Fixed to AF. The reviewer also noted that the **pooled** bootstrap rows resample cells rather than domain blocks — which the page already discloses, and the estimator's docstring now does too | |
| | **The guard was blind to every figure that lives in a script's //text// output rather than in the kappa JSON.** The reviewer mutated the ''self-named'' counts, the sourcing/reading split table, the resolution counts, the unweighted current-share table and the whole citation tally, and ''check_irr_figures.py'' passed on every one | **ACCEPTED, and the most useful finding after the kameleoon one.** The guard now parses those figures out of ''owner_irr_kappa-output.txt'' and ''owner_verify_sources_irr-output.txt'' (a new ''--verify-output''), and six mutations were added for them. Two of the six then **survived**: the self-named count and the split table were being checked with bare-digit needles like "17", which match anywhere on a long page, and the self-named needle was additionally satisfied by the //other// page's untouched copy. Both fixed — the split table is matched as a whole row, and the self-named count is checked wherever its sentence shape occurs on **every** page. 18 mutations, all caught | | | **The guard was blind to every figure that lives in a script's //text// output rather than in the kappa JSON.** The reviewer mutated the ''self-named'' counts, the sourcing/reading split table, the resolution counts, the unweighted current-share table and the whole citation tally, and ''check_irr_figures.py'' passed on every one | **ACCEPTED, and the most useful finding after the kameleoon one.** The guard now parses those figures out of ''owner_irr_kappa-output.txt'' and ''owner_verify_sources_irr-output.txt'' (a new ''%%--verify-output%%''), and six mutations were added for them. Two of the six then **survived**: the self-named count and the split table were being checked with bare-digit needles like "17", which match anywhere on a long page, and the self-named needle was additionally satisfied by the //other// page's untouched copy. Both fixed — the split table is matched as a whole row, and the self-named count is checked wherever its sentence shape occurs on **every** page. 18 mutations, all caught | |
| | **Process finding, and the one this sitting should be judged on: the reviewer was mid-review when the kameleoon fix landed**, so its report straddles two states of the artefact. It said so unprompted | **ACCEPTED as a real methodological failure of this sitting.** The rule is "do not edit a page under its reviewers" and it was broken — the fix was applied the moment two other reviewers reported, without waiting for the third. The reviewer re-checked everything against the post-fix state and its findings above are against that state, but the next sitting should hold fixes until every reviewer has reported, or re-run the ones whose ground moved | | | **Process finding, and the one this sitting should be judged on: the reviewer was mid-review when the kameleoon fix landed**, so its report straddles two states of the artefact. It said so unprompted | **ACCEPTED as a real methodological failure of this sitting.** The rule is "do not edit a page under its reviewers" and it was broken — the fix was applied the moment two other reviewers reported, without waiting for the third. The reviewer re-checked everything against the post-fix state and its findings above are against that state, but the next sitting should hold fixes until every reviewer has reported, or re-run the ones whose ground moved | |
| |
| Schema signal: tools[].name matching /webx[\s-]?ray/i with usedOrMentioned in {used, produced} fires on 7 papers. | Schema signal: tools[].name matching /webx[\s-]?ray/i with usedOrMentioned in {used, produced} fires on 7 papers. |
| Not used/produced (compared/mentioned/unclear): 0 papers. | Not used/produced (compared/mentioned/unclear): 0 papers. |
| Full-text sweep of paper.cols.txt for the same pattern: 15 papers, 0.3% of the 5859-paper corpus and 1.3% of the 1120 that ran a crawl. | Full-text sweep of paper.cols.txt for the same pattern: 15 papers, 0.3% of the 5859-paper corpus. 13 of them are among the 1120 that ran a crawl (1.2% of that population). |
| Schema papers not in the sweep: none (a sweep miss would mean the extractor read a rendering the sweep cannot see). | Schema papers not in the sweep: none (a sweep miss would mean the extractor read a rendering the sweep cannot see). |
| Sweep papers the schema misses: 8. | Sweep papers the schema misses: 8. |
| |
| Papers matching ANY of webXray / Tracker Radar / WhoTracks.me / Crunchbase / Disconnect-as-a-list: | Papers matching ANY of webXray / Tracker Radar / WhoTracks.me / Crunchbase / Disconnect-as-a-list: |
| 136 papers (2.3% of the corpus; 12.1% of the 1120 that crawled). | 136 papers (2.3% of the corpus). 107 of them are among the 1120 that crawled -- 9.6% of that population. |
| Year Corpus papers Naming an ownership resource Share | Year Corpus papers Naming an ownership resource Share |
| ----- ------------- ---------------------------- ----- | ----- ------------- ---------------------------- ----- |
| 26 of 26 literal figures/quotes located in the cited paper's .cols rendering. | 26 of 26 literal figures/quotes located in the cited paper's .cols rendering. |
| |
| === H. Evidence quotes behind the schema tuples === | === H. Evidence quotes behind the schema tuples (with PDF fallback) === |
| |
| partial 69% WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | webxray | methodology | "the webxray software platform is used to monitor third-party network traffic generated by loading a given web page and attribute such traffic to the entities which receive the data." | partial 69% WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | webxray | methodology | "the webxray software platform is used to monitor third-party network traffic generated by loading a given web page and attribute such traffic to the entities which receive the data." |
| partial 67% IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | classification:webxray | methodology | "The first is based on three manually-curated lists (Disconnect [30], WhoTracks.me [31] and webxray [32])" | partial 67% IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | classification:webxray | methodology | "The first is based on three manually-curated lists (Disconnect [30], WhoTracks.me [31] and webxray [32])" |
| exact 100% IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | classification:graph-based label propagation algorithm (custom) | methodology | "We validated our approach by using the manually compiled lists as a “ground truth” reference: we then looked for conflicts" | exact 100% IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | classification:graph-based label propagation algorithm (custom) | methodology | "We validated our approach by using the manually compiled lists as a “ground truth” reference: we then looked for conflicts" |
| Summary: 16 quotes: 4 exact, 11 partial (>=60% of 4-word windows), 1 below threshold. | Summary: 16 quotes: 4 exact, 11 partial (>=60% of 4-word windows), 0 rescued from the PDF, 1 below threshold in both renderings. |
| Below-threshold is not "unsupported": every one checked by hand was present, mangled by a column splice or a dropped citation marker. | Below-threshold is not "unsupported": every one checked by hand was present, mangled by a column splice or a dropped citation marker. |
| |
| owner_dbs.py, snapshots of 2026-08-17: webXray 827 owners / 3,215 domains; Tracker Radar 19,148 / 38,368; Disconnect 1,887 / 7,850. | owner_dbs.py, snapshots of 2026-08-17: webXray 827 owners / 3,215 domains; Tracker Radar 19,148 / 38,368; Disconnect 1,887 / 7,850. |
| owner_dbs.py: webXray owners with a parent_id 319 of 827 (38.6%); tree depth up to 6; largest owner groupm with 620 domains. | owner_dbs.py: webXray owners with a parent_id 319 of 827 (38.6%); tree depth up to 6; largest owner groupm with 620 domains. |
| owner_dbs.py: coverage of 45,525 registrable third-party domains -- webXray 657 (1.4%), Tracker Radar 5,539 (12.2%), Disconnect 2,277 (5.0%). | owner_dbs.py: coverage of 32,369 registrable third-party domains -- webXray 669 (2.1%), Tracker Radar 5,581 (17.2%), Disconnect 2,268 (7.0%). |
| owner_dbs.py: prevalence-weighted coverage -- webXray 54.5%, Tracker Radar 79.3%, Disconnect 75.8%. | owner_dbs.py: prevalence-weighted coverage -- webXray 58.6%, Tracker Radar 84.3%, Disconnect 80.5%. |
| owner_dbs.py: top 100 by prevalence -- webXray 70%, Tracker Radar 95%, Disconnect 91%; top 1,000 -- 26 / 67 / 67%; top 10,000 -- 5 / 27 / 16%. | owner_dbs.py: top 100 by prevalence -- webXray 71%, Tracker Radar 98%, Disconnect 94%; top 1,000 -- 26 / 69 / 68%; top 10,000 -- 5 / 29 / 17%. |
| owner_dbs.py: pairwise "needs a human" disagreement -- webXray vs TR 197 of 601 (32.8%), webXray vs Disconnect 216 of 461 (46.9%), TR vs Disconnect 584 of 1,532 (38.1%). | owner_dbs.py: pairwise "needs a human" disagreement -- webXray vs TR 198 of 612 (32.4%), webXray vs Disconnect 217 of 464 (46.8%), TR vs Disconnect 584 of 1,538 (38.0%). |
| owner_dbs.py: 16,396 of 47,836 domain_summary.json rows are hostnames not registrable domains; 19 rows are not hostnames at all, one of them the literal string "null". | owner_dbs.py: the ICANN-section fold merges 15,651 of domain_summary.json's 47,836 rows into 32,369 registrable domains; 19 rows are not hostnames at all, one of them the literal string "null". (The label-count heuristic that gives 16,396 answers neither question and is not used.) |
| webXray licence: PolyForm Strict License 1.0.0 (LICENSE.md in the surviving copy). | webXray licence: PolyForm Strict License 1.0.0 (LICENSE.md in the surviving copy). |
| Tracker Radar and Disconnect licences: CC BY-NC-SA 4.0 (LICENSE and entities.json "license" field). | Tracker Radar and Disconnect licences: CC BY-NC-SA 4.0 (LICENSE and entities.json "license" field). |
| ===== J2. Its unedited output ===== | ===== J2. Its unedited output ===== |
| |
| Run as ''python3 scripts/owner_dbs.py --cache out/webxray/cache --disagreements 25''. | Run as ''python3 scripts/owner_dbs.py %%--cache%% out/webxray/cache %%--disagreements%% 25''. |
| |
| <code> | <code> |
| ===== K. Unedited output: scripts/owner_adjudication.py ===== | ===== K. Unedited output: scripts/owner_adjudication.py ===== |
| |
| Run as ''python3 scripts/owner_adjudication.py --table''. | Run as ''python3 scripts/owner_adjudication.py %%--table%%''. |
| |
| <code> | <code> |
| |
| <bibtex bibliography></bibtex> | <bibtex bibliography></bibtex> |
| | |
| | ===== 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. |
| | |
| | ===== Embedded-output refresh, 2026-09-22 ===== |
| | |
| | **What was wrong.** The counts on this page were right; the //embedded copy of the |
| | script's output// in [[#I. Unedited output: scripts/report_webxray.mjs|§I]] was a |
| | pre-2026-09-11 paste. ''report_webxray.mjs'' has been re-run and the whole block |
| | regenerated rather than line-edited, so what §I shows is again what the script prints. |
| | |
| | Trigger: the shared quote checkers gained a ''pypdf'' fallback on 2026-09-04 and |
| | ''report_webxray.mjs'' was patched to use it, so its Summary line changed from |
| | "1 below threshold" to "0 rescued from the PDF, 1 below threshold in both renderings". |
| | The quote **counts** did not move — 16 quotes, 4 exact, 11 partial, 1 below threshold — |
| | so the wording was the only thing this refresh was filed for. Diffing the rest of the |
| | block against the fresh output found four more stale lines, listed below. |
| | |
| | <code> |
| | $ node scripts/report_webxray.mjs --quotes |
| | Summary: 16 quotes: 4 exact, 11 partial (>=60% of 4-word windows), 0 rescued from the PDF, 1 below threshold in both renderings. |
| | </code> |
| | |
| | ^ Line in §I (or, for A10, in §A) ^ Was ^ Is ^ Why ^ |
| | | §H Summary | ''1 below threshold'' | ''0 rescued from the PDF, 1 below threshold in both renderings'' | the fallback added 2026-09-04; **no count moved** | |
| | | §H heading | ''Evidence quotes behind the schema tuples'' | ''… (with PDF fallback)'' | same patch | |
| | | §A sweep line | ''15 papers … and 1.3% of the 1120 that ran a crawl'' | ''15 papers … 13 of them are among the 1120 that ran a crawl (1.2% of that population)'' | the 2026-09-11 denominator fix: a corpus-wide numerator was being divided by the crawled denominator. [[:programming:crawler:webxray]] has carried the corrected 1.2% since then; only this embedded paste was stale | |
| | | §E union line | ''136 papers (2.3% of the corpus; 12.1% of the 1120 that crawled)'' | ''136 papers (2.3% of the corpus). 107 of them are among the 1120 that crawled -- 9.6% of that population'' | same fix, larger figure | |
| | | **§A, row A10** | ''**136** (2.3% / 12.1%)'' | ''**136** (2.3% of the corpus); **107** … (**9.6%**)'' | the only **prose** figure this refresh moved. The content page and ''report_webxray.mjs'' both say 107 / 9.6%; this row still said 12.1% | |
| | | §Z, five ''owner_dbs.py'' lines | 45,525-domain frame; 54.5 / 79.3 / 75.8%; 16,396 rows | 32,369-domain frame; 58.6 / 84.3 / 80.5%; the ICANN fold merges 15,651 of 47,836 rows | the ICANN-section fold, adopted 2026-09-05. [[#C3.1 The frame, and what it excludes|§C3.1]], §B4 and §B6 have carried the 32,369 frame since then; again only the paste was stale | |
| | |
| | **The lesson, and it is the one this site keeps relearning.** Every figure in the |
| | prose was already correct. What was stale was the block that exists to //prove// the |
| | prose — so a reader checking the page against its own embedded output would have been |
| | shown a contradiction, in the direction of the numbers that had already been retracted. |
| | An embedded output block has to be regenerated whenever its script changes, not when |
| | its headline figure changes; and ''check_page_numbers.mjs'' cannot see this, because |
| | every value in the stale block is a real number that really was printed once. |
| | |
| | **Scope of this edit.** The §I block in full, the §A10 row, and the one sentence in §5 |
| | that quotes the quote-check verdicts. ''owner_dbs.py'' and ''owner_sample.py'' were |
| | **not** re-run — the §Z lines are literals inside ''report_webxray.mjs'' and were taken |
| | from its output, not recomputed. No other figure, fold or citation on this page was |
| | touched, and no ''%%{[citekey]}%%'' was added or moved. |
| | |
| | ^ Item ^ Value ^ |
| | | Date | 2026-09-22, unsupervised | |
| | | Command | ''node scripts/report_webxray.mjs %%--quotes%%'' | |
| | | Artifact | ''out/qc0922/report_webxray_quotes.txt'' (the full 232-line run pasted into §I) | |
| | | Script changes | none — ''report_webxray.mjs'' already had the fallback | |
| | | Reviewers | one ''sonnet'' figures-vs-script pass | |
| | | Pages saved | this page only — [[:programming:crawler:webxray]] already carries 107 / 9.6% / 1.2% and was verified unchanged | |
| |