Skip to content

Fix TechArticle schema headline leaking competitor name on /docs/iac/comparisons/ - #20580

Merged
CamSoper merged 1 commit into
masterfrom
seo/techarticle-headline-comparison-pages
Jul 30, 2026
Merged

Fix TechArticle schema headline leaking competitor name on /docs/iac/comparisons/#20580
CamSoper merged 1 commit into
masterfrom
seo/techarticle-headline-comparison-pages

Conversation

@workprentice

@workprentice workprentice Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

The defect

Every Pulumi-vs-competitor page under /docs/iac/comparisons/ publishes a TechArticle JSON-LD entity whose schema.org headline is the competitor's bare name, because the collector used Hugo's .Title (the short left-nav sidebar label) instead of the page's real SEO title. Verified on production before this fix:

Path <title> (correct) schema headline (wrong, before this PR)
/docs/iac/comparisons/terraform/ Pulumi vs. Terraform | Pulumi Docs Terraform
/docs/iac/comparisons/opentofu/ Pulumi vs. OpenTofu | Pulumi Docs OpenTofu
/docs/iac/comparisons/aws-cdk/ Pulumi vs. AWS CDK | Pulumi Docs AWS CDK
/docs/iac/comparisons/crossplane/ Pulumi vs. Crossplane | Pulumi Docs Crossplane
/docs/iac/comparisons/cloudformation/ Pulumi vs. AWS CloudFormation | Pulumi Docs AWS CloudFormation
/docs/iac/comparisons/ Pulumi Compared to Alternatives | Pulumi Docs Comparisons

The counter-example that pointed straight at .Title leakage: /docs/iac/comparisons/terraform/opentofu/ already had a correct headline ("OpenTofu vs. Terraform") only because its .Title happens to equal the full phrase. Every other comparison page's .Title is just the short menu label, so its headline came out wrong.

Why this matters

This is on the pages that carry the most weight for Pulumi's AI visibility. Per Profound (category "Infrastructure as Code", trailing 30 days), pulumi.com is the #1 cited domain in the category, and the comparison docs are individually among the most-cited /docs/ pages (terraform, opentofu, terraform vs opentofu, crossplane, aws-cdk, cloudformation together account for the large majority of /docs/ citations in that window). GA4 shows /docs/iac/comparisons/terraform/ as the #1 non-homepage organic landing page over the same window, with real sessions arriving from chatgpt.com and gemini.google.com. Structured data that mislabels these pages as being about the competitor works against exactly the queries ("pulumi vs terraform," "terraform alternatives," "cdk vs terraform") these pages are built to win.

The fix

Every comparison page already declares the correct, Pulumi-first SEO title via front-matter title_tag — the same field head.html already uses to render the actual <title> tag. This PR makes the TechArticle schema collector prefer it:

"headline" (or .Params.title_tag .Title)

This mirrors the fallback pattern already established in schema/collectors/faq-entity.html ("name" (or .Params.title_tag .Title)), so it's consistent with existing precedent in this codebase rather than a new pattern.

Scope: one line changed in layouts/partials/schema/collectors/article-entity.html. No visible copy, <title>, H1, or name field changes — this is schema-only.

Verification

  • Audited front matter on all 19 URLs under /docs/iac/comparisons/: every one has a title_tag set, all under ~90 characters, none polluted with a | Pulumi... suffix or keyword stuffing — the fallback resolves cleanly everywhere in this section.
  • For any docs page without a title_tag set, behavior is unchanged (falls through to .Title exactly as before) — this is additive, not a behavior change outside the affected pages.
  • Confirmed the collector's Go template brace/tag balance is intact after the edit.
  • Deliberately did not touch speakable/isPartOf gaps on this collector after finding an inline comment explaining speakable was intentionally removed as not applicable to developer tools — kept this PR to the one verified correctness defect rather than bundling in a judgment call.

🧠 This PR was created by workprentice on behalf of the Pulumi SEO/AEO agent's operator.

… pages

The TechArticle collector used Hugo's .Title for the JSON-LD headline
field, which on /docs/iac/comparisons/ pages is the short left-nav
label (e.g. "Terraform", "OpenTofu", "AWS CDK") rather than the
page's actual subject. Every comparison page already declares the
correct SEO title via title_tag (the same field head.html uses for
the <title> tag), so prefer it with the same or-fallback pattern
already used in schema/collectors/faq-entity.html.

This affects all 19 URLs under /docs/iac/comparisons/, which are
among Pulumi's most AI-cited and highest-traffic docs pages.
@workprentice

workprentice Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

@claude #new-review

@github-actions github-actions Bot added review:triaging Claude Triage is currently classifying the PR domain:infra PR touches workflows, scripts, infra, Makefile, or build config review:in-progress Claude review is currently running and removed review:triaging Claude Triage is currently classifying the PR labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Pre-merge Review — Last updated 2026-07-30T12:19:57Z

Tip

Summary: This is a one-line fix to the TechArticle schema collector (layouts/partials/schema/collectors/article-entity.html), which builds the JSON-LD headline emitted on docs pages. It swaps .Title for (or .Params.title_tag .Title) so the structured-data headline uses the page's real SEO title instead of Hugo's short sidebar .Title. The motivating bug: on /docs/iac/comparisons/ pages .Title is the bare competitor name (e.g. "Terraform"), which was leaking into the headline field and signaling to AI answer engines that Pulumi's comparison pages are about the competitor. The kind of wrongness that would block success here is a broken fallback (emitting an empty headline when title_tag is unset) or a mismatch with the rendered <title> — both checked out. The fix mirrors the identical (or .Params.title_tag .Title) precedent already used in faq-entity.html, and title_tag is confirmed as the same field head.html uses to build the rendered <title> tag. An infra/template pass plus verification of the two premises the code comment asserts (the head.html title source and the faq-entity.html precedent) ran against the sibling templates.

Review confidence:

Dimension Level Notes
mechanics HIGH
facts HIGH
Investigation log
  • Cross-sibling reads: not run (not a content change in a templated section)
  • External claim verification: 2 of 2 claims verified (0 unverifiable, 0 contradicted) — the two premises in the code comment (that head.html builds the rendered <title> from `.Params.title_ta
  • Cited-claim spot-checks: not run (no cited claims)
  • Frontmatter sweep: not run (no frontmatter in diff)
  • Temporal-trigger sweep: not run (no trigger words)
  • Code execution: not run (no static/programs/ change)
  • Code-examples checks: not run (no fenced code blocks in content files)
  • Editorial-balance pass: not run (not under content/blog/)
🚨 Outstanding ⚠️ Low-confidence 💡 Pre-existing ✅ Resolved
0 0 0 0

🔍 Verification trail

  • L14 in layouts/partials/schema/collectors/article-entity.html "head.html builds the rendered <title> from .Params.title_tag (so it is the page's real SEO title)" → ✅ verified (layouts/partials/head.html line 294: {{ if .Params.title_tag }}{{ $title = .Params.title_tag }}; source: repo template at head commit)
  • L18 in layouts/partials/schema/collectors/article-entity.html "same (or .Params.title_tag .Title) fallback precedent already used in faq-entity.html" → ✅ verified (layouts/partials/schema/collectors/faq-entity.html: "name" (or .Params.title_tag .Title); source: repo template at head commit)

🚨 Outstanding in this PR

No outstanding findings in this PR.

⚠️ Low-confidence

No low-confidence findings.

💡 Pre-existing issues in touched files (optional)

No pre-existing issues in touched files.

✅ Resolved since last review

No items resolved since the last review.

📜 Review history

  • 2026-07-30T12:19:57Z — Verified the TechArticle headline fix: the title_tag fallback matches head.html's <title> source and the faq-entity.html precedent; no blockers. (366b7f0)

  • Refresh this review — comment @claude #update-review. Say what you fixed, or which finding you dispute and why; both work in the same mention.
  • Ask for anything else — comment @claude with no hashtag (questions, one-off fixes). Leaves this review untouched.

Important

Please don't hide, resolve, or delete this comment! It breaks things!

📖 How pre-merge review works — the full lifecycle, short-circuits, and escape hatches.

@github-actions github-actions Bot added review:no-blockers Claude review completed cleanly; outstanding is empty and removed review:in-progress Claude review is currently running labels Jul 30, 2026
@pulumi-bot

Copy link
Copy Markdown
Collaborator

@pulumi-bot

Copy link
Copy Markdown
Collaborator

Lighthouse Performance Report

Commit: 366b7f0 | Metric definitions

Page Device Score FCP LCP TBT CLS SI
Homepage Mobile 🔴 39 6.2s 13.1s 883ms 0.001 6.2s
Homepage Desktop 🟡 77 0.7s 1.4s 310ms 0.037 2.5s
Install Pulumi Mobile 🟡 57 8.3s 16.6s 78ms 0.000 8.3s
Install Pulumi Desktop 🟡 82 1.2s 2.7s 0ms 0.016 1.2s
AWS Get Started Mobile 🟡 56 5.8s 9.7s 26ms 0.085 7.8s
AWS Get Started Desktop 🟡 89 1.2s 1.9s 0ms 0.033 1.2s

@CamSoper CamSoper left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated rubber stamp approval applied :shipit:


Generated by Claude Code

@CamSoper
CamSoper merged commit f510c80 into master Jul 30, 2026
12 checks passed
@CamSoper
CamSoper deleted the seo/techarticle-headline-comparison-pages branch July 30, 2026 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain:infra PR touches workflows, scripts, infra, Makefile, or build config review:no-blockers Claude review completed cleanly; outstanding is empty

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants