Skip to content
Merged
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
1 change: 1 addition & 0 deletions public/agents.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="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.">
<title>TinyStudio — The Desk</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">
Expand Down
1 change: 1 addition & 0 deletions public/audit.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="What the appraisal actually checks: four passes by hand, the evidence embedded — including a controlled AI-search test with verbatim answers and cited pages.">
<title>TinyStudio — The Website Appraisal</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">
Expand Down
1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="TinyStudio: the free leak audit of high-ticket service homepages. Each fault named in order of what it costs you, with the fix beside it. Six a month.">

Copy link
Copy Markdown

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:

#!/bin/bash
set -euo pipefail
rg -n -C 3 -- 'Six a month|six|a month|\$2,500|three-month minimum' public/index.html public/pricing.html || true

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,500 monthly desk price.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@public/index.html` at line 6, Update the description meta tag content in the
document head so the phrase “Six a month” explicitly states the unit as “Six
audits a month,” while preserving the rest of the description.

<title>TinyStudio — The Website Appraisal</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">
Expand Down
1 change: 1 addition & 0 deletions public/pricing.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="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.">
<title>Pricing &amp; terms — The Tiny Studio</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">
Expand Down
1 change: 1 addition & 0 deletions public/specimen.html
Original file line number Diff line number Diff line change
Expand Up @@ -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.">

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 Describe the specimen as non-client research

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">
Expand Down
43 changes: 43 additions & 0 deletions scripts/check-site.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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]);

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 Restrict the description search to the head

If a description is accidentally moved below </head> while remaining elsewhere in the document, this whole-document regex still finds exactly one tag and the check passes, even though the invariant and failure message require metadata in the head. Extract or otherwise bound the search to the document's <head> so this regression is actually detected.

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

Copy link
Copy Markdown

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:

#!/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);
}
NODE

Repository: 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.mjs

Repository: 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,
  }));
}
NODE

Repository: nish3451/TinyStudio.io

Length of output: 25129


Restrict the meta-description check to <head>.

The current regex scans the full document and treats data-name="description" as a match. A body element or data-name attribute can satisfy the head-description check.

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

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const tags = [...pageHtml.matchAll(/<meta\b[^>]*\bname="description"[^>]*>/gi)].map((match) => match[0]);
if (tags.length !== 1) {
failures.push(`Meta description must appear exactly once in the head of ${pageName} (found ${tags.length}).`);
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]);
if (tags.length !== 1) {
failures.push(`Meta description must appear exactly once in the head of ${pageName} (found ${tags.length}).`);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-site.mjs` around lines 785 - 787, Update the meta-description
matcher in the site-check logic around the tags collection so it first restricts
matching to the document’s <head> content and only recognizes the exact
name="description" attribute, excluding body elements and data-name attributes.
Preserve the existing exactly-one validation and failure message.

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;
Expand Down
Loading