diff --git a/.lane/reports/fix-clean-pagehead-self-decl-2026-08-14.md b/.lane/reports/fix-clean-pagehead-self-decl-2026-08-14.md
new file mode 100644
index 00000000..4c43e12c
--- /dev/null
+++ b/.lane/reports/fix-clean-pagehead-self-decl-2026-08-14.md
@@ -0,0 +1,35 @@
+# Lane 1: /agents, /pricing, /specimen page-head self-declaration
+
+Branch: `fix/clean-pagehead-self-decl-2026-08-14`
+PR: https://github.com/nish3451/TinyStudio.io/pull/210
+Commit: `3ff1398`
+
+## Change
+
+All three pages now self-declare their clean extensionless URLs in the head
+(the same form the worker serves at 200 and the sitemap lists), matching
+`/audit`:
+
+| Page | canonical / og:url / WebPage @id+url |
+| --- | --- |
+| /agents | `https://tinystudio.io/agents` (`agents#webpage`) |
+| /pricing | `https://tinystudio.io/pricing` (`pricing#webpage`) |
+| /specimen | `https://tinystudio.io/specimen` (`specimen#webpage`) |
+
+Before: all three declared the `.html` twin, which the worker 307-redirects.
+
+## Files touched
+
+- `public/agents.html` — canonical, og:url, WebPage @id/url -> clean
+- `public/pricing.html` — same
+- `public/specimen.html` — same
+- `scripts/check-site.mjs` — page-URL expectation tables (social share, structured data, canonical) now require the clean URL on all five pages; canonical comment updated
+
+## Validation
+
+- `node scripts/check-site.mjs` → "TinyStudio.io checks passed."
+- `npm test` (full suite: check, headings, sitemap, worker, ui, contract, viewport, narrow-pages) → exit 0
+
+## Notes
+
+- The `.html` twins remain allow-listed and served; this change only fixes what the pages declare about themselves. No redirect/route behavior changed.
diff --git a/public/agents.html b/public/agents.html
index 44495da3..2e3117d3 100644
--- a/public/agents.html
+++ b/public/agents.html
@@ -5,13 +5,13 @@
TinyStudio — The Desk
-
+
-
+
@@ -42,8 +42,8 @@
},
{
"@type": "WebPage",
- "@id": "https://tinystudio.io/agents.html#webpage",
- "url": "https://tinystudio.io/agents.html",
+ "@id": "https://tinystudio.io/agents#webpage",
+ "url": "https://tinystudio.io/agents",
"name": "TinyStudio — The Desk",
"description": "Seven specialists, one human signature. Each does a single job on your actual pages and numbers; nothing reaches you until a person has read and signed it.",
"inLanguage": "en",
diff --git a/public/pricing.html b/public/pricing.html
index 5e513b12..825f772d 100644
--- a/public/pricing.html
+++ b/public/pricing.html
@@ -5,13 +5,13 @@
TinyStudio — Pricing & terms
-
+
-
+
@@ -42,8 +42,8 @@
},
{
"@type": "WebPage",
- "@id": "https://tinystudio.io/pricing.html#webpage",
- "url": "https://tinystudio.io/pricing.html",
+ "@id": "https://tinystudio.io/pricing#webpage",
+ "url": "https://tinystudio.io/pricing",
"name": "TinyStudio — Pricing & terms",
"description": "One price, plainly stated: the appraisal is free, the desk is $2,500 a month on a three-month minimum, and the delivery guarantee is written out in full.",
"inLanguage": "en",
diff --git a/public/specimen.html b/public/specimen.html
index bcb96b72..53eb4cec 100644
--- a/public/specimen.html
+++ b/public/specimen.html
@@ -5,13 +5,13 @@
TinyStudio — The Website Appraisal — specimen
-
+
-
+
@@ -42,8 +42,8 @@
},
{
"@type": "WebPage",
- "@id": "https://tinystudio.io/specimen.html#webpage",
- "url": "https://tinystudio.io/specimen.html",
+ "@id": "https://tinystudio.io/specimen#webpage",
+ "url": "https://tinystudio.io/specimen",
"name": "TinyStudio — The Website Appraisal, specimen",
"description": "The appraisal, with the client's name removed: a real audit of a clinic homepage, four findings with evidence and fixes, read and signed by Nish.",
"inLanguage": "en",
diff --git a/scripts/check-site.mjs b/scripts/check-site.mjs
index a130cbf8..5c7469ff 100644
--- a/scripts/check-site.mjs
+++ b/scripts/check-site.mjs
@@ -1557,9 +1557,9 @@ if (!worker.includes("https://cloudflareinsights.com")) {
const socialSharePages = [
["homepage", siteHome, "https://tinystudio.io/"],
["audit page", siteAudit, "https://tinystudio.io/audit"],
- ["desk page", read("public/agents.html"), "https://tinystudio.io/agents.html"],
- ["pricing page", read("public/pricing.html"), "https://tinystudio.io/pricing.html"],
- ["specimen page", read("public/specimen.html"), "https://tinystudio.io/specimen.html"]
+ ["desk page", read("public/agents.html"), "https://tinystudio.io/agents"],
+ ["pricing page", read("public/pricing.html"), "https://tinystudio.io/pricing"],
+ ["specimen page", read("public/specimen.html"), "https://tinystudio.io/specimen"]
];
const SOCIAL_IMAGE_URL = "https://tinystudio.io/og-image.png";
@@ -1631,9 +1631,9 @@ for (const [pageName, pageHtml, pageUrl] of socialSharePages) {
const structuredDataPages = [
["homepage", siteHome, "https://tinystudio.io/"],
["audit page", siteAudit, "https://tinystudio.io/audit"],
- ["desk page", read("public/agents.html"), "https://tinystudio.io/agents.html"],
- ["pricing page", read("public/pricing.html"), "https://tinystudio.io/pricing.html"],
- ["specimen page", read("public/specimen.html"), "https://tinystudio.io/specimen.html"]
+ ["desk page", read("public/agents.html"), "https://tinystudio.io/agents"],
+ ["pricing page", read("public/pricing.html"), "https://tinystudio.io/pricing"],
+ ["specimen page", read("public/specimen.html"), "https://tinystudio.io/specimen"]
];
const ORGANIZATION_ID = "https://tinystudio.io/#organization";
@@ -1863,15 +1863,14 @@ for (const [pageName, pageHtml] of internalLinkPages) {
// link sits inside the head and points at the absolute https://tinystudio.io
// address of the page. The deployed worker 307-redirects every .html form to
// its clean extensionless twin, so a canonical must name the address that
-// serves 200, never the redirecting form: the audit page's canonical is the
-// clean /audit, while the remaining pages keep their .html form here until
-// they are migrated the same way.
+// serves 200, never the redirecting form: every page's canonical is its clean
+// extensionless address (/audit, /agents, /pricing, /specimen).
const canonicalPages = [
["homepage", siteHome, "https://tinystudio.io/"],
["audit page", siteAudit, "https://tinystudio.io/audit"],
- ["desk page", read("public/agents.html"), "https://tinystudio.io/agents.html"],
- ["pricing page", read("public/pricing.html"), "https://tinystudio.io/pricing.html"],
- ["specimen page", read("public/specimen.html"), "https://tinystudio.io/specimen.html"]
+ ["desk page", read("public/agents.html"), "https://tinystudio.io/agents"],
+ ["pricing page", read("public/pricing.html"), "https://tinystudio.io/pricing"],
+ ["specimen page", read("public/specimen.html"), "https://tinystudio.io/specimen"]
];
const canonicalLinkPattern = /]*\brel\s*=\s*["']canonical["'][^>]*>/gi;