Skip to content

fix(marketing): SEO/AEO/GEO audit fixes across the landing pages - #309

Merged
ecryptoguru merged 2 commits into
mainfrom
feat/seo-aeo-geo-audit
Aug 14, 2026
Merged

fix(marketing): SEO/AEO/GEO audit fixes across the landing pages#309
ecryptoguru merged 2 commits into
mainfrom
feat/seo-aeo-geo-audit

Conversation

@ecryptoguru

Copy link
Copy Markdown
Owner

DRAFT — three parallel audits (technical SEO, answer-engine optimization, generative-engine/LLM-citation optimization) against every non-blog marketing page, following up on the earlier UI/UX + content audit (#308).

Two real bugs caught while implementing, neither from the original audits

  1. "Five browser-local tools" is wrong — there are seven. Stated in three places (homepage FAQ, /tools meta description, llms.txt). All three corrected, and llms.txt's count is now ${tools.length}-derived so this can't silently drift again the way it apparently already had.
  2. My own first-pass GEO fix would have broken the production deploy. Fixing llms.txt's hardcoded "43/7" controls split, I imported VIBE_SECURITY_CONTROLS via the @lyrashield/security package alias — vibe-security-50.astro has an explicit comment explaining that exact import pulls in undici via the package's SSRF/fetch re-exports, breaks the Cloudflare Worker bundle, and previously broke the production deploy outright (workspace:* isn't understood by the plain-npm install step inside wrangler-action). Caught it against that comment before it ever shipped and switched to the same relative import the sibling page already uses safely.

GEO — llms.txt.ts, the highest-leverage single file for LLM citation

  • "Last updated" used new Date() at request time — read as "today" on every single request regardless of whether anything changed, the exact anti-pattern astro.config.mjs already documents avoiding for the sitemap. Now a hand-bumped content-date constant.
  • The 43/7 control split was hardcoded prose, duplicating a fact vibe-security-50.astro derives from a registry with its own build-time drift guard. Now imports the same registry, same safe path — the two pages structurally cannot disagree again.
  • Strengthened the "what is LyraShield" definition to name all four product surfaces (SaaS, CLI, GitHub Action, MCP server) as one product, added a standalone "release assurance" definition, an explicit pricing-today statement, and a citable open-source/license statement — verified against this repo's own README (which states MIT), not asserted from outside knowledge.
  • Added /support, /security-reporting, /privacy to the public URL list (all three were published in feat(marketing): hero collage, motion warm-up, and landing-page audit fixes #308 but never added here).
  • Enumerated the seven free tools by name.

AEO

  • ai-safety.astro had no FAQPage schema despite being exactly the "what is X / does Y do Z" profile every sibling trust page competes on. Added a 4-item FAQ restating existing "what this is not" content as Q&A, plus restructured the strongest boundary claim out of a checklist fragment into one self-contained, quotable sentence.
  • agents.astro's HowTo schema described 4 steps with no matching visible <ol> anywhere on the page. Added a real numbered list mirroring the schema 1:1.
  • evidence-vault.astro's genuinely sequential 4-step process had no HowTo schema at all despite being a clean fit (mirrors the working pattern already in sample-report.astro). Added it.
  • Un-buried two homepage FAQ answers so the direct answer leads instead of arriving after context-setting.

Technical SEO

  • Trimmed 3 titles that measured over ~65 chars after I verified the actual rendered length myself — several others the initial audit pass flagged turned out fine on direct measurement and were correctly left alone.
  • Fixed 2 meta descriptions that were far under 120–160 chars, trimmed 2 that were over (ai-safety.astro 182→143, index.astro 163→122).
  • Added dateModified to vibe-security-50.astro and evidence-vault.astro, which had none — both pages carry the site's most load-bearing numeric claims that other pages and llms.txt cite, so a total absence of freshness signal was disproportionately costly. Added matching visible "Last reviewed" text.
  • Removed a leftover internal-file reference (docs/claims-readiness.md, a path that only exists inside this repo) from methodology.astro, ai-safety.astro, and llms.txt.ts's public copy.

GEO citation quality

  • Fixed dangling-pronoun sentences that would mangle if an LLM quoted them in isolation (methodology.astro, vibe-security-50.astro).
  • Linked scan.astro's WebApplication entity back to index.astro's SoftwareApplication via isPartOf, so a knowledge-graph crawler sees one product with a free entry point, not two unrelated applications.

Verification

No node_modules, npm returns 403 — astro check/eslint/prettier/vitest could not run locally. Instead: re-derived and checked every assertion in seo.test.ts, agent-onboarding.test.ts, waitlist.test.ts, premium-preview.test.ts, and lite-scan.test.ts against the final state of every edited file by hand — 39 checks, all passing — rather than trusting the edits were safe. One assertion in seo.test.ts was deliberately updated: it pinned the old hardcoded "43 controls..." string, which the registry-driven fix correctly replaced; updated it to assert the registry wiring and the safe import path instead, so the test now actually fails if the file ever regresses to the broken package-alias import. CI is the gate.

Consciously not done: several P2/P3 subjective copy-rewrite suggestions from the audits (Speakable schema, some minor phrasing tweaks, compare-page pricing recency inline anchors) — skipped to control scope and risk on a branch that's already touching a lot of surface area.

Three parallel audits (technical SEO, answer-engine optimization, generative-
engine/LLM-citation optimization) against every non-blog marketing page.
Implemented the verified, high-confidence findings; skipped subjective P2/P3
phrasing suggestions to control risk.

Real bug caught while implementing a GEO suggestion (not from the audits
themselves): "five browser-local tools" is stated in three places (index.astro
FAQ, tools/index.astro meta description, llms.txt) but the tools array has
seven entries. All three now say seven, and llms.txt's tool count is now
${tools.length}-derived so this can't silently drift again.

Also caught while implementing: my own first pass at the llms.txt Vibe
Security 50 fix imported VIBE_SECURITY_CONTROLS via the "@lyrashield/security"
package alias. vibe-security-50.astro has an explicit comment explaining why
that specific import breaks the Cloudflare Worker bundle (pulls in undici via
the package's SSRF/fetch re-exports) and previously broke the production
deploy (workspace:* protocol isn't understood by the plain-npm install step
inside wrangler-action). Fixed to use the same relative import
vibe-security-50.astro uses before it ever shipped.

GEO (llms.txt.ts, the highest-leverage single file for LLM citation)
- "Last updated" used new Date() at request time, meaning it read as "today"
  on every request regardless of whether content changed — the opposite of
  the freshness principle astro.config.mjs already documents for the sitemap.
  Now a hand-bumped content-date constant.
- Vibe Security 50's "43 controls... 7 controls" was hardcoded prose,
  duplicating a fact vibe-security-50.astro derives from a registry with a
  build-time drift guard. Now imports the same registry (via the same safe
  relative path) so the two pages cannot disagree.
- Strengthened the top-line "what is LyraShield" definition to name all four
  product surfaces (SaaS, CLI, GitHub Action, MCP server) as one product,
  added a standalone "release assurance" definition, added an explicit
  pricing-today statement (free to join, no card, no announced plan yet), and
  added a citable open-source/license statement (verified against this
  repo's own README, which states MIT — not asserted from outside knowledge).
- Added /support, /security-reporting, /privacy to the public URL list (all
  three were recently un-drafted and published but never added here).
- Enumerated the five... er, seven free tools by name instead of only linking
  them, so an LLM can answer "what free tools does LyraShield offer" from
  this file alone.

AEO
- ai-safety.astro had no FAQPage schema despite being exactly the "what is
  X / does Y do Z" content profile every sibling trust page competes on;
  every sibling page (methodology, vibe-security-50, evidence-vault, scan,
  sample-report) has one. Added a 4-item FAQ restating existing "what this is
  not" content as Q&A, plus a standalone lead sentence restructuring the
  strongest boundary claim (guard scope vs. content moderation) out of a
  checklist fragment into one self-contained sentence.
- agents.astro's HowTo schema described four steps with no matching visible
  <ol> anywhere on the page — Google's HowTo/list-snippet feature wants the
  markup and schema to correspond. Added a real numbered list mirroring the
  four HowToStep entries 1:1, linking out to the #clients and #safety
  sections for steps 3 and 4.
- evidence-vault.astro's genuinely sequential 4-step "how evidence becomes
  assurance" process (Submit/Review/Version/Snapshot) had no HowTo schema at
  all despite being a clean fit; added it, matching the working pattern from
  sample-report.astro.
- Un-buried two homepage FAQ answers (the roadmap question, the
  "replacement for scanners" question) so the direct answer leads instead of
  arriving after two sentences of context-setting.
- Fixed one internally-jargon FAQ question phrasing on scan.astro ("inspect"
  -> "look for", matching how a person actually searches).

Technical SEO
- Trimmed three titles that exceeded ~65 chars after verifying the actual
  rendered length myself (about.astro, vibe-security-50.astro,
  docs/integrations/agent-rules.astro) — a few other pages the initial audit
  flagged turned out fine on direct measurement and were left alone.
- Expanded two meta descriptions that were far under the 120-160 target
  (support.astro, security-reporting.astro) and trimmed two that were over
  (ai-safety.astro from 182 to 143 chars, index.astro from 163 to 122).
- Added dateModified to vibe-security-50.astro and evidence-vault.astro's
  WebPage JSON-LD, which had none — both pages carry the site's most
  load-bearing numeric claims (the 50/43/7 split) that other pages and
  llms.txt cite, so their complete absence of a freshness signal was
  disproportionately costly. Added matching visible "Last reviewed" text.
- Removed a leftover internal-file reference (docs/claims-readiness.md,
  a path that only exists inside this repo, not on the public site) from
  methodology.astro, ai-safety.astro, and llms.txt.ts's public copy.

GEO citation-quality
- Fixed dangling-pronoun sentences that would mangle if an LLM quoted them
  in isolation: methodology.astro ("those facts" -> the actual noun phrase)
  and vibe-security-50.astro ("This is not... it is never shown" -> named
  subject in both clauses).
- Linked scan.astro's WebApplication entity back to index.astro's
  SoftwareApplication entity via isPartOf, so a crawler building a knowledge
  graph from JSON-LD sees one product with a free entry point rather than
  two unrelated applications.

Verification
No node_modules, npm returns 403 — astro check/eslint/prettier/vitest could
not run locally. Instead: re-derived and checked every assertion in
seo.test.ts, agent-onboarding.test.ts, waitlist.test.ts, premium-preview.test.ts,
and lite-scan.test.ts against the final state of every edited file by hand (39
checks, all passing) rather than trusting the edits were safe. One test
assertion in seo.test.ts was updated deliberately: it pinned the old hardcoded
"43 controls..." string, which the registry-driven fix correctly replaced —
updated it to assert the registry wiring and the safe import path instead of a
fixed string, so the test would actually fail if the file ever regressed to
the broken package-alias import. CI is the execution gate.

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@ecryptoguru, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 20 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2bdbc669-2a58-4cb1-b065-f13ef85a154e

📥 Commits

Reviewing files that changed from the base of the PR and between 5c36e96 and 7d9e25e.

📒 Files selected for processing (14)
  • apps/marketing/src/pages/about.astro
  • apps/marketing/src/pages/agents.astro
  • apps/marketing/src/pages/ai-safety.astro
  • apps/marketing/src/pages/docs/integrations/agent-rules.astro
  • apps/marketing/src/pages/evidence-vault.astro
  • apps/marketing/src/pages/index.astro
  • apps/marketing/src/pages/llms.txt.ts
  • apps/marketing/src/pages/methodology.astro
  • apps/marketing/src/pages/scan.astro
  • apps/marketing/src/pages/security-reporting.astro
  • apps/marketing/src/pages/support.astro
  • apps/marketing/src/pages/tools/index.astro
  • apps/marketing/src/pages/vibe-security-50.astro
  • apps/marketing/src/tests/seo.test.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

npm returns 403 in this sandbox so prettier could not be run locally to catch
this before CI. One expect(...).toContain(...) call in the new seo.test.ts
assertion was split across three lines but fit under printWidth 100 collapsed
to one — Prettier collapses single short-string arguments like this rather
than leaving them wrapped. Swept the rest of the file's multi-line toContain
calls by hand; the other four all exceed 100 chars collapsed and correctly
stay split.

Co-Authored-By: Claude <noreply@anthropic.com>
@ecryptoguru
ecryptoguru marked this pull request as ready for review August 14, 2026 20:55
@ecryptoguru
ecryptoguru merged commit c262e44 into main Aug 14, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant