Skip to content
This repository was archived by the owner on Sep 28, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1a47d6e
fix(worker): redirect the duplicate www host to the canonical apex
Aug 14, 2026
ee363d3
docs(evidence): re-verify the retired Agent Desk title finding and re…
Aug 14, 2026
95b3d62
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
9e5a6ff
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
cb23098
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
0cac6d7
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
c0b05d2
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
5c8cb88
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
14e3c3d
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
3b7d2fd
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
0253db5
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
6f083ea
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
92e7542
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
ca8a9cc
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
31d1378
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
c68beda
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
31cdecb
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
96a06c1
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
f61d4b8
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
9cf5abb
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
f9771ae
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
77ad8d0
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
90fae6f
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
5d7d7d9
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
795945c
Merge branch 'main' into docs/agent-desk-index-reverify-lane1-20260814
nish3451 Aug 14, 2026
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
57 changes: 57 additions & 0 deletions .lane/reports/docs/agent-desk-index-reverify-lane1-20260814.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Lane 1 — dogfood f41c8af0f8 (retired "TinyStudio Agent Desk" title in Google)

Date: 2026-08-14
Branch: `docs/agent-desk-index-reverify-lane1-20260814`
Base: fresh `origin/main` @ `5770bf3`

## Verdict

The finding was **half closed and half live**. The apex homepage — the exact
target named in the finding — is fixed and now verified fixed against a real
Google SERP. But the retired name still reaches Google through
`www.tinystudio.io`, a byte-identical duplicate of the site that no PR had
touched. This lane closed that host.

## What this lane did

1. Re-verified the shipped `noindex` + retired-framing fix on head and live.
2. Measured the live Google SERP (`site:tinystudio.io`, real browser) instead of
trusting the repo state — which is what surfaced the residual.
3. Traced the residual to `wrangler.jsonc` routing `www.tinystudio.io/*` at a
worker whose host dispatch only handled `app.`/`api.`.
4. Shipped a 301 canonical-host redirect plus four behavioural tests.

Full measurements, tables and root cause in
`docs/evidence/agent-desk-index-reverify-2026-08-14.md`.

## Key evidence

- Live SERP apex result: "TinyStudio — The Website Appraisal" ✅ (finding's
original symptom gone).
- Live SERP www results still carry Google's cached site name
"**- TinyStudio Agent Desk**" and the stale "The Tiny Studio" titles.
- `https://www.tinystudio.io/` served bytes `sha256 b37b0bbe…934e`, identical to
the apex; `http://www.tinystudio.io/` answered 200 with no HTTPS upgrade.

## Files touched

- `src/worker.js` — canonical-host 301 for `www.tinystudio.io`.
- `scripts/test-agent-worker.mjs` — 4 new guards.
- `docs/evidence/agent-desk-index-reverify-2026-08-14.md` — evidence receipt.
- `.lane/reports/docs/agent-desk-index-reverify-lane1-20260814.md` — this file.

No shared report file was written.

## Tests

`check-site` pass · worker 80/0 (was 76) · headings 6 · sitemap 7 · UI 16 ·
contract 8 · viewport 4 · narrow-pages pass · render-blocking pass.
Regression proof: disabling the host check yields `# pass 77 / # fail 3`.

## Overlap avoided

Open PR **#91** already fixes the `/agent-desk` canonical (the other
consolidation path for this same finding); it is `MERGEABLE` but `BLOCKED` on
review. This branch deliberately does not touch `public/agent-desk.html` or the
`check-site.mjs` desk guard, so it does not conflict and the two compose.
Open PRs #142/#95 cover the `/agents` canonical. Not duplicated here.
131 changes: 131 additions & 0 deletions docs/evidence/agent-desk-index-reverify-2026-08-14.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Retired "TinyStudio Agent Desk" title/snippet in Google — re-verification and residual fix

Date: 2026-08-14
Scope: backlog item `f41c8af0f8` — "[unreviewed-by-opus] Google still presents
the retired self-serve 'TinyStudio Agent Desk' title/snippet for tinystudio.io".

Verdict in one line: **the finding's original target — the apex homepage — is
fixed and verified fixed on live; the retired name still reaches Google through
a duplicate host nobody had closed, and this change closes it.**

## Environment

- Source baseline: fresh `origin/main` at `5770bf3`.
- Live target: `https://tinystudio.io/`, `https://www.tinystudio.io/`,
`http://www.tinystudio.io/`, and the served public pages.
- SERP measurement: Google `site:tinystudio.io`, 2026-08-14, real browser.

## Part 1 — what was already fixed (re-verified, no change needed)

The 2026-08-09 de-indexing pass (PR #46) put `noindex, nofollow` and retired
framing on the legacy desk surface. Re-verified on this head and on live:

- `public/agent-desk.html` head carries `<meta name="robots" content="noindex, nofollow" />`,
titles itself `TinyStudio — the retired Agent Desk`, and its description opens
"The self-serve Agent Desk is retired and is not the current offer."
- Live `https://tinystudio.io/agent-desk` → 200 serving exactly that head.
- Live `https://tinystudio.io/agent-desk.html` → 307 → `/agent-desk`, same head.
- The `check-site.mjs` dogfood guard ("Retired Agent Desk index guard") still
fails the build if the robots meta or the retired framing is removed.
- The legacy surface stays absent from `sitemap.xml`, and `llms.txt`/`offer.md`
keep the demotion statement.

**Live SERP, 2026-08-14 — the apex result is clean.** `site:tinystudio.io`
returns `https://tinystudio.io/` titled **"TinyStudio — The Website Appraisal"**
with the current leak-audit snippet. The title the finding reported
("tinystudio.io - TinyStudio Agent Desk", q5/google 2026-08-06) is **gone from
the apex homepage result**. That part of the finding is genuinely closed.

## Part 2 — the residual the finding is still right about

The same SERP still shows the retired product name, on a host nobody had
addressed:

| Indexed URL | Title Google presents |
|---|---|
| `https://tinystudio.io/` | TinyStudio — The Website Appraisal ✅ |
| `http://www.tinystudio.io/agents` | TinyStudio — The Desk **- TinyStudio Agent Desk** ❌ |
| `http://www.tinystudio.io/pricing.html` | Pricing & terms — **The Tiny Studio** ❌ |
| `http://www.tinystudio.io/specimen.html` | The Website Appraisal — specimen — **The Tiny Studio** ❌ |

The trailing "- TinyStudio Agent Desk" is Google's **site name** for the host,
not a page title. Google derives and caches a site name per host. `www.tinystudio.io`
is a *separate host entity* in the index, and its cached site name is still the
retired product's — from when the self-serve desk owned the root. The stale
"The Tiny Studio" titles fixed by PR #98 also survive on this host.

### Root cause

`wrangler.jsonc` routes `www.tinystudio.io/*` at this worker, but the worker's
host dispatch only special-cased `app.` and `api.`. `www` fell through to the
normal public-site handler, so the site answered **200** on a second hostname —
and over plain `http`, un-upgraded.

Measured on live before the fix:

- `http://www.tinystudio.io/` → `HTTP/1.1 200 OK` (no redirect, no HTTPS upgrade)
- `https://www.tinystudio.io/` → `200`, body **byte-identical** to the apex
(`sha256 b37b0bbe…934e` on both)
- `http://tinystudio.io/` → `200` (apex over plain http; see "Not fixed here")

Every page's `canonical`, every `og:url`, `robots.txt` and all seven
`sitemap.xml` entries already name `https://tinystudio.io`. The duplicate host
contradicted all of them. A page-level canonical is only a *hint*; Google had
plainly not taken it, since it kept indexing www URLs and kept a separate,
stale site name for them.

## The change

`src/worker.js` — canonical-host redirect ahead of all other dispatch:

```js
if (host === "www.tinystudio.io") {
const canonical = new URL(url);
canonical.protocol = "https:";
canonical.hostname = "tinystudio.io";
canonical.port = "";
return withSecurityHeaders(new Response(null, { status: 301, headers: { Location: canonical.toString() } }));
}
```

301 (not 302/307) is the point: it is the directive that collapses the
duplicate site entity — and its cached "TinyStudio Agent Desk" site name — into
the apex host. Path and query are preserved so campaign links keep working, and
plain `http` is upgraded to `https` in the same hop.

`scripts/test-agent-worker.mjs` — four guards:

1. www → `301` with `Location: https://tinystudio.io/`.
2. Path and query preserved; `http://www…/pricing?utm_source=x&utm_medium=y`
→ `https://tinystudio.io/pricing?utm_source=x&utm_medium=y`.
3. www never serves public-site HTML for `/`, `/audit`, `/agents`, `/agent-desk`
(asserted against a stub `ASSETS` binding that would return page HTML).
4. The apex host and the retired `app.`/`api.` 410 hosts are unaffected.

## Verification

- `node scripts/check-site.mjs` → "TinyStudio.io checks passed."
- `node --test scripts/test-agent-worker.mjs` → 80 pass, 0 fail (76 before).
- Full suite green: headings 6, sitemap 7, UI 16, contract 8, viewport 4,
narrow-pages pass, render-blocking pass.
- **Regression proof:** disabling the host check (`if (false)`) makes exactly
the three behavioural tests fail (`# pass 77 / # fail 3`); restoring it
returns 80/0. Guard 4 passes either way by design — it asserts the hosts this
change must *not* touch.

## Not fixed here (deliberate, separate items)

- **`/agent-desk` canonical still names the apex root.** That is the other
consolidation path for this same finding, and it is already fixed and waiting
in **open PR #91** ("stop the retired Agent Desk from claiming the apex root
as its canonical"), currently `MERGEABLE` but `BLOCKED` on review. Not
duplicated here on purpose — this branch does not touch
`public/agent-desk.html` or the `check-site.mjs` desk guard, so it does not
conflict with #91 and the two compose.
- **`http://tinystudio.io/` (apex over plain http) answers 200.** Same class of
duplicate-URL problem, different host; it is a Cloudflare "Always Use HTTPS" /
HSTS concern rather than this finding's mechanism. Left for its own item.
- **`/agents` canonical points at `/agents.html`.** Covered by open PRs #142/#95.
- No SERP change is claimed as immediate: recrawl and site-name refresh are
Google's timetable. What is claimed and proven is that the duplicate host —
the last surface still handing Google the retired name — no longer exists.
58 changes: 58 additions & 0 deletions scripts/test-agent-worker.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,64 @@ test("worker does not serve unlisted asset-like paths outside the public allow-l
assert.equal(res.status, 404);
});

// --- Canonical host redirect (dogfood: the retired "TinyStudio Agent Desk"
// title/snippet kept surfacing for tinystudio.io) ---
//
// www.tinystudio.io is routed at this worker by wrangler.jsonc and used to
// answer 200 with a duplicate of the public site, so Google held it as its own
// site with its own, stale site name. It must now redirect permanently to the
// apex host that robots.txt, sitemap.xml and every canonical already name.

test("www host redirects permanently to the canonical apex host", async () => {
const res = await worker.fetch(new Request("https://www.tinystudio.io/"), {});
assert.equal(res.status, 301, "the duplicate www host must answer a permanent redirect, not 200");
assert.equal(res.headers.get("Location"), "https://tinystudio.io/");
});

test("www host redirect preserves path and query, and upgrades plain http", async () => {
const res = await worker.fetch(
new Request("http://www.tinystudio.io/pricing?utm_source=x&utm_medium=y"),
{}
);
assert.equal(res.status, 301);
assert.equal(
res.headers.get("Location"),
"https://tinystudio.io/pricing?utm_source=x&utm_medium=y",
"the redirect must keep the visitor's destination and campaign parameters intact"
);
});

test("www host never serves a second copy of the public site", async () => {
const env = {
ASSETS: { fetch: async () => new Response("<html>duplicate site</html>", { status: 200 }) }
};
for (const target of [
"https://www.tinystudio.io/",
"https://www.tinystudio.io/audit",
"https://www.tinystudio.io/agents",
"https://www.tinystudio.io/agent-desk"
]) {
const res = await worker.fetch(new Request(target), env);
assert.equal(res.status, 301, `www must not serve ${target}`);
const body = await res.text();
assert.doesNotMatch(body, /duplicate site/, "www must not return public site HTML");
}
});

test("canonical host redirect leaves the apex and the retired hosts alone", async () => {
const env = {
ASSETS: { fetch: async () => new Response("<html>apex site</html>", { status: 200 }) }
};
const apex = await worker.fetch(new Request("https://tinystudio.io/"), env);
assert.notEqual(apex.status, 301, "the apex host must keep serving the site, not redirect");

const app = await worker.fetch(new Request("https://app.tinystudio.io/"), {});
assert.equal(app.status, 410, "the retired app host keeps its own retired response");

const api = await worker.fetch(new Request("https://api.tinystudio.io/"), {});
assert.equal(api.status, 410, "the retired API host keeps its own retired response");
});

test("retired app host frames the current offer as The Website Appraisal, not the Agent Desk", async () => {
const res = await worker.fetch(new Request("https://app.tinystudio.io/"), {});
assert.equal(res.status, 410);
Expand Down
28 changes: 28 additions & 0 deletions src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,34 @@ export default {
const url = new URL(request.url);
const host = url.hostname.toLowerCase();

// ---- Canonical host redirect (dogfood: Google still presents the retired
// self-serve "TinyStudio Agent Desk" title/snippet for tinystudio.io) ----
// wrangler.jsonc routes www.tinystudio.io/* at this worker, but nothing
// ever sent that host anywhere: it answered 200 with a byte-identical copy
// of the public site, on a second hostname and over plain http. Google
// therefore holds www.tinystudio.io as its own site, with its own site
// name, and that entity still carries the retired "TinyStudio Agent Desk"
// name from when the self-serve desk owned the root — which is why the
// retired product name keeps surfacing for this site even though the apex
// host's own title, description and site name are long since correct.
// robots.txt, sitemap.xml and every canonical and og:url on the site name
// https://tinystudio.io as the single address, so the duplicate host is
// sent there permanently and drops out of the index. A page-level
// canonical is only a hint; a 301 is the directive that retires the
// duplicate site entity along with its stale name.
if (host === "www.tinystudio.io") {
const canonical = new URL(url);
canonical.protocol = "https:";
canonical.hostname = "tinystudio.io";
canonical.port = "";
return withSecurityHeaders(
new Response(null, {
status: 301,
headers: { Location: canonical.toString() }
})
);
}

if (host === "app.tinystudio.io") {
return retiredAppResponse();
}
Expand Down
Loading