Skip to content

bake: report router roots that do not fit the path buffer and skip such route entries instead of panicking - #39196

Open
robobun wants to merge 8 commits into
mainfrom
farm/e6ee0f19/bake-long-router-root
Open

bake: report router roots that do not fit the path buffer and skip such route entries instead of panicking#39196
robobun wants to merge 8 commits into
mainfrom
farm/e6ee0f19/bake-long-router-root

Conversation

@robobun

@robobun robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Problem

  • A bake router root longer than about 4 KB aborts the process instead of producing an error:
    panic: range end index 5010 out of range for slice of length 4095 (exit 134).
  • Reachable from Bun.serve({ routes: { "/*": { dir, style } } }) in every release (the dir becomes a router root and that path has no feature gate), and from Bun.serve({ app: { framework } }) and bun build --app on canary or with BUN_FEATURE_FLAG_EXPERIMENTAL_BAKE=1. The bun:internal-for-testing FrameworkRouter constructor has the same join on its root option.
  • Cause: both Framework::resolve implementations (src/runtime/bake/mod.rs:384 for the dev server, src/runtime/bake/bake_body.rs:686 for bun build --app) and JSFrameworkRouter::constructor (src/runtime/bake/FrameworkRouter.rs:1800) resolve the root with resolve_path::join_abs, which normalizes into a fixed 4096 byte thread-local buffer (src/paths/resolve_path.rs:15) and indexes past its end when the result does not fit. The root is user input of arbitrary length.
  • The route scan has the same shape one step later: FrameworkRouter::scan_inner joined every directory and file under the root with FileSystem::abs (the same thread-local buffer), so a root that is itself acceptable but contains an entry whose full path does not fit aborted during the scan (panic: range end index 4151 out of range for slice of length 4095). Such entries exist: the OS limits the path you pass to a syscall, not how deep a tree can get.
  • src/runtime/bake/production.rs:548 re-joined the resolved root into the same thread-local buffer.

Fix

  • The three root sites resolve through bake_body::resolve_dir_option: a join_abs_string_buf_checked into MAX_PATH_BYTES - 1 bytes of a pooled PathBuffer, with the trailing separator stripped (previously only the constructor did that). MAX_PATH_BYTES - 1 is the limit Resolver::read_dir_info already applies to a directory path (src/resolver/resolver.rs:4191), so a root is rejected exactly when no directory lookup could succeed for it. bake: resolve app.root against the cwd and require it to be a string #39188 resolves app.root and can use the same helper.
  • The two resolve() implementations call it through resolve_router_root, which prints ENAMETOOLONG: Failed to resolve 'fileSystemRouterTypes[n].root' for framework: the resolved path must be shorter than N bytes and sets had_errors, the same path an unresolvable entry point takes, so Bun.serve throws its existing "Framework is missing required files!" error, bun build --app exits 1 with its existing summary line, and every bad root is still reported in one pass. The internal constructor throws an invalid-arguments error instead, since it is a JS constructor rather than a batch resolver.
  • An error rather than a silent skip is correct for a root because it is a broken configuration value, unlike a root that merely does not exist yet, which bake skips on purpose.
  • The scan joins each entry with the same checked join (entry_abs_path) and skips entries that do not fit, both for recursing into a directory and for registering a file. Skipping is the right outcome there: nothing could open such an entry, and read_dir_info returns None for the directory case already. Everything else under the root is still served.
  • With roots and entries both bounded by MAX_PATH_BYTES - 1, the re-joins into a full PathBuffer in dev server init (DevServer.rs, unchanged) and the production build (now a pooled PathBuffer instead of the 4 KB thread-local buffer, which is smaller than a PathBuffer on Windows) always fit.
  • The checked join compares the normalized length, so a root that is long as written but normalizes down to something that fits (routes/../routes/...) is still accepted; the old code accepted it too and a test pins that.
  • Not changed here: a root resolving outside the project root (bake: support fileSystemRouterTypes roots outside the project root #33203), and the thread-local join helpers themselves, which other open PRs (cli: stop aborting on --cwd and --tsconfig-override values longer than the path join buffer #38368, sourcemap: don't abort when a remapped source path exceeds the join buffer #37457, paths: heap-backed relative_alloc and join_abs_string_buf_spill; use them in _nodeModulePaths and the runtime linker #38392) are teaching to spill instead of overflow; this PR only removes bake's callers of the overflowing form.
  • Verified with test/bake/framework-router.test.ts. On the released binary the constructor test fails and the scan test aborts with the second panic above; with the scan test removed, the two Bun.serve tests abort with the first panic and the at-limit tests are wrongly accepted. With this change all pass: the internal constructor at exactly MAX_PATH_BYTES, a scan of a root 200 bytes below the limit holding index.ts plus a file and a directory with maximum-length names (only index.ts is discovered; skipped on Windows, whose own path limit is below MAX_PATH_BYTES), a two-entry framework reporting [0].root and [1].root, a routes dir, and Bun.serve plus bun build --app with roots of exactly MAX_PATH_BYTES (reported) and MAX_PATH_BYTES - 1 (looked up and skipped like any missing directory, so the re-joins run on a maximum-length root), plus the normalizing root. The per-platform limit comes from a new MAX_PATH_BYTES export in test/harness.ts (the same lines pack: report an error instead of panicking when --destination does not fit the path buffer #38749 adds) and is asserted in the error text, so the table is checked against the binary.
  • The bun build --app children are spawned without BUN_JSC_validateExceptionChecks and with leak detection off: loading any --app config trips a pre-existing unchecked exception in BakeGetDefaultExportFromModule before the framework is resolved, and every successful --app build leaks its transpilers at exit. These are the reasons test/bake/dev/production.test.ts is exempt from both checks; bake: check for exceptions in the production build's module helpers #38949 and bake: drop the production build's transpilers and framework projection #38233 fix them, after which the override can go. The tests stay in this file rather than production.test.ts because that file's existing tests run close to the default per-test timeout on a debug build.
  • bun bd test test/bake/dev/bundle.test.ts still passes (real router roots and trees through the dev server scan); a root written as routes/ is still served.

Background

  • Bake frameworks declare router types; each has a root directory that bake scans for route files. Bake keeps two copies of the Framework struct (mod.rs for the dev server, bake_body.rs for bun build --app), each with its own resolve() that turns the user's root into an absolute path; that is why the fix touches two call sites through one helper. FrameworkRouter::scan_inner is the walk over that directory that both of them, and the internal constructor, run afterwards.
  • resolve_path::join_abs (and FileSystem::abs, which wraps it) is bun's path.resolve: it joins against a base directory and normalizes into a caller-independent 4096 byte thread-local scratch buffer. join_abs_string_buf_checked is the variant for input of unknown length: it joins into a caller-provided buffer and returns None when the normalized result would not fit.
  • PathBuffer is bun's [u8; MAX_PATH_BYTES] path scratch type (4096 bytes on Linux, 1024 on macOS, 98302 on Windows), drawn from a per-thread pool so it does not live on the stack. A path of MAX_PATH_BYTES bytes leaves no room for the NUL terminator, which is why the resolver and this change both treat that length as already too long.
  • Missing router roots are not errors in bake: the built-in React framework declares a pages root that a project may not have, so read_dir_info_ignore_error returning None skips the router type. That is the behavior this change deliberately does not extend to over-long roots, and the behavior it does extend to over-long entries inside a root.

no test proof · iteration 0 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/bake/framework-router.test.ts

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@robobun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 29 minutes

Limit details: You’ve used all 5 included reviews currently available under your plan.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ce62e470-5296-4ef9-9507-9abeae970400

📥 Commits

Reviewing files that changed from the base of the PR and between b609492 and d697d00.

📒 Files selected for processing (5)
  • src/runtime/bake/FrameworkRouter.rs
  • src/runtime/bake/bake_body.rs
  • src/runtime/bake/production.rs
  • test/bake/framework-router.test.ts
  • test/harness.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 85297343-5395-46fd-ab02-f9e71dd907c2

📥 Commits

Reviewing files that changed from the base of the PR and between 5448c1e and b609492.

📒 Files selected for processing (5)
  • src/runtime/bake/FrameworkRouter.rs
  • src/runtime/bake/bake_body.rs
  • src/runtime/bake/mod.rs
  • src/runtime/bake/production.rs
  • test/bake/framework-router.test.ts

Included review availability: Your plan includes up to 5 reviews per rolling hour; 0 remain after this review.


Walkthrough

Changes

Framework router root resolution

Layer / File(s) Summary
Checked router-root resolution
src/runtime/bake/bake_body.rs, src/runtime/bake/FrameworkRouter.rs
Router roots now use bounded joining. Overlong roots return ENAMETOOLONG or an invalid-arguments error.
Framework resolution integration
src/runtime/bake/bake_body.rs, src/runtime/bake/mod.rs, src/runtime/bake/production.rs
Framework resolution records failed roots and returns ModuleNotFound. Production resolution uses a pooled PathBuffer.
Path-limit regression coverage
test/bake/framework-router.test.ts
Tests cover constructor, serving, build, boundary lengths, and normalized paths.

Possibly related PRs

  • oven-sh/bun#38368: Adds checked path handling and ENAMETOOLONG reporting in another CLI resolution path.
  • oven-sh/bun#39188: Updates Bake router and app root resolution with normalization and oversized-path rejection.
  • oven-sh/bun#39203: Updates path joining to use bounded buffers in another code path.

Suggested reviewers: jarred-sumner, dylan-conway

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the primary fix: report overlong router roots and skip entries instead of panicking.
Description check ✅ Passed The description provides detailed problem, fix, background, and verification information, although it uses different headings than the template.

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

@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 10:46 PM PT - Aug 15th, 2026

@robobun, your commit d697d00d1dd46eccdd999214d19df698ed8369a4 passed in Build #99173! 🎉


🧪   To try this PR locally:

bunx bun-pr 39196

That installs a local version of the PR into your bun-39196 executable, so you can run:

bun-39196 --bun

@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

Status: reproduced on the released binary: an over-long router root aborts through every entry point (Bun.serve({ routes: { "/*": { dir, style } } }), Bun.serve({ app }), bun build --app, the internal FrameworkRouter constructor), and self-review found that the route scan under an accepted root aborted the same way on an entry whose path does not fit. Current head: roots of MAX_PATH_BYTES or more are reported as ENAMETOOLONG: Failed to resolve 'fileSystemRouterTypes[n].root' for framework ... (the constructor throws), shorter roots are looked up normally, and the scan skips entries that do not fit. test/bake/framework-router.test.ts covers all of it, including both sides of the limit for the dev server and bun build --app and a scan over such a tree. Rebased on current main; review feedback so far is addressed.

Comment thread src/runtime/bake/bake_body.rs Outdated
Comment thread src/runtime/bake/bake_body.rs Outdated
Comment thread src/runtime/bake/bake_body.rs Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — the earlier same-class miss (JSFrameworkRouter::constructor) is now fixed and covered by a test, and the comment-cop feedback was addressed.

What was reviewed:

  • resolve_router_root uses join_abs_string_buf_checked into a pooled buffer and copies to Box<[u8]> before the guard drops; the None arm sets had_errors so the existing "missing required files" path fires.
  • All four router-root join sites in src/runtime/bake now go through a checked join; the production.rs re-join writes into a pooled PathBuffer so a Windows root between 4 KB and MAX_PATH_BYTES that now survives resolve() still fits.
  • Tests spawn subprocesses per entry point (Bun.serve({app}), routes.dir, bun build --app, internal constructor), drain pipes concurrently, assert the specific error text and exit codes, and pin that a long-as-written root that normalizes down still works.
Extended reasoning...

Overview

Replaces the unchecked resolve_path::join_abs (which normalizes into a fixed 4096-byte thread-local buffer and panics on overflow) with join_abs_string_buf_checked into a pooled PathBuffer at the four sites that resolve a bake router root: both Framework::resolve implementations (via a new shared resolve_router_root helper in bake_body.rs), JSFrameworkRouter::constructor, and the re-join in production.rs. On overflow the framework paths report ENAMETOOLONG and set had_errors (same collection pattern as the sibling resolve_helper), and the JS constructor throws an invalid-arguments error. Six new tests in test/bake/framework-router.test.ts cover every user-reachable entry point plus the normalizing case.

Security risks

None. The change strictly tightens handling of untrusted input: a user-controlled path that previously overflowed a fixed buffer and panicked now fails with a bounded error. No new privilege, filesystem, or network surface.

Level of scrutiny

Moderate. Bake is explicitly experimental (print_warning()), and the behavior change is scoped to over-long router roots that never worked before (they panicked). The fix uses existing in-tree helpers (join_abs_string_buf_checked, path_buffer_pool::get) with the same call shape as the dev-server re-join in DevServer.rs. The pooled-buffer lifetime is correct at each site: the result is copied to a Box<[u8]> (or into the arena) before the PoolGuard drops, and in production.rs the borrowed joined_root is only read on the next line before buf goes out of scope at loop-iteration end.

Other factors

My prior review flagged the missed JSFrameworkRouter::constructor sibling; that is now fixed (1e97fe2) with a dedicated test that throws instead of aborting. The comment-cop notices were addressed by shortening the helper's doc comment to one line (236e4d3). The bun build --app test unsets BUN_JSC_validateExceptionChecks for the child, which mirrors the existing no-validate-exceptions.txt entry for test/bake/dev/production.test.ts (pre-existing unchecked exception in BakeGetDefaultExportFromModule, tracked separately). Tests follow harness conventions: tempDir, bunEnv spread, Buffer.alloc(n, fill).toString(), concurrent pipe draining, describe.concurrent for the subprocess suite.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I re-reviewed after 1e97fe2/236e4d3/b609492 and found no bugs — the constructor sibling I flagged earlier is now routed through the same checked join, and the comment-cop notes are addressed. Because this touches all four bake router-root resolution paths (dev server, bun build --app, the production re-join, and the internal constructor) and the --app tests need ASAN/exception-check overrides tied to #38949/#38233, a human sign-off would still be worthwhile.

Checked: join_abs_string_buf_checked compares the normalized length against buf.len() (resolve_path.rs:1661), so slicing the pooled buffer to MAX_PATH_BYTES - 1 accepts exactly ≤ MAX_PATH_BYTES - 1 bytes — matches the boundary tests and the read_dir_info limit cited in the description.
Checked: on the None arm both resolve() loops leave fsr.root untouched but set had_errors, so the stale value is never read (fn returns Err(ModuleNotFound)), and entry_client/entry_server still resolve for batch error reporting.
Checked: the production.rs re-join is unchecked but writes into a full pooled PathBuffer; fsr.root is absolute and ≤ MAX_PATH_BYTES - 1 post-resolve(), so the join cannot overflow.
Checked: the pooled PathBuffer guard drops at the end of join_router_root, so no pool leak on either arm.

Extended reasoning...

Overview

This PR replaces a user-reachable panic (range end index N out of range for slice of length 4095) with a recoverable error when a bake fileSystemRouterTypes[n].root resolves to a path that does not fit in a PathBuffer. It introduces join_router_root / resolve_router_root in bake_body.rs (a join_abs_string_buf_checked into MAX_PATH_BYTES - 1 bytes of a pooled buffer) and routes all four call sites through it: both Framework::resolve copies (mod.rs and bake_body.rs), the JSFrameworkRouter::constructor, and the production.rs re-join. ~160 lines of new tests in framework-router.test.ts cover the internal constructor, both Bun.serve shapes, and bun build --app at both sides of the boundary plus a normalizing root.

Security risks

None. This tightens input validation on a user-supplied configuration path — a value that previously crashed the process now surfaces as ENAMETOOLONG and fails the framework load. No new file I/O, no privilege boundaries, no untrusted parsing.

Level of scrutiny

Medium. Bake is experimental but user-facing, and the change threads through four distinct entry points across three platforms with different MAX_PATH_BYTES values (1024 macOS / 4096 Linux / 98302 Windows). The core swap (join_absjoin_abs_string_buf_checked) is mechanical and I verified the checked helper's semantics match the boundary the tests assert. The production.rs re-join now uses a full pooled PathBuffer instead of the 4 KB thread-local one, which on Windows expands the accepted range — a behavioral widening the description calls out.

Other factors

  • My earlier inline finding (the JSFrameworkRouter::constructor sibling) was fixed in 1e97fe2 with a matching test, and both comment-cop notes were addressed in 236e4d3; all threads are resolved.
  • The bun build --app tests spread bunEnv and unset BUN_JSC_validateExceptionChecks / append detect_leaks=0 to ASAN_OPTIONS, citing pre-existing #38949/#38233 (same exemptions production.test.ts already carries). That is a documented workaround rather than a new safety-net removal, but it is the kind of env override a maintainer should sign off on.
  • Test quality is strong: describe.concurrent, tempDir, concurrent stdout/stderr/exit drain, exact stdout assertions, boundary at maxPathBytes - 1 vs maxPathBytes, and the per-platform limit is asserted in the error text so the test's constant table is checked against the binary.
  • Given the multi-file surface area and the platform-dependent limit, I am deferring rather than approving so a maintainer can confirm the MAX_PATH_BYTES - 1 threshold choice and the test env overrides.

…buffer instead of panicking

Both Framework::resolve implementations joined each user supplied router
root with join_abs, which writes into a fixed 4 KB thread-local buffer and
panics with "range end index N out of range for slice of length 4095" when
the resolved path does not fit. Resolve the roots through one shared helper
that uses a checked join into a PathBuffer and reports ENAMETOOLONG through
the existing had_errors path, so Bun.serve throws and bun build --app exits
with an error. The production build re-joined the resolved root into the
same thread-local buffer; join it into a PathBuffer like the dev server does.
…-app child

Loading any --app config trips the validator in BakeGetDefaultExportFromModule
before the framework is resolved, which is why production.test.ts is excluded
from validation; exclude only this child instead of the whole file.
…ng root too

Same join into the 4 KB thread-local buffer as the framework router roots;
it is a JS constructor, so it throws instead of reporting through had_errors.
Also shorten the resolve_router_root doc comment.
…he internal constructor

join_router_root resolves into MAX_PATH_BYTES - 1 bytes, the same length from
which the resolver's read_dir_info refuses a directory, so every accepted root
leaves a byte to spare in the path buffers the dev server and production build
re-join it into. The tests now pin that threshold on both sides (one byte below
is looked up and skipped like any missing directory, at the limit is reported)
for Bun.serve and bun build --app, and report both roots of a two-entry
framework.
Every bun build --app leaks its transpilers at exit (#38233), which is what
keeps production.test.ts out of LeakSanitizer; the successful build here
aborted under it on the ASAN lane.
FrameworkRouter::scan_inner joined every directory and file under an
accepted root through the 4 KB thread-local buffer, so a root that passes
the new limit but contains an entry whose path does not fit still aborted
the scan. Join entries with the same checked join and skip the ones that
cannot be opened. The root helper is now resolve_dir_option, strips the
trailing separator for every caller, and is what the internal constructor
uses directly; the tests read MAX_PATH_BYTES from the harness and add a
scan over such a tree.
@robobun
robobun force-pushed the farm/e6ee0f19/bake-long-router-root branch from b609492 to 8cb473b Compare August 16, 2026 05:07
@robobun robobun changed the title bake: report a fileSystemRouterTypes root longer than the path buffer instead of panicking bake: report router roots that do not fit the path buffer and skip such route entries instead of panicking Aug 16, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Beyond the inline nit, I also checked whether production.rs:548's unchecked join_abs_string_buf could still overflow after this change — it cannot: fsr.root is absolute and pre-validated to < MAX_PATH_BYTES by resolve_router_root, and the target is a full PathBuffer. Also confirmed that when resolve_router_root returns None, the stale (relative) fsr.root is never read: both resolve() implementations return Err(ModuleNotFound) on had_errors before any consumer sees it.

Extended reasoning...

The one finding this run is a nit-level latent test hang; the inline comment covers it. Recording two adjacent concerns that were examined and ruled out so a later pass does not re-derive them: (1) production.rs still uses an unchecked join, but its input is now guaranteed to fit; (2) the None branch leaves fsr.root un-rewritten, but had_errors short-circuits before use.

Comment thread test/bake/framework-router.test.ts Outdated
A temp dir whose length left exactly one byte before the target produced a
zero-length segment, which path.join drops, so the loop never advanced.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — both earlier findings (the unchecked JSFrameworkRouter::constructor join and the tree-builder loop's zero-length-segment fixed point) are addressed, and this pass found nothing further.

What was reviewed:

  • resolve_dir_option/resolve_router_root and the four call sites: checked join into MAX_PATH_BYTES - 1, trailing-slash strip, error reported through Output::err + had_errors like the sibling entry-point failures.
  • entry_abs_path in the scan: verified abs_buf_checked exists and returns None on overflow; both the dir-recurse and file-register arms skip on None and the pooled buffer outlives every use of abs_path.
  • production.rs re-join: now into a pooled PathBuffer, and fsr.root is already bounded so the unchecked join_abs_string_buf there cannot overflow.
  • Tests: boundary at exactly MAX_PATH_BYTES and MAX_PATH_BYTES - 1 for every entry point, the scan-skip case, and the normalizing-root case; the MAX_PATH_BYTES harness constant is asserted against the binary via the error text.
Extended reasoning...

Overview

Converts a user-reachable panic (range end index N out of range for slice of length 4095) in bake's router-root resolution into a reported ENAMETOOLONG error, and makes the route scan skip entries whose absolute paths would overflow the same buffer. Touches four Rust files in src/runtime/bake/ (~70 lines of production code), adds ~190 lines of tests to test/bake/framework-router.test.ts, and adds a MAX_PATH_BYTES constant to test/harness.ts.

Security risks

None. This tightens input validation (bounds-checks a user-provided path before writing into a fixed buffer) rather than loosening any check. No auth, crypto, or trust boundaries are involved.

Level of scrutiny

Medium. Bake is experimental and the change follows an established pattern — replace an unchecked thread-local-buffer join with the existing join_abs_string_buf_checked variant and report on None. The two resolve() implementations, the internal constructor, and the production re-join are the complete set of join_abs/fs.abs call sites on router roots/entries in this module; I grepped for siblings on the first pass and the one I found (the constructor) was fixed.

Other factors

This is my third look at the PR. The first pass flagged the missed constructor sibling (fixed in 1e97fe2) and the second flagged an environment-dependent hang in the test's tree-builder loop (fixed in d697d00 with Math.max(1, …)). Both fixes match what was suggested. Test coverage is thorough: every entry point, both sides of the exact byte limit, the scan-skip case with a real on-disk tree, and a normalizing root that must still be accepted. The bun build --app env overrides (disabling exception-check validation and leak detection) are pre-existing exemptions on production.test.ts with tracking issues named in the comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant