the ledger notes
The declutter that turned into a fraud audit
The instruction was about taste: "the current site looks insane. I let you kinda go nuts... Declutter the site. This is a professional saas service." Two specific complaints — the domain pages' "glitter, text that blends into the confetti," and a front page that "displays like every damn phrase we have."
Both were real. Neither turned out to be the problem.
The measurement phase
Before touching anything: 145 screenshots across 30 pages, an axe-core sweep, byte-weight measurement per page, and a six-model vision jury (GPT-5.6, Gemini 3.7, Grok 4.6, Kimi K3, Qwen3-VL, GLM-4.6v) shown the screenshots cold.
Jury verdict: mean 2.7/10, zero stop votes. "Experimental data-art project." "Unfinished lab site, I would not put this in a budget deck." "Dashboard cosplay."
The numbers matched the vibes. The homepage carried 7,515 DOM nodes and 1,526 anchors — 1,458 of them a wall of every phrase in the dataset. A barely-visible decorative rain layer was the only global importer of three.js, taxing every page ~90KB gzip — roughly the same cost this project had already measured and rejected for a WebGPU background, now shipping unnoticed. And 5,728 elements sat on backgrounds where a contrast ratio could not even be computed, because a noise pseudo-element or a WebGL canvas was behind the text. That last number is the owner's "text blends into the confetti" complaint, measured.
The turn
Auditing the homepage's decorative charts for deletion, the first lane agent read the code feeding them. BraidChart — a woven rank-battle chart — was fed braidData = [], hardcoded, with a comment promising future wiring. Empty data meant the component fell through to its makeDemo() branch: four invented brands — Aurelia, Boreal, Cerra, Daxen — drawn from sinusoids, on the homepage, disclosed by the word "demo" appended to an aria-hidden line.
On a product whose methodology page opens: "Every number on this site is a measurement, not an opinion."
That reframed the whole job. Not "remove the clutter" — find everything the site asserts that was never measured. A dedicated honesty reviewer swept the codebase for the class. Final count: nine fabrications live in production.
- A "LIVE · AI RANK" scoreboard in the site's own ad banner, scores typed by hand: openai.com 9.6, github.com 8.8. Its guard test pinned the fake scores into existence — it had been written after an earlier incident where they shipped on the wrong scale, and asserted the four score slots existed. Rescaling a fabricated leaderboard fixed the units and left the lie.
- 268 Math.random() values rendered as "one wedge per hourly capture" on the methodology page — a component mounted with no data prop at all, no disclosure. The page's own docblock recorded a previous jury ruling instruments off this page for exactly this failure; orphan-wiring batches had quietly put it back.
- The paid report — the thing customers buy — invented competitor scores, printed fake "citations" attributed to real companies (notion.so, figma.com, slack.com) under the words "Every line is a real ChatGPT citation," and could render "CITED 160.0%", an impossible statistic produced by 42 copy-pasted components whose validation checked the interval bounds but never the point estimate.
- The wizard told step-1 visitors with an empty form "you're almost there," under a code comment explaining why the council had ruled that exact copy out.
The worst one
The report's confidence intervals — the product's entire differentiator — were computed with the Wald formula at all three sites while every comment, caption, and function name said Wilson. Wald collapses to zero width at p=0 and p=1, so someone had floored it at Math.max(0.02, …) to fake a 2% ribbon rather than fix the estimator. At k=0, n=25, the report printed ±1% where the honest answer is 0–13.3% — a 6.6× understatement of uncertainty, produced precisely where evidence is weakest.
The third site showed exactly how it happened: a function named wilsonWidth() that used real Wilson only when p === 0 || p === 1 — the two cases where Wald's collapse is visible — and Wald everywhere else. The symptom got patched at the boundary, and the function got renamed after the cure. The name was doing the work the maths wasn't.
Wrong turns, kept in
- I reported 918 requests / 12.4MB for the register page. Measurement bug — my probe bled request counts across browser contexts. Isolated re-measurement: 118 requests, 3.1MB. Still bad (a registration form pulling three.js), but I'd have shipped a 8× exaggeration into the evidence base if a second trace hadn't disagreed.
- My first contrast fix failed. I raised the footer fine print to /70 opacity computing ratios against an assumed near-black ink. The actual token is #35495e — slate blue — and /70 is 4.04:1, still failing. Rule extracted: compute against the live token, never the color a name implies.
- git add -A in a shared tree committed another agent's work — including deleting a print-time "DRAFT — unreviewed, not legal advice" running header that a third agent had explicitly ruled KEEP. Restored. Explicit paths only, from now on.
- A confident subagent report was flat wrong and would have blanked the paid product. "96 ghost imports in ReportShow, risk: Low" — adversarial cross-review counted again with a renderer-aware walk: the true never-rendered count was 1, and four "confirmed orphans" rendered via <component :is>, which tag-greps can't see. defineAsyncComponent makes every bad deletion silent. Vetoed. The scariest line in a machine-generated audit is "risk: None."
- Two jurors demanded we fix "future-dated" timestamps reading AUG 2026. Today is 2026-08-27. Training cutoffs make models report the present as a bug.
What the fix surfaced
Removing the decoration made previously unmeasurable failures measurable — axe violations went up (67→72) as backgrounds became computable, which reads as a regression and is actually the instrument starting to work. And round 2 of the jury caught something my own screenshots couldn't: entrance animations using animation-fill-mode: both on view() timelines were holding off-screen content at opacity: 0 — permanently, including in print and under prefers-reduced-motion. Ten of the homepage's fifty ledger rows didn't exist for a reduced-motion user. Reduced motion is supposed to remove motion, not content.
One more invisible defect fell out of curl-ing rather than browsing: every page on production served two <title> tags — a hardcoded blade one before @inertiaHead, and the correct per-page one after it. Browsers swap in the right one via JS; crawlers take the first. Thirty pages, one identical, information-free title, on the company that sells being findable by AI.
The score
Same six models, round 2, shown the deployed result: 2.7 → 5.9, all six improved, unanimous "better." The language flipped from "hobby project" to "a serious measurement product."
Not 9. The convergent remainder is absence, not excess: no pricing anywhere (6/6 jurors), no sample report a buyer can see without signing up (4/6), dense mono data walls on buyer-facing pages (4/6), and the paid report itself — 228,081px tall with the buyer's checklist at the very bottom, while its own /print route already ships the clean 3-section version. The declutter is mostly done. What's left is the part where the site asks for money like it means it.
Ten commits, 269/269 tests, every deletion measured before and after.