Table of Contents
Provenance: Statistics — Hypothesis Testing
Working log behind Hypothesis testing. Every query with its denominator, the report script and its unedited output, the folds and their residue, the probes that were run and rejected, the quotes spot-checked, the external sources verified and rejected, and what could not be established.
Corpus-level caveats — the venue scope, the selection funnel, the provisional years, the duplicate records, the posters — are on Corpus and are not restated here. Citation keys are shared with the content page and the single Bibliography; this page adds no bibliography entries of its own.
Voice here is a working log, not prose. It is for someone checking a number.
The run
| Item | Value |
|---|---|
| Date | 2026-08-13 |
| Corpus | data/extract/run1, 5,859 extracted papers, 7 venues, 2010–2026 |
| Page status | New page. statistics:hypothesis_testing was a red link promised from start (“Hypothesis testing suitable for web measurements”) and from Pvalue corrections (“choosing the test whose p-values you are about to correct”). Nothing on the wiki covered it |
| Scripts added | scripts/test_fold.mjs, scripts/report_hypothesis_testing.mjs, scripts/ht_quotecheck.mjs |
| Code published on the page | pages/paired_and_clustered.py |
| Models | Opus 5 (author, all queries, all folds, all verification); one Sonnet sub-agent for the external-currency sweep; the review layer below |
start edit needed | None. start already links the page |
Scope decision: create, not broaden
The neighbouring page Pvalue corrections is 62 KB and shares this page's population exactly (the 1,025 hypothesisTest papers). Broadening it was considered and rejected:
- Its subject is multiplicity — what to do with many p-values. This page's subject is which test produces one. They are independent failure modes and a paper can have both.
- It already names this page as a sibling with a one-line scope statement, so the boundary was set by an earlier run rather than by this one.
- The
statistics:namespace has three other red links (biases,regression) that are separate items; folding test choice into the corrections page would have made the namespace incoherent.
Deliberate division of labour. These belong to the neighbours and are linked, not restated: the “at crawl scale the p-value stops carrying information” argument and the effect-size-vs-correction ratio (Pvalue corrections); cluster-robust standard errors as a modelling technique and mixed-effects models (Regression); committing to a test in advance (Study preregistration).
The page does re-derive one figure the corrections page also reports — the crawl-versus-user-study asymmetry — because it holds for paired testing as well as for correcting, and the parallel is the point.
Population and denominators
Every query names its own population. hypothesisTest is the denominator for the whole page.
Population Papers Share of 5,859 all extraction records 5,859 100.0% inferential — any statistics tuple that is not descriptive 1,762 30.1% hypothesisTest — >=1 tuple with kind == 'hypothesis-test' 1,025 17.5%
Definition, in report_hypothesis_testing.mjs:
const hasKind = (p, k) => p.statistics.some((s) => s.kind === k); const HT = rows.filter((p) => hasKind(p, 'hypothesis-test'));
This is deliberately the same definition report_pvalue_corrections.mjs uses, so the two pages' figures compose. Cross-checked: both scripts independently report 1,025, and the same per-venue hypothesis-test counts (PoPETs 149, USENIX 242, IEEE S&P 124, CCS 110, TheWebConf 236, IMC 71, NDSS 93).
1,806 hypothesis-test tuples across the 1,025 papers (1.76 per paper), carrying 798 distinct free-text method strings.
Cross-population definitions:
const crawled = new Set(rows.filter(POPULATIONS.crawled).map(key)); // lib.mjs const human = new Set(rows.filter((p) => p.participants.length > 0).map(key));
participants, not humanAnnotation — crowdworkers labelling data are annotators, not subjects, and conflating them double-counts Mechanical Turk.
The fold: ''test_fold.mjs''
statistics[].method is free text and agrees run-to-run on ~20% of exact strings, so it is never aggregated by exact string. 798 distinct strings describe about forty procedures. The fold is an ordered rule list; first match wins; anything matching no rule lands in residue and is printed.
Unmapped residue: 0 strings, 0 papers. Self-test: 146/146 cases pass (node scripts/test_fold.mjs).
Three things that make this fold harder than a spelling normaliser
1. “Wilcoxon” names two different tests. The Wilcoxon rank-sum test is Mann-Whitney U (two independent samples). The Wilcoxon signed-rank test is the paired one. A fold keyed on /wilcoxon/ merges an unpaired test with a paired one — the exact error the content page is about. Resolution:
- the signed-rank rule fires first
rank-sum/ranksum/ranked sumfold into the Mann-Whitney family- a paired or one-sample Wilcoxon resolves to signed-rank, because that is what those words mean
- a bare
“Wilcoxon test”gets its own bucket rather than being guessed at, and its size is published as a finding (10 papers)
\bpaired\b does not match inside “unpaired” (no word boundary between n and p), which is what keeps “unpaired Wilcoxon rank-sum” out of the paired family. There is a self-test case for it.
2. Many hypothesis-test tuples are not tests of the paper's hypothesis. They are assumption checks (Shapiro–Wilk, Levene, Mauchly), model diagnostics (Breusch–Pagan, Hosmer–Lemeshow, VIF, Ljung–Box) or not tests at all (Clopper–Pearson intervals, MLE, Chebyshev's inequality). The extractor scored them as hypothesis-test because they are tests. They go in NON_SUBSTANTIVE and are excluded from every “which test” figure, then reported separately:
UNSTATED (no test named) 73 papers, 56 spellings ASSUMPTION: normality check 38 papers, 15 spellings NOT-A-TEST: estimator, criterion or inequality 25 papers, 26 spellings ASSUMPTION: model diagnostic 25 papers, 23 spellings ASSUMPTION: variance / sphericity check 23 papers, 14 spellings NOT-A-TEST: confidence interval only 16 papers, 16 spellings OFF-PAGE: correlation significance 9 papers, 10 spellings ASSUMPTION: outlier / unimodality check 7 papers, 7 spellings NOT-A-TEST: factor analysis / measurement model 4 papers, 5 spellings OFF-PAGE: regression coefficient p-values 3 papers, 3 spellings
A query that counts kind == “hypothesis-test” and stops there reports Shapiro–Wilk and Clopper–Pearson as the paper's statistical test.
3. The same name is an assumption check or a substantive test depending on context. “Anderson-Darling test for normality” is an assumption check; “Anderson-Darling two-sample test” is a distributional comparison. Same for Kolmogorov–Smirnov, which this literature uses both ways. The normality-context rules therefore fire before the family rules, and both readings have self-test cases.
Bugs the self-test caught, that inspection did not
Recorded because each would have produced a wrong published number, and because two are ordering bugs of a kind that recurs.
| Bug | Effect | Fix |
|---|---|---|
/wilcoxon/ claimed the Peto–Peto test, whose own name is “generalization of the Wilcoxon test” for censored data | a survival test filed as an ambiguous Wilcoxon | moved the survival rule above the Wilcoxon rules |
An unanchored z[-\s]?test alternative matched the substring “z test” inside the string “Wald-Wolfowitz test” | the Wald–Wolfowitz runs test filed as a proportion test | every alternative in that rule \b-anchored on both sides |
\bwald\b claimed Wald–Wolfowitz, an unrelated procedure sharing a surname | runs test filed as a Wald test | negative lookahead \bwald\b(?![-\s]?wolfowitz) |
rank[-\s]?sum missed the real corpus spelling “ranked sum” | “Wilcoxon ranked sum tests” fell into the ambiguous bucket instead of Mann-Whitney | ranke?d?[-\s]?sum |
“paired Wilcoxon test”, “one-sided paired Wilcoxon rank test” and “one-sample Wilcoxon test” fell into the ambiguous bucket | overstated the ambiguity finding by 3 papers (13 → 10) | paired/one-sample Wilcoxon resolves to signed-rank |
cramer[-\s]?von missed the en-dash spelling “Cramer–von Mises” | 1 residue string | cram[eé]r?[-–\s]?von |
chi2_contingency matched no rule | 1 residue string | added to the chi-square rule |
“one-tailed tests of two independent proportions” matched no rule (word order reversed) | 1 residue string | added \btests? of (two )?(independent )?proportions?\b |
Changing the fold changed 17 published figures, and the page had already been written with the old ones. The Wilcoxon fixes above moved Mann-Whitney 212 → 213, signed-rank 82 → 85, and with them the spelling counts, both undercount percentages, the rank/exact totals, three cells of the per-period table, two cells of the study-shape table, the paired and unpaired unions, and one sentence in Open Questions. check_page_numbers.mjs caught all of them; reading did not. This is the trap the workdir README names (“changing a fold changes every number downstream of it”) and it fired exactly as described. Run the guard after every fold edit, not once at the end.
One correction inside that pass was made by guessing a table row from an adjacent figure rather than reading the report (Wilcoxon signed-rank in the study-shape table: guessed 13.2%/3.0%, actual 13.6%/2.7%). Caught on the next re-read. Do not patch a table cell from memory of a previous run's output.
Why the fold is not optional
Exact-string counting against the folded paper count. This is what an unfolded statistics.method histogram reports.
Family Folded Spellings Most common exact string Its papers Undercount Chi-square (χ²) 220 98 "chi-square test" 27 87.7% t-test (independent samples) 45 32 "two-sample t-test" 6 86.7% Proportion / z-test 61 44 "z-test" 9 85.2% Likelihood-ratio / Wald / F-test 32 17 "likelihood ratio test" 6 81.3% ANOVA 95 47 "one-way ANOVA" 31 67.4% Kolmogorov-Smirnov 93 35 "Kolmogorov-Smirnov test" 37 60.2% Mann-Whitney U 213 52 "Mann-Whitney U test" 90 57.7% Wilcoxon signed-rank 85 28 "Wilcoxon signed-rank test" 42 50.6% Kruskal-Wallis 91 15 "Kruskal-Wallis test" 49 46.2%
The item brief for this page quoted “Mann-Whitney U 68, Wilcoxon 45, Fisher's exact 42, t-test 39” from the previous corpus run's exact-string counts. Folded on the current corpus those are 213, 85 (signed-rank) + 213 (rank-sum), 80 and 236. Both the corpus growth and the folding move them; neither number was reusable.
Full-text probes: what was run, and what was rejected
Regex sweep over 5,855 paper.cols.txt files (4 extraction records have none). A probe count is not a finding. Three probes were majority or wholly false-positive and the page publishes the hand-read count.
| Probe | Raw | Read? | Genuine | What the rejects were |
|---|---|---|---|---|
| cluster-robust / clustered standard errors | 4 | all 4 | 3 | 1 reject: NDSS 2026 lightening-the-load — “clustering at the webpage level” is the paper's defence mechanism, not statistical clustering |
\bA12\b (sought as Vargha–Delaney Â12) | 45 | sample of 6 | probe DELETED | affiliation superscripts, ARM assembly listings (A10. A11. A12.), appendix labels, participant IDs, a cookie-policy set label. Vargha–Delaney must be spelled out |
| anytime-valid / always-valid / e-value | 17 | all 17 | 0 | every one is “always valid” in the security sense (an always-valid cast, a verifier that always validates, an always-valid BGP announcement) or an E-VALUE rule in an operational semantics |
| stochastic dominance / superiority | 2 | both | 0 | both are first-order stochastic dominance in auction/agent theory (MEV-Boost builder bidding; evaluated-agent metrics), not the Mann-Whitney estimand |
| Brunner–Munzel | 1 | 1 | 1 | — |
| rank-test effect size (CLES / Vargha–Delaney / Cliff's δ) | 67 | contexts sampled | 15 of the 213 MWU papers | the count is carried largely by fuzzing papers, where Â12 beside Mann-Whitney U is near-standard |
| Lilliefors | 0 | — | 0 | — |
| “unit of analysis” | 20 (7 ran a test) | not one by one | upper bound | published as “at most 7 of the 1,025” |
| “normality assumption” | 11 | not one by one | upper bound | — |
| heavy-tailed | 87 | not one by one | upper bound | not published as a figure |
| “non-parametric” | 248 (143 ran a test) | not one by one | upper bound | not published as a figure |
| equivalence test / TOST | 7 | not one by one | upper bound | not published as a figure |
A probe bug worth recording. The clustering probe was first written as /cluster(ed|-robust)?\s+standard\s+errors/ and found 1 paper. Papers write it the other way round — “standard errors are clustered at the user level”, “errors clustered at the product level” — so the single word order missed 3 of the 4. Both orders are now in the rule. A flat negative from one phrasing is not a negative.
The three genuine clustering papers, all 2023 or later:
| Paper | Clusters on | In hypothesisTest? |
|---|---|---|
| Becerril-Arreola & Bapna, TheWebConf 2023 | “errors clustered at the product level” | yes |
| Bobek & Pröllochs, TheWebConf 2026 | “clustered at the user level” + 5,000 bootstrap simultaneous bands | yes |
| Nenadic et al., PoPETs 2026 | “cluster standard errors at the website level” | no — its inference is all regression |
Because only 2 of the 3 have a hypothesis-test tuple, the report omits a “share of 1,025” column for the hand-read probe counts rather than printing one that mixes denominators. The page states the figure as corpus-wide.
Quote checking
scripts/ht_quotecheck.mjs verifies all 1,806 hypothesis-test evidence.quote values against the rendering the extractor read. Whitespace is normalised first, because a repaired two-column quote still wraps and grep -F fails on it about half the time.
quotes checked: 1806 exact (verbatim after whitespace normalisation) : 931 (51.6%) partial (>=60% of 5-word windows present) : 540 (29.9%) below threshold : 335 (18.5%) no full text on disk : 0
Below threshold is not “unsupported”. Five below-threshold quotes were chased by hand and all five are present:
| Paper | Why the match failed |
|---|---|
NDSS 2015 multiple-password-interference… | found verbatim; the 5-word-window score is low only because the quote is short |
USENIX 2018 the-battle-for-new-york | two-column interleaving splits “Wilcoxon signed-rank / test [65]” across an intervening column of body text |
PoPETs 2016 crowdsourcing-for-context… | same: “tests us-In actual practice, users of the crowdsourcing fea-ing the McNemar test” |
CCS 2015 vccfinder | the sentence is a table caption, reflowed |
NDSS 2019 the-crux-of-voice-insecurity | the paper itself writes “Wilcoxon Singed-Rank Test” — the extractor copied the typo faithfully, and it is in the source |
Every quote published on the content page was located by hand. All checked out except one class, below.
One paper's quotes are in the PDF and in none of the stored text renderings
Mai et al., PoPETs 2025, more-and-scammier-ads-…. The extraction carries four detailed methodology quotes (repeated-measures ANOVA, Friedman, Tukey HSD, Conover). None of paper.cols.txt, paper.norm.txt or paper.txt contains the string “Friedman”, “Conover”, “omnibus” or “172.47”. Re-extracting the stored paper.pdf with pypdf finds Friedman 7×, Conover 6×, and every quoted sentence verbatim:
FOUND since the rates do not approximately follow a normal distribution, we use
Friedman test as the omnibus test, which is a non-parametric alternative to ANOVA
FOUND we use one-way repeated measures ANOVA as the omnibus test since the ad load
data follow a normal distribution
FOUND we use the Conover post-hoc test with Holm-Bonferroni correction
FOUND Fleiss kappa score of κ = 0.74
paper.cols.txt also drops five of the ten authors from its header (Kieserman, Matsumoto, Andreou, Greenstadt, McCoy), which the PDF has.
Consequences, which generalise beyond this page:
- The extraction was faithful; the stored rendering is deficient. This is the opposite of a hallucination and would have been scored as one by any check keyed on
paper.cols.txt. quote_check.mjsandht_quotecheck.mjscan therefore produce false “unlocatable” verdicts. The dataset's own ~0.9% unlocatable rate is partly an artefact of text extraction, not of fabrication.- The content page footnotes this where it quotes Mai et al., so a reader who greps
paper.cols.txtand finds nothing is not misled. - Not generalised further. Whether other papers have the same defect was not measured — it would need a corpus-wide
pypdf-vs-colsdiff, which is a separate job. Logged as a TODO below.
External sources: verified, and rejected
All fetched 2026-08-13. Nothing here is from recall.
Verified
| Claim on the page | How verified |
|---|---|
| 15 methodological citations (Wilcoxon 1945, Mann & Whitney 1947, McNemar 1947, Cochran 1950, Lilliefors 1967, Lumley 2002, Campbell 2007, Fagerland & Sandvik 2009, Lydersen 2009, Rasch 2011, Fagerland 2012, Rochon 2012, Cameron & Miller 2015, Divine 2018) | api.crossref.org/works/<doi>/transform/application/x-bibtex, all 15 returned a matching record |
| Brunner & Munzel 2000, Biometrical Journal 42(1):17–25 | its DOI contains <, > and ; and breaks a URL path, so resolved by Crossref bibliographic search instead; the record matched on title, journal, volume, pages and both authors |
| Tang, Bauer & Christin, SOUPS 2025 — every quoted sentence | PDF downloaded from usenix.org/system/files/soups2025-tang.pdf with curl -A, text extracted with pypdf, all six quoted strings located verbatim, including “121 papers”, “479 assertions”, the 23% and 58% figures, the “Precise Test Name” recommendation and the Wilcoxon-ambiguity example |
scipy.stats.brunnermunzel added in SciPy 1.2.0 | SciPy 1.2.0 release notes: “The Brunner-Munzel test is now available as brunnermunzel” |
barnard_exact / boschloo_exact added in 1.7.0; permutation_test in 1.8.0 | SciPy release-notes pages and the docstring Added in version markers |
| SciPy 1.18.0 current on PyPI | pypi.org/pypi/scipy/json |
mcnemar and cochrans_q are in statsmodels, not SciPy | statsmodels.org/stable/generated/statsmodels.stats.contingency_tables.mcnemar.html; absent from the SciPy stats source |
| statsmodels 0.14.6 current | pypi.org/pypi/statsmodels/json |
| Local versions in the quoted demo output | python3 -c “import scipy, numpy, statsmodels” in this container: SciPy 1.17.1, NumPy 2.4.6, statsmodels 0.14.6 |
| IMC 2026 and PoPETs 2026 CFPs contain no statistical-reporting requirement | conferences.sigcomm.org/imc/2026/cfp/ and petsymposium.org/cfp26.php fetched and read; neither mentions statistical tests, significance or p-values |
| PoPETs author lists for 2 papers the index lacks | petsymposium.org landing pages fetched with curl -A and filled into out/authors.json by hand (fetch_authors.py could not parse them) |
Rejected, or could not be established
| Item | Disposition |
|---|---|
| USENIX Security '26 CFP | usenix.org returns 403 to every non-browser client. The page says USENIX Security is unverified, not “silent”. Not claimed either way |
| CONSORT 2025 | not used. Pvalue corrections already owns it and had already verified the article numbers; adding a second, weaker account would risk contradicting it |
| APA JARS-Quant | landing page reachable, the standards document not (redirect chain to psycnet.apa.org). Not cited |
| SAMPL guidelines | exist and were located on the EQUATOR network, but the actual guideline text could not be fetched to quote a line requiring the test be named. Not cited — an uncited “guidelines say X” is exactly the claim this log exists to prevent |
| Yates' correction is “deprecated” | claim weakened. No canonical deprecation statement was found. The page says “skip Yates' continuity correction” citing Campbell 2007, which is an evidence-based recommendation, not a formal retraction |
| Abadie et al., “When Should You Adjust Standard Errors for Clustering?” | fetched and verified, then dropped. Crossref gives year 2022 (online) where QJE 138(1) is a 2023 print issue; rather than publish an ambiguous year for a marginal citation, Cameron & Miller 2015 carries the point alone |
confseq / safestats / evalinger (anytime-valid tooling) | found only via search-result snippets, not fetched from a package index; confseq is not on CRAN (404). Not cited. Moot in any case: the corpus probe for anytime-valid inference returned 0 genuine hits, so the page does not recommend the area |
| ACM/IEEE artifact badging and statistics | not investigated. Flagged as untouched rather than silently omitted |
A first-guess DOI for Lydersen et al. (10.1002/sim.3489) | wrong — it resolves to an unrelated GEE paper. The correct DOI 10.1002/sim.3531 was confirmed by Crossref bibliographic search. Recorded because a plausible-looking DOI resolved to something real and wrong |
The published code
pages/paired_and_clustered.py, embedded on the page as <file python> and reproduced there in full.
- Synthetic data, fixed seed (
SEED = 20260813). Labelled as such on the page and in the docstring. It demonstrates a property of the tests, not a fact about the web. No measurement claim is made from it. - Embedded block verified byte-identical to the file by exact line-list equality, not by substring containment — 187 lines each as published. This claim went stale twice during the run: the Yates fix (A7) changed the file to 183 lines and the docstring fix (R4-2) to 187, and each time the embedded block had to be regenerated and re-verified. The generic reviewer caught the first of those staleness gaps. Re-embed and re-verify after every edit to the script, and re-state the line count from the check, not from memory.
- Both
<code>blocks on the page are the complete output of their part of the script — 25 lines for part A and 35 for part B — verified by exact line-list equality in both directions,page_lines == run_lines. - The first version of that check was wrong, and a reviewer caught it. It tested only
all(line in run for line in page)— that page ⊆ run — which passes on a truncated or spliced block. Both blocks were in fact silently cut: part A dropped its closing four-line interpretation, and part B dropped an entire mid-block paragraph, with no ellipsis marking either. This is precisely the failure the workdir README records as “'Real output' must be the whole output, or say where you cut”, and a subset test cannot see it. A containment check is not an equality check. - Runtime 3.2 s.
Choices inside the simulation, and one honest weakness
- Part A's counts are chosen to make the point, and the point is not “chi-square is conservative”. With 1,900 concordant and 100 discordant pairs, McNemar returns 10⁻⁹ where the marginal chi-square returns 0.046. The page says explicitly that the direction reverses in other configurations and that the real claim is “a test that ignores the design answers a different question”.
- Part B's ICC = 0.00 row is the rig-check. The naive test's false-positive rate there is 5.1% against a nominal 5%, which is what a correct test should do. Without that row the simulation would be unfalsifiable.
- The cluster-aware test is not exactly nominal either: 5.5%–6.4% across the sweep. That is aggregation to 30-versus-30 units making Mann-Whitney discrete and slightly anti-conservative, not a bug. The page states the range rather than claiming the fix is exact — at ICC 0 the cluster test is in fact worse (6.4% vs 5.1%), and the page says so.
- Weakness, stated: the cluster-mean aggregation is the crudest of the five remedies the page lists, chosen because it is the one that can be demonstrated in twenty lines. It is not a recommendation that it is the best remedy, and the page ranks cluster-robust errors and cluster permutation above it.
Report script and its unedited output
node scripts/test_fold.mjs # 146/146 self-tests node scripts/report_hypothesis_testing.mjs # every figure, with denominators node scripts/report_hypothesis_testing.mjs --wiki # DokuWiki tables node scripts/report_hypothesis_testing.mjs --list # the 1,025 papers node scripts/report_hypothesis_testing.mjs --quotes 'McNemar' # evidence behind a family node scripts/ht_quotecheck.mjs 'Mann-Whitney' --show # quote verification python3 pages/paired_and_clustered.py # the published demo # the guard, run BOTH windowed and whole-page node scripts/check_page_numbers.mjs pages/statistics_hypothesis_testing.txt \ out/ht_report_all.txt --code node scripts/check_page_numbers.mjs pages/statistics_hypothesis_testing.txt \ out/ht_report_all.txt '===== Use in Publications =====' '===== What to Report ====='
out/ht_report_all.txt is the concatenation of the report, the demo output and the quote-check output — the guard needs all three, because the page quotes figures from each.
Section Z of the report lists every number on the page that is not a corpus count — test dates, the four Tang et al. figures, per-paper figures quoted from individual papers, software versions, the demo's constants, and the corpus facts documented elsewhere (138 posters, the 68% and 20% run-to-run agreement figures). That block exists so the guard can account for every digit without adding entries to its shared ALLOW map. Both guard runs report OK.
Review log
Three focused reviewers in parallel on a frozen snapshot (out/review_ht/, frozen 2026-08-13T12:04Z), then fixes, then a generic pass. All were told explicitly that the author's context may not be exhaustive, and all were handed the page text, the report script, its output and these notes. Freezing first is deliberate: the workdir README records that applying fixes mid-review makes reviewers report already-fixed items and, once, report the fix itself as the error.
Author's own pass, before the reviewers
Run first because the README records that reviewers do not check rhetorical sentences. It found four things, three of them wrong, in prose rather than in tables.
| # | Finding | Disposition |
|---|---|---|
| A1 | “IMC … the least likely to run an inferential test.” One decimal place hides the truth: IMC is 71/638 = 11.129%, CCS is 110/990 = 11.111%. CCS is lower. The superlative was false | FIXED. The page now says the two are indistinguishable and no ranking should be read, and keeps the real point (the most empirical venue is among the least inferential). The report now also prints the table at three decimals so the next run cannot repeat it |
| A2 | “Kolmogorov–Smirnov is the one test crawl papers reach for more than user studies do.” There are two: KS (10.7% vs 4.6%) and the proportion / z-test (7.1% vs 5.5%) | FIXED. Both named |
| A3 | “No paper names what Mann-Whitney U actually tests.” This contradicted the page's own next sentence, that 15 papers report Â12 / Cliff's δ / CLES — which *are* the stochastic-superiority quantity | FIXED. Narrowed to the claim the probe actually supports: no paper names the estimand in words |
| A4 | The paired-binary finding was under-claimed. McNemar 19 papers / 1 crawl (which also had participants), sign test 6 / 1 (likewise), Cochran's Q 4 / 0 | STRENGTHENED, and the query added to the report so it is audited. New WRAP box: not one crawl paper without participants uses any of the three |
| A5 | The opening box said the 58 papers name no test “anywhere in their statistics tuples”; the script only inspects hypothesis-test tuples | FIXED, and the complement (109 of 1,025, 10.6%, name no substantive test at all) added to the report and the table. Measured while checking: only 4 of the 109 name a test in a tuple of another kind, so the loose claim was nearly true — but “nearly” is not a measurement |
| A6 | The trend claims rested on point estimates alone | STRENGTHENED. Fisher's exact added to the report for 15 comparisons: rank-based rise p = 0.00323, Mann-Whitney p = 0.000595, permutation p = 1.00 (flat, as claimed), and a new finding — reporting improved, p = 0.0338. Also caught that the last step is not individually significant (p = 0.121), so the page no longer implies the most recent rise stands alone |
| A7 | The published demo called chi2_contingency with SciPy's default correction=True, i.e. it applied Yates' correction — which the page's own table tells the reader to skip | FIXED. correction=False now passed explicitly with a comment. Output changed: chi2 3.967 → 4.103, p 0.0464 → 0.0428, ratio 4.16e7 → 3.84e7 |
| A8 | The bug table below contained a backslash-escaped pipe inside a table cell. DokuWiki does not treat a backslash-escaped pipe as an escape — the pipe still delimits, so the row rendered with 5 cells in a 3-column table and broke the table from there down | FIXED. Found by a cell-count consistency check over every table on both pages, not by reading. And then it happened again: the row you are reading originally quoted the offending character and broke this table too. The check caught that as well. Do not write a pipe inside a DokuWiki table cell, not even to talk about one |
''sonnet'' — figures against the script
Re-ran test_fold.mjs (146/146), report_hypothesis_testing.mjs, ht_quotecheck.mjs and the demo, confirmed the scripts were byte-identical to the frozen copies, and checked every table cell.
| # | Finding | Disposition |
|---|---|---|
| R1-1 | Every numeric table matches a fresh run exactly — the denominator table, the 26-row folded table, the undercount table, all 4×8 trend cells, the paired unions (165 / 592 / 916), the study-shape table, the reporting-gap table, the hygiene-stack table, the probe table, and all 19 paper counts in the “Which Test” table. Venue counts sum to 1,025 and venue totals to 5,859. All “X of Y” ratios recompute | No change needed. This is the check the page exists to survive |
| R1-2 | The IMC/CCS superlative does not survive un-rounding | ACCEPTED — same as A1, found independently. Two passes finding it separately is why the report now prints three decimals |
| R1-3 | Both <code> blocks are silently truncated or spliced, while the provenance page claimed they were verified complete. Part A dropped its closing four lines; part B dropped an entire mid-block paragraph. No ellipsis marked either | ACCEPTED, and the important find of the review. My verification was all(line in run for line in page) — a subset test, which passes on any cut. Both blocks are now the complete output of their part, verified by exact line-list equality in both directions (25 and 35 lines). The flawed check is recorded above so it is not rewritten |
| R1-4 | The demo applies Yates' correction by default while the page says not to | ACCEPTED — same as A7, found independently |
| R1-5 | The Python is otherwise correct: the McNemar/binomial identity holds bit-for-bit, the ICC formula is the right one-way random-effects ICC, the null is genuinely true by construction, and the ICC = 0 row returns 5.1% — the rig check works | No change |
| R1-6 | Spot-checked the Mai et al. PDF-vs-txt claim, plus Monzani, Razuvayevskaya and Umayya quotes, against the dataset itself. All verbatim | No change |
| R1-7 | Running check_page_numbers.mjs against the provenance page reports many unaccounted numbers, all of them historical or external (DOI fragments, the before/after fold values like 212 → 213, byte counts) | REJECTED as a defect. The guard is built to audit a content page against its report; a working log that deliberately records superseded numbers is out of its scope. Noted here so the next run does not “fix” it |
''sonnet'' — citations and quotes
| # | Finding | Disposition |
|---|---|---|
| R2-1 | “Becerril-Arreola & Bapna” — a co-author who does not exist. The TheWebConf 2023 paper has one author. Confirmed by its own ACM reference line, by grep -i bapna finding nothing in any of its three renderings, and by Crossref | FIXED. Note the shape of it: the bibliography entry was correct, so the page's prose contradicted its own citation. A reviewer checking only the .bib would have passed it. The sentence names three papers in a row and two of them genuinely are two-author, so the third acquired a co-author by parallelism |
| R2-2 | All 36 keys resolve; 0 duplicates within the 29 additions and 0 collisions with the 212 live keys; 0 unused additions; braces balanced; every entry has its required fields; 22 DOIs cross-checked; every quoted sentence from all 15 corpus papers located verbatim; all six methodological attributions match | No change |
| R2-3 | The Mai et al. claim — quotes in the PDF, absent from all three stored .txt renderings — independently verified in both directions | No change. Two passes have now confirmed it |
| R2-4 | Tang et al.: 121 papers / 479 assertions confirmed, and the 23% / 58% figures confirmed not swapped | No change |
| R2-5 | Divine et al. 2018, Rochon 2012 and Campbell 2007 were assessed from abstracts and search results, not primary full text (paywalled) | ACCEPTED as a limit, recorded in What could not be established. Divine et al.'s thesis is in its title, so the risk is low, but it is not zero |
''sonnet'' — external currency, as of 2026-08-13
| # | Finding | Disposition |
|---|---|---|
| R3-1 | The KS date cell said “1933/1948”. Kolmogorov's one-sample test is 1933; the two-sample test — the one this literature almost always uses — is Smirnov 1939; 1948 is Smirnov's table of critical values | FIXED to “1933 one-sample / 1939 two-sample”. Independently re-verified against the Wikipedia KS article and the Springer Encyclopedia of Statistical Sciences entry: Smirnov 1939, Bulletin of Moscow University 2(2):3–16 |
| R3-2 | All six software claims VERIFIED against SciPy release-notes pages and PyPI JSON. SciPy has still not gained a McNemar test, so that page claim stands | No change |
| R3-3 | Both CFP negative claims VERIFIED by fetching; the USENIX 403 reproduced independently | No change. A negative claim about a live document is the cheapest thing for a reader to disprove, so having it fetched twice matters |
| R3-4 | All 15 DOIs resolve and match; all 18 test dates correct apart from R3-1 | No change |
| R3-5 | Nothing since 2024 overturns the page. One 2025 arXiv refinement to cluster-robust SEs for few-large-clusters, not web-specific and not contradicting Cameron & Miller; e-value work continues with no venue adoption | CONFIRMS the page's currency claim. No change |
| R3-6 | Rasch et al.: Crossref gives online-first 2009, print 2011, Statistical Papers 52(1):219–231 | NO CHANGE. year = {2011} matches the volume/issue/pages actually cited. Recorded so the next run does not “correct” it to 2009 — and it is why abadie2023_when was dropped rather than published with an ambiguous year |
| R3-7 | No dead or renamed links | No change |
''fable'' — generic
Run on the post-fix snapshot out/review_ht/page_r2.txt. It found the single most consequential item of the whole review, and its closing observation is the one to keep.
| # | Finding | Disposition |
|---|---|---|
| R4-1 | The embedded <file> block was the pre-A7 version of the script, so the code on the page could not produce the output printed beside it, and this page's “177 lines each” verification claim was false | ALREADY FIXED before the review returned (re-embedded and re-verified at 183 lines), so this is a stale-snapshot artefact rather than a live defect — but the provenance claim it flags was real and is corrected above. The lesson is the reviewer's: the A7 fix updated the file and the output blocks and forgot the embed |
| R4-2 | The published script's docstring misdescribes its own Part B: “shows that permuting whole clusters fixes it”. Part B permutes nothing — it aggregates to cluster means. The page and this log both get it right; only the docstring was wrong, and the docstring is what a reader of the downloaded file sees | ACCEPTED and FIXED. The docstring now says “testing CLUSTER MEANS”, and adds that aggregation is the crudest remedy and that the better three are not demonstrated. Re-run, re-embed, re-verified (187 lines) |
| R4-3 | p = 1.00 was being read as evidence of flatness for permutation testing, and the page ran 15 uncorrected Fisher tests while its sibling page is about multiplicity | ACCEPTED, and it changed what the page claims. Holm across all 15 is now computed in the report and both columns are published. Consequences: the Mann-Whitney rise survives comfortably (Holm 0.00833), the rank/exact rise only just (0.0420), and “papers name their test more often now” does NOT survive (raw 0.0338 → Holm 0.372) and is now presented as “encouraging and unproven”. The permutation claim is now descriptive only, with an explicit statement that a large p on 2/97 vs 6/214 is absence of evidence and not a measure of stability. This is the most valuable single finding of the review — it removed one claim and correctly weakened another |
| R4-4 | Two probe-scoped negatives were stated as corpus facts in the opening box (“three papers in the whole corpus cluster their standard errors”; “no paper names the estimand”), against this log's own recorded lesson that a flat negative from one phrasing is not a negative | ACCEPTED and FIXED. Both are now attributed to the probe, with a pointer to the limitations section. The reviewer is right that a paper using GEE, or the phrase “adjusted for within-site correlation”, or “the probability a random site from A exceeds one from B”, would match neither probe |
| R4-5 | “Nine of the ten resolve the ambiguity nowhere” drops the qualifier the gap table carries (“nowhere else in the paper's tuples”) | ACCEPTED and FIXED |
| R4-6 | “every one checked by hand was present” is technically true of the five that were checked and reads as if all 335 were | ACCEPTED and FIXED. The page now says five of the 335 were chased and the other 330 were not |
| R4-7 | MISSING: attrition between the two crawls. McNemar's 2×2 has no cell for “unreachable in crawl 2”, and the demo's 2,000 sites silently succeed twice. This is the first thing that actually happens in a before/after crawl and the “population changed under you mid-crawl” case the site's brief names | ACCEPTED — the best content finding of the review. A new subsection Attrition: the pairs you lose between the two crawls covers complete-case pairing and reporting the count, checking the attrition is not differential in the outcome, and not silently switching to an unpaired test to keep the dropouts. It also states the crawl-specific twist: attrition is not random with respect to the outcome, because what makes a site unreachable and what makes it track are both correlated with how it is run |
| R4-8 | Unmeasured superlatives: “runs most and reports worst”, “the single most common way to lose power”, “the one error nobody guards against”, and a causal “it has the same explanation” | ACCEPTED and SOFTENED, all four. “nobody” had already become “almost nobody” in the author pass; the causal sentence now says “the likeliest explanation” and carries a footnote that the corpus shows the asymmetry and cannot show why |
| R4-9 | Housekeeping: a lowercase sentence start in What to Report; this section was a placeholder | FIXED |
| R4-10 | What is good: the page answers its own question; the demo's synthetic framing is honest and prominent; the unit-of-analysis section is correctly the most prominent thing; voice matches the neighbour; the textbook/measurement boundary holds | No change. Recorded because a review that only lists defects gives no signal about what not to change |
The reviewer's closing observation, which is the most useful sentence in the whole review log: across findings R4-1, R4-3, R4-4 and R4-6, every one is a case where the page's careful version of a claim exists somewhere — in the provenance, in a later section, in a table — and the prominent version dropped the qualifier. The opening box and the section leads are where hedges go to die. That is the lens to apply to the next page on this site before publishing it, and it is a different failure mode from the stale-figure one the guard catches.
What the review layer was worth
Six of the eight author findings were in prose, not tables — the framing sentences, a superlative, an internal contradiction and a scope word. The three focused reviewers between them found four items: two the author had already found independently (IMC/CCS, Yates), one genuinely new and the most valuable single find of the review (the code blocks were spliced and the check that “verified” them was a subset test), and one factual error in an author name that the bibliography got right and the prose got wrong. The figures themselves — hundreds of them — survived a full independent re-run without a single discrepancy, which is what the check_page_numbers.mjs guard is for and is the first time on this site that pass has come back empty.
What could not be established
* Whether the paper.cols.txt deficiency found in Mai et al. is widespread. One paper is confirmed to have content in its PDF and in none of its three stored text renderings. A corpus-wide pypdf-vs-cols diff would settle it and was not run. It bears on every quote-check figure on this site, so it is the highest-value follow-up here.
* Whether the 68% run-to-run agreement on statistics.kind still holds. It was measured on the previous corpus run and has not been re-measured; the page says so where it uses it.
* How much the 138 posters inflate the “no test named” rate of 5.7%. Not measured. The figure was not re-run excluding short records.
* Whether the 20 “unit of analysis” and 11 “normality assumption” matches are genuine uses. Not read one by one; published as upper bounds and marked as such in the report.
* Whether authors who write “median” about a Mann-Whitney result believe it or are being loose. Not answerable from text, and the page says so.
* The real intra-class correlation of web-measurement outcomes. The simulation shows everything depends on it and no paper reports one. This is the open question the page leads with, and it is genuinely open.
* Whether the two papers whose stated signed-rank/Mann-Whitney rule is keyed on sample size or variable type actually analysed their data correctly. Their designs make the stated rule and the correct rule coincide in the common case, and the page says the results are not in question. Establishing it properly would need their data.
Judgement calls
| Call | Why | A reasonable person might have |
|---|---|---|
| Create a page rather than broaden Pvalue corrections | multiplicity and test choice are independent failure modes over the same population; the corrections page already declared this boundary | merged them into one long “inference” page. The statistics: namespace would then have had one big page and three red links |
| Exclude assumption checks and confidence intervals from every “which test” figure | Shapiro–Wilk is not a test of the paper's hypothesis, and counting it as one inflates every family | reported one flat method histogram. That is what an unfolded query returns, and it would have put Shapiro–Wilk above McNemar |
| Give a bare “Wilcoxon test” its own bucket instead of assigning it | the paper did not say which test it ran, and the two differ in design | assigned by majority (rank-sum) and gained 10 papers in the wrong family. The ambiguity is the finding |
| Publish a synthetic simulation | the ICC-inflation effect cannot be shown from the corpus, because no paper reports an ICC | omitted it and asserted the effect verbally. The page would then be making its central claim without evidence |
| Use cluster-mean aggregation in the demo, the crudest of the five remedies | it fits in twenty lines and needs no new dependency | demonstrated cluster-robust errors or a cluster permutation test, which are better remedies. The page ranks those above aggregation and says the demo is not a recommendation |
| Name the two papers whose stated signed-rank/Mann-Whitney rule is keyed on the wrong criterion | the stated rule is what a reader copies, and both are widely read papers | left them anonymous. They are named with the explicit statement that their results are not in question and that their designs make the stated and correct rules coincide |
| Report 15 of 213 Mann-Whitney papers for the rank effect size, from a probe whose contexts were sampled rather than fully read | the union is small and the direction is unambiguous | read all 67 matches. The 15 is a cross of the probe with the fold, so it is a lower bound on a lower bound |
Drop abadie2023_when | Crossref's year (2022 online) and the print issue year (2023) disagree, and the citation was marginal | published it and picked a year. Cameron & Miller 2015 carries the same point |
No ~~DISCUSSION~~ on this page | comments belong on the content page; follows the precedent of pvalue_corrections and study_preregistration | added one |
Link five pages that do not exist yet (artifacts, design:automated_measurements, design:user_studies, statistics:biases, statistics:regression) | every one is already a red link promised by start and linked from Pvalue corrections; not linking them would make this page the odd one out | avoided red links. The site's convention is to promise them |
The run itself
| Item | Value |
|---|---|
| Date | 2026-08-13, single session, no human supervision |
| Corpus at the time | data/extract/run1, 5,859 extracted papers, 7 venues, 2010–2026 |
| Author | Claude (Opus 5) — every query, every fold, every quote check |
| Sub-agents | one sonnet external-currency sweep before writing; three review passes (sonnet × 3) on a frozen snapshot; one fable generic pass on the fixed page |
| New scripts | scripts/test_fold.mjs (146 self-tests, 0 residue), scripts/report_hypothesis_testing.mjs (carries its own two-sided Fisher exact, checked against scipy.stats.fisher_exact 1.17.1 on all 15 rows it prints), scripts/ht_quotecheck.mjs |
| New published code | pages/paired_and_clustered.py |
| Artifacts | out/ht_report.txt, out/ht_report_wiki.txt, out/ht_report_list.txt, out/ht_quotecheck.txt, out/paired_demo.txt, out/ht_bib_additions.bib, out/review_ht/ (both frozen snapshots and the full review log) |
| Bibliography | 29 entries appended — 15 external statistics references via the Crossref BibTeX transform, 2 hand-written (Brunner & Munzel, whose DOI breaks a URL path; Tang et al., which has no DOI), and 13 corpus papers via bibgen.mjs. Two keys the page cites (cassel2022_omnicrawl, demir2023_similarity) were already live and were deliberately not re-added. No duplicate keys; all 36 keys used on the page resolve |
| Note on the live bibliography | it has a pre-existing brace imbalance of −1 (one unmatched } somewhere in the 212 entries that were already there). The additions are balanced at 0, so the merge preserves the existing state rather than adding to it. It renders correctly today and was not touched — flagged here because a future run computing brace balance will see it and should not blame these additions |
| Mistakes caught by my own re-derivation | the IMC superlative that rounding hid; “the one test” where there are two; an internal contradiction in the opening box; a scope word (“statistics tuples” for “hypothesis-test tuples”); the demo silently applying Yates' correction that the page tells readers to skip; a backslash-escaped pipe that broke a table, and then the row describing that bug broke the same table the same way |
| Mistakes the reviewers caught that I did not | a co-author who does not exist (“Becerril-Arreola & Bapna” — the bibliography was right and the prose was wrong), and the code-block verification being a subset test rather than an equality test, which had silently passed two spliced blocks while the provenance page claimed they were complete |
| The most useful single guard | check_page_numbers.mjs. Editing test_fold.mjs after the page was written moved 17 published figures; reading the page did not catch one of them and the guard caught all of them. Run it after every fold edit |
| Accidental exposure | none. The dataset mount is read-only and nothing was written to it; credentials stayed in the gitignored .env |
Related
- Hypothesis testing — the page these notes are for.
- Corpus — corpus-wide provenance: venues, funnel, provisional years, posters, duplicates.
- pvalue_corrections — the sibling log; shares this page's 1,025-paper population.
