Skip to content

Mount docs under /docs/ so the 173 internal links resolve#34

Merged
LayerDynamics merged 1 commit into
mainfrom
site-docs-routing
Jun 8, 2026
Merged

Mount docs under /docs/ so the 173 internal links resolve#34
LayerDynamics merged 1 commit into
mainfrom
site-docs-routing

Conversation

@LayerDynamics

Copy link
Copy Markdown
Owner

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's slug: 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)

  • 89 content slugs → prefixed with docs/.
  • 15 root-relative links rewritten (6 in content, 9 in the landing page / Hero / QuickStart / CodeExample).
  • 4 sidebar slug entries in astro.config.mjs (the autogenerate directories are filesystem paths — unchanged).
  • 3 pre-existing dangling links fixed (surfaced by the link audit): /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.rs now emits slug: docs/crates/<name>.
  • New slug-prefix drift rule: every docs page slug must start with docs/, so any generator or hand-edit emitting a root slug fails CI instead of silently breaking navigation.

Test plan

  • npm run build succeeds — 91 pages; dist/index.html at root, docs under dist/docs/..., old root paths gone
  • Link integrity: all 57 unique internal /docs/ targets resolve to built pages (0 missing)
  • Drift gate in sync; forge-docs-check 17 rule fixtures + docs_sync + slug_prefix unit test
  • fmt --check + clippy -D warnings clean
  • CI inherits the rusty_v8 cache fix from main

On merge, deploy-site.yml redeploys (the change touches site/**).

🤖 Generated with Claude Code

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>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @LayerDynamics, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +50 to +60
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
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current frontmatter parser has two robustness issues:

  1. 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.
  2. Nested Key False Positives: Trimming leading whitespace (line.trim()) before checking for the slug: 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).

Suggested change
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
}

@LayerDynamics LayerDynamics merged commit 93eaf67 into main Jun 8, 2026
20 checks passed
LayerDynamics added a commit that referenced this pull request Jun 8, 2026
## 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)
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