Plan plan-changelog-sot — Website changelog now renders from CHANGELOG.md source-of-truth at build time. The hardcoded ChangelogEntry[] array on website/src/app/changelog/page.tsx (stale by 5+ major releases, last entry 0.6.3, mismatched 0.x scheme vs npm's 1.x) and the orphaned website/content/changelog/ directory are deleted. A vitest drift-guard test asserts every ## [X.Y.Z] heading produces exactly one rendered entry; structurally impossible for the rendered page to drift from CHANGELOG.md after this release. CR-46 / Rule 0 — replaces a recurring "rendered changelog goes stale" loop with a structural CI gate. Website-only patch; daemon code unchanged from 1.6.0.
Added
website/src/lib/changelog.ts— hand-rolled Keep-a-Changelog 1.1.0 parser (parseChangelog,readChangelog,getChangelog,renderInlineMarkdown,KNOWN_SECTION_HEADINGS). No new npm dependency — the format is tightly constrained and a regex-driven parser keeps the drift-guard surface small.getChangelog()wraps read+parse with a version-less fallback (no embedded version literals — that would itself create a new drift surface).scripts/copy-changelog-to-website.js—__dirname-relative copy script that runs frompredevandprebuildhooks, copies repo-rootCHANGELOG.mdintowebsite/CHANGELOG.md(gitignored). Resolves source path independent ofprocess.cwd()so it works from any invocation context (Vercel CI, manual, dev). Gracefully exits 0 when source is missing (Vercel CLI deploys that upload onlywebsite/).website/src/tests/changelog-parse.test.ts— 13-assertion drift-guard:EXPECTED_COUNT = 18, semver/ISO-date regex pins, no-duplicate-versions, latest-entry ==packages/core/package.json#version,KNOWN_SECTION_HEADINGSwhitelist coverage, historical[0.3.0]preserved per plan §1.4, and renderer fidelity (renderInlineMarkdownproduces<code>for `@massu/adapter-rails@1.0.0` literal markdown).renderInlineMarkdowninline-markdown renderer — dependency-free helper handling the four common inline forms in CHANGELOG bullets (code,text,bold,italic) so users see formatted output on/changeloginstead of raw backtick + bracket syntax.
Changed
website/src/app/changelog/page.tsx— hardcodedChangelogEntry[]array (legacy lines 31-264, frozen at0.6.3) replaced withconst changelog = getChangelog(). InlineChangelogEntryinterface moved to@/lib/changelog. Each<li>wraps{renderInlineMarkdown(item)}so backticks and links render correctly.website/package.json—predevandprebuildscripts added:node ../scripts/copy-changelog-to-website.js. Ensureswebsite/CHANGELOG.mdis in sync beforenext devornext buildreads it.website/.gitignore—/CHANGELOG.mdadded (derived build artifact; canonical source lives at repo root).website/tsconfig.json—target: "ES2017"→target: "ES2020". Fixes pre-existing TS1501 error onsregex flag insrc/tests/integration/sso-validation.test.ts:31per CR-9 (fix all encountered issues). Safe for Node 22 + Next.js 16 runtime.
Removed
website/content/changelog/— orphaned MDX directory deleted (grep -rn "content/changelog" website/src/returned 0 prior to deletion). The single file (2026-04-19-config-migration.mdx) had no consumer.
Verification
cd website && npx tsc --noEmit: 0 errorscd website && npm test: 18 files / 115 tests PASS (was 17/101 + 14 new after EXPECTED_COUNT bump)cd website && npm run build: exit 0,/changelogprerendered as static (○)- Rendered HTML inspection: 18 distinct version headings (1.6.1 through 0.3.0 preserved), 0 occurrences of stale
0.6.3legacy data,1.6.1appears in rendered output bash scripts/pre-push-light.sh(Node 22): ALL 7 GATES PASSbash scripts/massu-plan-status-validator.sh: PASSbash scripts/massu-plan-commit-drift.sh: PASS
Closes
- Plan
plan-changelog-sotaudit: converged at 0 gaps after 4 iterations (14 → 4 → 2 → 0). - Master plan row 4.10 drift-class — the "rendered changelog goes stale" loop that motivated the blog post review is now structurally impossible.