AIRANKS — The Authoritative Rankings for AI Web Content

AIRANKS measures AI visibility: we ask AI models real product and service questions, capture the complete answers as immutable observations, and publish what they contain — which brands were mentioned, which domains were cited, and which exact pages were linked. Every domain gets an AIR score from 1–10 (a decile of visibility in the active dataset; 0 means insufficient data), with the methodology in the open.

Skip to main content

AIRVER. FIGHTING — 2026

Artificial Intelligence Rankings

the ledger notes

The feature that never once worked

Build LogAugust 16, 2026 by Jeremy Schoemaker

Cycle 4 of the overnight improvement loop pointed the council at the two surfaces nobody had touched in three cycles: the report pipeline and live search. Six models, two rounds, and one chair with database access. The night produced a fix for a bug that had existed since the feature shipped — a feature whose primary use case had never executed successfully, ever — and nobody knew, because nobody had walked that exact path.

Round one: six confident diagnoses of a bug that wasn't there

The brief included a stat the chair had pulled from prod: 33 of 156 openai-family crawler hits in the last 7 days carried verified=NULL — the IP-verification verdict column, empty. Five of six seats built their overnight ranking around it. One labelled it VERIFIED that "report email has never fired because the flag defaults false and no mail provider is configured." Confident, plausible, coherent.

Between rounds, the chair ran the daily series keyed on date and family. The NULLs decomposed instantly: 292 anthropic rows on 08-10, 34 stragglers on 08-11 — the day the verified column's migration landed — and a handful of google rows where NULL is by design, because Google publishes no crawler IP ranges to check against. Every single openai and anthropic hit since 08-12 carries a real verdict. The claude.com range file fetches from prod in 66ms.

And the mail story: prod's .env has the flag ON and MAIL_MAILER=ses. The VERIFIED label was a guess wearing a costume.

Round two returned 22 retractions across all six seats. That is not the council failing — that is the council working. The doctrine says retracting on evidence is the highest-status act available, and this round was the richest demonstration yet.

The E2E the council demanded found the body in four minutes

The one thing every seat agreed on: nothing had exercised report submit or live search since the API auth gate cutover four hours earlier, and no code should change until a capped, chair-executed walk-through proved the surfaces alive. Priced at 6–7 cents (round one had been carrying a $0.36 estimate built from repo defaults; prod's backlog target is 5, not 25).

Live search: submitted "best electric cars," watched 5 runs stream in over 56 seconds, brand tally rendering. Alive.

Report one: existing phrase, completed in 30 seconds, score 60. Alive.

Report two: a new phrase — "best ai search ranking tool" — with the email opt-in ticked and an address attached. All three collection runs came back no_recognized_brand (a niche tool phrase names things the brand taxonomy doesn't know — expected), and then:

production.ERROR: Call to a member function getKey() on array

Status: failed. And here is the part that makes it a story. The report builder samples both observations and brand-less captures, and the docblock explains why: phrases about people and services rarely yield a recognized product brand, and without captures those phrases "would otherwise have no report at all." The captures-only case is the union's entire reason to exist.

That case had never worked. Not once. Laravel's Eloquent\Collection::map() demotes to a base collection only when the mapped result is non-empty — so a phrase with zero observations left an empty Eloquent collection, whose merge() tries to build a model dictionary by calling getKey() on the other side's plain arrays. Every prior report happened to use phrases with observations, so the trap never sprang. The six reports in the table were all the lucky path. The seventh was the designed-for path, and it was the one that died.

Red-before/green-after: the regression test reproduces the exact prod error on the old code, passes on the fix (->toBase() before the map). Deployed, report #7 re-dispatched, completed with a score of 65 — and email_sent_at: 04:29:02, the first report email the system has ever sent. SES accepted it synchronously inside the mail job; zero failures.

The tracer also caught a quieter one on the way: report #6 had the email checkbox ticked and still shipped email-less, because ticking the box reveals an address field and an empty string sails through nullable. The form now prefills the signed-in account's address.

The proof page that disclaimed its own evidence

The public /llm-crawled page — "LLM crawlers are actually here" — got IP verification in the 08-11 migration. The page never noticed. The controller didn't select the verified column; the copy still read "bot identity is self-reported… not reverse-DNS or IP verified"; and the database's one verified=0 row — a forged OAI-SearchBot claim from an IP OpenAI disowns — rendered as a genuine visit on a page whose entire purpose is proof. Bonus: the IP and User-agent columns had been rendering blank since launch, because those fields weren't in the select either. A detector shipped unarmed, in the most literal way we've logged yet.

Now: middleware-observed rows only, forged rows excluded, injectable rows (there's an open POST endpoint that accepts client-supplied bot names, 20/min) excluded, the verdict shown per row, and the disclaimer replaced with the truth. Site totals dropped from 3,146 to 3,142 — four rows of non-proof gone.

One more number worth sitting with: verified OAI-SearchBot crawls — the metric this product treats as its leading indicator — currently read zero, ever. GPTBot did an 88-page site crawl on 08-14 and ChatGPT-User fetched pages for real users the same two days, then openai went silent 26 hours before the auth gate went up. The indicator isn't broken. It just hasn't fired yet. Those are different facts, and the page now knows the difference.

Ledger

  • 1,016 tests green (was 1,011; the "1006/1007 mystery failure" from the handoff turned out to be a MinIO skip-guard, not a failure — measured, not assumed).
  • ~7¢ of spend bought: two surfaces verified post-cutover, one never-worked code path found and fixed, one first-ever email, one silent opt-in no-op fixed.
  • 22 retractions, six seats, zero relitigated settled questions.
  • The phantom from cycle 3 got its epilogue too: parsing the failed 908-row upsert out of the log showed the sole constraint violator was '' — the phantom hadn't just been polluting scores, it had been crashing the hourly job outright before the guard landed. Same bug, three costumes, all dead.

The lesson the loop keeps teaching: the diagnosis you ship in a handoff is one session's inference, and the cheapest thing in the world is to re-run the count before betting a night on it. Five seats bet on the NULLs. The series took ninety seconds and refuted them all.

← Back to blog