Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ Subsystem one-liners:

- **Fresh worktree setup needs `npm run setup` after `npm install`** — global npmrc has `ignore-scripts=true`. Without it, `hugo-apps/node_modules` won't be populated and `better-sqlite3`'s native binding won't build. Symptoms: hugo-apps tests fail resolving `@mediapipe/tasks-vision`, `npm test` hangs.

- **`ignore-scripts=true` silences `postbuild:apps` — build artifacts wired into it are NOT produced by local `npm run build:all`** — the global npmrc `ignore-scripts=true` (see above) means npm **lifecycle hooks never fire**. The `postbuild:apps` hook is where the #1604 island-fingerprint step (`build:island-manifest`, which writes `hugo/data/island_manifest.json`) and 8 static guards live. During a local `build:all`, none of them run. Symptom class: fresh JS/CSS **compiles** (Vite emits `navigator-<hash>.js`) but is **never referenced** — `hugo/layouts/partials/island-src.html` falls back to the unhashed `/js/<name>.js`, Hugo bakes the stale path, and the approuter ships old bundles sitting next to the new ones. **Merged fixes look "not deployed" even though the deploy succeeded.** CI dodges this because `deploy.yml`/`unit-tests.yml` run `npm run postbuild:apps` as an **explicit step** (see deploy.yml:217-223 comment). Fix (2026-08-10): `build:all` now calls `npm run build:island-manifest` **explicitly** (not via the hook), and `scripts/deploy-mta.cjs` Step 2.5 fails the deploy if `hugo/public/index.html` bakes only unhashed island paths while a Vite manifest exists. Rule: any build **artifact** (not just a guard) needed for a correct ship must be an explicit step in `build:all`, never left to a `post*`/`pre*` lifecycle hook.

- **`hugo/content/tutorials/` is entirely generated** — Never edit; overwritten by `npm run fetch-tutorials`. Edit `scripts/parsers/` or source tutorials in `sap-tutorials` org.

- **Never run `publish-content` from a workstation** — Use `gh workflow run rebuild-content.yml`. Workstation publishes skip CI validation; the server-side no-revert guard catches the worst stale-cache regressions but not everything.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"build:display": "cd app/display-app && npm install && npm run build",
"copy-joule-vendor": "node scripts/copy-joule-vendor.mjs",
"check-deploy-cap-target": "node scripts/check-deploy-cap-target.cjs",
"build:all": "npm run prebuild && npm run fetch-tutorials -- --regenerate && npm run fetch-advocates && npm run fetch-homepage-shelves && npm run fetch-verb-definitions && npm run fetch-shelf-definitions && npm run fetch-featured-topics && npm run fetch-topic-clusters && npm run fetch-topics-gallery && npm run build:css && npm run build:apps && npm run build:analytics-explorer && npm run copy-joule-vendor && npm run build:explore && npm run build:hugo && npm run build:highlight && npm run build:display && npm run build:sdl",
"build:all": "npm run prebuild && npm run fetch-tutorials -- --regenerate && npm run fetch-advocates && npm run fetch-homepage-shelves && npm run fetch-verb-definitions && npm run fetch-shelf-definitions && npm run fetch-featured-topics && npm run fetch-topic-clusters && npm run fetch-topics-gallery && npm run build:css && npm run build:apps && npm run build:island-manifest && npm run build:analytics-explorer && npm run copy-joule-vendor && npm run build:explore && npm run build:hugo && npm run build:highlight && npm run build:display && npm run build:sdl",
"build:deploy": "npm run check-deploy-cap-target && npm run build:all",
"deploy": "node scripts/deploy-mta.cjs",
"build:admin": "npm --prefix app/admin-shell run build",
Expand Down
31 changes: 31 additions & 0 deletions scripts/deploy-mta.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,37 @@ async function main() {
ok('build:deploy complete (explore bundle + manifest included via build:all)');
}

// ---- Step 2.5: verify Hugo baked FINGERPRINTED island bundles ---------
// WHY (2026-08-10): the #1604 island-fingerprint pipeline builds
// hugo/data/island_manifest.json in `build:island-manifest`. That step was
// originally ONLY wired into the `postbuild:apps` npm lifecycle hook — but
// this repo runs with `ignore-scripts=true` globally, so the hook is SILENT
// during a local `npm run build:all`. Result: the manifest was never
// written, hugo/layouts/partials/island-src.html fell back to the UNHASHED
// /js/<name>.js path, and the approuter shipped a stale bundle while the
// fresh (fingerprinted) one sat unreferenced next to it. The compiled fixes
// were present but never served. build:all now calls build:island-manifest
// explicitly; this guard is the belt-and-suspenders that fails the deploy if
// that ever regresses again (renamed step, reordered pipeline, etc.).
if (!args.dryRun && !args.skipBuild) {
const viteManifest = path.join(ROOT, 'hugo', 'static', 'js', '.vite', 'manifest.json');
const homepage = path.join(ROOT, 'hugo', 'public', 'index.html');
if (fs.existsSync(viteManifest) && fs.existsSync(homepage)) {
const html = fs.readFileSync(homepage, 'utf8');
// A correctly fingerprinted homepage references at least one hashed
// island bundle: /js/<name>-<8+hexish>.js. If EVERY island script tag is
// the bare unhashed fallback, the manifest never took effect.
const hashed = /\/js\/[a-zA-Z0-9-]+-[A-Za-z0-9_-]{8,}\.js/.test(html);
if (!hashed) {
die(1, 'Hugo baked only UNHASHED island bundle paths despite a Vite manifest existing.\n' +
' hugo/data/island_manifest.json was likely not built (ignore-scripts=true\n' +
' silences the postbuild:apps hook). Fresh JS fixes will NOT be served.\n' +
' Fix: ensure `npm run build:island-manifest` runs inside build:all, then rebuild.');
}
ok('island bundles fingerprinted in hugo/public (manifest took effect)');
}
}

// ---- Step 3: mbt build (+ fresh-mtar verify) -------------------------
step(3, 'Package MTA (mbt build)');
if (args.skipBuild) {
Expand Down
Loading