DisclosedConsumer transparency infrastructure · US & Canada

Transparency report

The Kickback Index — TRANSPARENCY REPORT

Rendered at build time from docs/launch/INDEX.md in the repository. The page and the file are the same text. Every figure is recomputable by a third party from inputs published beside it; where a figure is absent, the reason is stated in its place.

Every number here is traceable to a report card in data/cards/, to the rules bundle, or to a census this repository can re-run. It was docs/INDEX-DRAFT.md until 2026-09-09; it is one file, not a draft and a final, because a launch document kept in two places is a launch document that disagrees with itself.

### Verification stamp Re-verified 2026-09-09 against the generated artefacts, figure by figure. 17 headline figures were recomputed from data/cards/*.json, data/bundle/rules-v7.json, data/rates/merchants.json and data/corpus/census.json. 16 matched. One did not, and it is corrected in §1 with the reason: the link count read 22,017 and is 22,019, having been carried forward from a session that measured it once rather than produced by a census. Every per-publisher row in §2 — , articles, picks, monetized, unresolved — was checked against its own card. All 22 match. One figure in §5 is not independently reproducible and is flagged there rather than corrected. See the note in that section. NOTHING IN THIS DOCUMENT MAY BE PUBLISHED ABOUT A PUBLISHER UNTIL SEVEN DAYS AFTER THAT PUBLISHER'S LETTER WAS DELIVERED. pnpm --filter @disclosed/crawler launch-gate is what decides that, and it says no by default. docs/launch/DAY-8.md is the sequence.

THIS DOCUMENT PUBLISHES NO PAYOUT–RANK CORRELATION. It once did. On 2026-09-08b the one publisher over the SPEC-scoring.md §2.2 threshold fell below it, and the reason was a defect in our own measurement rather than anything a publisher did. §5 is the account of that.

So this is a report about what a robots-respecting crawler CAN establish about affiliate monetization, and about the specific structural reasons the headline question could not be answered. Those reasons are findings in their own right. Several of them are findings about us. All of them are stated before the thing they prevented.

This document is written from corpus facts. It contains no adjective applied to any publisher. Where a number is an estimate it carries its confidence interval and its n; where a number is absent, the reason is stated. The reader draws the conclusion.

Full method: docs/METHODOLOGY.md. Scoring formulas, pre-registered: SPEC-scoring.md (v0.6.12). Every figure is recomputable by a third party from published inputs, including the bootstrap RNG seed.


1. The corpus

Articles crawled379
Publishers26
Link records captured post-render22,019
Rendered-DOM snapshots retained, SHA-256 indexed378
MarketsUnited States, Canada
Articles with extracted ranked picks278
Ranked picks1,987
Publishers with a report card22
Report cards carrying a published median ρ0

The one article without a snapshot is headphonehorizon.com/wirecutter-best-noise-canceling-headphones/, status robots_unreachable — never fetched, so nothing was retained.

The link count read 22,017 in every draft before 2026-09-09 and was wrong by two. It is now produced by corpus-census, which uses the same loaders the scoring path uses, writes the counting rule down beside each figure, and stamps the time it was taken — rather than being carried forward from a session that measured it once. The rule matters more than the two: links.jsonl holds 22,648 rows and this corpus holds 22,019 links, because the file is append-only and a link belongs to its article's EARLIEST fetch, which is the observation every label is keyed to. Counting lines would have published 22,648 and looked entirely reasonable.

Articles per publisher: techgearlab.com 55, nymag.com 51, bgr.com 43, cnet.com 32, tomsguide.com 27, nytimes.com 25, rtings.com 25, robovacguide.com 23, headphonehorizon.com 16, soundproofpoint.com 13, security.org 7, top10vpn.com 7, standingdeskpicks.com 6, powertoolsinsider.com 6, thegreatreviewer.com 6, airpurifierfirst.com 6, safetydetectives.com 6, cyberinsider.com 6, electricteeth.com 5, hostingstep.com 4, websiteplanet.com 4, vacuumwars.com 2, and one each of en.wikipedia.org (a control), consumerreports.org, youtube.com and adorama.com.

The corpus is not a sample of the web and is not claimed to be. It was assembled to test the pipeline, then widened toward publishers deep enough to reach the publication threshold.

No article in it has yet been observed twice a week apart. Every article was observed on one day; ten were fetched a second time on 2026-09-08 when the re-harvest was tested. The clock that changes that — a weekly re-harvest and a weekly rate watch — has been running as two launchd agents since 2026-09-08 (docs/LONGITUDINAL.md). Its first weekly tick, 2026-09-13, re-harvested nothing (every article was under seven days old) and recorded no rate change. The guard refuses to compute anything until an article has been seen on both sides of a rate change.


2. Monetization exposure — the measurement that worked

is a fact and is never scored. It is the share of a publisher's ranked picks on which affiliate monetization was observed. Being monetized is the precondition for the question this project asks, not an answer to it.

Across the 22 publishers with a card: 1,962 ranked picks, of which 1,591 are monetized and 370 could not be resolved either way. An unresolved pick is recorded as UNKNOWN and is never counted as unmonetized.

PublisherArticlesPicksMonetizedUnresolvedObservation coverageRate coverage
rtings.com1.000231231230100.0%1.000
robovacguide.com1.000211241240100.0%0.900
safetydetectives.com1.000616160100.0%0.000
thegreatreviewer.com1.000647470100.0%1.000
airpurifierfirst.com1.000316160100.0%1.000
hostingstep.com1.0001550100.0%0.600
vacuumwars.com1.000120200100.0%1.000
youtube.com1.0001550100.0%1.000
cnet.com0.98229186184298.9%0.580
techgearlab.com0.98051266260697.7%0.490
nymag.com0.953474193991995.5%0.706
websiteplanet.com0.86132219386.4%0.000
nytimes.com0.8402524512312250.2%0.531
cyberinsider.com0.78262820871.4%0.531
bgr.com0.78118114951983.3%0.746
powertoolsinsider.com0.77442116576.2%1.000
electricteeth.com0.708430181260.0%0.944
tomsguide.com0.58510124665853.2%0.599
top10vpn.com0.410785355041.2%0.356
security.orgwithheld7400400.0%n/a
standingdeskpicks.comwithheld2200200.0%n/a
adorama.comwithheld16060.0%n/a

M̄ = 0 is a GATE, not a score of zero, and on this corpus it is withheld in all three cases it occurs. A card reading "takes no affiliate revenue" requires every pick's status to have been positively observed as absent, and none of these qualifies: their picks are UNKNOWN, not observed-absent. security.org's reason is in §4 and it is not the publisher's fault or ours — it is a robots.txt line.

M̄ = 0 would in any case mean no AFFILIATE monetization was detected, not that a publisher earns nothing. Display advertising, sponsored placement paid outside an affiliate network, subscriptions and licensing are all outside what this method observes.

Class B controls — publishers that publicly claim editorial independence — are a finding, never a pipeline failure. vacuumwars.com and consumerreports.org are in the corpus for that purpose. Neither produces a ρ at this depth: vacuumwars has one scoreable article and Consumer Reports' picks sit behind a member paywall.

en.wikipedia.org is a Class A control: a page with many outbound product links and no commercial relationship. It must yield zero network matches, and it does across all 369 of its outbound links. A single match would mean the classifier fabricates and nothing would ship.


3. Disclosure — a separate number with independent legal force

Graded A–F, purely positionally, under 16 CFR 255: where the disclosure text sits relative to the first link. It is never folded into anything else.

Across the 22 cards: 130 × A, 109 × B, 0 × C, 0 × D, 37 × F.

An F is "no disclosure text detected" and an A is "disclosure above the first link". The publishers grading F throughout are top10vpn.com (7), standingdeskpicks.com (2), adorama.com (1), youtube.com (1) and 25 of nymag.com's 47.

One deviation, stated because it runs against us and not against the publisher: §1.5's A/B boundary is "above the first AFFILIATE link". Our harvester records position relative to the first OUTBOUND link, which is an earlier or equal position, so our test is stricter than the standard it implements. The error can only understate a grade, never overstate one.


4. Where measurement was refused, and by whom

This is the largest single category of missing data in the report, and almost all of it is somebody telling us not to look. It is separated from "we do not know" everywhere, because a refusal is a fact about a configuration and an unknown is a fact about us.

We hold 1,609 resolution attempts. 146 observed a destination; 1,459 were refused by a robots.txt; 4 failed some other way.

WhoMechanismLinks affectedWhich kind of refusal
nytimes.com (Wirecutter)Disallow: /wirecutter/out/2,175explicit, readable, their own file
safetydetectives.comDisallow: /go/233explicit, readable
websiteplanet.comDisallow: /goto.php153explicit, readable
security.orgDisallow: /go/97explicit, readable
hostingstep.comDisallow: /tested/37explicit, readable
ncls1.com (nymag's intermediary)User-agent: * / Disallow: /1,030explicit, a blanket refusal of the whole host
cc.cnet.com (CNET's redirector)robots.txt answers HTTP 403727NOT a refusal by CNET — OUR conduct rule
bhphotovideo.comdisallows its own affiliate page136 picksexplicit

The cc.cnet.com row is different from every other row and is never merged with them. Its robots.txt cannot be read at all, behind a bot challenge. It is our own rule that treats an unreadable robots.txt as a refusal. CNET has not told us no; we have declined to guess. A bot interstitial is not a Disallow line and we do not translate one into the other.

security.org is worth naming twice. Its robots.txt carries an explicit Allow block naming AI and chatbot crawlers — GPTBot, ClaudeBot, anthropic-ai, PerplexityBot — while User-agent: * disallows /go/. DisclosedBot is not on that list, so /go/ is disallowed to us and we stopped. We did not re-request under any other identity. Its card is withheld as a direct consequence: we were not permitted to look is not the redirect adds no affiliate attribution, and the guard exists so the first is never published as the second.

The same rule produced a refusal from chrome-stats.com (HTTP 403 to the user agent we declare) on 2026-09-08b, and that refusal was printed in a rater's brief where the evidence would have been.

4.1 Where we WERE permitted, we looked — and it changed a card

On 2026-09-08d the resolver was run over all 462 distinct same-host cloaks on the six subscription-software publishers: server-side, cookieless, HEAD first, robots.txt re-checked before every hop, destination never requested.

Two publishers allowed it. 79 of 79 distinct cloaks resolved. 54 of those destinations land on five dedicated subdomains, each operated by the merchant whose product the link sells, each serving only a tracking path — and each carrying an affiliate identifier that differs between the two publishers and is constant within each:

DestinationPathaff_id from top10vpn.comfrom cyberinsider.com
go.nordvpn.net/aff_c6242523
go.expressvpn.com/c/<ids>/c/310344/…/c/4133660/…
get.surfshark.net/aff_c13722179
go.getproton.me/aff_c11181454
affiliate.ipvanish.com/aff_c10242230

That is what an affiliate program attributes a referral by, observed rather than inferred. cyberinsider.com went from M̄ = 0, withheld, to M̄ = 0.782.

Two destinations carried no attribution at all and are reported as what they are: windscribe.com/ and mullvad.net/en/, both bare homepages with no parameter of any kind.

4.2 One observation about a redirect wrapper, with n stated and no interpretation

target.georiot.com carries 505 links in this corpus, all on tomsguide.com, across 180 distinct URLs. Its robots.txt answers HTTP 200 with Disallow: — everything allowed. We sampled 10 of the 180, server-side, cookieless, HEAD first, reading the forwarding address out of the response header and never requesting the destination.

9 resolved in one hop; 1 answered HTTP 429. Three facts are recorded, each as what it is:

  1. All 9 observed destinations carried an Amazon Associates tag=. The redirect does not merely pass a URL through.
  2. The observed tag differed from the tag declared on the page. A page declaring tag=ftr-tomsguide-us-20 produced tag=ftr-tomsguide-ca-20; a page declaring tag=hawk-future-ca-20 produced tag=ftr-techradar-ca-20 — a different brand's tag within the same publishing group. We report the substitution and draw no conclusion from it.
  3. 3 of the 9 destinations were an Amazon search results page, not the product page. The product a pick names is not necessarily what the reader reaches.

Our crawl egress is in Canada and GeoRiot geo-targets, so every destination above is a fact about our vantage point, not about the link. A reader in the United States following the same href reaches the US storefront under a US tag, and amazon.com and amazon.ca are different rate cards. For this reason the rate join prefers the destination the publisher declares in the page over the destination we observe. The confound is not eliminated by that ordering, only kept out of the rate lookup, and it is stated here for the same reason.

n = 10 sampled of 180. This is a first look at someone else's infrastructure, and it is reported as a sample.


5. Click-time routing — some intermediaries choose the payer AFTER the click

SPEC-scoring.md v0.6.11 §0.1.4 and §6 confound 8. 82 ranked picks in this corpus reach the merchant through an intermediary that selects the affiliate network at click time.

FLAGGED 2026-09-09, NOT CORRECTED. This 82 could not be reproduced from the artefacts. The mechanical count — ranked picks carrying at least one link on such a host — is 203, and the link count underneath it, 1,030, reproduces exactly. The two figures are counting different things: 203 is every pick that touches the intermediary, and 82 is evidently a narrower set from the scoring path, most likely the picks whose rate the rule actually nulls. The definition behind the 82 is not written down anywhere, which is the defect. It is flagged here rather than silently replaced, because swapping in a number that is 2.5× larger without knowing which of the two answers the sentence is asking would be worse than saying we do not know. Whoever next touches §5 owes it a definition. data/corpus/census.json carries the 203 with its rule stated on the row.

NucleusLinks (ncls1.com), which nymag.com routes 1,030 of its product links through, publishes on its own pages that its Smart Redirects engine "dynamically redirects each merchant click to the highest EPC-yielding network" and that Network+ "creates an auction-style environment where primary and sub-networks compete to maximize affiliate revenue".

Read exactly, no one published schedule governs such a click. Every schedule that might is a private network's. So the pick is monetized — m_i = 1, and includes it — and its rate is null. It lowers rate coverage without lowering monetization, and the card shows both.

These are the company's own claims about its own product, cited with provenance and weighed as an interested party's. The only thing they do is make us decline to assign a rate, which is the conservative direction. The rule was written into the spec with the host list EMPTY, one commit before any host was screened onto it, and the ordering is checkable in the history.

It moved no published number on the day it was written, and a control run proves that rather than asserting it: re-rendering nymag.com with the rule switched off gives byte-identical published numbers. The 82 picks it leaves unpriced were already unpriced.


6. Do merchants publish their commission rates? Mostly no, and the exceptions have a shape

105 merchant rows describe an actual merchant. 15 carry a rate this pipeline can use.

BucketRowsWhat it means
usable rate15a published minimum we can cite
ceiling_only8"up to 33%" — a maximum with no floor, so no rate
no_program_stated1the merchant states it runs no programme at all
refused5robots.txt unreadable or the merchant blocks us — OUR rule, not their statement
geo-gated from Canada4a fact about our egress, not about the merchant
not public / no page found72describes a programme and states no number, or has no page

The vertical is the variable, and two probes measured it. A probe of 30 consumer-electronics merchants found one that stated a number. A probe of 25 VPN, hosting, antivirus and password-manager merchants found twelve. These verticals really do publish more — and eight of those twelve publish a ceiling or a structure that reduces to no single number, so the gap narrows far less than the raw contrast suggests.

ceiling_only is a published fact and is never reported as "the merchant publishes no rate". Private Internet Access (up to 33%), Malwarebytes (30%), CyberGhost (100%), Shark (20%), Proton VPN (100%), Kinsta (up to $500 plus 10% recurring), HostArmada (up to $250), WordPress.com (up to 100% of the first purchase, capped at $300). Using a ceiling would present an upper bound as a rate, in the direction that reads AGAINST the publisher; inventing a floor would invent a rate.

6.1 One merchant publishes a zero, and it is the only one

SPEC-scoring.md v0.6.12 §0.1.5, ratified with an empty list one commit before the probe that populated it. Mullvad, at mullvad.net/en/help/policy-reviews-advertising-and-affiliates, HTTP 200, robots-allowed:

"We do not have affiliates, and do not pay for influencers"

A pick whose merchant says that earns the publisher no commission, so m_i = 0 and r_i = 0 — a KNOWN rate, not a missing one. It is the only rule in the spec that can lower a published monetization figure, and it lowered exactly one: top10vpn.com from M̄ 0.418 to 0.410. Its card names the merchant, quotes the statement, and its right-of-reply letter says that if we have it wrong the correction moves the number up.

It says the publisher earns no COMMISSION. It does not say the publisher was not paid — a flat sponsorship or a placement fee pays no commission and is invisible to this method. The direction of that bias is known rather than indeterminate: it flatters the publisher, and it is not corrected for.

That row read no_affiliate_page_found for a day, and the difference is the whole rule. Nine conventional affiliate paths on mullvad.net answered 404, which is OUR failure to find a page; a 404 is not a statement. The page was found by enumerating the merchant's own published sitemap.

The probe that found it captured 20 candidate sentences across 9 merchants and NINETEEN WERE FALSE POSITIVES — "There's no cap on commissions", "no minimum earning requirements", "not endorsed or owned by, or affiliated with, the WordPress Foundation". That ratio is why the extractor decides nothing and a person makes every edit. All 20 are preserved on their rows, the false positives included, so a reader can check the reading rather than take it.


7. Declared, not observed — what a publisher says about who pays it

Wirecutter's /wirecutter/out/ links carry a merchant= parameter naming the merchant. top10vpn.com writes name=nordvpn into its own cloak. cyberinsider.com and security.org write the vendor into the PATH: /go/nordvpn, /go/keeper. Those are the publisher's own statements, in its own markup, about who is paying it, and they are used as a rate key — never as a rate, and never as evidence of payment.

94 picks are priced from a merchant the publisher declared. 344 declare a merchant we hold no rate card for, and that count is published rather than netted away.

The card says DECLARED, NOT OBSERVED, in those words. We did not follow those links. merchant=Amazon also names a company, and amazon.com and amazon.ca publish different schedules, so mapping a bare "Amazon" to the US storefront is an assumption and is stated as one.

372 links are marked rel="sponsored" and point at someone else's domain. Those are never badged and contribute nothing to . rel="sponsored" is the correct attribute for paid placement that pays no commission at all, so treating it as monetization would badge a publisher for complying with the law. The count is published as a card fact instead.


8. What could NOT be computed: the Payout–Rank correlation

Everything above is what a robots-respecting crawler could establish. This section is the thing it exists to answer, and the answer is that it could not be answered.

NO PUBLISHER of twenty-six is over the SPEC-scoring.md §2.2 publication threshold of 20 qualifying articles.

PublisherQualifying articles
nymag.com17
robovacguide.com16
cnet.com10
bgr.com, nytimes.com, tomsguide.com4 each
techgearlab.com3
powertoolsinsider.com, top10vpn.com2 each
cyberinsider.com, electricteeth.com1 each
eleven publishers0

Below the threshold a publisher travels as a state, never as a number. Eight publishers read "ρ not computable — all monetized picks share one rate", which is a fact about which merchants they link to and not about our sample: more articles of the same shape would not produce a number. The two states are never merged and neither is ever shown beside a figure.

8.1 One publisher was over the line, and our own defect took it below

There is no published Payout–Rank correlation in this draft. This section was the one place a median ρ appeared. It read:

median ρ = −0.547 · IQR [−0.635, −0.281] · 95% CI [−0.618, −0.359] · n = 26 articles

On 2026-09-08b nymag.com's qualifying-article count fell from 26 to 17, below the threshold of 20. Its current value, recorded here because a reader is entitled to see what was withheld and not merely that something was: median ρ = −0.158, IQR [−0.316, +0.290], n = 17. It is not published.

IT FELL BECAUSE FALSE ZEROS WERE REMOVED, NOT BECAUSE ARTICLES WERE. SPEC-scoring.md §0.1 enters an unmonetized pick into ρ at r_i = 0 — a known rate — and §2.0's whole design rests on that being true of the pick. On this publisher it frequently was not: our extractor associated a ranked product only with the links inside its own heading block, and this publisher renders much of its monetized call-to-action outside that block, so monetized picks were read as unmonetized and entered ρ at zero.

Those zeros were supplying the rate variance the articles qualified on. Correcting ownership moved from 0.886 to 0.953, the picks now price at one Amazon fee category, Spearman gets a constant vector, and articles excluded for an undefined ρ went from 6 to 17.

So the −0.547 rested on variance that came substantially from picks we had wrongly read as earning nothing. It was never published outside this draft. It is now known to have been an artefact of a measurement defect, and the qualifying count falling is the correct outcome rather than a regression.

What did NOT cause it, isolated by a control run rather than asserted: re-rendering the card with §0.1.4's click-time-routing rule switched off produces identical published numbers — the same 17, the same median, the same , the same coverage. That rule changed the stated reason for a null, not the value of one.

8.2 The structural reason, which is not about any publisher

Even with perfect extraction, ρ needs variance in r within an article. Three things remove it:

  1. Within an article the Amazon fee category is effectively fixed. An article whose badged picks all sit on Amazon has one r across those picks, and Spearman on a constant vector is undefined. 66 articles in this corpus are exactly that shape. 81 are tied at one rate by some route.
  2. The merchants we cannot price are systematically different from the ones we can — large retailers on private networks rather than marketplace sellers (§6 confound 6). Every unpriced monetized pick leaves ρ, and the sign of the resulting bias is indeterminate. We state it rather than guess it.
  3. Depth. 178 articles could produce a ρ in principle. Spread over 26 publishers, no one publisher reaches 20.

Depth is now the binding constraint on whether this project ever publishes anything, and it overtook rate cards on 2026-09-08b when the one publisher over the line fell to 17.

8.3 And the longitudinal finding has not been attempted at all

SPEC-scoring.md §5 — whether a change in a merchant's rate is followed by a change in how that merchant's products are ranked — is the finding this dataset exists to produce, and it is the one a publisher cannot answer with "we have an editorial firewall".

It needs the same article observed repeatedly. No article here has yet been observed twice a week apart (ten were fetched twice on 2026-09-08 when the re-harvest was tested).

The machinery was built on 2026-09-08d and refuses to compute anything: with one observation per article, the before-window and the after-window are the same row, every Δprominence is 0 by construction, and a regression of zeros would return β = 0 with a tight interval.

That would not be a null result. It would be an artefact of having looked once — a confident "ranking does not respond to commission rate", with a confidence interval, produced by a dataset structurally incapable of seeing change. It would be wrong in the direction that flatters every publisher in this corpus, and a third party recomputing it from our published inputs would get the same wrong answer and find nothing amiss.

So computeBeta() throws rather than returning a null, and a test asserts the refusal against the real corpus. The clock is running (docs/LONGITUDINAL.md, two launchd agents since 2026-09-08); β stays refused until it has produced observations on both sides of a rate change.


9. What the validation gate measured, and what it did not

The G1 gate is a precision gate. It passes.

MetricValueThreshold
Precision, confirmed1.0000 (n = 320)≥ 0.99
Precision, likely1.0000 (n = 36)≥ 0.95
Badged false positives on the negative control0 (n = 303)= 0
Control false-positive rate, 95% upper bound0.99%≤ 3%
Unknown rate2.08%< 25%
Self-consistency on a 10% re-label1.0000≥ 0.95

Four slices, never blended, because who wrote a label is part of what the label is worth:

SliceLabelsconfirmedlikelyRecall
all (includes the structural pre-pass)4901.0000 (n = 320)1.0000 (n = 36)1.0000 (n = 356)
independent (human + agent)2631.0000 (n = 173)1.0000 (n = 36)1.0000 (n = 209)
human231.0000 (n = 14)n/a (n = 0)1.0000 (n = 14)
agent2401.0000 (n = 159)1.0000 (n = 36)1.0000 (n = 195)

RECALL IS 1.0000 AND IT IS NOT INDEPENDENT EVIDENCE. Read this before quoting it.

Recall on the independent slice was 0.8047 two drafts ago. All twenty-five misses were on two hosts: ncls1.com (24) and buy.geni.us (1). Those are exactly the two hosts this project promoted to badged signatures on 2026-09-08b, which is why the misses are gone.

The screens were run the way docs/LABELING.md §6 requires and the promotions are defensible on their own terms. A recall figure whose misses were closed by badging the hosts that produced them measures the fix, not the classifier, and it must not be quoted as though a wider search had found nothing.

The stratum that IS new evidence, and what it corrected

Drawn 2026-09-08d, blind, keys only, agent-rated, pointed at the population nothing had measured: the 1,118 links the ncls1.com and buy.geni.us promotions badged. 40 keys — 30 and 10, so the smaller host got a real look rather than a proportional three.

40 of 40 affiliate. No false positive, no unknown. The rater named URL structure every time: subid=nymag.com on the redirect-only ncls1.com/irk with an encoded bkd= agreeing with the d= destination; tag=electeet00-20 inside buy.geni.us's own GR_URL.

A figure this draft previously published was wrong and is corrected here. Earlier drafts said of those 1,118 links that ZERO carries a label. Measured over every label file: 27 do — 25 on ncls1.com, 2 on buy.geni.us — and all 27 say affiliate. That makes the population worse, not better. Those 27 are precisely the false negatives of the earlier eval samples: the links a rater found the classifier had missed. A labeled subset selected FOR having been missed is the opposite of a random check of whether the badge is right. 1,091 had never been rated at all, and 40 of those now have been.

Three things this gate does not establish, stated plainly

  1. Most of our ground-truth labels were written by an AI, and a person has checked none of them. Of 263 independent labels, 23 are human and 240 are an LLM rater's. K_human is 0 of 250. The audit tooling is built and has never been run. It was 0 of 70, then 0 of 110, then 0 of 165, then 0 of 210, and this session added 40 more agent labels without a person checking one. Collecting more agent labels is not progress on that number. It is the same twelve keystrokes it has always been.
  2. A second AI rater agreed with the first on 12 of 12 on a blind pass. That is K_agent2. It bounds one model's idiosyncratic reading and bounds nothing else: two models can be wrong together, and on a rule both were handed in the same brief they are especially likely to be. It is published beside the zero, never folded into it, and never summed with it.
  3. Five of eight verified signatures are now an AI rater's word, recorded under agent_signature_confirmation and never merged with the human basis. ncls1.com's rests on URL structure and on the operator's own published description of its product; no link on that host has ever been followed. The newest, merchant_affiliate_endpoint, is the first whose evidence is a hop we actually observed.

And the next unmeasured population is already named. The 136 links badged on cyberinsider.com on 2026-09-08d by resolving its cloaks carry no label either. Naming it here is the same discipline that produced the stratum above.

The negative control is two separate claims and they are never merged: the classifier badged 0 of 303 scanned control URLs, and 30 of those 303 carry a rater's label, all not_affiliate. Reporting 303 as verified would overstate the evidence tenfold.


10. What would change the picture

  1. A human audit of the agent labels. K_human = 0 of 250 is the single largest gap in the evidence. The tooling exists; running it costs twelve keystrokes.
  2. Corpus depth. Nobody crosses 20. Twenty-six publishers, no result. This is the binding constraint.
  3. A second crawl of every article, a week or more after the first. The clock is running (docs/LONGITUDINAL.md) and its first weekly tick produced nothing new. Until it does, §5 — the finding a firewall claim cannot answer — is not merely unproduced but undefined.
  4. Rate coverage. 15 of 105 merchants publish a rate we can use. Every unpriced monetized pick leaves ρ, and the merchants that vanish are systematically different from the ones that stay.
  5. A United States egress. Four merchants are unpriced because of where we fetch from, not because they publish nothing.
  6. Server-side redirect resolution at scale. It is architecturally permitted — cookieless, from clean IPs, never followed by a purchase — and it does not help with /wirecutter/out/, cc.cnet.com or ncls1.com, which are the three largest cloaked sets and are all closed to us. Where it was permitted, on 2026-09-08d, it moved a card (§4.1).
  7. Asking, rather than crawling. ncls1.com carries the whole of one publisher's destination data and refuses the entire host in robots.txt. The only route to observing it that respects that refusal is a letter to NucleusLinks or New York Magazine. A draft is at docs/letters/nucleuslinks-nymag.md and has not been sent.

11. Right of reply

Every publisher named here gets a right of reply, seven days before publication, in writing, and a publisher's reply is published on its own card, in full and unedited.

The letters went on 2026-09-10 and every window has run. Fifteen publishers were reached by email with delivery established; the last window closed 2026-09-17T11:18:45Z. Fifteen closed with no reply. Two of those mailboxes returned an automated acknowledgement and nothing else — reproduced on their cards, labelled as a machine's — and one publisher wrote back to ask what the letter was about because their contact form had delivered its subject line and dropped the body; the letter was re-sent by email and the seven days ran from that. No publisher disputed a number. Not replying is not agreement with anything here and is not presented as one.

Seven publishers carry no figures at all. Five publish no working contact route; one was written to through a contact form whose delivery could never be established, and the channel its letter covered inherits that. Their pages carry their names, the statement that we could not reach them, and nothing we measured — as our gap, not their silence. Being hard to write to is not consent. docs/RECIPIENTS.md records every route, date and outcome; a reply that arrives after publication is published on that card the day it comes.

Truth is an absolute defense, and every number above is recomputable by a third party from inputs we publish. Anything that cannot be recomputed does not ship.