Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions docs/evidence/agent-desk-title-canonical-2026-08-12.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Retired Agent Desk title/snippet: stop claiming the apex root as the canonical

Date: 2026-08-12
Scope: `public/agent-desk.html` (head canonical/og:url), `scripts/check-site.mjs`
(regression guard). This receipt records a deterministic, repository-side
change to what the legacy surface declares about itself. It is not a live
Google-index measurement, and it claims nothing about when or whether Google's
search results change after this change.

## Why this pass exists

Google has presented the retired self-serve "TinyStudio Agent Desk"
title/snippet for tinystudio.io. Two earlier repository-side passes already
addressed the legacy surface's own head
(`docs/evidence/agent-desk-retired-title-2026-08-09.md` added `noindex,
nofollow` and retired framing; PR #100 pointed the retired `app.`/`api.` 410
hosts at The Website Appraisal), but one index-facing wire remained: the
legacy page still declared the homepage as its canonical.

- `public/agent-desk.html`, served at `/agent-desk` and `/agent-desk.html`
(worker `PUBLIC_ASSET_PATHS`), still carried
`<link rel="canonical" href="https://tinystudio.io/" />` and
`<meta property="og:url" content="https://tinystudio.io/" />`.
- The 2026-08-09 receipt itself diagnosed the original mechanism: the legacy
page's title "consolidated through its canonical" onto the homepage URL
(`evidence-fixtures/ai-search/evidence.json`, q5 / google, 2026-08-06:
"tinystudio.io - TinyStudio Agent Desk" attached to the homepage URL).
The de-indexing pass cut the title and description wires but left the
canonical wire in place.
- Live-before state (2026-08-12): `curl -s https://tinystudio.io/agent-desk`
returned 200 with `noindex, nofollow`, the retired title/description — and
still declared `https://tinystudio.io/` as its canonical and og:url. A
noindex page whose canonical names a live page tells Google it is a
duplicate of that page: the same consolidation that handed the retired
title to tinystudio.io, re-declared on every recrawl until the removal is
processed. Google's own guidance is that a page you do not want indexed
should not canonicalize to another URL.

Every other owned page follows one convention — the canonical and og:url name
the page's own served `.html` twin (`/agents.html`, `/pricing.html`,
`/specimen.html`, and the audit page's clean `/audit`) — and the legacy page
was the only one claiming the apex root.

## What changed

1. `public/agent-desk.html` head: the canonical and og:url now name the
legacy page itself (`https://tinystudio.io/agent-desk.html`, the same
self-address form the desk, pricing and specimen pages use) instead of the
homepage. The consolidation wire is cut: no page declares the retired
surface as a duplicate of `tinystudio.io/` any more, so a recrawl can no
longer merge the retired page's signals or title onto the homepage URL.
2. `scripts/check-site.mjs`: the retired-desk dogfood guard now fails `npm
run check` when the legacy page's canonical is missing, duplicated, or
points anywhere but `https://tinystudio.io/agent-desk.html`, and when its
og:url points anywhere else — so the apex-root claim cannot silently
return. (Regression verified by reverting the HTML change: both
assertions fire on the old apex-root values.)

## What deliberately did not change

- The visible legacy UI copy and the tool itself: `agent-desk.html` remains a
working self-serve surface, still served at `/agent-desk` and
`/agent-desk.html`, still `noindex, nofollow`, still retired-framed. Old
deep links and bookmarks keep working.
- `robots.txt` (no Disallow was added: a disallowed page cannot be crawled to
see the noindex meta, so that would slow de-indexing, not speed it up),
`sitemap.xml`, the worker's routing, and the 410 hosts (already corrected
by PR #100, verified live 2026-08-12).
- The homepage and the other public pages: their own titles, descriptions and
canonicals were already current; this pass only fixes the legacy surface.
- No redirect was added for `/agent-desk`: the page stays reachable, it is
just no longer indexable or canonicalizable onto the homepage.

## What is tested and what is not

Tested: the extended guard fails loudly on regression (the canonical and the
og:url are asserted directly), and the full suite passes on this commit —
`npm run check` green, `npm test` green (92 subtests: 6 headings, 7 sitemap,
55 worker, 16 UI, 8 product contract), exit code 0.

Not tested: whether or when Google drops the old title/snippet from its
results. De-indexing and re-consolidation are live processes that start only
after Google recrawls the pages; nothing here implies a ranking, visibility,
lead or revenue outcome. The honest measure is a future controlled re-run
recorded through `evidence-fixtures/ai-search` (or Search Console), once
enough time has passed for a recrawl.

## Verification (reproduce)

```
npm run check
npm test
git diff --check
```

All three checks pass on this commit. Live-before state (2026-08-12):

```
curl -s https://tinystudio.io/agent-desk # noindex + retired head, canonical/og:url still -> homepage
curl -s https://app.tinystudio.io/ # 410, already names The Website Appraisal (PR #100)
curl -s https://api.tinystudio.io/ # 410, already names The Website Appraisal (PR #100)
```

After deploy, the same fetch of `/agent-desk` should show the self-canonical
`https://tinystudio.io/agent-desk.html`.

## Closeout

This closes the repository-side item against current main: the legacy Agent
Desk surface no longer declares itself a duplicate of the homepage through
its canonical or og:url, and CI fails if either returns.
4 changes: 2 additions & 2 deletions public/agent-desk.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
content="The self-serve Agent Desk is retired and is not the current offer. TinyStudio's current offer is the free leak audit of high-ticket service homepages."
/>
<meta property="og:type" content="website" />
<meta property="og:url" content="https://tinystudio.io/" />
<link rel="canonical" href="https://tinystudio.io/" />
<meta property="og:url" content="https://tinystudio.io/agent-desk.html" />
<link rel="canonical" href="https://tinystudio.io/agent-desk.html" />
Comment on lines +18 to +19

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Point metadata at the non-redirecting Agent Desk URL

Under the configured Cloudflare asset deployment, /agent-desk.html redirects to its extensionless twin; the repository documents this behavior in scripts/check-site.mjs lines 1587-1591 and explicitly says canonicals must name the address serving 200 rather than the redirecting form. Consequently, these new values do not identify the page's own final URL and may leave search engines or social scrapers resolving another URL instead of receiving the intended direct self-reference. Use https://tinystudio.io/agent-desk for both the canonical and og:url, and make the new guard expect that URL.

Useful? React with 👍 / 👎.

<meta property="og:image" content="https://tinystudio.io/og-image.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
Expand Down
44 changes: 41 additions & 3 deletions scripts/check-site.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,9 +1115,11 @@ for (const [pageName, pageHtml] of ownedPages) {
// google (2026-08-06): title "tinystudio.io - TinyStudio Agent Desk" against
// the homepage URL, the legacy page's title consolidated through its canonical.
// The legacy page must therefore stay out of the index: its head keeps a
// robots noindex, nofollow meta, and its title and description frame the
// surface as retired, so neither the search index nor a scraper can re-present
// the retired self-serve product as the current offer.
// robots noindex, nofollow meta, its title and description frame the
// surface as retired, and its canonical and og:url name the page's own
// served .html address instead of the apex root — so neither the search
// index nor a scraper can re-present the retired self-serve product as the
// current offer or fold its identity into the homepage.
const retiredDeskHead = retiredDesk.match(/<head\b[^>]*>([\s\S]*?)<\/head>/i)?.[1] ?? "";
const robotsMeta = /<meta\b(?=[^>]*\bname="robots")(?=[^>]*\bcontent="noindex,\s*nofollow")[^>]*>/i;
if (!robotsMeta.test(retiredDeskHead)) {
Expand All @@ -1131,6 +1133,42 @@ const retiredDeskDescription =
if (!/\bretired\b/i.test(retiredDeskDescription)) {
failures.push("Retired Agent Desk description must frame the surface as retired.");
}
// The legacy page must not claim the apex root as its canonical: while the
// page was served at the root, its canonical and og:url pointed at
// https://tinystudio.io/, which is exactly how the retired title consolidated
// onto the homepage (the q5 evidence above). A noindex page canonicalizing to
// a live page tells Google it is a duplicate of that page. The legacy page
// now declares its own canonical .html twin — https://tinystudio.io/agent-desk.html,
// the same self-address form every other owned page canonicals to (the desk
// page names /agents.html, pricing names /pricing.html, specimen names
// /specimen.html) — so neither a search engine nor a scraper can fold the
// retired surface's identity into the homepage again.
const retiredDeskLiveHead = retiredDeskHead.replace(/<!--[\s\S]*?-->/g, "");
const retiredDeskCanonicalLinks = [
...retiredDeskLiveHead.matchAll(/<link\b[^>]*\brel\s*=\s*["']canonical["'][^>]*>/gi)
].map((match) => match[0]);
const retiredDeskCanonicalHref =
retiredDeskCanonicalLinks[0]?.match(/\bhref\s*=\s*["']([^"']*)["']/i)?.[1] ?? "";
if (retiredDeskCanonicalLinks.length !== 1) {
failures.push(
`Retired Agent Desk page must carry exactly one canonical link in its head (found ${retiredDeskCanonicalLinks.length}).`
);
} else if (retiredDeskCanonicalHref.trim() !== "https://tinystudio.io/agent-desk.html") {
failures.push(
`Retired Agent Desk canonical must point at its own address https://tinystudio.io/agent-desk.html, not the apex root (found ${JSON.stringify(retiredDeskCanonicalHref)}).`
);
}
const retiredDeskOgUrl =
retiredDeskLiveHead.match(/<meta\b[^>]*\bproperty\s*=\s*["']og:url["'][^>]*>/i)?.[0] ?? "";
const retiredDeskOgUrlContent =
retiredDeskOgUrl.match(/\bcontent\s*=\s*["']([^"']*)["']/i)?.[1] ?? "";
if (!retiredDeskOgUrlContent) {
failures.push("Retired Agent Desk page must keep an og:url meta in its head.");
} else if (retiredDeskOgUrlContent.trim() !== "https://tinystudio.io/agent-desk.html") {
failures.push(
`Retired Agent Desk og:url must be its own address https://tinystudio.io/agent-desk.html, not the apex root (found ${JSON.stringify(retiredDeskOgUrlContent)}).`
);
}

// ---- Meta descriptions (dogfood) -------------------------------------------
// The leak audit this site sells flags a homepage whose served HTML carries no
Expand Down
Loading