Skip to content

T-CTJF-dedupe-monorepo-h3-skew

Status: closed/done · Impact: medium · Complexity: small

The augmented_books adoption (T-6C0Z, #929) shipped learn_web — now at solutions/augmented/apps/learn_web after T-C9RD — with a nitro.prerender.ignore: ["/__nuxt_content"] workaround because prerendering @nuxt/content’s SQL-dump route crashed on an h3 v1/v2 version skew. An empirical test isolated the real cause and a robust fix, so the workaround can be removed instead of carried forward.

LocationRole today
solutions/augmented/apps/learn_web/package.jsonPins @nuxt/content 3.10.0, which declares no direct h3 dependency, so its /__nuxt_content route handler’s h3 import floats to whatever the tree resolves
solutions/augmented/apps/learn_web/nuxt.config.tsCarries nitro.prerender.ignore: ["/__nuxt_content"] to skip the route that crashes on the h3 skew

solutions/augmented/apps/learn_web builds and prerenders /__nuxt_content without the nitro.prerender.ignore workaround, because @nuxt/content is pinned to a version that declares its own h3 v1 dependency and thus pins its route handler to h3 v1 independent of the rest of the tree.

  1. Bump @nuxt/content 3.10.03.15.0 in solutions/augmented/apps/learn_web/package.json (3.15 declares "h3": "^1.15.11" directly).
  2. Remove the nitro.prerender.ignore: ["/__nuxt_content"] block from solutions/augmented/apps/learn_web/nuxt.config.ts (keep content.experimental.sqliteConnector: "native" — that addresses the unrelated better-sqlite3 build issue).
  3. Regenerate bun.lock; build learn_web and confirm /__nuxt_content prerenders.
LocationKindChange
solutions/augmented/apps/learn_web/package.jsonmodify@nuxt/content 3.10.03.15.0
solutions/augmented/apps/learn_web/nuxt.config.tsmodifyRemove nitro.prerender.ignore
bun.lockmodifyRegenerated for the @nuxt/content bump
  • AC-1: solutions/augmented/apps/learn_web/package.json pins @nuxt/content >= 3.15.0.
  • AC-2: solutions/augmented/apps/learn_web/nuxt.config.ts no longer sets nitro.prerender.ignore for /__nuxt_content.
  • AC-3: bun run build in solutions/augmented/apps/learn_web prerenders /__nuxt_content and exits 0 (no h3 skew crash).
  • solutions/augmented/apps/augmented_web and other sibling apps that declare @nuxt/test-utils keep transitive h3 v2 (h3-next) copies in the store; Bun 1.3.14 ignores overrides on npm-aliased deps, so those are not deduped here. Relying on @nuxt/content’s own h3 pin sidesteps them — a full store dedupe is part of the pnpm migration (T-UWRG).
  • none
  • Surfaced by T-6C0Z’s prerender crash; resolved by an empirical bump/drop test (2026-07-19) — see post-mortem.

Captured by /sdlc:task-work on 2026-07-19. PR: #961.

Ran a 4-cell matrix in a throwaway worktree (workaround removed in every cell; sqliteConnector: "native" kept):

CellChangeResult
0 — controlnothing else changedPASS (fresh isolated .bun/ linker scopes the route to h3@1.15.11)
1bump @nuxt/content 3.103.15PASS
2drop @nuxt/test-utilsFAIL — the h3 skew crash
3bump content and drop test-utilsPASS
  • Dropping @nuxt/test-utils is the wrong lever — it causes the crash (Cell 2), not fixes it. @nuxt/content@3.10 declares no h3; @nuxt/test-utils happens to declare a direct h3: ^1.15.4 that incidentally pinned content’s route handler to h3 v1. Remove it and content drifts to h3@2.0.1-rc → the crash (Cannot read properties of undefined (reading 'set') at setResponseHeader in the h3 v2 build).
  • Bumping @nuxt/content to 3.15.0 is the robust lever — 3.15 declares "h3": "^1.15.11" itself, pinning its route to h3 v1 regardless of what test-utils does (Cell 3 survives even with test-utils gone). Layout-independent.
  • Cell 0 also passed under a fresh Bun 1.3.14 isolated-linker install, i.e. the workaround may already be dead weight in that layout — but the content-3.15 pin is the fix that holds regardless of linker state, so it’s the one shipped here.
  • AC-1/AC-2: auto — the two edits.
  • AC-3: agent-manual — learn_web build prerenders /__nuxt_content and exits 0.
  • The original T-CTJF worktree was a stale planning/draft stub 64 commits behind main with no lease; it was torn down and re-branched fresh. A draft task left with a live worktree is a cleanup gap.

← Back to Tasks