Skip to content

Generate the static mirror at deploy time instead of committing it - #121

Merged
ledwards merged 3 commits into
claude/root-vc-seo-llm-discovery-fb2218from
restructure-static-mirror
Aug 4, 2026
Merged

Generate the static mirror at deploy time instead of committing it#121
ledwards merged 3 commits into
claude/root-vc-seo-llm-discovery-fb2218from
restructure-static-mirror

Conversation

@ledwards

@ledwards ledwards commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Proposal on top of #120merge this into claude/root-vc-seo-llm-discovery-fb2218 and #120 updates in place. Nothing here is force-pushed over your work; it's one commit on top of faf71b5.

The argument

The mirror is generated from config/*.js and then committed. That's what makes drift possible, and everything built to close the gap — findDrift, checkPages, build:pages:check, four drift tests, the CI step blocked on workflow scope, and the open question about a cron — exists only because derived files are tracked as sources.

So don't sync it. Stop committing it.

This makes npm run build assemble dist/ from scratch and points Netlify at that. A config edit reaches the static pages on the next deploy because that is the only way the pages come into existence. There is no committed copy to go stale, so there is nothing to check and nothing to re-sync.

What changed

98 files, +202 / −10,463.

#120 this
Generated files in git ~12,400 lines 0
Drift possible yes no
build:pages:check + drift tests 4 tests, CI step pending deleted
Cron / auto-sync open question not a thing
/package.json, /scripts/, /tests/ served yes 404
Tests 229 230 passing
  • netlify.tomlcommand = "npm run build", publish = "dist"
  • scripts/build-assets.js — wipes and rebuilds dist/, copies the static assets, then calls writePages()
  • scripts/build-pages.js — writes into dist/, reads sources from the repo; findDrift/checkPages removed
  • index.html is now a template — the sentinel regions are empty and the build injects into dist/index.html
  • config/{firm,portfolio,team,jobs}.js — guarded module.exports footer, so build-pages.js can require() them and the vm sandbox is gone. They still load as classic browser scripts in the bundle and in welcome.htm
  • removed from git: about/, jobs/, portfolio/, team/, sitemap.xml, llms*.txt, robots.txt, plus the previously committed js/app.bundle.js, vendor copies, and source maps

Your canonical / og:url / og:image fixes and the config/firm.js extraction are untouched — they were real bugs and they carry over as-is.

On the two blockers in your description

The Netlify build command doesn't need to be read from the UI. .gitignore ignores css/xterm.css, js/xterm*.js*, and js/aalib.js*, and index.html references all three. The site works today, so a build already runs, and npm run build is the only script that produces them. Setting it in the toml captures existing config.

The workflow-scope CI step is moot. There's nothing to check. .github/workflows/test.yml already runs npm run build; if a config edit breaks the generator, CI fails there.

Verification

  • npm test — 230/230
  • npm run build — 79 mirror files, 212 files in dist/
  • Every local src/href across all 76 built HTML files resolves inside dist/. The only things that stopped being served are bundled sources and vendor source maps
  • Served dist/ and loaded it: terminal boots with no console errors; firm / portfolio (63) / team (7) are live globals and module is undefined, so the dual-mode guard is load-bearing in a real browser; welcome.htm renders its config-driven tables; /portfolio/zed/ renders
  • End-to-end: edited one line in config/portfolio.js and rebuilt — it propagated to 12 files (bundle, index.html, both llms files, Zed's page, the portfolio index, and 5 sibling "More from the portfolio" sections). No commit involved

Trade-off worth naming

Under publish = "." a failed build still served the committed HTML. Now a failed build fails the deploy. I think that's the right direction — Netlify keeps the last good deploy live rather than shipping stale pages — but it is a real change from "the output is committed, so it survives a failed build," and it's your call.

🤖 Generated with Claude Code

The mirror was committed to the repo, which made it possible for the
generated HTML to disagree with config/*.js. Everything built to close
that gap — the --check drift guard, its tests, the CI step, and the
open question about a cron to re-sync — existed only because derived
files were being tracked as sources.

Make the mirror a build artifact instead:

 - npm run build now assembles dist/ from scratch and Netlify publishes
   that, so config/*.js reaches the static pages on deploy and there is
   nothing left that can go stale
 - index.html in the repo root is a template; the build injects the
   JSON-LD and <noscript> blocks into dist/index.html
 - the pure-data configs carry a guarded module.exports footer, so
   build-pages.js can require() them and the vm sandbox is gone. They
   still load as classic browser scripts in the bundle and welcome.htm
 - dropped findDrift/checkPages, build:pages:check, and the drift tests

Also removes the previously committed build output (js/app.bundle.js,
the vendor copies, the source maps) for the same reason.

Publishing dist/ rather than "." means scripts/, tests/, package.json,
and netlify.toml are no longer served from root.vc. config/*.js still
ships: welcome.htm loads it with raw <script src> tags.
@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cli-website Error Error Aug 3, 2026 9:33pm

@ledwards

ledwards commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

How to validate this against real Netlify.

GitHub test passes here, but Netlify only builds deploy previews for PRs targeting main, so this PR doesn't get one — #120 does. That's actually the useful path: merge this into claude/root-vc-seo-llm-discovery-fb2218 and #120's Netlify preview rebuilds using the new command = "npm run build" / publish = "dist". That preview URL is the definitive check, because it's the first time the toml build settings are exercised by Netlify rather than by me locally.

Worth clicking on that preview:

  • / boots the terminal, /portfolio/zed/ and /team/lee/ render (directory-index routing still works from dist/)
  • /welcome.htm renders its portfolio table — that's the config/*.js raw <script src> path, the one thing the dual-mode export footer could plausibly break
  • /robots.txt, /sitemap.xml, /llms.txt serve
  • /package.json now 404s where it currently returns the file

If the preview build fails on Netlify for a reason that doesn't reproduce locally, the likely culprit is the build command already set in the site UI — the toml now overrides it, so a mismatch would show up as a missing asset rather than a hard failure.

The Vercel check failing on this PR is pre-existing: it fails identically on #120 and is unrelated to these changes. Separate question whether that integration should still be connected at all.

@ledwards

ledwards commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 245d64b — the red Vercel check is fixed, and not by disconnecting the integration.

Root cause: the Vercel project is connected at the repo level, so it attempted a build on every branch. Only ai-incarnations carries a vercel.json, so main-line builds had nothing to read and failed. The check was reporting a real failure — of a deployment that was never supposed to happen here.

vercel.json on this branch sets git.deploymentEnabled: false, which Vercel documents as turning off automatic deployments for branches carrying the file. Confirmed working: the failing Vercel check no longer appears on this PR.

ai-incarnations carries its own vercel.json without that key, so it keeps deploying successfully — its builds are green today and stay that way. The README now says so explicitly, including the vercel.json add/add conflict to expect if that branch is ever merged down, and that it should be resolved toward whichever host is actually serving the domain at the time. That conflict is a feature: it forces a human decision instead of one config silently winning.

Two notes:

  • This reaches main when Add a crawlable static mirror, generated at deploy time #120 lands, which also fixes the red check on main itself. If you'd rather not wait, I can split vercel.json into a standalone PR straight to main — it's independent of the static-mirror work and would green everything immediately.
  • main has no branch protection and no required status checks, so nothing was depending on the Vercel context existing. I checked before making it disappear rather than turn green.

The remaining Vercel Agent Review check reports skipping — insufficient Credit. That's a billing state on the Vercel side, unrelated to this, and it reports neutral rather than failing.

The Vercel project is connected at the repo level, so it attempted a
build on every branch. Only ai-incarnations carries a vercel.json, so
builds on this line had nothing to read and failed — posting a red check
on this PR, which has nothing to do with Vercel.

root.vc is served by Netlify. Set git.deploymentEnabled: false so
branches carrying this file don't trigger a Vercel deployment.

Byte-identical to the copy on #122, which lands the same file on main
along with the README rationale. The two merge cleanly in either order.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ledwards
ledwards force-pushed the restructure-static-mirror branch from 245d64b to b8b64dc Compare August 3, 2026 23:46
@ledwards

ledwards commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Force-pushed b8b64dc (was 245d64b): dropped the README "Hosting" section from this branch. It now lives only on #122, which lands vercel.json on main directly.

Reason: both branches adding a ## Hosting section in the same region of the README would have conflicted when this line eventually merges down. vercel.json itself is byte-identical across the two branches, so it merges cleanly in either order — verified with a diff.

Net effect here is unchanged: this branch still carries vercel.json, so this PR stays green whether or not #122 lands first.

Records that Netlify serves root.vc from dist/, that the Vercel project
belongs to the parked ai-incarnations branch, and why the two vercel.json
files deliberately differ — so nobody reconciles them and breaks that
branch's deploys.

Folded in from #122 so this line carries the whole change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ledwards
ledwards merged commit 3950651 into claude/root-vc-seo-llm-discovery-fb2218 Aug 4, 2026
2 checks passed
@ledwards
ledwards deleted the restructure-static-mirror branch August 4, 2026 01:26
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