-
Notifications
You must be signed in to change notification settings - Fork 0
SEO: add truthful page meta descriptions #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
| <head> | ||
| <meta charset="utf-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
| <meta name="description" content="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."> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When this description is consumed by a crawler or shown as a search snippet, “the client's name removed” presents the specimen as anonymized client work. The page explicitly states that the clinic is not a client and that the audit comes from public-homepage research, so the new metadata creates the proof claim the page disclaims; describe it as an unnamed clinic instead. AGENTS.md reference: AGENTS.md:L2-L3 Useful? React with 👍 / 👎. |
||
| <title>TinyStudio — The Website Appraisal — specimen</title> | ||
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | ||
| <link rel="preload" as="style" data-fonts-css href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,200;0,9..144,300;0,9..144,400;1,9..144,200;1,9..144,300&family=Karla:wght@300;400;500;600;700&display=swap"> | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -866,6 +866,49 @@ for (const [pageName, pageHtml] of ownedPages) { | |||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // ---- Meta descriptions (dogfood) ------------------------------------------- | ||||||||||||||||
| // The leak audit this site sells flags a homepage whose served HTML carries no | ||||||||||||||||
| // description, so the site's own five public pages must not carry the same | ||||||||||||||||
| // fault. Each page keeps exactly one valid, non-empty description meta tag in | ||||||||||||||||
| // its head, within a practical search-snippet length, distinct per page, and | ||||||||||||||||
| // free of the offer promises the repo refuses to make. | ||||||||||||||||
| const metaDescriptionPages = [ | ||||||||||||||||
| ["homepage", siteHome], | ||||||||||||||||
| ["audit page", siteAudit], | ||||||||||||||||
| ["desk page", read("public/agents.html")], | ||||||||||||||||
| ["pricing page", read("public/pricing.html")], | ||||||||||||||||
| ["specimen page", read("public/specimen.html")] | ||||||||||||||||
| ]; | ||||||||||||||||
|
|
||||||||||||||||
| const seenDescriptions = new Map(); | ||||||||||||||||
| for (const [pageName, pageHtml] of metaDescriptionPages) { | ||||||||||||||||
| const tags = [...pageHtml.matchAll(/<meta\b[^>]*\bname="description"[^>]*>/gi)].map((match) => match[0]); | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If a description is accidentally moved below Useful? React with 👍 / 👎. |
||||||||||||||||
| if (tags.length !== 1) { | ||||||||||||||||
| failures.push(`Meta description must appear exactly once in the head of ${pageName} (found ${tags.length}).`); | ||||||||||||||||
|
Comment on lines
+885
to
+887
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
node <<'NODE'
const pattern = /<meta\b[^>]*\bname="description"[^>]*>/gi;
const samples = [
'<html><head></head><body><meta name="description" content="body"></body></html>',
'<head><meta data-name="description" content="wrong"></head>',
];
for (const sample of samples) {
console.log([...sample.matchAll(pattern)].length);
}
NODERepository: nish3451/TinyStudio.io Length of output: 164 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- plan candidates ---'
git ls-files | rg -i '(^|/)(plan|plans|readme|agents|contributing)(\.|/|$)|(^|/).*plan.*\.(md|txt)$' | head -80
printf '%s\n' '--- target context ---'
cat -n scripts/check-site.mjs | sed -n '760,815p'
printf '%s\n' '--- related head parsing and checks ---'
rg -n -C 3 'matchAll|<head|description|pageHtml' scripts/check-site.mjsRepository: nish3451/TinyStudio.io Length of output: 6877 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- repository instructions ---'
cat AGENTS.md
printf '%s\n' '--- current plan candidates ---'
for f in docs/plans/2026-06-18-002-fix-minimal-input-agent-desk-plan.md specs/003-wellness-clinic-launch/plan.md; do
if [ -f "$f" ]; then
printf '\n### %s\n' "$f"
cat "$f"
fi
done
printf '%s\n' '--- page source locations ---'
sed -n '1,130p' scripts/check-site.mjs
printf '%s\n' '--- all description tags in checked page files ---'
rg -n -i '<meta[^>]*(name|data-name)[^>]*description|description[^>]*>' public/*.html
printf '%s\n' '--- verifier: current matcher versus proposed matcher ---'
node <<'NODE'
const current = /<meta\b[^>]*\bname="description"[^>]*>/gi;
const proposedHead = /<head\b[^>]*>([\s\S]*?)<\/head>/i;
const proposedTag = /<meta\b(?=[^>]*\sname\s*=\s*"description"(?:\s|>))[^>]*>/gi;
const samples = [
'<html><head></head><body><meta name="description" content="body"></body></html>',
'<head><meta data-name="description" content="wrong"></head>',
'<head><meta name="description" content="valid"></head>',
'<head><meta class="x" name = "description" content="valid"></head>',
'<head><meta name="description" content="valid"><meta name="description" content="duplicate"></head>',
];
for (const sample of samples) {
const head = sample.match(proposedHead)?.[1] ?? '';
console.log(JSON.stringify({
sample,
current: [...sample.matchAll(current)].length,
proposed: [...head.matchAll(proposedTag)].length,
}));
}
NODERepository: nish3451/TinyStudio.io Length of output: 25129 Restrict the meta-description check to The current regex scans the full document and treats Suggested matcher change- const tags = [...pageHtml.matchAll(/<meta\b[^>]*\bname="description"[^>]*>/gi)].map((match) => match[0]);
+ const head = pageHtml.match(/<head\b[^>]*>([\s\S]*?)<\/head>/i)?.[1] ?? "";
+ const tags = [...head.matchAll(/<meta\b(?=[^>]*\sname\s*=\s*"description"(?:\s|>))[^>]*>/gi)].map((match) => match[0]);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
| continue; | ||||||||||||||||
| } | ||||||||||||||||
| const content = tags[0].match(/\bcontent="([^"]*)"/i)?.[1] ?? ""; | ||||||||||||||||
| const trimmed = content.trim(); | ||||||||||||||||
| if (!trimmed) { | ||||||||||||||||
| failures.push(`Meta description on ${pageName} must not be empty.`); | ||||||||||||||||
| continue; | ||||||||||||||||
| } | ||||||||||||||||
| if (trimmed.length > 160) { | ||||||||||||||||
| failures.push(`Meta description on ${pageName} must fit a search snippet (${trimmed.length} > 160 chars).`); | ||||||||||||||||
| } | ||||||||||||||||
| const prior = seenDescriptions.get(trimmed); | ||||||||||||||||
| if (prior) { | ||||||||||||||||
| failures.push(`Meta description on ${pageName} must be unique; it duplicates ${prior}.`); | ||||||||||||||||
| } else { | ||||||||||||||||
| seenDescriptions.set(trimmed, pageName); | ||||||||||||||||
| } | ||||||||||||||||
| for (const claim of forbiddenClaims) { | ||||||||||||||||
| if (trimmed.toLowerCase().includes(claim.toLowerCase())) { | ||||||||||||||||
| failures.push(`Meta description on ${pageName} must not promise: ${claim}`); | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| 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; | ||||||||||||||||
|
|
||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: nish3451/TinyStudio.io
Length of output: 8317
State the unit in
Six a month.If this refers to audit capacity, change it to
Six audits a month.The meta description can appear without the page context, so the current wording is ambiguous with the$2,500monthly desk price.🤖 Prompt for AI Agents