We just audited every button on the site. Here’s what we found.
Five parallel agents, eighty pages, every clickable element traced to its destination. Three production 404s, one dead-code conditional, a Stripe portal landing on the wrong tab. Here is the receipt.
Published 2026-05-06 (Build 2117). The full fix log spans builds B2101–B2117 in the public git history. This post translates the receipts for a non-engineering audience.
The audit
On May 6, 2026, we ran a navigation audit of every clickable element on songforgeai.com. Five parallel agents covered different surface areas — navbar + homepage chrome, the forge / refine / crucible product flows, account + transactional surfaces (login, dashboard, pricing, billing), content + admin + error pages, and a runtime-handler hunt for buttons whose destination depends on user state. Roughly 80 pages, hundreds of clickable elements, every href verified to resolve to a real route.
It was the most thorough nav audit we’ve ever done. We found things we didn’t expect.
What we found
Three production 404s:
- The Elite week chips on
/examples— the “songs scored 90+ this week” row that surfaces social proof — were rendering links to/s/<songId>. Our share-page route resolves songs byshare_slug, notid. Every chip in that callout was 404’ing. Silently. The headline number was honest; the chips beneath it didn’t go anywhere. - The admin telemetry dashboard at
/admin/system-healthdeep-linked to misbehaving songs via/dashboard/songs?songId=<id>. The/dashboard/songsroute is a redirect that strips its query string, AND the dashboard reads?song=not?songId=. Triple-bug silently breaking the operator-only telemetry-to-song-detail handoff. - A dead-code CTA at
/c/<id>(Crucible verdict permalinks): the “Forge a replacement” vs “Forge your next one” button branched on whether the verdict was COLLAPSED or SURVIVED — but both branches routed to/forge. Pure cosmetic logic. The intent was to send collapsed verdicts to refine mode and survived verdicts to a fresh forge; that branch had been silently broken at some point in the last hundred builds.
Several smaller paper-cuts:
- The Stripe customer portal’s return URL was
/dashboard, which lands the user on the songs tab instead of where they came from (the Billing tab). Free re-click required. - The pricing page sends unauthed visitors to
/login?signup=true&redirect=/pricing— but the login page didn’t read theredirectparam. Users would sign in, land on the dashboard, then have to navigate back to pricing to complete checkout. - The signup verb on the Free tier card was “Start Free.” The signup verb in the navbar is “Sign Up — Free.” The signup verb on the bottom-of-page CTA was “See full plans.” Three different verbs for the same action across three surfaces. Cohesion is a small thing, but the absence of cohesion is a tell.
- The trash page’s “Restore” action removed the song from the list with no acknowledgment, no path back to the dashboard.
- The 404 page was Next.js’s default white “This page could not be found” with no brand chrome and no CTA back to the product. Every typo’d URL was leaking the visitor.
Most of these were live for weeks or months before this audit. None of them showed up in any user complaint we received.
What we shipped
Builds 2101 through 2117, in one session, on the public git history:
- B2101 — the three production 404s fixed at the source.
- B2102 — Stripe portal returns to
/dashboard?tab=billing; login honors?redirect=; a checkout-success banner now welcomes returning Stripe customers by name. - B2103 — branded 404 page; restore confirmation banner with a clear link to the dashboard; mobile signup CTA copy now matches desktop.
- B2104–B2117 — the wider audit response: design-tokens ratchet retargeted at the new monolith candidate, test-count floor raised, a duplicate blog slug fixed, the homepage hero converged on a single primary CTA, the bottom-of-page final CTA stopped asking for more reading and started asking for the action, an above-the-fold trust strip surfaces the rubric and audit infrastructure on the front door, the StatusBadge now polls every 60 seconds instead of once on mount, the Person schema gained an external
sameAsfor E-E-A-T, the Suno-keyword cluster consolidated to a single canonical pillar, hreflang reciprocity wired on the four English root pages, plus a newnpm run audit:retry-vortexdetector for the cosmetic-iteration anti-pattern that burned 14 builds on a single H1 readability problem earlier this month.
Every commit cites the audit section it closed and the moat it advanced. The git log is the audit response. You can read it.
Why we’re publishing this
Three reasons.
One: a published trust posture is binding. We say at /the-receipts that we publish our findings before external researchers do. The deep audit was internal in origin but its findings land like external ones — broken stuff, dead code, drift. The contract is the same: surface it, fix it, ship the receipt. Quietly patching is the wrong posture for a tool that claims to publish a standard.
Two: the empty-state-as-honesty pattern has limits. Nobody buys a $69/month tool because it has zero testimonials and zero external implementations. They buy it because the things they can verify are tight. A live nav audit with 14 fixes is what a tight surface looks like. Zero broken buttons isn’t a goal we hit by accident.
Three: if you’re evaluating SongForgeAI right now, you should know what we found and what we shipped. The audit’s full output (5 agent reports, 12-section synthesis, prioritized 24-item action plan) lives in our own git history; the meta is public, the fixes are public, the trajectory is public. That’s the deal.
What we couldn’t fix without you
The audit also found things that aren’t fixable from inside the codebase:
- The conversion architecture wants a free anonymous forge of one song per IP, mirroring the no-login Crucible. That’s a multi-day engineering lift with abuse plumbing, not a click.
- The trust posture wants three real founder-interview testimonials with audio. Those are operator-curated, not engineering-curated.
- The category-ownership posture wants one external academic citation of the Lyric Scoring Standard. Outreach work, not code.
- The standards moat wants the calibration corpus to grow from 22 hand-scored entries to 250+. That’s scoring time, not script time.
Those four sit on the desk. They’re the next move.
The trust math
Engineering audits compound the same way bias disclosures do. A tool that ships pristine published findings is statistically improbable; the question is whether the maintainers will surface their own drift or wait to be caught. We’d rather catch ourselves and ship the receipts than wait for a churn signal.
The next entry on this beat lands when the next audit does. Watch /blog.