fix(public): disambiguate Tiny Studio from unrelated tiny studio brands - #29
Conversation
Google AI answers conflate tinystudio.in with unrelated apps and studios named Tiny Studio. The homepage now states plainly, in visible copy and in the Organization structured data, that Tiny Studio is the independent product company at tinystudio.in behind Promptly, Drishti, and 0509 and is not affiliated with any other app or studio using the name. Adds a public brand disambiguation test wired into npm test and npm run ci.
There was a problem hiding this comment.
nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
📝 WalkthroughWalkthroughThe homepage now includes Tiny Studio identity and non-affiliation messaging in visible content and Organization structured data. A new Node.js test validates these details and runs through both npm test and CI. ChangesBrand disambiguation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
scripts/test-public-brand-disambiguation.mjs (1)
20-23: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winMake JSON-LD extraction independent of attribute order.
Lines 20-23 only match a
scripttag whosetypeattribute is first, uses double quotes, and has no whitespace around=. A harmless markup change can makeorgNodereturnnulleven when the Organization node is present. Match thetypeattribute independently of its position and quote style.Proposed fix
const jsonLdBlocksOf = (html) => - [...html.matchAll(/<script\s+type="application\/ld\+json"[^>]*>([\s\S]*?)<\/script>/gi)].map( - (m) => m[1] + [...html.matchAll( + /<script\b[^>]*\btype\s*=\s*(['"])application\/ld\+json\1[^>]*>([\s\S]*?)<\/script>/gi + )].map( + (m) => m[2] )🤖 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/test-public-brand-disambiguation.mjs` around lines 20 - 23, Update jsonLdBlocksOf to recognize JSON-LD script tags regardless of attribute order, single or double quotes around the type value, and whitespace around the equals sign. Preserve extraction of the script contents while matching type="application/ld+json" independently of neighboring attributes.
🤖 Prompt for all review comments with 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.
Inline comments:
In `@scripts/test-public-brand-disambiguation.mjs`:
- Around line 39-46: Update bodyText and the related assertion to inspect only
the rendered hero paragraph, excluding content inside template elements, hidden
elements, and inline CSS-hidden elements. Prefer selecting the intended hero
paragraph directly and extracting its visible text, while preserving the
existing normalization used for assertions.
- Around line 68-83: Normalize org.description once after the initial type
assertion, using the established string type guard and an empty-string fallback
for non-string values. Update the subsequent product-name and affiliation
assertions to call .includes() on that normalized string, while preserving their
existing required-content checks.
---
Nitpick comments:
In `@scripts/test-public-brand-disambiguation.mjs`:
- Around line 20-23: Update jsonLdBlocksOf to recognize JSON-LD script tags
regardless of attribute order, single or double quotes around the type value,
and whitespace around the equals sign. Preserve extraction of the script
contents while matching type="application/ld+json" independently of neighboring
attributes.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 9122dae1-055b-4ab2-ab6a-bf022fe44e2b
📒 Files selected for processing (3)
package.jsonpublic/index.htmlscripts/test-public-brand-disambiguation.mjs
| // Strip markup so assertions run against the visible, human-readable text. | ||
| const bodyText = (html) => | ||
| html | ||
| .replace(/<script\b[\s\S]*?<\/script>/gi, " ") | ||
| .replace(/<style\b[\s\S]*?<\/style>/gi, " ") | ||
| .replace(/<[^>]+>/g, " ") | ||
| .replace(/\s+/g, " ") | ||
| .trim() |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Limit the text assertion to rendered content.
bodyText removes tags, but it keeps text inside <template>, hidden elements, and elements hidden with inline CSS. A future change could move the non-affiliation copy out of the visible hero while this test still passes. Scope the assertion to the intended hero paragraph or use a parser that excludes non-rendered content.
🤖 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/test-public-brand-disambiguation.mjs` around lines 39 - 46, Update
bodyText and the related assertion to inspect only the rendered hero paragraph,
excluding content inside template elements, hidden elements, and inline
CSS-hidden elements. Prefer selecting the intended hero paragraph directly and
extracting its visible text, while preserving the existing normalization used
for assertions.
| ok( | ||
| typeof org.description === "string" && org.description.length > 0, | ||
| "organization carries a description" | ||
| ) | ||
| ok( | ||
| org.description && | ||
| org.description.includes("tinystudio.in") && | ||
| org.description.includes("Promptly") && | ||
| org.description.includes("Drishti") && | ||
| org.description.includes("0509"), | ||
| "organization description names the unique products and home so the entity cannot be mistaken for another tiny studio" | ||
| ) | ||
| ok( | ||
| org.description && org.description.includes("not affiliated"), | ||
| "organization description states it is not affiliated with other tiny studio brands" | ||
| ) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Reuse the description type guard before calling .includes().
The check at Lines 68-70 does not stop execution. If org.description is a truthy non-string value, Lines 72-78 and 80-82 throw TypeError. Normalize the description once, then use the normalized string for all assertions.
Proposed fix
if (org) {
+ const description = typeof org.description === "string" ? org.description : ""
ok(org.name === "Tiny Studio", "organization name is Tiny Studio")
ok(org.alternateName === "tinystudio.in", "organization alternateName is tinystudio.in")
ok(org.url === "https://tinystudio.in/", "organization url is the tinystudio.in home")
ok(
- typeof org.description === "string" && org.description.length > 0,
+ description.length > 0,
"organization carries a description"
)
ok(
- org.description &&
- org.description.includes("tinystudio.in") &&
- org.description.includes("Promptly") &&
- org.description.includes("Drishti") &&
- org.description.includes("0509"),
+ description.includes("tinystudio.in") &&
+ description.includes("Promptly") &&
+ description.includes("Drishti") &&
+ description.includes("0509"),
"organization description names the unique products and home so the entity cannot be mistaken for another tiny studio"
)
ok(
- org.description && org.description.includes("not affiliated"),
+ description.includes("not affiliated"),
"organization description states it is not affiliated with other tiny studio brands"
)
}📝 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.
| ok( | |
| typeof org.description === "string" && org.description.length > 0, | |
| "organization carries a description" | |
| ) | |
| ok( | |
| org.description && | |
| org.description.includes("tinystudio.in") && | |
| org.description.includes("Promptly") && | |
| org.description.includes("Drishti") && | |
| org.description.includes("0509"), | |
| "organization description names the unique products and home so the entity cannot be mistaken for another tiny studio" | |
| ) | |
| ok( | |
| org.description && org.description.includes("not affiliated"), | |
| "organization description states it is not affiliated with other tiny studio brands" | |
| ) | |
| const description = typeof org.description === "string" ? org.description : "" | |
| ok( | |
| description.length > 0, | |
| "organization carries a description" | |
| ) | |
| ok( | |
| description.includes("tinystudio.in") && | |
| description.includes("Promptly") && | |
| description.includes("Drishti") && | |
| description.includes("0509"), | |
| "organization description names the unique products and home so the entity cannot be mistaken for another tiny studio" | |
| ) | |
| ok( | |
| description.includes("not affiliated"), | |
| "organization description states it is not affiliated with other tiny studio brands" | |
| ) |
🤖 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/test-public-brand-disambiguation.mjs` around lines 68 - 83, Normalize
org.description once after the initial type assertion, using the established
string type guard and an empty-string fallback for non-string values. Update the
subsequent product-name and affiliation assertions to call .includes() on that
normalized string, while preserving their existing required-content checks.
… leave the June-20 bundle (#81) * fix(public): add the tinystudio.in release lane (Cloudflare Pages deploy path repair) The live site has served the 2026-06-20 bundle (07acd07) since June 20 while 17+ public PRs merged to main; the Cloudflare Pages git connection for tiny-studio-3f5 never shows checks/statuses on commits and no deploy workflow or secrets exist in the repo. The fleet Workers token lacks Cloudflare Pages:Edit, so no automation on this box can publish today. Add an in-repo release lane that works the moment a Pages-scoped token is provisioned (documented fail-closed message): - scripts/prepare-public-deploy-bundle.mjs: filtered bundle (public/ minus the snoozed-by-Nish managed-service buyer path from PRs #10/#11; every other merged fix preserved), fail-closed in both directions - scripts/test-public-deploy-bundle.mjs: regression guard, wired into npm test/ci (62 checks) - scripts/publish-public-site.mjs: prepare -> wrangler pages deploy to tiny-studio-3f5 -> live verification - scripts/check-public-live-deploy.mjs: live proof for the deploy-path accept (H2-after-H1 /promptly/support/ #18/#20, JSON-LD /contact/ #19, real 404s #34, homepage portfolio-only #29 + no buyer path) - .github/workflows/deploy-public-site.yml: vps-verify lane on push to main - wrangler 4.120.0 devDependency verify: npm test (603 checks, 0 failures); node scripts/prepare-public-deploy-bundle.mjs; git diff --check * fix(public): attach the source commit to Cloudflare Pages deployments wrangler pages deploy accepts --commit-hash/--commit-message/--commit-dirty for dashboard provenance. The bundle already records source_commit in deploy-manifest.json; pass it through so the Pages dashboard links the deployment to the exact tinystudio-in commit that produced the bundle. verify: node --check scripts/publish-public-site.mjs; node scripts/test-public-deploy-bundle.mjs (62 checks, 0 failures) Co-authored-by: CommandCodeBot <noreply@commandcode.ai> --------- Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
…ource fixed in PR #29, live blocked on missing Cloudflare token (#182) (#184) The Google AI answers disambiguation item is already fixed on main: commit 4202d54 (PR #29) put the "independent product company at tinystudio.in, not affiliated with other apps or studios using the name" statement in every public page's Organization JSON-LD, in the homepage visible copy, in llms.txt, and in its generator template, and wired scripts/test-public-brand-disambiguation.mjs into npm test and npm run ci. Re-verified against fresh origin/main: the guard script passes (11 checks, 0 failures) and the source homepage carries the identity statement. Live tinystudio.in still serves a stale bundle with no JSON-LD and no disambiguation copy, and check-public-live-deploy.mjs fails 7/15 checks; the deploy lane is fail-closed on the missing CLOUDFLARE_API_TOKEN secret (NEEDS-NISH). No source change is possible or needed; this report documents the verification. Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Closes the AI-answer confusion where Google AI answers conflate Tiny Studio / tinystudio.in with unrelated apps and studios that share the name.
What changed
alternateName: tinystudio.inand a description naming the unique qualifiers (tinystudio.in, Promptly, Drishti, 0509) plus the non-affiliation statement.npm testandnpm run ci.Why this shape
Follows the repo's own ai-search-audit-workflow no-hack rules: plain, crawlable, truthful copy that answers the confusion for a human first, plus structured data that already fits the content. No AI-only pages, hidden text, or keyword stuffing. The homepage is the entity-defining page; other public pages reference the same stable
#organizationid.Validation
npm run ci: exit 0, all suites pass (new test: 11 checks, 0 failures)git diff --check: cleanSummary by CodeRabbit
New Features
Tests