diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index 2983a55..3a947de 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -75,6 +75,43 @@ export default defineConfig({
],
],
+ /**
+ * Per-page description, og:title and canonical.
+ *
+ * VitePress gives every page a unique
but leaves `description` and the
+ * og:* tags at whatever the site-level config says — so all 19 pages shipped
+ * the same meta description and the same og:title. Search Console reports that
+ * as duplicate metadata, the search snippet for every page is identical, and
+ * sharing a deep link shows the homepage's card no matter which page it is.
+ *
+ * `description` comes from page frontmatter, falling back to the site default.
+ */
+ transformPageData(pageData) {
+ const path = pageData.relativePath.replace(/(^|\/)index\.md$/, "$1").replace(/\.md$/, "");
+ const canonical = `${SITE}${base}${path}`;
+ const title = pageData.frontmatter.title ?? pageData.title;
+ const description = pageData.frontmatter.description ?? pageData.description;
+
+ pageData.frontmatter.head ??= [];
+ pageData.frontmatter.head.push(
+ ["link", { rel: "canonical", href: canonical }],
+ ["meta", { property: "og:url", content: canonical }],
+ );
+ if (title) {
+ const scoped = path === "" ? "resilix — load limiting for JavaScript" : `${title} · resilix`;
+ pageData.frontmatter.head.push(
+ ["meta", { property: "og:title", content: scoped }],
+ ["meta", { name: "twitter:title", content: scoped }],
+ );
+ }
+ if (description) {
+ pageData.frontmatter.head.push(
+ ["meta", { name: "description", content: description }],
+ ["meta", { property: "og:description", content: description }],
+ );
+ }
+ },
+
themeConfig: {
siteTitle: "resilix",
outline: [2, 3],
diff --git a/docs/decisions.md b/docs/decisions.md
index 2d7acbd..10627e2 100644
--- a/docs/decisions.md
+++ b/docs/decisions.md
@@ -1,3 +1,7 @@
+---
+description: "Why resilix is shaped the way it is — sixteen design decisions with the alternatives that were rejected. Every ADR-00N comment in the source resolves here."
+---
+
# Design decisions
Why resilix is shaped the way it is. Source comments cite these by number (`ADR-007`), so this
diff --git a/docs/guide/breaker.md b/docs/guide/breaker.md
index c3f28b7..2e66d23 100644
--- a/docs/guide/breaker.md
+++ b/docs/guide/breaker.md
@@ -1,3 +1,7 @@
+---
+description: "Three trip conditions — failure rate, slow-call rate and a consecutive backstop — over a dual-bound window, and an honest account of when a circuit breaker is the wrong tool."
+---
+
# Circuit breaker
diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md
index 7961eeb..fb7fa47 100644
--- a/docs/guide/getting-started.md
+++ b/docs/guide/getting-started.md
@@ -1,3 +1,7 @@
+---
+description: "Install resilix and build your first pipeline: slow-call circuit breaking, marking time-to-first-byte on streams, and classifying SQL errors correctly."
+---
+
# Getting started
```bash
diff --git a/docs/guide/hedging.md b/docs/guide/hedging.md
index aeb9b2d..1dd0b50 100644
--- a/docs/guide/hedging.md
+++ b/docs/guide/hedging.md
@@ -1,3 +1,7 @@
+---
+description: "Hedged requests at the measured p95, Netflix's four criticality buckets, and relative per-tenant fairness that needs no quota to configure."
+---
+
# Hedging, criticality and fairness
diff --git a/docs/guide/index.md b/docs/guide/index.md
index 7616acf..7464503 100644
--- a/docs/guide/index.md
+++ b/docs/guide/index.md
@@ -1,3 +1,7 @@
+---
+description: "Why resilix exists: JavaScript's load limiting is locked inside gRPC and the AWS SDK, and a failure-rate circuit breaker is blind to an upstream that degrades without erroring."
+---
+
# What resilix is
diff --git a/docs/guide/limiter.md b/docs/guide/limiter.md
index a9e79e4..8664ae6 100644
--- a/docs/guide/limiter.md
+++ b/docs/guide/limiter.md
@@ -1,3 +1,7 @@
+---
+description: "Adaptive concurrency limiting for JavaScript: Vegas queue estimation over an O(1) P² quantile estimator, shedding load proportionally rather than at a cliff."
+---
+
# Adaptive concurrency limiting
diff --git a/docs/guide/manual-control.md b/docs/guide/manual-control.md
index 6f49050..7360284 100644
--- a/docs/guide/manual-control.md
+++ b/docs/guide/manual-control.md
@@ -1,3 +1,7 @@
+---
+description: "Drive resilix policies by hand with gate(). Every policy is a synchronous state machine, so it works from a stream consumer or a queue worker."
+---
+
# Driving policies by hand
diff --git a/docs/guide/opossum.md b/docs/guide/opossum.md
index cd45dfc..59550eb 100644
--- a/docs/guide/opossum.md
+++ b/docs/guide/opossum.md
@@ -1,3 +1,7 @@
+---
+description: "Migrate from opossum in one line. The compatibility shim passes 362 of 362 of opossum's own test suite, run unmodified."
+---
+
# Migrating from opossum
diff --git a/docs/guide/reading-the-code.md b/docs/guide/reading-the-code.md
index eb67c75..ab9004f 100644
--- a/docs/guide/reading-the-code.md
+++ b/docs/guide/reading-the-code.md
@@ -1,3 +1,7 @@
+---
+description: "A map from every source file to the paper or chapter behind it, and a dependency-ordered path through the codebase."
+---
+
# Reading the code
Every non-obvious number and control loop in resilix came from somewhere. This page is the index
diff --git a/docs/guide/retry.md b/docs/guide/retry.md
index 768e850..f92968a 100644
--- a/docs/guide/retry.md
+++ b/docs/guide/retry.md
@@ -1,3 +1,7 @@
+---
+description: "Retry with full jitter, shared budgets that hold amplification near 1.1x instead of 3x, Google SRE client-side throttling, and a token-bucket rate limiter."
+---
+
# Retry, budgets and throttling
diff --git a/docs/guide/roadmap.md b/docs/guide/roadmap.md
index 25bc87a..1019afd 100644
--- a/docs/guide/roadmap.md
+++ b/docs/guide/roadmap.md
@@ -1,3 +1,7 @@
+---
+description: "What has shipped in each resilix version, what is coming next, and what is deliberately not planned."
+---
+
# Roadmap
resilix is **pre-release**. The public API is settling but not frozen; anything user-visible
diff --git a/docs/guide/telemetry.md b/docs/guide/telemetry.md
index 931b522..8e2e298 100644
--- a/docs/guide/telemetry.md
+++ b/docs/guide/telemetry.md
@@ -1,3 +1,7 @@
+---
+description: "Built-in OpenTelemetry instrumentation: counters, histograms and pull-based gauges, with an observer that can neither influence nor break an admission decision."
+---
+
# Telemetry
diff --git a/docs/guide/undici.md b/docs/guide/undici.md
index 29967f4..551b402 100644
--- a/docs/guide/undici.md
+++ b/docs/guide/undici.md
@@ -1,3 +1,7 @@
+---
+description: "Compose resilix onto undici's Dispatcher and every call site in the process is guarded at once, including ones you do not own."
+---
+
# Guarding undici
`resilix/fetch` covers the WHATWG API, but Node services overwhelmingly reach the network through
diff --git a/docs/guide/verdicts.md b/docs/guide/verdicts.md
index d6b8f76..2f6bf82 100644
--- a/docs/guide/verdicts.md
+++ b/docs/guide/verdicts.md
@@ -1,3 +1,7 @@
+---
+description: "One settled call, read differently by each policy. Why a 404 is healthy, a 429 is backpressure, and our own rejections are never evidence about the upstream."
+---
+
# The verdict model
diff --git a/docs/specs/adaptive-limiter.md b/docs/specs/adaptive-limiter.md
index ff4e78c..b45e96f 100644
--- a/docs/specs/adaptive-limiter.md
+++ b/docs/specs/adaptive-limiter.md
@@ -1,3 +1,7 @@
+---
+description: "The v0.3 spec: Vegas queue estimation, P² streaming quantiles, the baseline problem, and every default with its source."
+---
+
# Spec: adaptive concurrency limiter (v0.3)
**Status:** implemented in v0.3.
diff --git a/docs/specs/hedging-and-priority.md b/docs/specs/hedging-and-priority.md
index 2c60177..2b0908b 100644
--- a/docs/specs/hedging-and-priority.md
+++ b/docs/specs/hedging-and-priority.md
@@ -1,3 +1,7 @@
+---
+description: "The v0.5 spec: hedged requests, Netflix criticality buckets, and relative tenant fairness."
+---
+
# Spec: hedging, criticality and tenant fairness (v0.5)
**Status:** implemented in v0.5. Two of the four open questions are now resolved; see §7.
diff --git a/docs/specs/index.md b/docs/specs/index.md
index ccb80d0..49d4a8a 100644
--- a/docs/specs/index.md
+++ b/docs/specs/index.md
@@ -1,3 +1,7 @@
+---
+description: "Design specs written before the code they describe, each carrying the provenance of every default it proposes."
+---
+
# Specs
A spec is the *how* — the algorithm, the field list, the edge cases, the provenance of every
diff --git a/docs/specs/retry-and-throttling.md b/docs/specs/retry-and-throttling.md
index 83e6233..dd3ae70 100644
--- a/docs/specs/retry-and-throttling.md
+++ b/docs/specs/retry-and-throttling.md
@@ -1,3 +1,7 @@
+---
+description: "The v0.4 spec: jitter strategies, retry budget arithmetic, and Google SRE's client-side throttling formula."
+---
+
# Spec: retry, budgets, throttling and rate limiting (v0.4)
**Status:** implemented in v0.4.