Skip to content

Replace boolean flag parameters with two-variant enums - #37180

Open
dylan-conway wants to merge 4 commits into
mainfrom
claude/boolean-to-enum-refactor-fc3db6
Open

Replace boolean flag parameters with two-variant enums#37180
dylan-conway wants to merge 4 commits into
mainfrom
claude/boolean-to-enum-refactor-fc3db6

Conversation

@dylan-conway

Copy link
Copy Markdown
Member

What does this PR do?

Positional booleans such as eql_long(a, b, true), link(true) or GlobWalker::init(.., true, true, false, true, true) don't say what they mean at the call site. This adds bun_core::bool_enum!, which declares a Copy two-variant enum (Name::{No, Yes} or domain-named variants like Scope { Local, Global }; false variant first and Default; from_bool for values computed at runtime, deliberately no Into<bool>), and uses it to retype boolean parameters, mode-like fields, opaque tuple slots and a few non-predicate -> bool returns (→ Result / ControlFlow / named enum) across the Rust workspace. Call sites now read CheckLen::Yes, StopMode::Abrupt, Chunk::Last, TlsRole::Client.

Behaviour is unchanged. Deliberately left as bool: FFI/repr(C) and codegen-dictated signatures (.classes.ts hooks, host fns), wire/lockfile layouts, const generics, predicates (is_*/has_*), plain locals, named on/off option fields and single-arg setters, and parameters where every caller passes the same literal (the other variant would trip -D dead_code). C++ and TS sources are out of scope.

How did you verify your code works?

  • cargo check --workspace (+ --tests) clean on aarch64/x86_64 macOS, x86_64/aarch64 Linux, x86_64 Windows; cargo clippy --workspace clean.
  • Every hunk was re-read specifically for polarity inversions (variant order vs from_bool, == Yes vs old if flag, ControlFlow direction, tuple/argument order).
  • Debug build: a script exercising fs, glob, TOML, shell, zlib/zstd, base64, TextDecoder, inspect, GC, spawn, serve/fetch (redirect/close/HEAD), transpiler and Bun.build produces byte-identical output to the released binary; spot-ran shell, glob, toml, inspect, serve static/routes/file, body-clone, css color, fs-mkdir and cli env test files, all passing.

…t workspace

Call sites like `eql_long(a, b, true)`, `link(true)`, or
`GlobWalker::init(.., true, true, false, true, true)` don't say what the
booleans mean. This introduces `bun_core::bool_enum!`, which declares a
`Copy` two-variant enum (`Name::{No, Yes}` or domain-named variants, false
variant first and `Default`) with a `from_bool` constructor for runtime
values, and uses it to retype boolean parameters, mode-like fields, opaque
tuple slots and a few non-predicate `-> bool` returns throughout `src/`.
Call sites now read `CheckLen::Yes`, `Scope::Global`, `StopMode::Abrupt`,
`Chunk::Last`, etc.

Behaviour is unchanged. Left as `bool` on purpose: FFI/`repr(C)` and
codegen-dictated signatures, wire/lockfile layouts, const generics,
predicates (`is_*`/`has_*`), plain locals, named on/off option fields and
single-argument setters, and parameters where every caller passes the same
literal (the unused variant would be dead code).

@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 reviewed this PR and the automated bug-hunting pass found no issues. The changes I inspected (the bool_enum! macro, ResetOutcome, HttpScheme, ConnectionHeader, ModulePhase, Subdomains, IdentOrRefKind, Expanded, and the CheckLen/WsBefore/Chunk call-site rewrites) all preserve polarity correctly. That said, at 300 files and ~21k diff lines spanning TLS/proxy verification, the HTTP client, the package manager, and the parser/bundler, plus a new workspace-wide bool_enum! convention, a maintainer sign-off is warranted.

Extended reasoning...

Overview

This PR introduces bun_core::bool_enum!, a macro that declares a two-variant Copy enum (false-variant first, Default, from_bool, deliberately no Into<bool>), and applies it across ~300 files in the Rust workspace to replace positional bool parameters with named enums (CheckLen::Yes, Chunk::Last, TlsRole::Client, etc.). A handful of non-predicate -> bool returns are also retyped to ControlFlow, Result, or a named enum (ResetOutcome, Expanded). No behaviour change is intended.

Security risks

The refactor touches security-sensitive paths: boringssl hostname matching (Subdomains), TLS role and reject_unauthorized plumbing in uws/ssl_wrapper/WebSocketProxyTunnel, HTTP proxy selection (HttpScheme, AllowProxyUrl), HPACK never-index for sensitive headers, and package-install/lockfile code. A single polarity inversion in any of these could silently weaken a security check. I spot-checked several of the trickier variant orderings (HttpScheme { Https, Http } vs url.is_http(), Subdomains::from_bool(flags & SINGLE_LABEL_SUBDOMAINS != 0), RejectUnauthorized, ConnectionHeader { Close, KeepAlive }, ModulePhase { Evaluation, Defer } at the FFI boundary, ResetOutcome vs the old !retained test, IdentOrRefKind packing) and each preserves the original semantics — but I have not read every one of the ~300 files.

Level of scrutiny

High. The change is mechanical per-hunk, but the aggregate is a workspace-wide type-signature change across every major subsystem, including hot paths (parser, printer, resolver) and safety-critical ones (TLS, install). The primary failure mode — a swapped variant order or an inverted == Yes — would compile cleanly and might only surface as a subtle runtime divergence. The Rust type system catches missed call sites but not polarity errors. Per the repo's review guidance, new cross-cutting abstractions and workspace-wide conventions should have maintainer agreement.

Other factors

  • No new tests are added; the PR description states behaviour is unchanged and verified by byte-identical output against the release binary on a scripted workload plus spot-running existing test files. That's reasonable for a pure refactor, but CI is the real gate here.
  • The bool_enum! macro itself is small and correct (false-variant = discriminant 0 = Default; from_bool(true) → second variant).
  • The diff is far too large (~889k characters, truncated in my context) for me to have verified every hunk; I sampled the visible portion and the higher-risk semantic renamings.
  • No prior review comments or CI results are visible on the timeline yet.

alii pushed a commit that referenced this pull request Aug 15, 2026
…enums (#39166)

### Problem
- `IntermediateOutput::code()` and `code_standalone()` in
`src/bundler/Chunk.rs` take `force_absolute_path: bool` and
`enable_source_map_shifts: bool`. Of their seven callers, four pass bare
literals for both flags (`code_standalone(.., false, false, ..)` in
`writeOutputFilesToDisk.rs` and `generateChunksInParallel.rs`, `code(..,
false, false)` in `MetafileBuilder.rs` and `bake/DevServer.rs`) and a
fifth for one of them, so at the call site nothing says which flag is
which; the metafile caller compensates with trailing comments.
- This is the `bare_bool_args:src/bundler/Chunk.rs` finding recorded in
`mordant-baseline.toml`.

### Fix
- Each flag becomes a two-variant enum next to `CodeResult`:
`ReferencePathStyle::{ImporterRelative, OutdirRelative}` replaces
`force_absolute_path` (`false` / `true`) and
`SourceMapShiftTracking::{Disabled, Enabled}` replaces
`enable_source_map_shifts`. Two constructors hold the derivations the
callers used to spell out: `ReferencePathStyle::for_chunk(chunk,
compile)` (the `compile && !IS_BROWSER_CHUNK_FROM_SERVER_BUILD` test
both output loops had inline) and
`SourceMapShiftTracking::for_source_map(option)` (the `!=
SourceMapOption::None` test three callers had).
- `code()` / `code_standalone()` match on `SourceMapShiftTracking` to
pick the `code_with_source_map_shifts::<true / false>` instantiation,
exactly as the `if` on the bool did, and pass `ReferencePathStyle`
through to the one place the old bool was read
(`use_outdir_relative_path`). Every caller maps its previous value onto
the matching variant. No behavior change.
- Deletes the baseline entry. With `-p bun_bundler`,
`MORDANT_BASELINE_WRITE=1` writes a `[bun_bundler]` section identical to
this edit.
- Tests, in the files that already cover these paths, pin the value each
caller selects. They pass before and after this change (it is a
refactor) and were checked against a build with the mappings
deliberately inverted, where all of them fail while the pre-existing
tests around them still pass:
- `test/bundler/bundler_splitting.test.ts`
(`splitting/ChunkReferencePaths`, the two `code()` output loops): entry
points in nested directories import the shared chunk as
`../../chunk-*.js` and each other as `../site/index.js`, or as
`publicPath + outdir path` when a public path is set; a build without
source maps has no `//# debugId`; with source maps, `util("admin")`,
which follows the rewritten dynamic import on the same line, still maps
to its source column, for both a shorter and a longer substituted path;
the outdir and in-memory loops produce the same code and mappings.
- `test/bundler/standalone.test.ts` (`sourcemaps`, the three
`code_standalone()` callers): without source maps nothing map related
appears in the document; with them, the whitespace-minified inlined
script maps `function greet` back to its source column across the data:
URI written over the asset import, exactly one debugId is emitted and it
is inside the script, and the document still ends at `</html>`; same
through an outdir.
- `test/bake/dev/css.test.ts` (`asset referenced in css`, the DevServer
caller): the served stylesheet has its asset reference resolved and no
debugId trailer.
- Other verification:
- `cargo dylint --all -p bun_bundler` with the entry removed: clean on
this branch; with the old `src/` restored it reports exactly this
finding over the baseline (`over-baseline.txt`: `bun_bundler 1`).
- Byte-for-byte comparison of this build's output against the installed
release bun (main from 65 commits back; the two commits since then that
touch these files, #38819 and #38604, rename a flag and change thread
pool waiting, not output) over 48 output files: nested entry points with
a shared chunk and an asset with no / linked / external / inline source
maps and with a `--public-path`, a root-level entry, standalone HTML in
every source map mode and with a public path, and a metafile. All
identical, including `.map` mappings and `//# debugId` comments.
- `bun bd test` on `bundler_splitting`, `bundler_compile_splitting`,
`standalone`, `metafile`, `bundler_html`, `bundler_naming`,
`bundler_files`, `test/js/bun/sourcemap/` and
`test/bake/dev/css.test.ts`: pass. `bun build --compile` with and
without `--sourcemap` (the `OutdirRelative` + `Enabled` combination) was
checked by hand: `/$bunfs/root/...` frames without a map, original file
names with one; `bun-build-compile-sourcemap.test.ts` asserts the same
but hits the 5 s default timeout under the ASAN debug build here, since
each test copies the 830 MB debug binary.
  - `cargo clippy -p bun_bundler --no-deps` is clean.

### Background
- After the bundler prints a chunk, references to other output files
(imports of sibling chunks, asset URLs, server component boundaries) are
still placeholders; `IntermediateOutput::code()` replaces them with real
paths once every output path is known. `force_absolute_path` chose
whether those paths are relative to the importing chunk's directory
(default) or to the outdir (`bun build --compile`, whose chunks all load
from one virtual root); a configured public path forces the
outdir-relative form either way, which is why standalone HTML and the
metafile could always pass `false`.
- A source map shift records how much longer or shorter each substituted
path is than its placeholder. The chunk's source map was generated
against the placeholder text, so `output_source_map.finalize(&shifts)`
needs them for any chunk that gets a map; `enable_source_map_shifts`
turned that bookkeeping (and the `//# debugId=` comment) on. HTML
chunks, CSS and the metafile never get a map, hence their literal
`false`.
- mordant is the advisory Rust lint pack CI runs;
`mordant-baseline.toml` records the pre-existing findings per (lint,
file) so only new ones are reported. Fixing a recorded finding lets its
entry be deleted.
- #37180 is a tree-wide pass over the same kind of parameter that also
covers this site; it has been conflicting with main since it was opened.
This PR is the one-site version, like the other `bare_bool_args` entries
being retired individually.

<details>
<summary>Unrelated bugs noticed while writing the tests (not touched
here, handed off separately)</summary>

- `BuildArtifact.sourcemap` points at the next chunk instead of the
chunk's map whenever a build has more than one chunk
(`js_bundle_completion_task.rs` assumes the map follows its chunk in the
output list; the list builder groups maps after all chunks). The tests
here look maps up by path instead.
- `Bun.build({ compile: true, target: "browser", sourcemap: "linked" })`
emits `//# sourceMappingURL=/$bunfs/root/...` (the executable public
path leaks into standalone HTML builds; the CLI emits a relative URL).
The tests here do not assert the URL.
- `expectBundled`'s `snapshotSourceMap.mappings` check ends in `expect(a
=== b)` with no matcher, so it never compares against the map; the tests
here use `SourceMapConsumer` directly.
- `standalone.test.ts`'s two "falls back to normal compile" tests write
an `app` executable into the test runner's cwd.
</details>
@alii

alii commented Aug 16, 2026

Copy link
Copy Markdown
Member

@robobun update

@robobun

robobun commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Branch is current with main as of 8ed4565. History on top of dylan's commit 3d809d1: f4f845e (merge of 325 commits of main, 114 conflicted files, described below), 2ce8911 (records the bool_enum! from_bool dead_code escape in the source-lint inventory), 8ed4565 (merge of the next 8 commits of main). The diff against main is now 528 files (+7600/-4464), down from 539 (+8116/-4720); apart from the inventory line everything is under src/.

Second merge (8ed4565), 4 conflicts: #39310 replaced diff-match-patch with a Myers diff, so diff_match_patch.rs and this PR's CheckLines enum (declared there, used only by the two dmp.diff calls that #39310 deleted) are gone, while the IsAgent/AnsiColors retyping of DiffConfig::default in printDiff.rs still applies and was kept; pretty_format.rs is now identical to main (#39310 removed the one helper this PR had touched); in PipeReader.rs, #39296's new limit.reached() condition in read() was kept with received_hup still typed ReceivedHup. Checked the same way as the first merge: all 12 triples, --tests, clippy, fmt, the dead-code inventory lint, plus printing/diffexample, util/bun-stdin-slice (the test #39296 added), spawn and bunshell, all passing on a debug build.

How the first merge's conflicts were resolved:

Call sites added on main since the base that pass a bool to a function this PR retypes, fixed after the merge: src/parsers/xml.rs (IsSingleLine), src/install/{audit_fix,update_transitive}.rs (ExtendedManifest, InstallPeer), src/install/migration/npm_lock.rs (CheckLen), src/install/isolated_install.rs build_store and its callers in prune.rs (InstallRootDependencies), src/jsc/Task.rs, src/runtime/server/mod.rs and src/runtime/test_runner/jest.rs (IsRejection), src/runtime/server/server_body.rs (Flavor), and src/runtime/ipc.rs stop_for_vm_teardown (Notify, Windows only).

Verification on the merged tree:

  • cargo check --workspace clean for all 12 CI triples (bun run rust:check-all), --tests clean on the host, cargo clippy --workspace clean, cargo fmt --check clean.
  • Every bool_enum still declared has uses; the 31 that were removed are exactly the ones listed above.
  • Debug build passes these files: xml, toml, shell lex/parse, css + color + css-modules, spawn, node fs, pbkdf2, quic-stream, mysql datetime round trip, valkey, html-rewriter, http proxy, filter-workspace, transpiler, framework-router, bun-audit, bun-update-transitive, bun-prune, migrate, minimum-release-age, isolated-install, node-http2 (incl. the syscall-fault file touched by http2: resolve BatchSegment to its bytes in one place #39139), h2-conformance, websocket-server. The only failures seen (the XML deep-nesting timeout, the 30s websocket send benchmark, and 9 localhost connect tests in net/socket.test.ts) reproduce identically with a main debug build or the released binary in this container, so they are unrelated to the merge.

@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 reviewed this PR and the automated bug-hunting pass found no issues. Because it's a ~300-file mechanical refactor whose entire risk surface is polarity inversions the type system can't catch — and it touches TLS verification, the package manager, bundler, parser, and HTTP client — a human spot-check across a sample of hunks is still warranted before merge.

Checked the bool_enum! macro (false-variant first, from_bool maps true→second variant) and spot-checked polarity on ResetOutcome vs. ast_memory_allocator, HttpScheme in env_loader, Subdomains in boringssl, ConnectionHeader, and the ControlFlow conversion in HTMLScanner — all preserve the original branch direction.

Extended reasoning...

Overview

This PR introduces bun_core::bool_enum! and retypes boolean flag parameters, mode-like fields, opaque tuple slots, and a handful of non-predicate -> bool returns to two-variant enums across ~300 files spanning essentially every Rust crate in the workspace: bun_core, ast, bundler, js_parser/js_printer, css, http/http_jsc, install, jsc, resolver, react_compiler, shell, sql, runtime/api, bake, and more. The diff is ~888k characters. The stated invariant is that behaviour is unchanged.

Security risks

Several touched paths are security-sensitive: boringssl/lib.rs hostname matching (Subdomains), http/lib.rs check_server_identity / AllowProxyUrl, RejectUnauthorized in the WebSocket proxy tunnel, NeverIndex for HPACK sensitive headers, and reject_unauthorized plumbing in the SSL context cache. A polarity flip in any of these would fail open. I spot-checked Subdomains, HttpScheme, and AllowProxyUrl and they preserve the original branch direction, but I have not exhaustively verified every security-adjacent hunk in a diff this size.

Level of scrutiny

This is a pure refactor with no intended behaviour change, so per-hunk the review is mechanical: confirm the false-variant maps to what was previously false and that every == Yes / == SomeVariant / from_bool(...) preserves polarity. However, the type system cannot catch a swapped variant order or a == No that should have been == Yes, and there are hundreds of such conversions across critical subsystems. That combination — huge surface, silent-on-error failure mode, security-relevant paths — puts it well outside what I'm comfortable approving without a human sampling the diff.

Other factors

  • No prior human review on the PR; the only timeline activity is a robobun merge-from-main.
  • The PR ships no new tests (by design — behaviour is unchanged), so correctness rests on the existing suite plus the author's byte-identical output check.
  • cargo check/clippy clean on all targets guarantees no type-level mistakes but says nothing about polarity.
  • The bug-hunting system found nothing, and my own spot-checks (ResetOutcome, HttpScheme, Subdomains, ConnectionHeader, ControlFlow in HTMLScanner, CloneText, Chunk) all check out — but that covers a small fraction of 300 files.

@robobun

robobun commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator
Updated 1:55 PM PT - Aug 16th, 2026

@robobun, your commit 8ed4565321bbb35e3d0dfd875d6c8714812920e1 passed in Build #99529! 🎉


🧪   To try this PR locally:

bunx bun-pr 37180

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

bun-37180 --bun

@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 reviewed this PR and the automated bug hunt found no issues. Given the scale (529 files, +7630/-4482, with 114 merge conflicts resolved against 325 commits of drift) and that several retyped flags sit on security-sensitive paths (RejectUnauthorized, AllowProxyUrl, TlsRole, cert verification in check_server_identity), a human sign-off is still warranted — both for the polarity audit and for the workspace-wide convention this introduces.

What was reviewed:

  • bool_enum! macro: false-variant is discriminant 0 and Default, from_bool(true) → second variant — consistent.
  • Spot-checked polarity on HttpScheme { Https, Http } vs url.is_http(), ResetOutcome::Recycled vs old !retained, Subdomains, ConnectionHeader, Chunk::{More,Last}, CloneText { Adopt, Clone } — all match the original bool sense.
  • ControlFlow conversion in HTMLScanner (on_*_tag returning Break → stop) preserves the previous true → stop contract.
Extended reasoning...

Overview

This PR introduces bun_core::bool_enum! and mechanically retypes positional bool parameters, mode-like fields, and a few non-predicate -> bool returns as two-variant enums across ~529 files in the Rust workspace. The visible diff (truncated at ~30%) covers ast, bundler, css, http/h2/h3, install, js_parser/printer, jsc, react_compiler, resolver, runtime, and more. A bot merge against main resolved 114 conflicting files and dropped 31 enum declarations superseded by types main had since introduced.

Security risks

Several retyped flags gate security decisions: RejectUnauthorized in the WebSocket proxy tunnel, AllowProxyUrl feeding check_server_identity and SNI selection, TlsRole::Client for the SSL wrapper, NeverIndex for HPACK sensitive headers, and HttpScheme for proxy env selection. Every one I traced preserves polarity, but a single inverted from_bool or swapped variant order in the ~70% of the diff I could not read would silently weaken TLS verification or flip a security default.

Level of scrutiny

High. Each hunk is trivial in isolation, but this is (a) a repo-wide code-style decision that maintainers should ratify, (b) an 888k-character diff far exceeding what automated review can exhaustively verify for polarity, and (c) freshly rebased over 325 commits with conflict resolution done by automation. The PR description's own verification is diligent (byte-identical output vs release, per-hunk polarity re-read, targeted test files) but is self-reported.

Other factors

No new tests are added — coverage relies entirely on existing suites, which is reasonable for a behaviour-preserving refactor but means any polarity flip in a rarely-exercised branch would not be caught. No human has reviewed yet; CI build #99254 is in progress. The bool_enum! macro itself is sound and the sampled call sites are correct, so I have no specific concern to flag — the deferral is purely about scale, security surface, and the architectural sign-off this warrants.

@robobun

robobun commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Two follow-ups on the merged head.

Source lints. The only red check on f4f845e was test/internal/source-lints/dead-code-escapes.test.ts: bool_enum! carries one #[allow(dead_code)] on the generated from_bool (it is emitted for every enum and only some of them call it), which takes src/bun_core/lib.rs from 1 escape to 2. This was already true of the original commit; it only showed up now because the GitHub workflows had never run on this PR before the merge. 2ce8911 records the escape in dead-code-escape-limits.json, the documented route for macro-generated items. Buildkite (#99225), clippy, mordant, miri and format were all green on the merge commit itself.

Polarity. Both reviews above point at the same risk: a variant used the wrong way round is invisible to the compiler, and the merge re-applied a few hundred hunks by hand. So I checked the whole diff against main mechanically rather than by sampling:

  • Read the bool_enum! declarations (362 distinct types, 724 variant names) to learn which variant of each enum stands for true.
  • For every line in git diff main that uses one of those variants, rewrite it back to bool form (E::TrueVariant to true, E::FalseVariant to false, E::from_bool(x) to x, x == E::TrueVariant to x, x == E::FalseVariant to !x, if c { E::T } else { E::F } to c, : E to : bool) and require the result to exist in main's copy of the same file, whitespace and rustfmt wrapping aside. Single-argument lines such as a bare Foo::Yes, only count together with their neighbouring lines, so they cannot match an unrelated true, somewhere else in the file. A line that reconstructs is polarity preserving by construction.
  • Result: 2888 lines reconstruct; 90 of them are the let x = x == E::Yes; shadowing lines, which have no counterpart in main and were checked for orientation instead; 0 inversions. 130 lines turned out to be pre-existing enums that merely share a name (bake::Side, options::Side, uws CloseKind, io Chunk, ...) and were excluded.
  • The 117 lines that do not reconstruct I read against main's code by hand. They are the renamed mode-like fields (is_weak to Strength, is_exclude to MatcherKind, base to RegistryMode, use_scalar to Producer, is_cjs to ModuleFormat, is_md_format to CpuProfileFormat, is_gzip/is_compress to ZlibFormat/ZstdOp, is_stderr to PipeKind, prefix to UpdatePosition, drop/is_recv in udp, ...), if/else turned into match, and sites where the variant is chosen by name. All of them keep the original branch direction.
  • The one thing worth knowing as a reader: two enums stand in for bools of opposite sense and are therefore used by name. TlsRole is declared { Server, Client } because every from_bool site and every adopt_tls/start_tls/init_with_ctx caller is in is_client sense, while resolve_reject_unauthorized used to take is_server; its five callers pass Server/Client exactly where main passed true/false, and the function unwraps with role == Server. FunctionNesting likewise covers build_hir's is_top_level and inference's is_function_expression; it has no from_bool callers at all. Both check out at every use.
  • The security-relevant ones named in the reviews, specifically: the three adopt_tls callers (socket_body, MySQL, Postgres) wrap or name exactly the values main passed, the two proxy tunnels hand the SSL wrapper TlsRole::Client where main passed true, and us_socket_t::adopt_tls gives C (is_client == Client) as i32, (request_cert == Yes) as i32, (reject_unauthorized == Yes) as i32 where main had the bools; every TlsRole use in the tree was looked at individually; every AllowProxyUrl, HttpScheme and Subdomains line and all but one NeverIndex line reconstruct to main (the remaining NeverIndex line is the lshpack FFI unwrap, (never_index == Yes) as c_int).

The change on top of the original commit remains the conflict resolution described in my earlier comment plus the inventory line; nothing here alters the refactor itself, so the sign-off the reviews ask for is on the convention, which is dylan's call.

@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 reviewed this PR and the bug-hunting pass found no issues; robobun's mechanical polarity reconstruction (2888 lines round-tripping to main, plus the 117 hand-checked non-reconstructing lines) also came back clean. Because this is a 529-file workspace-wide refactor that introduces a new bool_enum! convention, retypes flags on security-sensitive TLS/cert-verification paths (TlsRole, RejectUnauthorized, AllowProxyUrl, NeverIndex), and was hand-merged across 114 conflicting files, a maintainer sign-off on the convention itself is still warranted — as the last robobun comment already notes.

What was reviewed:

  • Spot-checked polarity on the visible diff hunks (ResetOutcome, HttpScheme, Subdomains, ConnectionHeader, Chunk, AllowProxyUrl, CloneText, Strength) — all match the original bool sense.
  • Confirmed bool_enum! places the false-like variant first with discriminant 0/Default, so from_bool and zero-init stay consistent with the prior bool semantics.
  • Checked that FFI boundaries unwrap with == Variant before crossing to C (lshpack, us_socket_t::adopt_tls, BunString__createExternal, visible-width) rather than casting the enum.
Extended reasoning...

Overview

This PR adds a bun_core::bool_enum! macro that declares two-variant Copy enums (false-like variant first, discriminant 0, Default; from_bool for runtime values; deliberately no Into<bool>) and applies it across ~529 files in the Rust workspace to replace positional bool parameters, mode-like fields, opaque tuple slots, and a handful of non-predicate -> bool returns. The diff is +7630/-4482 and touches essentially every subsystem: parser/printer, bundler, CSS, HTTP (h1/h2/h3, proxy tunnels, TLS), install/lockfile, glob, react-compiler, io, jsc, and more. The branch was 325 commits behind main and robobun hand-resolved 114 conflicting files during the update merge, deleting 31 enums that main had since typed independently.

Security risks

The refactor retypes flags on TLS and certificate-verification paths: TlsRole { Server, Client } (fed to adopt_tls/start_tls/SSL wrapper init), RejectUnauthorized, AllowProxyUrl (gates SNI/hostname selection in check_server_identity), Subdomains (X.509 host matching), HttpScheme (proxy env-var selection), and HPACK NeverIndex (RFC 7541 sensitive-header literal). A silent polarity flip on any of these would weaken security without a compile error. robobun's mechanical reconstruction reports every one of these lines round-trips to main's bool form, and I spot-checked the visible hunks — the two proxy tunnels pass TlsRole::Client where main passed true, resolve_reject_unauthorized unwraps with role == Server where main took is_server: bool, and the FFI sites cast via (x == Variant) as c_int rather than transmuting the enum. I did not find an inversion, but the sheer number of security-relevant call sites plus the hand-merged conflicts means a maintainer should confirm.

Level of scrutiny

High. This is not a mechanical rename the compiler enforces — the whole risk class (variant used the wrong way round) is invisible to rustc. It is also a cross-cutting API-design decision: bool_enum! becomes the house style for every future flag parameter, and the repo's own review guidance says new cross-cutting abstractions need maintainer agreement. robobun's final comment explicitly defers the convention sign-off to a maintainer.

Other factors

No automated tests are added (behaviour is claimed unchanged; existing suites are the coverage). Buildkite/clippy/miri/format are reported green on the merge head, and robobun ran a substantial subset of test files against a debug build. The one source-lint failure was addressed by recording the macro's #[allow(dead_code)] in the escape inventory. Given the scale, the hand-merged conflicts, the security-adjacent surface, and the pending convention decision, this falls squarely outside what an automated approval should cover.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants