Skip to content

Gate deploy on CI, strip GPS from headshot, per-page share metadata, blog polish - #132

Merged
will-white merged 2 commits into
mainfrom
claude/eloquent-ptolemy-63puql
Oct 27, 2026
Merged

will-white merged 2 commits into
mainfrom
claude/eloquent-ptolemy-63puql

Conversation

@will-white

@will-white will-white commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Two commits. The first is repo and workflow fixes from the Renovate backlog clean-up (#125–#131). The second covers site fixes and improvements: a privacy fix for the headshot, correct share metadata for each page, and blog polish.

Repo / workflow changes (first commit)

Deploy is gated on CI

  • ci.yml is now also a reusable workflow (workflow_call). deploy.yml calls it as a ci job, and build needs: ci. Before this, the deploy only built and never ran prettier or lint, so a push to main that failed CI but still built was published anyway.
  • ci.yml no longer triggers on push to main itself, so CI doesn't run twice. On main it now shows up as ci / lint-and-build inside Deploy Next.js site to Pages.
  • ci.yml: permissions: contents: read. A new push to a PR cancels the PR's in-flight run; calls from the deploy get a unique group, so they never cancel each other.
  • The Next.js build cache key now includes **.mdx, so a blog-post-only change refreshes the cache.

Renovate (checked with renovate-config-validator)

  • rebaseWhen: behind-base-branch: Renovate rebases and regenerates every open PR's lockfile after each merge. Most of the manual lockfile work in the last run was PRs sitting behind main.
  • Minor/patch devDependency bumps are grouped into one dev dependencies (non-major) PR.
  • Weekly lockFileMaintenance.
  • @types/node capped at <25 to match the Node 24 runtime.

Node 24 everywhere

  • Devcontainer image typescript-node:5-22-bookworm → 5-24-bookworm (the tag exists on MCR). CI and deploy already ran Node 24.
  • Devcontainer installs pnpm with npm install -g pnpm instead of corepack enable. pnpm switches itself to the packageManager version, and corepack is no longer bundled with newer Node releases.
  • README: "Node.js 20+" → "Node.js 24".

merge-renovate-prs skill

  • §0: REST (gh api) equivalents for Claude Code cloud sessions, where gh pr … / gh run … fail with a GraphQL 403. Merge with sha= so a Renovate force-push can't slip in an unverified head.
  • §6.3: replaces the update → revert package.json → install --no-frozen-lockfile recipe. It no longer works on pnpm 12 (the lockfile keeps the stale specifier and --frozen-lockfile fails); this is what broke the chore(deps): update react monorepo to v19.3.0 #131 regeneration. pnpm update --no-save <pkg> leaves package.json alone, and I checked that it reproduces chore(deps): update react monorepo to v19.3.0 #131's lockfile byte for byte.
  • Updated for pnpm 12, the new Renovate settings, the new shape of main's workflow runs, and a git checkout -- . vs. staged-files gotcha.

Testing

  • pnpm exec prettier --check ., pnpm lint, and pnpm build pass locally on pnpm 12.15.0.
  • Both workflow files parse. I could not run actionlint here.
  • This PR's own CI exercises ci.yml through its pull_request trigger. The workflow_call path in deploy.yml only runs after merge. Watch the first deploy on main and check that it shows ci / lint-and-build → build → deploy, all green.

Not in this PR (needs a repo setting)

main is unprotected. A branch rule requiring lint-and-build would stop red PRs from being merged, and would make Renovate automerge for minor/patch bumps safe to turn on later.

Site changes (second commit)

Privacy and page weight

  • app/images/headshot.jpg was the original 1.4 MB Pixel photo, served as-is because images aren't optimised for static export. It still had its EXIF GPS latitude and longitude. It's replaced by a metadata-free 1024px WebP (125 KB) and a 128px avatar (6 KB) for the header, which loads on every page. Alt text is now "William White at a mountain lake, with a dog in the background" instead of "headshot".
  • Note: the original file is still in git history, which this PR doesn't change.

Share previews / SEO

  • Pages set only title and description, so they inherited the root layout's openGraph, twitter and alternates objects. Shared links to any page previewed as the home page, linking to /. pageMetadata() / articleMetadata() in app/lib/metadata.ts now build the canonical URL, Open Graph, Twitter and RSS alternate tags for every page.
  • Posts get og:type=article, article:published_time, and their own generated card at /og/blog/<slug>/card.png.
  • OG images are route handlers that export real .png files. The opengraph-image.tsx convention exported an extensionless file, and GitHub Pages picks Content-Type from the extension.

Blog

  • Build-time syntax highlighting (rehype-pretty-code + Shiki, GitHub light/dark themes), with no client JS.
  • Heading anchors (# on hover), reading time, and newer/older links at the end of each post.
  • Inline code no longer renders with literal backticks.
  • RSS: atom:link rel="self" and a deterministic lastBuildDate (the newest post's date).

Other

  • The ⌘K palette now searches blog posts, and shows "Ctrl K" on non-Apple devices.
  • The theme follows the visitor's system setting by default (it was always dark).
  • CI: pnpm check-links fails the build on broken internal links in out/. I confirmed it catches an injected bad link.

Site testing: typecheck, lint, Prettier, build and the link check all pass. I checked the built HTML for each page's og/canonical tags, and confirmed no GPS data remains in the exported images. Playwright screenshots in light and dark mode covered: a post (highlighting on a test Go block, anchors, newer/older links), the blog index, the palette searching posts, and the homepage (only the 6 KB and 125 KB images are requested), with no console errors.

Not done: the resume still lacks the MapLarge role that the homepage and structured data mention. That needs the author's own details.

https://claude.ai/code/session_0196LghwXY1w3ByYdCGUjWJB


Generated by Claude Code

… pnpm 12

- deploy.yml calls ci.yml (now a reusable workflow) and builds only after
  format, lint and build pass, so a push that fails CI is no longer
  published. ci.yml gets read-only token permissions and PR-scoped
  cancel-in-progress; the Next cache key now includes .mdx sources.
- renovate.json: rebase PRs whenever they fall behind main, group non-major
  devDependency bumps into one PR, weekly lockfile maintenance, and keep
  @types/node on the Node 24 runtime.
- devcontainer: Node 24 image to match CI; install pnpm via npm instead of
  corepack (pnpm self-manages to packageManager). README: Node.js 24.
- merge-renovate-prs skill: REST equivalents for cloud sessions (gh GraphQL
  is blocked), pnpm 12 notes, `pnpm update --no-save` replacing the
  update-then-revert recipe that no longer works on pnpm 12, and the new
  shape of main's workflow runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0196LghwXY1w3ByYdCGUjWJB
- Headshot: the original 1.4 MB Pixel photo was served as-is (images are
  unoptimized for static export) with its EXIF GPS location intact.
  Replace it with a metadata-free 1024px WebP (125 KB) and a 128px avatar
  (6 KB) for the header, and give it real alt text.
- Metadata: pages set only title/description, so every page inherited the
  root openGraph/twitter objects and shared links previewed as the home
  page. pageMetadata()/articleMetadata() build canonical URL, Open Graph
  and Twitter tags per page; posts are og:type article with their own
  generated card image. OG images are now route handlers exporting real
  .png files, so GitHub Pages serves them as image/png.
- Blog: build-time syntax highlighting (rehype-pretty-code, light/dark),
  heading anchors, reading time, newer/older post links, no literal
  backticks around inline code. RSS gains atom:link self and
  lastBuildDate.
- Command palette searches blog posts and shows Ctrl K off Apple devices.
- Theme follows the visitor's system setting by default.
- CI: check the static export for broken internal links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0196LghwXY1w3ByYdCGUjWJB
@will-white will-white changed the title chore: gate deploy on CI, tune Renovate, align Node 24, fix skill for pnpm 12 Gate deploy on CI, strip GPS from headshot, per-page share metadata, blog polish Oct 27, 2026
@will-white
will-white merged commit 15d578e into main Oct 27, 2026
1 check passed
@will-white
will-white deleted the claude/eloquent-ptolemy-63puql branch October 27, 2026 06:00
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.

2 participants