docs/plans/2026-06-01-debug-docs-dev-server-oom.md
Objective: Fix docs dev-server OOM; done when root cause is documented, fix lands, and / plus /docs/ai respond without runaway RSS.
Goal plan: docs/plans/2026-06-01-debug-docs-dev-server-oom.md
Template: docs/plans/templates/task.md
Primary template: docs/plans/templates/task.md
Applied packs:
Task source:
/ plus /docs/ai respond without runaway RSS.Completion threshold:
PORT=3002 pnpm --filter www dev can serve / and /docs/ai within a bounded memory window during focused verification.pnpm --filter www check:docs, relevant typecheck/lint checks, and browser/HTTP proof are recorded.node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-06-01-debug-docs-dev-server-oom.md passes.Verification surface:
/ and /docs/ai.pnpm --filter www check:docs, pnpm --filter www typecheck, and a scoped lint/fix gate if implementation files change.http://localhost:3002/ and http://localhost:3002/docs/ai.Constraints:
Boundaries:
apps/www docs app runtime/config, generated Fumadocs source shape, local dev-server process evidence.http://localhost:3002/ and http://localhost:3002/docs/ai.Output budget strategy:
rg, sed, ps, lsof, and route probes. Cap tool output; save large HTML/log/process snapshots to /tmp and inspect slices/counts instead of streaming full output.Blocked condition:
Task state:
Current verdict:
Completion rule:
update_goal(status: complete) while any required checklist item
remains unchecked. If an item does not apply, check it and add N/A: <reason>.update_goal(status: complete) until every completion threshold
above is satisfied, final handoff evidence is recorded, and
node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-06-01-debug-docs-dev-server-oom.md passes.Start Gates:
| Gate | Applies | Evidence |
|---|---|---|
| Skill analysis before edits | yes | Loaded autogoal and debug; followed root-cause-first debugging. |
| Active goal checked or created | yes | get_goal returned null, then create_goal created active goal for this plan. |
| Source of truth read before edits | yes | Read apps/www/source.config.ts, apps/www/next.config.ts, apps/www/src/lib/source.ts, docs route, search route, generated .source/*, and Fumadocs runtime generation. |
| Tracker comments and attachments read | N/A: no tracker link | User reported failure directly in thread. |
| Video transcript evidence required | N/A: no video | No video evidence supplied for this task. |
docs/solutions checked for non-trivial existing-code work | N/A: local dev-server runtime bug | Used repo source and generated Fumadocs/Next output; no solution artifact applied. |
| TDD decision before behavior change or bug fix | N/A: process/RSS regression | Verification is bounded dev-server route proof plus typecheck/docs checks. |
| Branch decision for code-changing task | N/A: no branch requested | Work continues on current checkout; no git branch hygiene requested. |
| Release artifact decision | N/A: dev-server bug unless package public behavior changes | No changeset unless package manifest/public API changes. |
| Browser tool decision for browser surface | yes | Prefer Browser plugin for final route proof; use HTTP/process probes for memory profiling. |
| PR expectation decision | N/A: no PR requested | No commit/push/PR. |
| Tracker sync expectation decision | N/A: no tracker | No issue/Linear sync. |
| Output budget strategy recorded | yes | Narrow commands and /tmp artifacts only. |
| Browser pack selected | yes | Applied browser pack. |
| Browser route / app surface identified | yes | / and /docs/ai on localhost:3002. |
| Browser tool decision recorded | yes | Browser proof if server is stable; HTTP proof is acceptable for low-level memory profiling. |
| Console/network caveat policy recorded | yes | Final proof checks route responses; console/network only if Browser automation is reachable after fix. |
Work Checklist:
<video-transcripts> XML, or marked N/A with reason..agents/**, .claude/**,
.codex/**, skills, hooks, commands, prompts, or user-action tooling.Completion Gates:
| Gate | Applies | Required action | Evidence |
|---|---|---|---|
| Named verification threshold | yes | Run route/RSS proof plus docs/type checks | NODE_OPTIONS=--max-old-space-size=4096 PORT=3002 pnpm --filter www dev served /, /docs/ai, /api/search?query=insertNode; repeat hits stabilized near 12.1 GB RSS instead of runaway growth. |
| Bug reproduced before fix | yes | Record failing test/repro | Baseline capped repro: / rose to ~16 GB RSS and /docs/ai hit V8 heap OOM; original unbounded process reached ~37 GB RSS and stopped answering. |
| Targeted behavior verification | yes | Run focused proof | Fixed run: / 200, /docs/ai 200, /api/search?query=insertNode 200 under 4 GB V8 heap cap; repeat requests did not keep growing materially. |
| TypeScript or typed config changed | yes | Run relevant typecheck | pnpm --filter www typecheck passed. |
| Package exports or file layout changed | N/A | No package exports changed | No pnpm brl needed. |
| Package manifests, lockfile, or install graph changed | yes | Check manifest impact | apps/www/package.json script changed only; no dependency or lockfile change, so pnpm install not needed. |
| Agent rules or skills changed | N/A | No agent files changed | No sync needed. |
| Workspace authority proof | yes | Verify in owner workspace | Commands ran from /Users/zbeyens/git/plate against apps/www. |
| Browser surface changed | yes | Capture route proof or caveat | HTTP/process proof used because Browser MCP did not expose a usable in-app navigation tool in this turn. |
| Browser final proof | yes | Record exact caveat | Route proof: / and /docs/ai returned 200 on localhost:3002; no screenshot captured. |
| CI-controlled template output changed | N/A | No template output changed | Generated .source files are expected local output from checks/dev. |
| Package behavior or public API changed | N/A | No public package API changed | No changeset. |
| Registry-only component work changed | N/A | No registry component behavior changed | No registry changelog. |
| Docs or content changed | N/A | No docs content changed | Plan file only. |
| High-risk mini gate | yes | Record realistic failure mode and boundary | Risk: dev code highlighting is simpler than production; boundary is dev-only env PLATE_WWW_DYNAMIC_DOCS=1, production build still keeps Shiki highlighting. |
| Agent-native review for agent/tooling changes | N/A | No agent tooling changed | No agent-native review. |
| Local install corruption suspected | N/A | Not an install corruption signature | Failure reproduced as deterministic route compile/RSS growth. |
| Autoreview for non-trivial implementation changes | N/A: not run | Record reason | User requested autogoal/debug, not autoreview; source-backed checks and route proof are recorded. |
| PR create or update | N/A | No PR requested | No commit/push/PR. |
| Task-style PR body verified | N/A | No PR requested | No PR body. |
| PR proof image hosting | N/A | No PR requested | No hosted image. |
| Tracker sync-back | N/A | No tracker | No issue/Linear sync. |
| Final handoff contract | yes | Fill final handoff fields | See final handoff contract below. |
| Final lint | partial | Run lint or scoped equivalent | pnpm --filter www lint:fix fails on existing parser/config errors across generated and TS files; scoped eslint on touched app files passed, with next.config.ts ignored by repo lint config. |
| Output budget discipline | partial | Record accidental output and recovery | Two broad generated-file outputs were accidentally streamed (.source/browser.ts, .source/dynamic.ts); recovered by using capped probes and summaries. |
| Goal plan complete | yes | Run completion checker | To run after this plan update with .agents/skills/autogoal/scripts/check-complete.mjs. |
| Browser interaction proof | partial | Exercise route or record blocker | HTTP route proof used; Browser plugin did not expose direct page-control tool. |
| Browser console/network check | N/A | Low-level server memory fix | Console/network not the failure surface. |
| Browser final proof artifact | yes | Record route proof | /tmp/www-nohighlight-probe-1.out, /tmp/www-nohighlight-probe-2.out, and route/RSS lines recorded in this plan. |
Phase / pass table:
| Phase | Status | Evidence | Next |
|---|---|---|---|
| Intake and source read | complete | Reproduced OOM and traced generated Fumadocs/Next route graph. | done |
| Implementation | complete | Patched dev docs source, dev aliases, search/copy markdown, code highlighting, and home preview import boundary. | done |
| Verification | complete | Route/RSS proof, check:docs, typecheck, scoped eslint. | done |
| PR / tracker sync | N/A | No PR/tracker requested. | done |
| Closeout | complete | Final handoff ready. | done |
Findings:
next-server (v16.2.6) reached roughly 37 GB RSS and stopped answering both /docs/ai and /; an earlier process hit V8 heap limit near 65 GB./ compiled to runaway RSS and /docs/ai failed with V8 heap OOM in JsonParse / GlobalEval.includeProcessedMarkdown and search/copy processed markdown amplified memory; switching those paths to raw avoids eager processed markdown.async alone did not fix it because generated server.ts still exposed a dynamic import map and Next compiled every MDX body target.dynamic removes the all-MDX body import map; collections/server is aliased to .source/dynamic.ts only when PLATE_WWW_DYNAMIC_DOCS=1.dist aliases; PLATE_WWW_DEV_SOURCE=1 opts back into source aliases for package hacking.Decisions and tradeoffs:
Implementation notes:
apps/www/package.json: dev sets PLATE_WWW_DYNAMIC_DOCS=1 for build:source and next dev.apps/www/source.config.ts: dev dynamic docs, no dev Shiki/rehype pretty-code highlighting, raw code metadata preserved for copy buttons.apps/www/next.config.ts: Turbopack filesystem cache remains disabled, workspace dev aliases prefer dist with PLATE_WWW_DEV_SOURCE=1 source opt-in, and dev docs alias collections/server to .source/dynamic.ts.apps/www/src/app/(app)/docs/[[...slug]]/doc-page.tsx: loads async/dynamic MDX body before rendering and uses raw markdown for copy.apps/www/src/app/api/search/route.ts: search indexes raw markdown to avoid processed markdown hydration.apps/www/src/components/playground-preview-lazy.tsx and home pages: defer the heavy playground preview graph.Review fixes:
Error attempts:
| Error / failed attempt | Count | Next different move | Resolution |
|---|---|---|---|
async: true Fumadocs collection still OOMed | 1 | Use dev-only dynamic compilation instead of import map | Fixed with PLATE_WWW_DYNAMIC_DOCS=1 and alias to .source/dynamic.ts. |
| Webpack dev fallback still OOMed/hung | 1 | Stop bundler swap, reduce route graph | Fixed by route graph changes instead. |
| Broad generated-file output streamed | 2 | Use capped probes and summaries | Recorded; subsequent proof kept concise. |
Verification evidence:
pnpm --filter www check:docs passed.pnpm --filter www typecheck passed.pnpm --filter www lint:fix failed on existing lint parser/config problems across generated and TS files; scoped eslint on touched app files passed, with next.config.ts ignored by repo lint config.NODE_OPTIONS='--max-old-space-size=4096' PORT=3002 pnpm --filter www dev:
/: 200, first-hit RSS ~2.9 GB -> ~4.5 GB./docs/ai: 200, first-hit RSS ~4.5 GB -> ~10.5 GB./api/search?query=insertNode: 200, first-hit RSS ~10.5 GB -> ~12.4 GB./, /docs/ai, /api/search?query=insertNode, /docs/installation/plate-ui: all 200; RSS stayed around ~12.0-12.1 GB instead of runaway growth.PORT=3002 pnpm --filter www dev: / 200 and /docs/ai 200; RSS ended around ~10.4 GB after compiling those two routes.Final handoff contract:
/ and /docs/ai; target routes respond under a 4GB V8 heap cap and stabilize.check:docs, typecheck, scoped eslint, route/RSS proof.Task-style PR body contract:
<!-- auto-release:start --> block. If a changeset is
part of the diff and repo policy expects auto release, include that block.๐ Fixes #123 or ๐ Fixes โ N/A, then
an emoji confidence line like ๐ข 95-100% confidence.| Phase | ๐งช Tests | ๐ Browser |.Reproduced and Verified rows. Mark passing proof with ๐ข, repro or
failing proof with ๐ด, and non-applicable cells with โ N/A.**โ
Outcome**, **โ ๏ธ Caveat**,
**๐๏ธ Design**, and **๐งช Verified**.Summary / Verification PR body, an
adaptive prose body from a git helper skill, plain ## Outcome sections, or
an unrelated generated badge footer unless the caller or repo template
explicitly asks for it.gh pr view --json body output or a concise source-backed summary
of that output.Final handoff / sync:
Timeline:
Reboot status:
| Question | Answer |
|---|---|
| Where am I? | Closeout |
| Where am I going? | Final response |
| What is the goal? | Fix docs dev-server OOM; prove root cause, patch if repo-owned, and verify / plus /docs/ai. |
| What have I learned? | See Findings and Verification evidence. |
| What have I done? | Patched docs dev graph and verified target routes. |
Open risks:
/docs/ai and search; acceptable compared with the prior runaway, but still expensive.PLATE_WWW_DYNAMIC_DOCS=1; production/non-dynamic generation keeps Shiki.