Skip to content

chore(docs): fix broken anchors + homepage meta + dup calculator title#610

Merged
amavashev merged 2 commits intomainfrom
chore/fix-broken-anchors-homepage-meta-dup-titles
May 9, 2026
Merged

chore(docs): fix broken anchors + homepage meta + dup calculator title#610
amavashev merged 2 commits intomainfrom
chore/fix-broken-anchors-homepage-meta-dup-titles

Conversation

@amavashev
Copy link
Copy Markdown
Contributor

Summary

PR A from the second-pass audit (2026-05-09). Three independent fixes bundled — all P1/P2 surgical edits, no semantic changes.

1. Broken internal anchors (13 unique, 19 link instances)

Wrote .scripts/anchor-scan.mjs to parse all id="..." attrs from the built HTML and report any markdown link with #anchor whose target lacks that id. The pre-PR scan reported 24 broken anchors; 11 are scanner false positives (9 calculator state-encoded #s=eyJ... URLs which are intentional client-side state, and 2 relative-path links the scanner can't resolve). The other 13 are real and fixed.

Slug typos / drift:

Link Fix Sources
#starting-a-new-billing-period-reset_spent #starting-a-new-billing-period-reset-spent (slugifier replaces _-) 3× from troubleshooting-and-faq.md
#balance-polling-alerts-no-custom-metric-required #balance-polling-alerts-for-signals-without-a-counter (section renamed) 2× from incidents/*
#pillar-4-events--webhooks-v0125 #pillar-4-events-webhooks-v0-1-25 (slugifier strips & and splits the version number) 1× from security.md
#try-it-without-a-server #dry-run-mode (target section was renamed) 1× from blog
#observability-with-metricsemitter-v050 #observability-with-otlp-metrics-v0-5-0 (target section was renamed in v0.5.0 release) 1× from blog

Stable explicit anchors (target slug fragile or contains unicode em dash):

  • how-to/api-key-management-in-cycles.md: added <a id="available-permissions"> before ### Available permissions (27 total). The (27 total) count was leaking into the slug, so the count-bumps would silently break inbound links. 3 inbound links resolved by this single anchor.
  • how-to/troubleshooting-and-faq.md: added <a id="spring-boot-illegalstateexception-nested-cycles"> before ### Spring Boot: IllegalStateException — nested @Cycles. The em dash in the heading slugified to a literal character in the rendered id (spring-boot-illegalstateexception-—-nested-cycles), which the link-as-written can't reach.

Stale reference dropped:

  • how-to/handling-streaming-responses-with-cycles.md:244 referenced #programmatic-cycleslient — typo and the spring-boot starter page has no such section. Reworded to link to the page generally; the section can be added later if programmatic-CyclesClient docs ever land for the starter.

2. Homepage description (P2)

index.md had no description: in frontmatter, so the homepage fell back to the site-wide default defined in .vitepress/config.ts:641. The home page is the single most-trafficked page; it should not share its description with every other page that omits one.

Added: "Runtime authority for autonomous AI agents — pre-execution gating on cost, risk, and tool actions. Open protocol, self-hosted, Apache 2.0." (140 chars, under SEO budget).

3. Duplicate calculator titles (P2)

calculators/ai-agent-blast-radius-risk.md and calculators/ai-agent-blast-radius-standalone.md both used the exact title "AI Agent Blast Radius Risk Calculator". Two indexable URLs competing for the same SERP slot.

Renamed the standalone variant to "AI Agent Blast Radius Calculator (Full Screen)" with a distinct description ("Full-screen interactive calculator for AI agent blast radius — reversibility, visibility, audience size, with an editable runtime-authority containment factor."). Risk variant (the docs page that hosts the marketing copy + embedded calc) keeps its original title.

Tooling: .scripts/anchor-scan.mjs

Standalone, ~50 lines, no dependencies. Walks .vitepress/dist/*.html for id="..." attrs and walks all .md source for [text](path#anchor) links; reports anchors not present in the target page's id set. Mirrors the precedent set by .scripts/link-audit.mjs and the other one-shot maintenance scripts already in .scripts/. Useful for future audit rounds.

Verification

  • vitest run — 90/90 pass
  • vitepress build — clean
  • anchor-scan output: 24 broken → 11 (all 11 remaining are scanner false positives by inspection)
  • Rendered HTML for homepage shows the new description in <meta name="description"> and <meta property="og:description">
  • Rendered HTML for both calculator pages shows distinct titles
  • Manual smoke test on deployed preview: click each fixed anchor and confirm it lands on the right section

Out of scope

P1 #2 (truncation sweep — 87 titles + 73 descriptions over budget) and P2 #5 (Person vs Organization in JSON-LD) are deferred to follow-up PRs, as proposed in the evaluation. P1 #1 (PDF links) is mostly a false positive — the deployed site has the PDFs, only npm run build (without :with-pdfs) misses them.

amavashev added 2 commits May 9, 2026 07:34
Three independent fixes from the second-pass audit (2026-05-09):

1) Broken anchors (P1). Wrote .scripts/anchor-scan.mjs and ran it
against the built HTML. Found 13 unique broken internal anchors (24
link instances when counting duplicates across source files); the
remaining scanner output is calculator state-encoded `#s=eyJ...` URLs
and one relative-path link my scanner can't resolve — both false
positives. Fixed:

  Slug typos / drift:
    /how-to/budget-allocation-and-management-in-cycles
      #starting-a-new-billing-period-reset_spent → -reset-spent
      (3× from troubleshooting-and-faq.md — slugifier replaces _ with -)

    /how-to/monitoring-and-alerting
      #balance-polling-alerts-no-custom-metric-required
      → #balance-polling-alerts-for-signals-without-a-counter
      (2× from incidents/* — section was renamed)

    /admin-api/guide
      #pillar-4-events--webhooks-v0125 → -events-webhooks-v0-1-25
      (1× from security.md — slugifier strips `&` and splits version
      number with hyphens)

    /how-to/integrating-cycles-with-openclaw
      #try-it-without-a-server → #dry-run-mode (1× from blog)
      #observability-with-metricsemitter-v050
      → #observability-with-otlp-metrics-v0-5-0 (1× from blog)

  Stable explicit anchors (target heading slug is fragile or contains
  unicode em dash that doesn't survive slugify the same way the link
  expects):
    how-to/api-key-management-in-cycles.md: <a id="available-permissions">
      before `### Available permissions (27 total)` — slug carried the
      `(27 total)` count which is fragile (3 inbound links).
    how-to/troubleshooting-and-faq.md:
      <a id="spring-boot-illegalstateexception-nested-cycles">
      before `### Spring Boot: IllegalStateException — nested @Cycles`
      — em dash got slugified to a literal `—` char in the rendered id.

  Stale reference (target section never existed):
    how-to/handling-streaming-responses-with-cycles.md:244 referenced
    `#programmatic-cycleslient` — typo, AND the spring-boot starter
    page has no such section. Reworded to point at the page generally;
    section can be added later if/when programmatic CyclesClient docs
    land for the starter.

2) Homepage description (P2). index.md had no `description:` in
frontmatter, so the home page fell back to the site-wide default
defined in .vitepress/config.ts. Added an intentional description
matching the page's hero copy: "Runtime authority for autonomous
AI agents — pre-execution gating on cost, risk, and tool actions.
Open protocol, self-hosted, Apache 2.0." (140 chars; under SEO
budget).

3) Duplicate calculator titles (P2). calculators/ai-agent-blast-radius-
risk.md and calculators/ai-agent-blast-radius-standalone.md both used
the exact title "AI Agent Blast Radius Risk Calculator". Renamed the
standalone variant to "AI Agent Blast Radius Calculator (Full Screen)"
with a distinct description, so the two pages don't compete for the
same SERP slot. Risk variant (the docs page) keeps the original title
unchanged.

Tooling: .scripts/anchor-scan.mjs is a one-shot scanner that parses
all id="..." attrs from .vitepress/dist/*.html and reports any markdown
link with a `#anchor` whose target page lacks that id. Useful for
future audits; ~50 lines, no dependencies.

Verified:
- vitest 90/90 pass
- vitepress build clean
- anchor-scan: 24 broken → 11 (all 11 are scanner false positives —
  9 calculator state URLs, 2 relative-path resolution gaps).
- Homepage description in rendered HTML: meta + og:description both
  reflect the new value (was: default fallback).
- Standalone calculator: <title>"AI Agent Blast Radius Calculator
  (Full Screen) — Cycles"</title>; risk variant unchanged at "AI
  Agent Blast Radius Risk Calculator — Cycles".
@amavashev amavashev merged commit 54a6fab into main May 9, 2026
5 checks passed
@amavashev amavashev deleted the chore/fix-broken-anchors-homepage-meta-dup-titles branch May 9, 2026 11:38
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