Vol. 001 — July 2026 The switch-decision paper Cards on file: 7
Technical supplement — Vol. 001

How the verdicts are actually produced.

The reader-facing Method section is three steps and exists to earn a reader's trust. This page is the spec sheet. It is written for engineers, it names the tools, and it states the limitations rather than the highlights.

The problem

What the system does

The technical problem is not writing comparisons. It is gathering distributed, adversarial, multilingual opinion about a fast-moving object and separating signal from vendor noise — where the noise is well-funded, deliberately shaped for search, and frequently indistinguishable from first-hand experience at the surface level.

Three properties make that tractable. Every voice is reached through a permalink, so it can be re-read. Every source carries two independent scores rather than one, so "credible" and "disinterested" cannot be silently traded against each other. And every published claim is checked against its own receipt by an agent that did not write it, whose verdict is cryptographically bound to the exact bytes it approved.

Every number on this page is computed from the repository at build time, not typed. If a figure here is wrong, the build is wrong — which is the same standard the cards are held to. Generated 2026-08-20.
Architecture

The pipeline

Six stages. The sweep parallelises; the verification does not — you cannot verify a card that does not exist yet. The two loops are the interesting part: one runs until a card passes, the other runs when the world changes.

SwitchCards research pipeline Six stages run left to right: sweep, normalise, score, synthesize, verify, publish. Sweeps run in parallel across per-platform channels; synthesis and verification are single-agent. A failed verification loops back to synthesis and repeats until it passes. A signature gate between verification and publication requires the verdict to carry a SHA-256 of the exact card being published. A dashed, event-triggered loop returns from publication to sweep — nothing is scheduled. CHANNELS — agent-reach (MCP), parallel reddit github api hn x youtube 小红书 ⚠ B站 exa zenn/qiita v2ex ⚠ 知乎 ⚠ 掘金 jina reader ⚠ = channel with a published, quoted failure mode — disclosed on the card, never silently skipped FAIL → fix → re-verify 01 SWEEP parallel agents saturation stop 02 NORMALISE verbatim quote + url + date 03 SCORE reliability × neutrality · stake 04 SYNTHESIZE single agent verdict + confidence 05 VERIFY different agent adversarial, loops 06 PUBLISH build → validate → deploy → live SHA GATE VERIFIED-CARD- SHA256 must equal sha256(card.json) ARTEFACT WRITTEN AT EACH STAGE — the receipts directory, published in full quotes.md facts.md sources.json card.json verify.md site/ · sitemap every quote,before any prose checkable claims+ disambiguation two scores,per row the compression— not the evidence PASS/FAIL +numbered defects CSP from realscript hashes RE-SWEEP — event-triggered, NOT scheduled: a dated claim goes false · a tooling defect invalidates coverage · a verification fails Parallel: 01. Single-agent: 04, 05. Nothing runs on a timer — see “freshness”. switchcards.uk — technical supplement

Solid arrows are the build path. The amber loop is the adversarial FAIL cycle. The dashed loop is event-triggered — see freshness, where the honest answer is that nothing is on a timer.

StageRunsWritesGate
SweepOn demand, parallel — one agent per source cluster (Reddit · GitHub/HN · X/YouTube · 中文 · 日本語)quotes.md — every quote verbatim, with URL and date, before any prose is writtenSaturation stop, all threads, all languages
NormalisePer source, inlinefacts.md — hard checkable claims and the disambiguation traps around themA quote extracted is not a page read
ScorePer (source, topic) pairsources.json + sources-registry.json — reliability and neutrality, independentlyVendor sources may carry facts, never verdicts
SynthesizeSingle agent — cannot parallelise a judgementcard.json — the compression; the directory is the receiptsNo claim without a receipt above it
VerifyA different agent, adversarially. Repeats until PASSverify.md — PASS/FAIL plus a numbered defect list naming the exact fieldVERIFIED-CARD-SHA256 must match card.json
Publish./deploy.sh — the only deploy pathsite/, sitemap.xml, _headers (CSP from real script hashes)Structural gate, then a live gate after propagation
Ingestion

Reaching the sources

Channels are reached through agent-reach, an MCP layer over per-platform clients, because plain HTTP fetching cannot see most of what matters. Ordinary pages come through direct fetch or Jina Reader. A logged-in browser is the last resort, used once, operator-authorised, and disclosed on the card that needed it.

ChannelReached byKnown limit — disclosed, not worked around
Redditagent-reachListing pages 403; search and single-post reads work. Comment trees render partially — one thread hid 51 replies behind 17 collapse nodes, so "read in full" is a claim we no longer make.
GitHubapi.github.comThe API, never the HTML — issue state and dates are the point, and HTML rate-limits. The cleanest differentiator we have: licence fields are objective and re-runnable.
Hacker Newshn.algolia.comCounts are per thread, never merged. A card once described two threads summed as one ~1,850-comment thread. It was 1,206 + 598.
X / Twitteragent-reachServer-blocked to plain fetch. Where a capture was needed it is stored as a dated capture file in the card's receipts.
YouTubeagent-reach + transcriptsTranscript where one exists; otherwise description and comments only.
小红书agent-reach, signed URLsA bare /explore/<id> is rejected — search first, then read the ?xsec_token= URL. Currently blocked at search (AUTH_REQUIRED, four attempts, three agents); the session is read from a Chrome/Chromium profile specifically.
B站agent-reachNo subtitle track — the player API answers code 0 with an explicit empty list. That is a definitive negative, not a fetch failure, so spoken content is never cited; description and comments only.
V2EXJina ReaderAPI is SSL-broken; the reader render is lossy and silently drops replies — eleven missing from one thread. Quotes verified individually; exhaustive reading not claimed.
知乎direct fetchArticle pages read fine. Search is CAPTCHA-walled — so we can say what the pages we reached contain, and cannot say what 知乎 contains.
掘金 · Zenn · Qiitaagent-reach + fetch掘金 search tokenises spaces badly; query with an explicit type and sort instead.
Exa (semantic web)agent-reachFree tier; returned HTTP 429 on one sweep date and not on the next. Treated as intermittent, and its absence is recorded on the card that lost it.
Channel failures are published on the card, not hidden. This is a design decision with a cost: it makes our coverage look worse than a competitor who simply does not mention the platform they could not read. The alternative is worse — a silent gap reads as coverage. Every card's footer names what was skipped and why, and quotes the error where we have it.
The inverse failure is real and we shipped it. One card published four sources as "login-walled, not re-verifiable" and a whole platform as a coverage gap. All of them read fine — the sweep had used plain fetching instead of the mandated channel layer. A card that invents a weakness is as dishonest as one that invents a strength; it just feels like modesty at the time. Registered as defect #39; the fix is a contract rule that nothing may be called a gap until the channel has been tried and the error quoted.
Source scoring

Two axes, never collapsed into one

Every source carries reliability and neutrality as separate 0.0–1.0 scores, per (source, topic) pair rather than per domain. Both are ours, not the publisher's, and both are printed in the ledger on the card itself.

reliability — 0.0 noise → 1.0 primary

How likely is this to be factually correct and re-checkable? A vendor's own pricing page scores high here. It is the primary source for its own prices.

neutrality — 0.0 vendor/paid → 1.0 no stake

What does this source gain if you believe it? The same vendor pricing page scores 0.1. Reliable and disinterested are different questions.

Collapsing these into a single "trust" number would make that page either uncitable or verdict-bearing, and both are wrong. Split, it does exactly one job: primary for prices and tiers only, never allowed to carry the verdict. The same split lets a hostile venue raise a source's weight — a Codex-favourable head-to-head posted in a Claude-partisan subreddit is more credible for being posted there, not less.

sources-registry.json — real rows, per (source, topic)
"ai-coding-agents": [
  { "source": "api.github.com/repos",  "type": "primary",     "reliability": 1.00, "neutrality": 1.00,
    "note": "License, language, created, stars. Objective, re-runnable." },
  { "source": "hn.algolia.com",        "type": "primary",     "reliability": 0.90, "neutrality": 0.85,
    "note": "One entry per thread, real points/comments." },
  { "source": "snorkel.ai/leaderboard", "type": "eval house",  "reliability": 0.90, "neutrality": 0.85,
    "note": "Its own two surfaces disagreed on #1 — treat top-of-board gaps as noise.
             Sells data services = mild stake." },
  { "source": "xiaohongshu.com",       "type": "sentiment",   "reliability": 0.60, "neutrality": 0.70,
    "note": "SIGNED urls only. EXCLUDE reseller/中转-API vendors, who saturate the topic." },
  { "source": "anthropic.com + openai.com", "type": "vendor", "reliability": 0.90, "neutrality": 0.10,
    "note": "Primary for prices/tiers ONLY. Never a verdict." }
]
A living store, updated every sweep. Deliberately not a frozen allowlist — a source that was independent last quarter may not be this one.

Stake detection

Stake is a property of the voice, not the domain, so it is detected per source at sweep time and the exclusion is published by name. The classes that get excluded from the voice count:

  • Vendor employees and official accounts — including the highest-engagement post in an entire corpus, which is precisely why engagement volume is used as a signal nowhere on any card.
  • Sponsored reviewers — one of the highest-reach English-language "tests" of a model discloses vendor sponsorship in its own description. It carries nothing.
  • Affiliate and lead-gen properties — of ten first-page results for one comparison, four were commercial or affiliate; for a second phrasing, six of ten.
  • Comped beta testers and embargoed access — one detailed production writeup was pulled from the card face after its own second paragraph disclosed pre-release access under embargo.
  • Course sellers, ambassadors and resellers — checked at the bio level, not the post level.
  • Second-hand relays — a compilation of someone else's benchmark data is a citable source but not a voice, and is excluded from n.
The rule that makes this auditable rather than decorative: an exclusion is applied even when the excluded source agrees with us. The embargoed writeup was being used to rebut a vendor's own disclosed weakness in that vendor's favour — the highest-risk seat an unaudited source can occupy — and it was removed for stake, not for being wrong. Excluded sources stay in the published ledger with their URL and their stake, so the exclusion can be argued with.
Verification

The eval loop, and what it costs

In the vocabulary this is a verifier loop over a retrieval pipeline, run adversarially, with the corrections log as its published artefact. It is not novel. What is unusual is that the loop is allowed to be expensive, allowed to fail repeatedly, and its failures are printed on the product.

A synthesizing agent writes the card. A different agent — with no memory of writing it — audits it against the receipts directory and returns PASS or a numbered defect list naming the exact field. The builder fixes; the verifier re-runs. Only a PASS publishes. Self-review does not count, because an agent that both gathers and judges its own work reliably misses its own mistakes.

RuleWhat it means in practice
Live permalinkClaims are checked against the source as it stands, not against the sweep's notes. A claim that cannot be re-reached is dropped, not softened.
Sources > briefWhen the research brief and the live source disagree, the source wins and the disagreement is published.
Universal negatives"Nobody says X" is not publishable. It becomes a count over a stated corpus, or it is cut.
Re-grep, don't re-readOn re-verification, every retired phrase is grepped across the whole card with an asserted count of zero — at the numeral level.
Signature bindingA PASS carries VERIFIED-CARD-SHA256. The build recomputes it. Any edit to the card voids its pass.

A claim that got dropped

A card cited a quotation from a B站 video. On verification it could not be located — not in the video description, not in 184 comments including all eight uploader replies, not in the reply API. The quote was deleted and treated as fabricated, along with the claim resting on it. No attempt was made to find a weaker source that would support the same sentence; the sentence went too.

When the brief disagreed with the source

A verification round was briefed that a thread stood at 187 comments and one commenter at 20. The live source read 183 and 19. The card printed 183 and 19. This is a small example on purpose — the rule is only worth anything if it also runs when the stakes are trivial.

The expensive one

A third independent verifier failed a card that two rounds had already improved, and found four claims that were false on the card's own publication date — a vendor had changed which plans included a model that same day. The announcement was inside two sources the card already cited: one author's very next post, and a note whose title was the announcement, quoted from its last paragraph while its first went unread.

A quote extracted from a page is not the same thing as a page that was read. That is the standing lesson, and the card publishes it about itself in its own coverage footer — including the detail that a grep of all four receipt files for the announcement's key phrases returned zero hits. It was never weighed and rejected. It was never seen.

Verifying the verifier

The strongest evidence that the loop is real rather than ceremonial is the second-order catch: the register of cut material was itself certifying a true sentence as fabricated. A quotation had been removed as invented; it was genuine, correctly attributable to a source the card already cited, and the original error was a misattribution rather than a fabrication. A false accusation of fabrication, living inside the artefact whose entire job is to prevent fabrication, is worse than the error it replaced. It was found by a verifier auditing the corrections rather than the card.

cards/<slug>/verify.md — the header that gates publication
# Adversarial verification — round 6
VERDICT: PASS
VERIFIED: 2026-08-10
VERIFIED-CARD-SHA256: 20c797ce…50f2887   ← recomputed at build; a one-byte edit voids it

## Rounds on this card
R1 FAIL — 8 defects
R2 FAIL — 2 (half-fixes; both survivors in verdict_note, the most-read field)
R3 FAIL — 2 (12 card-face citations with no ledger row)
R4 FAIL — 2 (the page itself misreported which rows were quoted)
R5 FAIL — 2 (a stale quantity, spelled "594.0 GB" — the guard searched "594 GB")
R6 PASS
R7 scoped re-sign after fixing R6's non-blocking item

Every FAIL was right.
The most-verified card on this site carries a verification record of 169 KB across 6 files — against a 104 KB card. The audit is larger than the artefact it certifies. 7 of 7 published cards carry a signature bound to their exact bytes.
Defect register

A bug is not fixed until it cannot silently return

Content verification catches wrong claims. It does not catch a generator that renders the right data wrongly, or a guard that has been passing for a month without testing anything. That is a separate register with a separate discipline.

70 defects are registered, numbered 1 to 70 with no gaps. Every entry names the bug, its root cause, and its guard. The rule for closing one: fix it, register it, add the guard, then prove the guard fails on the old broken state and passes on the fix. A guard that was never seen red is not evidence of anything.

70
defects registered, no gaps
54
with a mechanical guard
28
with a checklist guard
95
failure conditions in the validator

The validator is 67 KB against the generator's 40 KB — roughly 1.7× more code checking the output than producing it. That ratio is the honest summary of where the engineering went.

Three defects worth naming

  • A stale approval shipped a rewritten card. The publish gate checked that the string VERDICT: PASS appeared in the verification file. It did — from a round that had audited a completely different version. The gate was checking a proxy, not the thing. Fixed by binding the verdict to a SHA-256 of the card and recomputing it at build.
  • A red validator did not block a deploy. The deploy chain piped the validator into tail; in a pipeline the shell reports the last command's exit status, so a failing gate returned zero. Fixed by making one script the only deploy path, with the validator run unpiped under set -euo pipefail.
  • The same defective idiom existed in four places, and fixing the guard fixed only the guard. A non-global regex read the first link of each item and never the body prose. The copy inside the generator — the one the reader sees — told readers a card had 136 sources with 36 quoted, when 58 were. A validator that agrees with a page is worth nothing if both are wrong the same way.
The register exists because the failures rhyme. Nearly every entry is the same shape: a confident sentence about something nobody read through — including sources the cards themselves cited, and the project's own generated output. The guards target that shape rather than the individual mistakes, which is why three separate registrations of one non-global-regex bug count as a process failure and not three unlucky afternoons.
Sentiment

Counting voices

  • Counts, never percentages. A sentiment bar is a count of independent voices with a roster behind it. No card carries a percentage derived from a sample too small to support one.
  • A source is not a voice. A source can be cited for a fact and excluded from n: eval houses, vendor docs, trade press, and relays of someone else's data are all citable and none of them are people with an opinion.
  • Posture is classified toward the decision, not the tool. "This is impressive but I am not moving my production loop" is not positive sentiment about a switch. The question a card answers is whether to switch, so the axis has to be the switch.
  • Under-claim, never over-claim. sample counts distinct sources and may never exceed the ledger. This is enforced mechanically — the advertised n must reconcile against the sentiment segments and the ledger.
A worked example of the last rule, kept deliberately: one card's ledger grew from 111 to 136 rows during a re-sweep, and its advertised sample stayed at n=65. Extending a voice count piecemeal produces a number nobody can re-derive, so the smaller, auditable figure was kept and the discrepancy documented. An earlier version of the same card carried n=75 with no roster at all; building the roster took it to 65. No evidence was deleted — nine analysts and relays simply stopped counting as voices.
Confidence

Why most cards say LOW

Confidence is assigned to the verdict, not to the effort. It answers one question: if you follow this card and it turns out badly, how surprised should we be? Sample size, evidence independence, and whether the decisive measurement exists at all are what move it. Volume of research does not.

Of 7 published cards, 6 are LOW. The most heavily researched card on the site — 136 ledger rows, 6 verification artefacts on disk — is one of them, because the number that would settle its central question does not exist anywhere in any language, and no amount of sweeping conjures it.

A card is allowed to say, on its face, that its own strongest finding is weaker than it looks. One does: it separates a wide-open quality question from a near-settled economics question, and then warns that "near-settled" describes a moving object — because the defect a verifier found had landed on the near-settled half. Publishing LOW honestly is the product. A site whose verdicts are all HIGH is a site that is not checking.
Freshness

What triggers a re-sweep

Nothing is on a timer, and this page will not pretend otherwise. There is no scheduler in this repository. Re-sweeps are event-triggered and operator-initiated, and the cost is stated plainly below in limitations.

The triggers that have actually fired:

  • A dated claim goes false. A card published seven days before a model's weights shipped had four load-bearing claims expire on that date. It was re-swept on three axes — licence, self-hosting, access — and republished with the corrections on its face.
  • A tooling defect invalidates a sweep's coverage. Discovering the mandated channel layer had been skipped forced a full re-sweep of one card, which then found seven further defects in the same pass.
  • A verification fails. The loop is itself a re-sweep trigger — a defect list can send the builder back to the sources rather than to the prose.

Staleness is handled by dating everything and forbidding claims that decay silently. Relative time expressions — "recently", "this week", "five days old" — fail the validator, because they are true when written and false later with no edit. Quoted speech is exempt: a source's words are never altered to satisfy a checker.

Two quantities were caught decaying mid-verification during one re-sweep: a published floor moved between two dates as new artefacts shipped, and a provider that did not serve a model on the first date did on the second. Both are printed as dated reversals rather than quietly swapped values, and the card now states that every such count is "a dated floor, not a fact."
Limitations

What this system does not do

Stated because a reader auditing the method needs them, and because a system's real shape is in its gaps. Current as of the build date at the top of this page.

LimitationDetail
Small library7 published cards. Not a corpus. Every methodological claim on this page is demonstrated across single digits of artefacts.
Thin voice countsLedgers range from 11 to 136 rows, 427 in total. Two cards rest on fewer than twenty independent voices. The sentiment sections on those cards are indicative, not statistical, and say so.
Grandfathered auditsThe two oldest cards carry signatures re-issued for mechanical fixes, not transcript-backed re-verifications. They have never been through the adversarial loop as it now runs. This is the oldest correctness liability on the site.
No schedulerRe-sweeps are manual and event-triggered. A card can therefore be stale for as long as it takes someone to notice — which has happened, and is why one card carries a correction dated after its own publication.
Unguarded defectsOf 70 registered defects, 2 carry no automated or checklist guard and one more has a manual guard only. They are marked as such in the register rather than quietly closed.
Manual guards are people28 defects are guarded by a checklist line, not a machine. A checklist is a promise, and promises degrade. The mobile-rendering guard is one of these, and it had never actually been run: the first time every page was rendered at 375px, one card was overflowing the viewport by 316px in both themes — past a green validator, because static analysis cannot see a layout. Fixed, and registered. Nothing mechanical had objected.
One dead source, disclosedA cited page returns HTTP 567 behind a bot wall. It is flagged as the weakest item on its card rather than removed, and a third-party index that carries the same text verbatim is named beside it.
Channel coverage movesOne high-volume channel is currently blocked at search after previously working. Cards swept before and after that change do not have comparable coverage, and each says so in its own footer.
Sweeps are not a serviceThe pipeline is agent-orchestrated per card, run from a workstation. It is not a hosted, always-on ingestion system, and this page does not claim one.
Stack

What it is built with

LayerChoiceNote
GeneratorNode.js, ESM, zero runtime dependenciesbuild.mjs — data plus templates to static HTML. No framework, no package manifest, no install step.
Validatorvalidate.mjs — structural gate and a --live gate95 failure conditions. The live pass curls every page and every external evidence link after deploy.
Deploydeploy.sh, set -euo pipefailThe only deploy path. Build, validate unpiped, deploy, wait for propagation, live-validate. Credentials parsed from .env, never sourced.
HostingCloudflare PagesStatic output plus Pages Functions. Host canonicalisation in middleware, because cross-host redirect rules are silently ignored by the platform.
BackendPages Functions + Cloudflare D1Request intake, hashed-IP rate limiting, constant-time admin auth with a database-backed lockout. No raw IPs stored.
Anti-abuseCloudflare Turnstile + honeypotServer-side verification is environment-gated; the widget is asserted present on every form page by the validator.
EmailResendFire-and-forget inside waitUntil, fully caught. A dead key costs a notification, never a request.
Security headersCSP from real SHA-256 script hashesComputed at build over the generated output. No unsafe-inline in script-src, ever.
FontsSelf-hosted woff2Newsreader and JetBrains Mono, inlined @font-face plus preloads. No third-party font request on any page.
Research layeragent-reach (MCP) + direct fetch + Jina ReaderPer-platform clients for Reddit, GitHub, HN, X, YouTube, 小红书, B站, Exa. Logged-in browser automation is a last resort and is disclosed when used.
OrchestrationClaude agents — parallel sweepers, single synthesizer, separate verifierRoles are defined as contracts in the repository, not as prompts typed per run.
Structured dataArticle · BreadcrumbList · FAQPageNo Review or AggregateRating — our scores are ours, not aggregated user ratings, and marking them up as such would be a lie in machine-readable form.
The sweep engine is not open source today. The receipts are. Every card ships its full source ledger — 427 rows across 7 cards, including every source that was read and not quoted, with the reason — so the method can be audited from the output without access to the code.

Reader-facing summary: the Method section. Every card's own coverage footer carries the gaps specific to that sweep. All 7 cards →