跳转到内容

20260915-1901-astro-starlight-migration Rebuild the docs site on Astro + Starlight with on-demand rendering

  • status: completed
  • priority: P1
  • owner: claude/session-20260915-1901
  • completedAt: 2026-09-16 06:30
  • createdAt: 2026-09-15 19:01

The site is a VitePress 1.6.4 static build deployed to Cloudflare Workers as assets only. VitePress has no runtime rendering: it is build-time SSG plus a client SPA, with no dynamic routes, no request-time data loading and no access to Cloudflare bindings. Upcoming work needs dynamic content served from the same site, so the framework has to change.

Target: Astro 7 + Starlight, Cloudflare adapter, hybrid rendering. Starlight pages stay prerendered (prerender: true is its default even under output: 'server'), so the 294 existing Markdown pages keep today's cost and latency profile as static assets, and only routes that opt out with export const prerender = false execute in a Worker.

Acceptance criteria:

  1. Every URL the current build publishes still resolves, with no change to _redirects semantics.
  2. The generated explorer sidebar, breadcrumbs, frontmatter meta block, directory index pages and the generated docs/sitemap.md behave as they do today.
  3. Chinese full-text search is no worse than the current MiniSearch bigram tokenizer.
  4. The three Mermaid pages still render, with ELK layout.
  5. bun run docs:lint passes unchanged; the quality gate command still works.
  6. At least one route renders on demand in a Worker and can read a Cloudflare binding.
  7. Non-Markdown linked assets are still copied into the build output, with the 25 MiB guard intact.

Rebuilding the docs site on Astro + Starlight

  • blocked by: (none)
  • blocks: (none)

Plan: docs/plan/20260915-1901-astro-starlight-migration.md. The concrete dynamic feature is not yet specified; this task delivers the platform, not the feature.

  • campaignId: l1-5k89db54-20260915190438, project 7li8qh57, baseBranch main
  • L1 (coordination, main worktree, no cron): issue 5k89db54
  • L2-A yf6wxxkf - platform: scaffold, in-place content loader (G1), hybrid rendering (G4). Blocks B and C.
  • L2-B v61em621 - site shell: sidebar, breadcrumb, doc meta, CSS, Mermaid (G3). Held in todo until A merges.
  • L2-C fut7wvuf - build pipeline: search (G2), asset copy, redirects, URL parity, deploy. Held in todo until A merges.
  • G4 uses a runtime probe route only; no Cloudflare resource (D1/KV/R2) is provisioned in this campaign.
  • Removal of .vitepress/ is held in L2-C until L1 releases it after B merges.
  • 2026-09-16: G1 achieved. Astro 7.3.2 + Starlight 0.42.0 render all 287 pages in place from bizplan/ and docs/ at byte-identical URLs. docsLoader() is not used; a plain glob() loader (base ., patterns bizplan/**/*.md, docs/**/*.md, !docs/templates/**) with generateId stripping .md and a trailing /index preserves case and dots. git status --porcelain bizplan docs empty; 52-vs-52 empty route diff on a three-directory sample; docs:lint green with scripts/lint-docs.mjs unmodified.
  • Accepted deviations, recorded so they are not re-litigated:
    1. 61 of 287 pages carry no YAML frontmatter (all of docs/plan/ and docs/task/, plus docs/changelog.md and one file under docs/decisions/). A parseData wrapper injects title from the first # heading, mirroring the fallback .vitepress/site-tree.ts already uses. Downstream sidebar and meta code must tolerate absent kind/status.
    2. Astro 7.3.2 defaults to the Saetteri Markdown processor; markdown.remarkPlugins throws. The leading-H1 strip is an mdast plugin via markdown.processor: satteri({ mdastPlugins }), avoiding a second processor and the @astrojs/markdown-remark dependency.
    3. Starlight's own Markdown transforms only run under src/content/docs, so heading anchor links are missing for in-place content. Fixed by markdown.processedDirs: ['bizplan','docs'] in the Starlight options block; assigned to L2-B.
  • This BKD server parses six-field cron expressions (seconds first); */15 * * * * would mean every 15 seconds. Campaign crons use 0 */15 * * * *.
  • Open: the root index.md is a VitePress layout: home hero page with no Starlight equivalent and is excluded from the collection, so / has no page. Awaiting the owner's decision; assigned to L2-B either way.
  • 2026-09-16: Platform workstream merged twice. Second pass closed a site-wide regression the URL set diff could not see: Astro does not rewrite relative Markdown links, so 215 of 288 pages emitted in-site hrefs that 404. A mdast plugin now resolves each .md link against its linking file and maps it through the collection's own id rule, sharing one DOC_PATTERN with the loader so a link is only rewritten once its target is a published page. 1271 links rewritten; the residual is 4 external GitHub links plus one transient.
  • The body heading now outranks a diverging frontmatter title, restoring descriptive prose on 25 index pages that the leading-heading strip was deleting. Accepted cost: <title>, Pagefind result titles and prev/next labels carry the long form on those pages.
  • The content invariant is a commit-range diff against git merge-base main HEAD, not a fixed baseline: a fixed SHA reported L1's own PMA commits as workstream violations.