From 45552528f8999664a1c08753ae70ad1ca600fe6d Mon Sep 17 00:00:00 2001 From: nish3451 <257724087+nish3451@users.noreply.github.com> Date: Mon, 10 Aug 2026 21:18:33 +0530 Subject: [PATCH] fix(public): give both appraisal intake fields persistent labels and kill the two "The Tiny Studio" document titles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The homepage and /audit intake forms labelled their fields only with placeholder text, which disappears the moment a buyer starts typing and is not a persistent programmatic label; both served pages now carry a stable aria-label on the website and email inputs. /pricing and /brief-requested still branded their document titles "The Tiny Studio" — the spaced name the site's own identity copy disavows — while every other page said TinyStudio; both titles now match the brand (and the pricing title matches its own og:title). Two deterministic guards in check-site.mjs make both regressions impossible: every one of the six served appraisal titles must name TinyStudio and never "The Tiny Studio", and every intake website/email input must carry a non-empty aria-label. The retired /agent-desk page is excluded deliberately: its title frames itself as retired and it is noindex. verify: npm run check --- public/audit.html | 4 +-- public/brief-requested.html | 2 +- public/index.html | 4 +-- public/pricing.html | 2 +- scripts/check-site.mjs | 57 +++++++++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/public/audit.html b/public/audit.html index 87556a55..9057274e 100644 --- a/public/audit.html +++ b/public/audit.html @@ -77,8 +77,8 @@

We read your page as a customer with intent reads it.

Four passes, by hand, on the surfaces that decide whether someone who arrived ready to buy stays that way. You get a short, plain document — each fault named, in order of what it costs you, with the fix beside each one. No deck. No dashboard.

- - + +

Thirty seconds to ask. Findings inside five working days. Yours to keep either way.

diff --git a/public/brief-requested.html b/public/brief-requested.html index a40ec132..70409ce0 100644 --- a/public/brief-requested.html +++ b/public/brief-requested.html @@ -3,7 +3,7 @@ -Request received — The Tiny Studio +Request received — TinyStudio diff --git a/public/index.html b/public/index.html index ae3544c6..5a9ff9aa 100644 --- a/public/index.html +++ b/public/index.html @@ -71,8 +71,8 @@

Most of them leave before they ever get in touch.

We read the one page your revenue depends on the way a customer with intent reads it, and show you the exact points at which they go.

- - + +

Thirty seconds to ask. Findings inside five working days. No call at any point.

diff --git a/public/pricing.html b/public/pricing.html index 454be253..571fe1b5 100644 --- a/public/pricing.html +++ b/public/pricing.html @@ -4,7 +4,7 @@ -Pricing & terms — The Tiny Studio +TinyStudio — Pricing & terms diff --git a/scripts/check-site.mjs b/scripts/check-site.mjs index 2cb3c4c2..81c44b3f 100644 --- a/scripts/check-site.mjs +++ b/scripts/check-site.mjs @@ -1492,6 +1492,63 @@ for (const [pageName, pageHtml, expected] of canonicalPages) { } } +// ---- Document titles (brand consistency) ---------------------------------- +// Two served pages still branded themselves "The Tiny Studio" — the spaced +// name the site's own identity copy disavows (it collides with "The Tiny +// Studio LA" and other unrelated businesses) — while every other title said +// "TinyStudio": /pricing served "Pricing & terms — The Tiny Studio" and +// /brief-requested served "Request received — The Tiny Studio", both +// byte-identical on origin/main. Title tags are a first-order SERP signal, so +// every one of the six served appraisal pages must now name the brand in its +// document title and must never return the spaced "The Tiny Studio" form. +// The retired /agent-desk surface is deliberately excluded: its title frames +// itself as retired and it is noindex. +const titlePages = [ + ["homepage", siteHome], + ["audit page", siteAudit], + ["desk page", read("public/agents.html")], + ["pricing page", read("public/pricing.html")], + ["specimen page", read("public/specimen.html")], + ["brief-requested page", read("public/brief-requested.html")] +]; + +for (const [pageName, pageHtml] of titlePages) { + const title = pageHtml.match(/([^<]*)<\/title>/i)?.[1] ?? ""; + if (!title) { + failures.push(`Document title must exist on ${pageName}.`); + continue; + } + if (!title.includes("TinyStudio")) { + failures.push(`Document title on ${pageName} must name TinyStudio (found ${JSON.stringify(title)}).`); + } + if (title.includes("The Tiny Studio")) { + failures.push(`Document title on ${pageName} must not use the spaced "The Tiny Studio" form (found ${JSON.stringify(title)}).`); + } +} + +// ---- Intake field labels (activation) ------------------------------------- +// Both appraisal intake forms (homepage and /audit) labelled their fields +// only with placeholder text, which disappears the moment a buyer starts +// typing and is not a persistent programmatic label. Each intake input must +// carry a non-empty aria-label so the field keeps its name for assistive +// tech and for the browser's own validation announcements, no matter what +// the field contains. +const intakePages = [ + ["homepage", siteHome], + ["audit page", siteAudit] +]; + +for (const [pageName, pageHtml] of intakePages) { + for (const input of pageHtml.matchAll(/<input\b[^>]*>/gi)) { + const tag = input[0]; + if (!/\bname="(?:website|email)"/.test(tag)) continue; + const aria = tag.match(/\baria-label="([^"]*)"/)?.[1] ?? ""; + if (!aria.trim()) { + failures.push(`Intake input on ${pageName} must carry a persistent programmatic aria-label (placeholder-only labels disappear as buyers type): ${tag}`); + } + } +} + for (const migration of ["migrations/0002_agent_runs.sql", "migrations/0003_agent_usage_limits.sql"]) { if (!existsSync(new URL(`../${migration}`, import.meta.url))) { failures.push(`Missing migration: ${migration}`); continue;