21 Blog Posts. Zero Author Attribution in AI Search. Here's What We Found.
I ran a schema audit on whtnxt.io with Claude Code and found zero author attribution on all 21 posts. Here's what was broken, what we fixed, and the 5-step audit you can run on your own site.
Schema markup has always been framed as an SEO tactic. Add some tags, get a breadcrumb trail in search results, maybe a star rating. That framing made sense when the only system reading your structured data was Google's crawler at indexing time.
There is a second system reading it now, and it is deciding something more important than your search snippet.
Perplexity, ChatGPT Search, and Google AI Overviews read schema at retrieval time, per query, to resolve who wrote the content and whether that person is credible enough to cite by name. When one of these systems pulls up a blog post and asks "who wrote this," it does not read the byline. It follows a chain in the structured data: BlogPosting.author → @id → Person → sameAs → LinkedIn, X, GitHub. If that chain is intact, the AI attributes the post to you. If it is broken, the content was written by yoursite.com.
Most agency and consultant sites have a broken chain. Most do not know it.
Download the full audit workflow. 9 steps. Runs on any site. Takes about an hour. No signup, no form. Free.
The rest of this post is what the audit found when I ran it on whtnxt.io, and why some of the gaps surprised me.
What Was Actually Broken
I had 21 published posts on whtnxt.io. Every one had a byline (Edward Chalupa, Founder, Whtnxt), a visible author photo, a publish date, a category tag. All the things that signal authorship to a human reader.
Last week I ran a schema audit with Claude Code. What came back: zero author attribution on any of them. Not machine-readable, not in the HTML source, not visible to AI retrieval systems. Every post was attributed to whtnxt.io. Not to me.
The byline on the page does not count. The author @id does.
Claude Code ran a full audit against the live site and source files. Here is what it found, and here is also where I had been quietly wrong for a year.
Gap 1: Two conflicting organization entities.
The homepage had both a LocalBusiness (@id: https://whtnxt.io/#business) and a separate Organization (@id: https://whtnxt.io/#organization). Two nodes in the knowledge graph for the same company, with no agreement on which was canonical. Any blog post trying to declare a publisher had nothing consistent to point to, so both references existed in a state of conflict that AI systems cannot resolve.
Gap 2: Wrong entity type.
LocalBusiness is for dentists, plumbers, and restaurants. It is the type for directory-listed businesses with a physical address and walk-in hours. An agency without either is not a LocalBusiness, and the distinction matters for a specific reason: publisher on a BlogPosting must reference an Organization with a logo declared as an ImageObject for Article rich result eligibility. A LocalBusiness publisher quietly fails that check.
The logo itself was also wrong. It was set as a plain URL string: "logo": "https://...". The schema.org validator passes this without error, but the Article rich result silently fails anyway. It has to be {"@type": "ImageObject", "url": "..."}, and most guides do not mention this distinction.
Gap 3: Person @id anchored to the wrong domain.
The about page defined a Person entity with @id: https://echalupa.com/about#edward. That IRI is anchored to a different domain than the page where it was defined (whtnxt.io). Blog posts on whtnxt.io cannot form a valid attribution chain to a cross-domain IRI unless echalupa.com also defines and serves that entity. It does not. Every attribution chain on every post was broken at the root.
Gap 4: 21 blog posts with zero schema.
No BlogPosting entity. No author @id. No BreadcrumbList. Every post was invisible to AI retrieval systems, and the visible byline had no machine-readable equivalent anywhere in the HTML.
What the Fix Looked Like
Five files, one session with Claude Code.
BaseLayout.astro: Added a named head slot so schema renders in <head>, not <body>. Google accepts both locations, but head placement is preferred because it ensures schema is present before JavaScript runs.
index.astro (homepage): Removed LocalBusiness entirely. Consolidated to two entities: WebSite (@id: https://whtnxt.io/#website) and Organization (@id: https://whtnxt.io/#publisher). Fixed logo to ImageObject. Moved personal social profiles out of Organization.sameAs into Person.sameAs, where they belong.
about.astro: Changed Person @id to https://whtnxt.io/about#person, anchored to this domain. Added mainEntityOfPage, a ProfilePage entity, alumniOf. Fixed worksFor to reference #publisher by @id rather than an inline object.
blog/[slug].astro: Added BlogPosting schema to all 21 posts via the template. Every post now has "author": { "@id": "https://whtnxt.io/about#person" } and "publisher": { "@id": "https://whtnxt.io/#publisher" }, so the attribution chain closes automatically on every post published going forward.
blog/index.astro: Added CollectionPage, BreadcrumbList, and ItemList enumerating all 21 posts for carousel rich result eligibility.
Validation confirmed: all JSON-LD valid, entity graph coherent across all four page types, every @id reference pointing to the same three canonical IRIs.
Before: zero schema on all blog posts, two conflicting organization entities, no attribution chain. After: 11 schema blocks across 4 page types, single coherent entity graph, every post attributable to a named person with verified external profiles.
The Audit (Abbreviated)
The full workflow is 9 steps covering classification, gap report format, implementation by framework, and per-page schema requirements. Here is the short version.
Classify first. Determine whether your primary entity is a Person, Organization, or both. For an agency founder publishing under your own name, you need both. Do not use LocalBusiness unless you have a walk-in location listed in directories.
Audit your HTML. Search each key page's source for application/ld+json. Build a quick table of what is present vs. missing. If any page shows nothing, that page has no AI attribution layer.
Check the entity graph. Three things must be true: every reference to your Organization uses the same @id IRI; your Person @id is anchored to the domain where it is defined; and your blog posts declare author as an @id reference, not a name string.
Check the silent failure modes. These all pass the validator: Organization.logo as a plain URL string, author as an inline name object, publisher pointing to a Person instead of an Organization, and schema injected via JavaScript after page load.
Validate. Google Rich Results Test on a blog post URL, Schema.org Validator on your about page, and a manual chain trace following author @id all the way through to the Person entity's sameAs profiles. The validators will not catch a broken link if the @id points to a URL that simply does not define the entity.
Schema markup in 2026 serves two masters: the crawler that determines rich result eligibility and the AI system that decides whether your published thinking gets attributed to you or evaporates into an anonymous domain. Most sites optimize for the first and ignore the second, often without realizing the second audience even exists.
I had been publishing into a quiet void for a year, and the fix was one session. If you run this audit and find the same gaps, the fix is smaller than it sounds.