mirror of
https://github.com/paperclipai/paperclip-docs.git
synced 2026-11-07 06:16:07 -10:00
# PR1 — server-render the docs root and split it from interior routes (Phase 1) **Do not merge — Dotta alone may merge.** This PR is opened for review only, per the hard write-gate on the approved plan. ## Provenance | item | link | |---|---| | Accepted plan | [PAP-16672 · plan document](https://paperclip-dev.tail29c1aa.ts.net/PAP/issues/PAP-16672#document-plan) | | Phase 0 review packet | [PAP-16671 · packet comment](https://paperclip-dev.tail29c1aa.ts.net/PAP/issues/PAP-16671#comment-f653273d-6450-4f8d-bcd6-f805ad28b923) | | Implementation candidate | [PAP-16682](https://paperclip-dev.tail29c1aa.ts.net/PAP/issues/PAP-16682) | | Independent QA — **PASS** | [PAP-16683](https://paperclip-dev.tail29c1aa.ts.net/PAP/issues/PAP-16683) | | Finalization / this PR | [PAP-16684](https://paperclip-dev.tail29c1aa.ts.net/PAP/issues/PAP-16684) | | Full evidence gallery (screenshots + raw JSON probes) | https://pages.paperclip.ing/pap-16684-pr1-evidence/ | Base: approved `main` @ `2ab76e8e4`. Head: `f5bbba24c` (exactly one commit on top; `main` has not moved). ## What changed - **1.1 — root-only landing shell.** The hero is *physically absent* from interior documents (removed at build time, not CSS/JS/ARIA hidden); the build throws if removal fails. Header, footer, search, sidebar, breadcrumbs and article nav are preserved on every page. - **1.2 — server-rendered homepage directory** generated from the same canonical `site/content.json` manifest that already feeds the sidebar, breadcrumbs, prev/next, routes and sitemap. No second URL manifest was introduced. - **Single descriptive H1 per interior page** (was 2 — the hero H1 bled onto every route). - **Truthful runtime UI.** `Loading…` / `Could not load this guide.` no longer ship inside success HTML; they are produced only by `app.js` at runtime on the empty, `hidden` `#runtime-status` mount, so they can only appear during a genuine client transition or failure. ``` scripts/verify-static-routes.mjs | 200 +++++++++++++++++++++++++++++++++- site/app.js | 90 ++++++++++++---- site/build-release.mjs | 189 ++++++++++++++++++++++++++++++-- site/index.html | 17 ++-- site/styles.css | 70 ++++++++++- 5 files changed, 528 insertions(+), 38 deletions(-) ``` `.site/` is **generated build output and remains uncommitted** (gitignored): `git ls-files | grep '^\.site/'` → 0 files. ## Before → after, raw HTTP/HTML for the six representative routes Both trees built with the identical command and base path, then served by a production-equivalent static server (real 404 status, honors `_redirects`). "Before" is a real build of approved `main` @ `2ab76e8e4`. | route | HTTP | content type | H1 count before → **after** | H1 text (after) | `id="landing"` before → after | `Loading…` | `Could not load this guide.` | internal directory anchors | |---|---|---|---|---|---|---|---|---| | `/` | 200 | `text/html` | 1 → **1** | Everything you need to run Paperclip. | 1 → 1 (root-only ✓) | 1 → **0** | 1 → **0** | 4 → **184** | | `/guides/welcome/what-is-paperclip/` | 200 | `text/html` | 2 → **1** | What is Paperclip? | 1 → **0** | 1 → **0** | 1 → **0** | 4 → 4 | | `/reference/api/overview/` | 200 | `text/html` | 2 → **1** | API Overview | 1 → **0** | 1 → **0** | 1 → **0** | 4 → 4 | | `/how-to/add-mcp-server-to-agent/` | 200 | `text/html` | 2 → **1** | Add an MCP server to an agent's toolkit | 1 → **0** | 1 → **0** | 1 → **0** | 4 → 4 | | `/reference/changelog/` | 200 | `text/html` | 2 → **1** | Documentation Changelog | 1 → **0** | 1 → **0** | 1 → **0** | 4 → 4 | | `/guides/welcome/this-route-does-not-exist/` | **404** | `text/html; charset=utf-8` | 1 → **1** | Not found | 0 → 0 | 0 → 0 | 0 → 0 | 0 → 0 | Machine-readable probes: [before-raw.json](https://pages.paperclip.ing/pap-16684-pr1-evidence/before-raw.json) · [after-raw.json](https://pages.paperclip.ing/pap-16684-pr1-evidence/after-raw.json). ### Homepage bleed and false state — absence proof - `id="landing"` returns **zero** matches in every interior document. Only inlined `#landing-*` **CSS selector text** remains (stylesheet, not markup). - Interiors carry no directory manifest (4 internal anchors — the footer); the 184-anchor directory is root-only. - The two false-state phrases appear in **0** built HTML files across the whole bundle. ### 404 / noindex / sitemap - Real HTTP **404** for the nonexistent route (root base and `/paperclip-docs/` subpath build). - `404.html`: exactly one `<h1>Not found</h1>`, `<meta name="robots" content="noindex, nofollow">`, `<title>Not found | Paperclip Docs</title>`. - Absent from `sitemap.xml` (0 occurrences); no built file for the route. - `sitemap.xml` has 184 `<loc>` (183 routes + root) and the root directory anchor set covers **183/183** non-root sitemap routes — 0 missing. - `_redirects` contains **no wildcard `200` rewrite** (0 lines with a `200` status), so unknown routes cannot be masked as success. - `robots.txt`: `User-agent: * / Allow: /` + `Sitemap: https://docs.paperclip.ing/sitemap.xml`. ## Focused checks — rerun on the final revision (`f5bbba24c`) | command | result | |---|---| | `npm run docs:test:static-routes` | **PASS** — "Static route verification passed (5 representative routes + /guides/welcome/this-route-does-not-exist/, root and /paperclip-docs/ builds)." | | `npm run docs:build` | **PASS** — "Generated 183 crawlable route pages plus sitemap.xml and robots.txt." | `git status` is clean after the build (no generated output enters the tree). ## Browser matrix — desktop 1440×900 and mobile 390×844 Run with Playwright + Chromium 1228. The QA sandbox could not exercise this (blank-glyph text rendering); the root cause turned out to be that **no fonts are installed on the host at all** — installing DejaVu TTFs with a minimal fontconfig makes text render correctly, which unblocked the full interactive matrix here. Screenshots: https://pages.paperclip.ing/pap-16684-pr1-evidence/ ### Per-route, JavaScript enabled (both viewports) All six routes on both viewports: expected HTTP status, **exactly 1 `<h1>`** with the correct text, `#landing` present **only** on `/`, no `Loading`/`Could not load this guide.` text in the rendered body, `#runtime-status` hidden, **no horizontal overflow**. ### Interactive | check | result | |---|---| | root directory link → interior (client nav) | ✅ `/guides/welcome/what-is-paperclip/`, single H1 "What is Paperclip?", hero gone, not stuck loading | | direct load vs client-nav parity | ✅ identical H1 set | | back / forward history | ✅ back → `/` with hero restored; forward → interior with correct H1 | | home nav from an interior doc | ✅ `/` with hero | | theme toggle | ✅ toggles (`dark` → light) | | desktop sidebar / TOC / breadcrumbs / prev-next / search / footer | ✅ 191 sidebar links, 14 TOC links, breadcrumbs rendered, article nav present, search control present, 15 footer links | | mobile drawer | ✅ opens (screenshot `mobile-drawer-open.png`) | | mobile horizontal scroll | ✅ none | | unknown route | ✅ 404 page, single H1, noindex | ### JavaScript disabled | check | result | |---|---| | `/` directory usable with JS off | ✅ 202 anchors present in raw markup; hero + card directory fully rendered | | clicking a directory link with JS off | ✅ full page load to `/reference/api/overview/` | | that interior page with JS off | ✅ 1 H1 ("API Overview"), no hero, no false loading/error state, 6368 chars of real article text | | mobile with JS off | ✅ root and interior both render correctly | ### Console / network No JavaScript errors and no page errors on any route. Exactly two non-2xx requests, **both reproduced identically on approved `main` @ `2ab76e8e4`** — neither is introduced by this PR: - `GET /redirects.json` → 404. Pre-existing: neither the before nor after build emits this file. Verified byte-for-byte identical behaviour on `main`. - `GET https://api.github.com/repos/paperclipai/paperclip` → 403. Unauthenticated GitHub API rate limit for the header star counter; environmental, external, not a product defect. Also confirmed unchanged before → after on the same interior page: header (1), footer (1), search controls (4), sidebar links (191), TOC links (14), article nav (2), article text length (4328 chars). The **only** rendered difference is the intended H1 2 → 1 and the removed hero. ## Verified against the real Cloudflare Pages deploy, not just a local server The Cloudflare Pages check on this PR is **green** and produced a live preview: **https://pap-16682-server-render-root.paperclip-docs-74t.pages.dev** I reran the entire matrix against that real deploy. Every invariant reproduces **identically** to the local run — so these results hold on actual production hosting, including Cloudflare's own 404 handling: | route | HTTP | H1 | `#landing` | `Loading…` | `Could not load…` | noindex | anchors | |---|---|---|---|---|---|---|---| | `/` | 200 | 1 — Everything you need to run Paperclip. | present (root-only) | 0 | 0 | – | 184 | | `/guides/welcome/what-is-paperclip/` | 200 | 1 — What is Paperclip? | absent | 0 | 0 | – | 4 | | `/reference/api/overview/` | 200 | 1 — API Overview | absent | 0 | 0 | – | 4 | | `/how-to/add-mcp-server-to-agent/` | 200 | 1 — Add an MCP server to an agent's toolkit | absent | 0 | 0 | – | 4 | | `/reference/changelog/` | 200 | 1 — Documentation Changelog | absent | 0 | 0 | – | 4 | | nonexistent route | **404** | 1 — Not found | absent | 0 | 0 | **yes** | 0 | Browser matrix on the live preview, desktop 1440×900 and mobile 390×844: identical outcomes — client nav, direct-load parity, back/forward, home-nav, theme toggle, 191 sidebar links, 14 TOC links, mobile drawer opens, no horizontal scroll, and with **JavaScript disabled** the root directory (202 anchors) navigates by real page load into an interior with 1 H1, no hero, no false state and 6368 chars of article text. **Console/network on the live deploy: zero page errors.** The same two known non-product requests appear (`/redirects.json` and the GitHub star-count API). `/redirects.json` returns **404 on live production `docs.paperclip.ing` today** and on the `main` branch preview — conclusively pre-existing and unrelated to this PR. Screenshots from both the Cloudflare deploy and the local server are in the gallery: https://pages.paperclip.ing/pap-16684-pr1-evidence/ ## Out of scope — pre-existing observation, not a regression On the `--base-path /paperclip-docs/` subpath build, 4 footer links (`/reference/api/overview`, `/guides/org/agents/`, `/guides/org/adapters/`, `/guides/getting-started/five-minute-path/`) are emitted un-prefixed. Building approved `main` @ `2ab76e8e4` with the identical flag reproduces **exactly the same 4 links**, so this is a pre-existing footer-template issue untouched by this PR. Smallest fix would be routing the footer's hardcoded hrefs through the base-path prefixer, in a separate ticket. ## Merge policy `.site/` is generated output and is intentionally uncommitted. **This PR must remain open and unmerged — Dotta alone may merge it.** Co-authored-by: ClaudeCoder <[email protected]> Co-authored-by: Claude Opus 5 (1M context) <[email protected]>