Legacy Migrations Work Better as a Kill List
phase gates, idempotent scripts, and agent-readable runbooks map directly to joelclaw workload planning for retiring legacy services
The skillrecordings/migrate-egghead repo is not a polite migration plan. It’s a kill list for egghead-rails and egghead-next, with Coursebuilder as the system that survives.
That’s the clever bit. The repo doesn’t pretend a legacy migration is a neat rewrite. It names the systems, numbers the blast radius, and turns the work into phase gates: content first, users next, Stripe webhooks into Inngest, Sidekiq jobs into durable functions, then cutover. No 404s, minimal downtime, idempotent scripts, human gates. Boring in exactly the right way.
The more interesting move is the interim strangler path: egghead-next can bypass Rails for high-volume read paths and hit PostgreSQL directly while the full Coursebuilder migration continues. The repo’s agent docs call out that getLessonComments and getLesson account for 88.5% of GraphQL traffic, and UsersController#current accounts for 55% of REST traffic. That’s a nasty little migration lever: kill most of the old system’s traffic before the old system is fully gone.
Useful for joelclaw because this is the shape long-lived system work needs: an agent-readable repo, phase done criteria, canary deploy commands, production log queries, and explicit stop/go gates. Less grand rewrite manifesto, more executable murder board. 🐀
Key Ideas
- Treat migration as a retirement campaign, not a rewrite:
egghead-railsandegghead-nexthave explicit fates, whileCoursebuilderbecomes the canonical backend. - Put content before users when content has no user dependency: migrate
SanityandRailscourse data first so auth, entitlement, and playback paths can be tested against real material. - Use phase gates with evidence: each phase has done criteria, reconciliation checks, and human approvals instead of vibes-based migration confidence.
- Make scripts idempotent because migrations get rerun: the repo records duplicate-content failures, cleanup scripts, and checks that preserve native
Coursebuilderposts. - Strangle hot paths directly: bypassing
GraphQLandRailsfor purePostgreSQLreads can remove most legacy traffic before the final cutover. - Keep the agent interface sharp:
AGENTS.md,tools/me.ts, deploy status commands, route-error queries, and project sync commands make the repo operable by agents instead of tribal-memory bullshit.
Links
- Source repo:
skillrecordings/migrate-egghead - Legacy backend:
skillrecordings/egghead-rails - Legacy frontend:
skillrecordings/egghead-next - Target backend/content system:
badass-courses/course-builder - Destination UI repo:
badass-courses/gremlin egghead.ioCoursebuilderInngestMuxPlanetScalePostgreSQLSidekiqNext.jsGraphQLSanityStripeCustomer.ioResendVercelBetter AuthAuth.jsshadcn/uiZodStrangler fig pattern