Skip to content

Real URLs: Cloudflare Pages + BrowserRouter, dead-page cut, a11y ride-alongs#62

Merged
isaacsight merged 5 commits into
mainfrom
feat/real-urls-cloudflare
Jul 21, 2026
Merged

Real URLs: Cloudflare Pages + BrowserRouter, dead-page cut, a11y ride-alongs#62
isaacsight merged 5 commits into
mainfrom
feat/real-urls-cloudflare

Conversation

@isaacsight

Copy link
Copy Markdown
Owner

What this does

Every deep link becomes a real, citable URL. kernel.chat/issues/421 currently serves an HTTP 404 and bounces to /#/issues/421 — uncitable addresses on a publication whose thesis is provenance.

  • createHashRoutercreateBrowserRouter; legacy /#/… citations resolve at module scope via src/utils/legacyHashRedirect.ts (6 tests; auth hashes left to the OAuth interceptor)
  • public/_redirects SPA fallback; artifacts/plates/sitemap stay static 200s
  • Sitemap regenerated from the issue registry (9 routes + 68 issues; it previously listed 4 URLs including /#/engine)
  • CI presses to Cloudflare Pages (all law gates kept); deploy-gh-pages.yml is the dispatch-only rollback
  • Cuts nine grep-verified dead pages (4,068 lines) incl. PricingPage — the EnginePage chat tree stays parked, untouched
  • A11y: back-to-top grows 98×13 → 122×44; skip link past the masthead in folio grammar

Before merging (owner setup, ~10 min)

  1. Create the Cloudflare Pages project kernel-chat (direct upload, no git integration — CI uploads dist/)
  2. Add repo secrets CLOUDFLARE_API_TOKEN (Pages:Edit) and CLOUDFLARE_ACCOUNT_ID
  3. After first deploy verifies on kernel-chat.pages.dev: add the kernel.chat custom domain, repoint DNS, remove the domain from GH Pages settings

Rollback: gh workflow run deploy-gh-pages.yml + DNS back to GH Pages.

Verification

tsc clean · 794/794 tests · 236.33KB gzip JS (<300KB) · vite preview: /issues/421 direct, /#/issues/415 resolves to the 415 spread, artifacts/index.html static, zero console errors.

🤖 Generated with Claude Code

Your Name and others added 5 commits July 20, 2026 15:58
Every deep link previously served HTTP 404 and bounced to a hash
route; a publication arguing provenance had uncitable addresses.

- router.tsx: createHashRouter → createBrowserRouter. Legacy /#/…
  citations resolve at module scope (before the router captures
  location) via new utils/legacyHashRedirect.ts — 6 tests; auth
  hashes are ignored and left to the OAuth interceptor.
- main.tsx: post-auth URL cleanup writes plain paths, PostHog
  capture_pageview → 'history_change' so pushState pageviews count.
- 20 hash hrefs across the routed surface rewritten to real paths;
  MagazineFrame's goHome now uses useNavigate.
- public/_redirects: /* /index.html 200 (real files served first, so
  artifacts and plates stay static 200s).
- scripts/build-sitemap.mjs replaces the stale 4-URL sitemap (it
  listed /#/engine) with 9 routes + 68 issues, regenerated in CI.
- deploy.yml now presses to Cloudflare Pages (wrangler-action v3,
  project kernel-chat); all law gates kept. deploy-gh-pages.yml is
  the workflow_dispatch rollback; 404.html + CNAME retained for it.
- e2e specs updated to path URLs. PUBLISHING.md §VII rewritten.

Gates: tsc clean, 794/794 tests, build 236.27KB gzip JS (<300KB).
Verified in vite preview: /issues/421 direct 200, /#/issues/415
resolves to the 415 spread, artifacts/index.html serves static.

Co-Authored-By: Claude Fable 5 <[email protected]>
Count what gets read; cut what doesn't. None of these nine pages is
reachable from router.tsx and none is imported outside its own file
(grep-audited; the sole 'AdminPage' hit was the substring inside
WorkspaceAdminPage, itself cut): LeaderboardPage, PlayPage,
TerminalPage, PricingPage (billing died 2026-04-16; a price page
contradicts the ¥0 masthead), AdminPage, WorkspaceAdminPage,
ApiDocsPage, AuthorProfilePage, ExplorePage. Exclusive dependencies
go with them: useSynthesisState, discovery/SearchBar, TopicGrid.

Kept deliberately: the EnginePage chat tree (parked product, not
junk) and FeedCard/AuthorCard/useDiscovery/discoveryStore, which the
parked tree still imports. public/play and synthesis-state stay —
the build:synth pipeline owns them.

Gates: tsc clean, 794/794 tests, build 236.27KB gzip JS.

Co-Authored-By: Claude Fable 5 <[email protected]>
The colophon's back-to-top control measured 98×13 — half the WCAG
2.5.8 minimum. Padding + negative margin grow the hit area to
122×44 while the printed mark stays optically where it was
(white-space: nowrap keeps it on one line inside the 40px-wide
colophon column; the earlier declaration order let the block's own
padding: 0 win, now removed).

Layout gains the keyboard reader's shortcut: a skip link ahead of
the masthead, off-canvas until focused, folio grammar, targeting
main#feature-well (tabIndex -1). Styled with house tokens only.

Gates: adherence + editorial clean, tsc clean, 794/794 tests.
Verified in vite preview: target measures 122×44; link focusable
with the :focus reveal rule in the sheet.

Co-Authored-By: Claude Fable 5 <[email protected]>
deploy.yml and package.json both reference 'npm run sitemap' →
scripts/build-sitemap.mjs, but the file itself sat untracked on disk
and was never git-added in the routing commit. CI on this PR would
have failed at the sitemap step. Caught during THE STACKS Task 4
review while checking out a sibling branch and finding the script
missing.

Co-Authored-By: Claude Fable 5 <[email protected]>
@isaacsight
isaacsight merged commit d94ed74 into main Jul 21, 2026
3 of 4 checks passed
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