Skip to content

feat(memory): expose JSC extraMemorySize in system memory API, watchdog, and doctor - #2302

Closed
lidge-jun wants to merge 1 commit into
devfrom
codex/bun14-mem-diagnostics
Closed

feat(memory): expose JSC extraMemorySize in system memory API, watchdog, and doctor#2302
lidge-jun wants to merge 1 commit into
devfrom
codex/bun14-mem-diagnostics

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

  • Surface JSC extraMemorySize — the counter Bun 1.4's external-memory reporting fixes actually move — in the three memory observability surfaces:
    • /api/system/memory jscHeap gains extraMemorySize (src/server/management/system-routes.ts).
    • Memory watchdog samples gain optional jscHeapSize / jscExtraMemorySize via a static bun:jsc import; the call is guarded so introspection failure never breaks sampling, and the sampler stays synchronous (src/server/memory-watchdog.ts).
    • ocx doctor renders jscExtra=… when the API reports it (src/cli/doctor.ts).
  • Thresholding (observedMemoryCounter) is deliberately unchanged: observability only, no behavior change.
  • Plan doc: devlog/_plan/260822_260822-bun14-followup-memory/010 (parent PR devlog: Bun 1.4 follow-up memory roadmap (research + decade docs) #2301). Adversarially audited (5 review rounds) before implementation.

Verification

  • OCX_TEST_NO_QUEUE=1 bun test --isolate tests/memory-watchdog.test.ts — 15 pass / 0 fail (3 new tests: injected JSC sample round-trip, default-sampler JSC counters under Bun, endpoint extraMemorySize shape).
  • OCX_TEST_NO_QUEUE=1 bun test --isolate tests/doctor.test.ts — 46 pass / 0 fail.
  • bun x tsc --noEmit — exit 0.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

…og samples, and doctor

Bun 1.4 external-memory reporting fixes move extraMemorySize; surface it so
the 6h watchdog ring and /api/system/memory can attribute native-memory
changes. Static bun:jsc import keeps the sampler synchronous; the call is
guarded so introspection failure never breaks sampling. Thresholding
(observedMemoryCounter) is unchanged — observability only.

Unit: devlog/_plan/260822_260822-bun14-followup-memory/010
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner August 21, 2026 15:42
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • ^dev$
  • ^preview$

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4595f34b-15bb-42b6-8914-9bd9f5d8f464

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 48 / 80

지금 dev HEAD c0cbe494e에서 /api/system/memory jscHeapheapSize/heapCapacity/objectCount만 있음. src/server/management/system-routes.ts:54-62bun:jsc heapStats()를 동적 import. 워치독 src/server/memory-watchdog.ts:79-90 defaultSampleprocess.memoryUsage()만. 쓰레스홀드 observedMemoryCounter는 rss/external/arrayBuffers. extraMemorySize 없음. 이 PR이 그 세 면에 extraMemorySize를 관측만 추가. 쓰레스홀드 안 바꿈. 본문이 그거 명시. 드래프트 아님. base가 dev가 아님. codex/bun14-followup-memory-docs (#2301). dev 대비 스코어는 관측 전용.

핵심. system-routes.ts jscHeap.extraMemorySize를 숫자면 그대로, 아니면 0. 워치독은 정적 import { heapStats } from "bun:jsc" 후 try/catch로 jscHeapSize/jscExtraMemorySize optional. 닥터 src/cli/doctor.ts jscExtra=. 테스트 3장: 주입 샘플 라운드트립, 기본 샘플러가 Bun에서 숫자, 엔드포인트 shape. doctor 스위트 46 pass라 함. 관측 전용 계약은 맞음. 정적 import는 010 플랜의 sync 샘플러 제약. defaultSample이 async가 아님.

구멍. 정적 import 실패는 try/catch가 못 잡음. 로드 타임. Bun에선 살아 있음. node 툴링이 이 모듈을 가져오면 프로세스 기동이 죽음. 기존 system-routes는 동적 import라 그 구멍이 없음. API는 없으면 0, 워치독은 undefined. 닥터는 !== undefined라 0도 찍힘. 두 면이 다름. extraMemorySize를 observedBytes에 안 넣은 건 맞음. JSC extra랑 external이 겹칠 수 있음. 넣으면 워닝이 이중. #2301 없이 이 PR만 dev에 머지하면 플랜 문서가 없음. 동작은 됨. 스택을 뒤집지 말 것.

types.ts/config.ts 안 만짐. 스플릿 안 씹힘. 리베이스하지 말고 닫으라는 케이스 아님. #2188 L1–L9 사이드카 이미 dev. x_search 넣지 말 것. Grok OAuth Chat 기본(#2255)/GUI 옵트인 Responses(#2266)/#2283이랑 다른 레인임. 프리뷰 배포 아님. 카탈로그는 그대로 Ox Alpha x-preview-f-free + deepseek-v4-flash-vision-exp. v2.29.0 태그됨. v2.30.0-preview.20260821 있음. 관측만, 핫패스 아님. 그래서 48. #2301 먼저.

해결방안: #2301 머지 다음에 이 패치로 가라. 쓰레스홀드에 extraMemorySize 넣지 말 것. 정적 import는 Bun 전제면 유지. 주석에 node에서 이 모듈 import 금지를 남겨라. API 0 vs 워치독 omit을 맞춰라. 없으면 필드 생략이 기존 jscHeap: null 패턴이랑 같음. 0을 진짜 0으로 보이게 하지 말 것. 020 GC 훅 이 PR에 넣지 말 것. 스플릿이 memory-watchdog.ts를 옮기면 리베이스하지 말고 닫고 다시 짜라. 지금은 그 정도 아님.

이 댓글은 grok-bot이 작성했습니다

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact stacked head cac21afb726a25c3e35ef072e5c907e429df443e. Exposing the JSC native-memory counter is useful, but I am requesting changes before this becomes an integration candidate:

  1. This PR targets codex/bun14-followup-memory-docs, so normal dev Cross-platform CI does not run. Land/fix #2301 first, then retarget or rebase this runtime PR onto current dev and obtain exact-head code CI. Do not merge this into the docs parent first, because that would make the runtime diff enter dev through the docs PR without the normal code gate.

  2. src/server/management/system-routes.ts converts a missing/non-numeric heapStats().extraMemorySize into 0, while the watchdog and doctor types correctly treat this field as optional. “Unavailable” is not the same measurement as zero. Keep one contract across all three surfaces: include extraMemorySize only when the runtime returned a finite numeric value, otherwise omit it. Add a fail-closed regression for the unavailable/malformed counter rather than pinning a fabricated zero.

  3. The doctor parsing/formatting change has no focused regression in tests/doctor.test.ts. Please assert both that a numeric jscHeap.extraMemorySize is retained/rendered as jscExtra, and that an absent or malformed field is omitted without changing the existing memory heuristic.

  4. Please adjust the wording that calls this “Bun 1.4 extraMemorySize visibility”. The current local Bun 1.3.14 heapStats() already exposes a numeric extraMemorySize; the 1.4-specific claim should be about the verified reporting/allocator behavior change, not the existence of the property itself.

After those points and exact-head dev CI, the sampling addition looks small and appropriately scalar-only.

lidge-jun added a commit that referenced this pull request Aug 22, 2026
…ockers closed

Rebuilds the harness halves of #2303 and #2304 directly on dev, without the
#2302 runtime commit those PRs were stacked on. Merging them as stacked would
have dragged in the extraMemorySize: 0 fabrication that #2302 still carries,
and would also have reverted unrelated coordinator work that landed on
src/cli/doctor.ts after the stack was cut.

scripts/bun-gc-relief-eval.ts

  Records rssBeforeLoad and derives postLoadGrowth and recoveryFraction. The
  controlling 260731 gate is "at least 50% of post-load RSS GROWTH is gone",
  and the previous shape could not express that: rssAfterLoad - rssPlus60s
  cannot separate recovery from ordinary drift, and the recorded verdict
  divided recovered bytes by total post-load RSS, which answers a different
  question than the gate asks. recoveryFraction is null when growth was not
  measurable, so a cell that proves nothing does not read as 0% recovery.

  A child-side gc-error now rejects the waiting cell instead of expiring into
  a ten-second "gc receipt timeout" that hides the real cause.

scripts/macos-rss-retention-harness-child.ts

  The SIGUSR2 collector is installed only under OCX_GC_EVAL=1. It was gated by
  a comment saying the 7h retention protocol never sends that signal, which is
  a claim about one sender rather than a property of the process; a stray
  signal would have collected inside the measurement that protocol exists to
  take.

scripts/smol-worker-ab.ts

  payloadMb and runs are validated as bounded integers. Previously runs=0
  produced a report claiming completionSuccess over an empty result set with
  the median fields silently absent, and a negative payload ran a meaningless
  workload instead of refusing. Medians are computed only once both arms are
  complete, so a verdict can never be derived from a partial set.

  The header claimed to measure the audited shapes of history, restore and
  policy workers; it imports none of them. It now says what it is: a synthetic
  screening of the array-plus-JSON burst shape those workers share.

The FAIL verdicts both harnesses recorded stand. No production Bun.gc(true)
call and no smol: true flag is landed here.

The GC harness needs a live upstream fixture to produce new numbers, so the
recorded RSS cells are NOT regenerated by this commit and the 020 table still
carries the old denominator. Re-running the cells and rewriting that table
around recoveryFraction is deliberately left as the next measurement pass
rather than claimed here.
Base automatically changed from codex/bun14-followup-memory-docs to dev August 22, 2026 11:20
@lidge-jun

Copy link
Copy Markdown
Owner Author

@lidge-jun lidge-jun closed this Aug 22, 2026
luvs01 pushed a commit to luvs01/opencodex that referenced this pull request Aug 22, 2026
Records why the four-PR stack was rebuilt on dev rather than merged: only
lidge-jun#2301 targeted dev, so dev CI never ran on the runtime diff, and a stacked
merge would have reverted coordinator work that landed on src/cli/doctor.ts
after the stack was cut (-94/+6 against current dev).

lidge-jun#2302 was closed rather than landed. It coerces a missing or non-numeric
extraMemorySize into 0 while the watchdog and doctor both type the field
optional, so a counter that was never read would surface as jscExtra=0MB
inside a series whose only purpose is showing whether native memory grows.

Also records the wp1 holdout lidge-jun#2359 landing after the author fixed the
exclusion that broke provider-live-models.test.ts:163, and the close of
issue lidge-jun#2330 with the reasoning for the two slugs deliberately left exposed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants