fix(frontend): stop AdSense loading outside eligible marketing pages - #198
Merged
Merged
Conversation
… pages AdSense rejected ClawAI for "low value content": AdSenseHead was mounted in the root layout with no pathname check, so the ad loader executed on auth, portal, chat, billing and settings routes. A correct pathname-aware hook existed but was never wired into anything mounted in the tree. - Move AdSenseHead to (marketing)/layout.tsx only; split the loader script into AdSenseScriptLoader, which re-checks isAdUnitEligible(pathname) even in review mode (reviewMode no longer bypasses eligibility). - Add CHAT_SHARE_REVIEW_LOCKDOWN_ENABLED: a temporary, single-flag override that forces every public chat share to no-ads/noindex/excluded-from- sitemap-and-RSS for the AdSense review window, regardless of the per-share safety-scan verdict. Wired into both RSS implementations (rss.service.ts and the separate global-rss.service.ts), the sitemap chat chunks, and buildSharedChatMetadata. - Regression test (adsense-route-boundary.test.ts) asserts the route boundary structurally so this class of bug can't reappear silently. - Fill a robots.txt gap: 4 auth sub-routes were missing from PRIVATE_ROUTE_PREFIXES. Knowledge delta: rules/38 (AdSense eligibility architecture), rule 39 + finish-worktree-branch-with-pr skill (every agent-created worktree/branch ends with a PR and release notes), docs/03-architecture/adsense-eligibility.md, public-chat-shares.md addendum, frontend CLAUDE.md dated note. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
AdSense rejected ClawAI for "low value content." Root cause: the AdSense
loader script was mounted in the root Next.js layout with no pathname check,
so it executed on every route — login, dashboard, chat, billing, settings —
not just on reviewed editorial pages. A correctly pathname-aware hook already
existed in the codebase but was never wired into anything actually mounted.
This PR implements the P0 fixes from the AdSense low-value-content
remediation brief: stop the script from loading anywhere ineligible, and
temporarily pull public shared chats out of ads/indexing/sitemap/RSS while
the account is under review.
AdSenseHeadout of the root layout into(marketing)/layout.tsxonly — structurally impossible to load on
(auth),(portal),(payment).AdSenseScriptLoader, which re-checksisAdUnitEligible(pathname)even in review mode (reviewModeno longerbypasses eligibility — that bypass was the actual bug).
CHAT_SHARE_REVIEW_LOCKDOWN_ENABLED: one flag that forces every publicchat share to no-ads / noindex / excluded-from-sitemap / excluded-from-RSS,
regardless of its own safety-scan verdict, for the review window. Wired
into both RSS implementations (there are two —
rss.service.tsand aseparate
global-rss.service.tsfor the all-languages feed, easy to missand caught by the full test run), the sitemap's chat chunks, and shared-chat
metadata.
adsense-route-boundary.test.ts) thatreads each layout's source and fails if AdSense is referenced outside
(marketing)— guards the exact class of bug that caused the rejection.hand-maintained private-route prefix list.
Release notes
For the AdSense review: the ad script no longer loads anywhere except
genuinely eligible public marketing pages, and public shared AI chats are
temporarily excluded from ads, search indexing, the sitemap, and RSS feeds
until the account is approved and shared chats get a dedicated content
review. No user-facing behavior changes outside of ad/indexing exposure —
sharing conversations still works exactly as before.
Remaining work (P1, not in this PR)
Per the remediation brief's own "do not fix low-value-content by generating
filler" guidance, this PR intentionally does not touch
/learncontent,run the full multilingual content audit, or rewrite locale copy — that is
real editorial judgment per article/locale, not something to do in bulk in
one pass. Also not done here: the full AdSense-eligible-page audit table,
Auto Ads audit, and ad-density review (sections 4, 13, 14 of the brief).
Recommend scoping those as a separate, content-focused follow-up.
Test plan
npx tsgo --noEmit(claw-frontend) — 0 errorsnpm run lint(claw-frontend) — 0 errors (4 pre-existing warnings, unrelated)npm test(claw-frontend) — full suite green; 3 pre-existing flakytimeouts under full-suite load (roles/smart-router/contact-form
forms), confirmed unrelated by passing in isolation
npm run build(claw-frontend) — succeedsnpm run knowledge:verify/npm run audit:check— OK/login,/chat,/dashboard,/settings, or a/share/chat/*page🤖 Generated with Claude Code