seo: three pages shared one description and none had a canonical - #33
Merged
Conversation
`render.py` hardcoded a single sentence into the head of all three pages:
"Coverage and completeness counts over California's public wildfire datasets.
Unofficial." A search result for the DINS page and a search result for the
perimeters page were therefore indistinguishable, and neither said what its own
page counts. `page()` now takes a description per page, each restating what that
page already says of itself in its own standfirst.
The descriptions state NO count. The committed `site/` is built from `data/raw/`
and the test build is built from the fixtures, so a figure hardcoded in
`render.py` would be true of one build and false of the other. CONTRIBUTING's
rule is that a number is counted or it is not published, and these counts belong
to CAL FIRE's files, which change underneath us. Nothing here says how many
records, how many incidents or how much is covered.
There was also no canonical, and no Open Graph, on any page. These pages are one
of six project sites on the shared `chelseakr.github.io` origin, served from
PATHS rather than domains of their own, so the canonical a single-domain habit
produces ("/") is not this site's root: it is a different address, it 404s, and
all six sites would claim it. A crawler that believes them folds six unrelated
projects into one document. `SITE_URL` and `CANONICAL_PATH` are keyed by
`active`, the value each page already uses to mark its own nav entry, so the
canonical and the highlighted tab cannot disagree about which page this is.
No `og:image`: this repository ships no image, and inventing one would be adding
the first. `twitter:card` is `summary`, which promises none.
The page parser in `tests/test_pages_html.py` could not see any of this. It
recorded `name=` metas only, so every `property="og:..."` tag was invisible to
it, and `<link rel="canonical">` is not a meta tag at all. It now records both,
and the existing title-and-description checks were extended rather than joined
by a parallel SEO suite. `tests/test_published_site.py` gains the same assertion
over the COMMITTED bytes, beside the rooted-link check that already holds the
same subpath property for `href` and cannot catch a canonical, because a
canonical is an absolute URL rather than a rooted path.
Observed, by breaking it: canonical line deleted; `SITE_URL` set to the bare
origin; `CANONICAL_PATH` collapsed so all three pages share one canonical; and
the original defect restored, one description for all three. A fifth, hand
editing the committed `site/index.html` canonical to the shared origin, fails
the published-bytes check. Restored, `make verify` exits 0, including
html-validate, axe, the Playwright reflow specs and the determinism check.
`make site` was run from the real `data/raw/` files. Its diff is head-only:
every changed line is a `canonical`, `og:*`, `twitter:card` or `description`
tag, and not one published figure moved. A `make site` on the unmodified tree
beforehand produced an empty diff, so the committed figures already matched the
data.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ChelseaKR
force-pushed
the
seo/per-page-canonical-and-description
branch
from
August 29, 2026 16:47
fb96c9e to
c4422eb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
render.pyhardcoded one sentence into the head of all three pages:So a search result for the DINS page and a search result for the perimeters page were indistinguishable, and neither said what its own page counts. There was also no canonical and no Open Graph on any page.
What this changes
page()now takes adescriptionper page, each restating what that page already says of itself in its own standfirst, plus a canonical,og:*andtwitter:card.index.htmlhttps://chelseakr.github.io/perimeter/perimeters.htmlhttps://chelseakr.github.io/perimeter/perimeters.htmldins.htmlhttps://chelseakr.github.io/perimeter/dins.htmlSITE_URLandCANONICAL_PATHare keyed byactive, the value each page already uses to mark its own nav entry, so the canonical and the highlighted tab cannot disagree about which page this is.The descriptions state no count
Deliberately. The committed
site/is built fromdata/raw/; the test build is built from the fixtures. A figure hardcoded inrender.pywould be true of one build and false of the other. CONTRIBUTING's rule is that a number is counted or it is not published, and these counts belong to CAL FIRE's files, which change underneath us. Nothing added here says how many records, how many incidents, or how much is covered. Noog:imageeither: this repository ships no image, andtwitter:cardissummary, which promises none.Why a missing canonical matters more here
These pages are one of six project sites on the shared
chelseakr.github.ioorigin, served from paths rather than domains of their own. A canonical of/is not this site's root; it is a different address, it 404s, and all six sites would claim it.test_no_published_link_is_rooted_at_the_serveralready holds that property forhrefbut cannot catch a canonical, because a canonical is an absolute URL rather than a rooted path.The gate
The parser in
tests/test_pages_html.pyrecordedname=metas only, so everyproperty="og:..."tag was invisible to it and<link rel="canonical">is not a meta tag at all. It now records both. The existing title-and-description checks were extended, not joined by a parallel SEO suite.tests/test_published_site.pygains the same assertion over the committed bytes.index.html has no canonical URLSITE_URLset to the bare originindex.html points at the shared origin, which is a different siteCANONICAL_PATHcollapsed to one URLassert 1 == 3assert 1 == 3site/index.htmlcanonical hand-edited to the originindex.html canonicalises to 'https://chelseakr.github.io/'Restored,
make verifyexits 0, includinghtml-validate,axe, the Playwright reflow specs and the determinism check.make sitewas run from the real datamake siteon the unmodified tree first produced an empty diff, so the committed figures already matcheddata/raw/.site/diff is head-only: every changed line is acanonical,og:*,twitter:cardordescriptiontag. Not one published figure moved.Not changed
No repository setting, Pages config, ruleset or DNS. No
sitemap.xmlorrobots.txtwas added:robots.txtunder a project path is inert, because only the origin root is honoured andhttps://chelseakr.github.io/robots.txt404s.🤖 Generated with Claude Code