Skip to content
This repository was archived by the owner on Oct 13, 2026. It is now read-only.

feat(seo): per-page meta descriptions and markdown-free titles - #30

Merged
zz-plant merged 4 commits into
mainfrom
seo/canonical-og-sitemap
Oct 8, 2026
Merged

zz-plant merged 4 commits into
mainfrom
seo/canonical-og-sitemap

Conversation

@zz-plant

@zz-plant zz-plant commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #29, which merged before these two fixes landed. That PR left two gaps:

  • all 53 pages shared one meta description;
  • the cross-wiki-diff title showed literal backticks in <title> and og:title.

Each doc page now gets a description taken from its own text. Titles now use the H1's visible text.

Changes

  • Per-page descriptions. <meta name="description">, og:description and the TechArticle description come from the page's first prose paragraph after the H1:
    • only top-level paragraphs count, so lists, tables, code blocks, blockquotes and HTML blocks are skipped;
    • a paragraph must end a sentence (., ! or ?), which skips lead-ins such as "Use environment variables instead:";
    • bold-label callouts (**Quick start**: …, glossary entries **Claim** — …), parenthetical asides, "See [page] …" pointers and image-only paragraphs are skipped;
    • markdown and inline code formatting are stripped and whitespace collapsed. The text is cut at the last word boundary within 155 characters, with "…" added only when cut. The longest result is 156 characters.
  • Home page keeps the site description ("Refract — the open claim-history layer for public knowledge. …").
  • Fallback: a page with no usable paragraph uses the site description, and the build logs it. Today that is glossary only, because it is all **Term** — definition entries.
  • Titles. <title>, og:title, the JSON-LD headline and the search index use the visible text of the H1. "Tutorial: Cross-wiki comparison with `refract diff`" becomes "Tutorial: Cross-wiki comparison with refract diff". The body H1 still renders refract diff as code, and heading anchors are unchanged. Breadcrumb names come from docs/nav.json labels, not from the H1. None of those labels contains markdown, and the new test covers them.
  • Search index. Its excerpt now uses the same description. This replaces getExcerpt(), a regex excerpt that left list markers and ** in the text. For example, install's excerpt was "- Node.js 20+ or Bun v1.2+".
  • Tests (tests/seo.test.ts, 5 new):
    • <title> matches the visible H1 text;
    • the home page keeps the site description;
    • descriptions are unique apart from the listed fallbacks (index, glossary);
    • each description appears in its page's body text and, when cut, ends at a word boundary;
    • every description is 160 characters or fewer;
    • no backtick or asterisk appears in any title, description, OG value or JSON-LD string.

Sample descriptions:

Page Description
tutorials/fandom-canon Monitor how a Fandom wiki's canon pages change over time: when lore-critical statements appear, disappear, or are rewritten — and how editorial consensus…
interpretation Refract emits a deterministic event stream. This page explains how to read it.
mcp refract mcp starts a JSON-RPC server over stdio that exposes the Refract engine to AI agents via the Model Context Protocol. (wikihistory mcp also works.)

Pages whose first prose paragraph is a weak summary

The rule picks these paragraphs correctly, but the pages have no intro sentence, so the description describes one section rather than the page. A one-sentence intro under each H1 would fix them. That is a copy decision, so this PR leaves the markdown alone.

  • install: "Run the CLI as node packages/cli/dist/src/cli.js , …" (from the build-from-source section).
  • security: "When using --cache, revision content is persisted to ~/.wikihistory/refract.db …"
  • schema: "ModelInterpretation and modelInterpretation on EvidenceEvent are never set …"
  • quickstart: "By default, this fetches up to 20 recent revisions …" ("this" refers to a code block).
  • cli: "All commands work with wikihistory as a backward-compatible alias …"
  • faq: the rate-limit answer.
  • frontier-use-cases: "It does not report what a document says now. …"

Verification

  • npm run lint: no errors. The 3 warnings are the existing noDescendingSpecificity ones in assets/style.css.
  • npm test: 4 files, 75 tests pass (70 on main).
  • npm run build: 53 pages built, and it logs the one fallback page (glossary).
  • xmllint --noout dist/sitemap.xml passes with 53 URLs, and JSON-LD parses on all 53 pages.
  • Mutation checks: each of these makes the new tests fail:
    • raw H1 titles with backticks;
    • the site description on every page;
    • no length cap;
    • cutting mid-word;
    • raw markdown in descriptions.

Positioning line (commit 6965eec)

The site described Refract three ways. AGENTS.md says to "describe Refract as a deterministic observation engine", which is how the README leads, so that wording now appears everywhere it was stated:

Where Before After
Home H1 / <title> Refract: deterministic observation layer for model evaluation — Refract Refract: deterministic observation engine for revision histories
Site meta description Refract — the open claim-history layer for public knowledge. Deterministic event stream of claims, sources, and disputes across revision histories. A deterministic observation engine for revision histories. It reads a page's edits and emits a typed event for each change.
Sidebar tagline (every page) The open claim-history layer for public knowledge. A deterministic observation engine for revision histories.
Opening sentence, Why Refract and Concepts (now their meta descriptions) Refract is the open claim-history layer for public knowledge Refract is a deterministic observation engine for revision histories

The home subtitle, which mentions model evaluation as a use, is unchanged, and so are the model-evaluation pages. A title that already starts with "Refract" no longer gets a "— Refract" suffix. Lint, 75 tests and the build pass.

🤖 Generated with Claude Code

zz-plant and others added 4 commits October 8, 2026 00:48
Every built page now carries a canonical URL at the trailing-slash address
GitHub Pages serves it from, Open Graph and twitter:card tags, and one
JSON-LD block: WebSite plus SoftwareSourceCode on the home page, TechArticle
plus BreadcrumbList on doc pages. The build also writes dist/sitemap.xml
listing every page. It has no <lastmod> because the deploy checkout is
shallow and cannot date pages from git history.

Titles and the meta description are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in the squash merge of #29 so the follow-up PR only shows new changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each doc page's meta description, og:description and TechArticle
description now come from its first prose paragraph after the H1, trimmed
at a word boundary to 155 characters. Lists, tables, code, blockquotes,
images, lead-ins ending in a colon, bold-label callouts, asides and
"See ..." pointers are skipped. The home page keeps the site description,
as does any page with no usable paragraph; the build logs those (today:
glossary).

Titles in <title>, og:title, the JSON-LD headline and the search index use
the H1's visible text, so the cross-wiki-diff title loses its literal
backticks.

The search index excerpt now uses the same description, replacing the
regex-based getExcerpt(), which left list markers and ** in excerpts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The site described Refract three ways: the home H1 said "observation
layer for model evaluation", the meta description and sidebar said "the
open claim-history layer for public knowledge", and AGENTS.md says to
describe it as a deterministic observation engine, which is what the
README leads with. The home H1, the site description, the sidebar
tagline and the opening sentences of Why Refract and Concepts now use
the README line. Those openings are the pages' meta descriptions now.

The home <title> no longer appends "— Refract" to an H1 that already
starts with the name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zz-plant
zz-plant merged commit 880d31b into main Oct 8, 2026
1 check passed
@zz-plant
zz-plant deleted the seo/canonical-og-sitemap branch October 8, 2026 20:59
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant