Mount docs under /docs/ so the 173 internal links resolve#34
Conversation
The site serves a marketing landing page at `/` (src/pages/index.astro) and the Starlight docs were intended to live under `/docs/` — every internal doc link is authored as `](/docs/...)`. But Starlight derives each page's URL from its `slug:` frontmatter, and all 89 pages had root slugs (`crates/forge`, `api/runtime-fs`), so the docs rendered at the site root (`/crates/forge/`) and all ~173 `/docs/` links 404'd. (`base:` was never set; this never worked since the site landed.) Mount the docs under `/docs/` to match the authored links: - Prefix all 89 content `slug:` values with `docs/`. - Rewrite the 15 root-relative links that pointed straight at root doc paths (6 in content, 9 in the landing page / Hero / QuickStart / CodeExample). - Update the 4 explicit sidebar slug entries in astro.config.mjs (the `autogenerate` directories are filesystem paths and are unchanged). - Fix 3 pre-existing dangling links surfaced by the link audit: two `/docs/crates/forge-cli` -> `/docs/crates/forge` (the CLI page is forge.md), and `/docs/guides/permissions` -> `/docs/internals` (no permissions guide exists; internals.md has the Capabilities & Permissions section). Durability (keep the pipeline self-maintaining): - cratepage.rs now emits `slug: docs/crates/<name>` for generated crate pages. - New `slug-prefix` drift rule: every docs page slug must start with `docs/`, so any generator or hand edit that emits a root slug fails CI instead of silently breaking site navigation. (forge-etch's single-page generator has no production caller — committed API pages are maintained via the forge:api markers — so the rule guards it without a forge-etch refactor.) Verification: `npm run build` succeeds (91 pages); landing at `/`, docs under `/docs/`, old root paths gone; all 57 unique internal `/docs/` link targets resolve to built pages (0 missing). Drift gate in sync; forge-docs-check 17 rule fixtures + docs_sync + slug_prefix unit test; fmt + clippy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @LayerDynamics, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
There was a problem hiding this comment.
Code Review
This pull request introduces a new documentation check, slug-prefix, which ensures that all markdown and MDX documentation pages are served under the /docs/ path to prevent broken links and 404 errors. Along with the check and its tests, the PR updates all existing documentation files, Astro components, and configuration files to prepend docs/ to their slugs and internal links. Feedback on the implementation highlights potential robustness issues in the frontmatter parser, specifically regarding UTF-8 BOM handling and nested key false positives, and provides a suggestion to address them.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| fn frontmatter_slug(src: &str) -> Option<String> { | ||
| let body = src.strip_prefix("---")?; | ||
| let end = body.find("\n---")?; | ||
| for line in body[..end].lines() { | ||
| let line = line.trim(); | ||
| if let Some(rest) = line.strip_prefix("slug:") { | ||
| return Some(rest.trim().trim_matches(['"', '\'']).to_string()); | ||
| } | ||
| } | ||
| None | ||
| } |
There was a problem hiding this comment.
The current frontmatter parser has two robustness issues:
- UTF-8 BOM Bypass: If a markdown file starts with a UTF-8 Byte Order Mark (
\u{FEFF}),strip_prefix("---")will fail, causing the file to be silently skipped by this check. - Nested Key False Positives: Trimming leading whitespace (
line.trim()) before checking for theslug:prefix means nested keys (e.g., inside a description block or a nested YAML object) will be incorrectly parsed as the page's slug.
We can fix both issues by stripping the BOM if present and matching slug: only at the start of the line (without trimming leading whitespace).
| fn frontmatter_slug(src: &str) -> Option<String> { | |
| let body = src.strip_prefix("---")?; | |
| let end = body.find("\n---")?; | |
| for line in body[..end].lines() { | |
| let line = line.trim(); | |
| if let Some(rest) = line.strip_prefix("slug:") { | |
| return Some(rest.trim().trim_matches(['"', '\'']).to_string()); | |
| } | |
| } | |
| None | |
| } | |
| fn frontmatter_slug(src: &str) -> Option<String> { | |
| let src = src.strip_prefix("\u{feff}").unwrap_or(src); | |
| let body = src.strip_prefix("---")?; | |
| let end = body.find("\n---")?; | |
| for line in body[..end].lines() { | |
| if let Some(rest) = line.strip_prefix("slug:") { | |
| return Some(rest.trim().trim_matches(['"', '\'']).to_string()); | |
| } | |
| } | |
| None | |
| } |
## Summary Removes the deprecated `runtime:ui` documentation. It's a **phantom** — no `crates/ext_ui`, no `sdk/runtime.ui.ts` — it only documented a legacy alias of `runtime:window`. For v1 with no users, the deprecated surface is noise. > This is the runtime:ui removal that was meant to ride with #34 but got orphaned: #34 was merged at its earlier commit (`55029c0`, routing only), so this change never reached `main`. Cherry-picked clean onto current `main` as a standalone, non-stacked PR. ## Changes - **Delete** `site/src/content/docs/api/runtime-ui.md` (−435 lines; `runtime-window.md` already documents windows/dialogs/menus/tray comprehensively). - Repoint every reference to `runtime:window` with **verified** export names: homepage `CodeExample` (`openWindow`→`createWindow`), `Hero` nav, `Footer` API link, and `runtime-updater.md`'s example (`showDialog` → the real `dialog.message({ kind, title, message, buttons }) → Promise<number>`). - Also fixes 4 Footer links that used object syntax (`href: '/getting-started/'`) — missed by #34's `href="..."` rewrite — now under `/docs/`. ## Test plan - [x] `npm run build` → 90 pages, no errors; `runtime-ui` gone from `dist`, `runtime-window` present - [x] Link integrity: all 57 unique `/docs/` targets resolve (0 missing); zero `runtime:ui`/`runtime-ui` refs; zero root-relative doc links - [x] Drift gate in sync; every remaining API page has a backing SDK module (no other phantoms) Note: no PR-level CI builds the Astro site (deploy-site runs only on merge to `main`), so the build was verified locally. On merge, `deploy-site.yml` redeploys. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Problem
The docs site is up, but ~173 internal links 404. The site has a marketing landing page at
/(src/pages/index.astro) and the Starlight docs were intended to live under/docs/— every cross-link is authored as](/docs/...). But Starlight derives each URL from the page'sslug:frontmatter, and all 89 pages had root slugs (crates/forge,api/runtime-fs), so docs rendered at the site root (/crates/forge/) and the/docs/links never resolved.base:was never set — this never worked since the site landed.Verified live before the fix:
https://forge-deno.com/docs/crates/forge/→ 404,https://forge-deno.com/crates/forge/→ 200.Fix — mount the docs under
/docs/(match the authored links, don't dumb them down to root)docs/.astro.config.mjs(theautogeneratedirectories are filesystem paths — unchanged)./docs/crates/forge-cli→/docs/crates/forge(×2),/docs/guides/permissions→/docs/internals.Result: landing page stays at
/; docs move to/docs/crates/forge/,/docs/getting-started/,/docs/api/runtime-fs/, etc.Durability (keeps the pipeline self-maintaining)
cratepage.rsnow emitsslug: docs/crates/<name>.slug-prefixdrift rule: every docs page slug must start withdocs/, so any generator or hand-edit emitting a root slug fails CI instead of silently breaking navigation.Test plan
npm run buildsucceeds — 91 pages;dist/index.htmlat root, docs underdist/docs/..., old root paths gone/docs/targets resolve to built pages (0 missing)forge-docs-check17 rule fixtures +docs_sync+slug_prefixunit testfmt --check+clippy -D warningscleanrusty_v8cache fix frommainOn merge,
deploy-site.ymlredeploys (the change touchessite/**).🤖 Generated with Claude Code