Skip to content

Send a canonical Link header for games that name one - #7

Merged
dmccoystephenson merged 1 commit into
mainfrom
feat/canonical-link
Oct 5, 2026
Merged

dmccoystephenson merged 1 commit into
mainfrom
feat/canonical-link

Conversation

@dmccoystephenson

Copy link
Copy Markdown
Member

Why

Each arcade game can be reached at up to three addresses: its slug host (overwinter.play.danielstephenson.dev), an old alias (overwinter.danielstephenson.dev), and the portal page that frames it (danielstephenson.dev/play/overwinter). Only the portal page declares a canonical URL and carries the VideoGame structured data. Neither arcade host says anything, so search engines see the same game three times and split its ranking across them.

What

  • registry.py: a new optional canonical: key holding an https URL. It is validated strictly, so it can't contain spaces, quotes or <>, the characters a header value would otherwise need escaped. Without the key nothing changes.
  • server.py: when the game has a canonical URL, every HTML response for it (slug host and aliases, GET and HEAD) carries Link: <url>; rel="canonical", the header form of a canonical link that Google and Bing honor. Assets, the API host, 404s and games without the key send no header. The value is reset on every request, the same way isolate is, so a reused keep-alive connection can't leak one game's header into another response.
  • Tests: HTML vs non-HTML on a static game, a tak game and its alias, no header without the key, keep-alive reuse, and five invalid URL shapes refused. The reset and the HTML-only check were each mutation-probed: removing either makes a test fail.

Rollout

games.yaml in the gateway rejects unknown keys, so the canonical: entries can only be added after this ships in a release and the gateway is on it. A follow-up gateway PR will add one line per game, pointing at https://danielstephenson.dev/play/<portal-slug>.

python -m pytest: 138 passed.


drafted by Claude on behalf of Daniel Stephenson

🤖 Generated with Claude Code

https://claude.ai/code/session_01BZQMN1M5hQKfUpPwDkMjqd

A game reachable at its slug host, an alias and the portal page that frames
it was indexed three times. The optional `canonical:` registry key adds
`Link: <url>; rel="canonical"` to the game's HTML responses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BZQMN1M5hQKfUpPwDkMjqd
@dmccoystephenson
dmccoystephenson merged commit 92e99cd into main Oct 5, 2026
3 checks passed
@dmccoystephenson
dmccoystephenson deleted the feat/canonical-link branch October 5, 2026 05:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant