Repository navigation
Description
Part of #649. Runs after #654 closes (ruling 3 on #649).
Benchmark
| Field | Value |
|---|---|
| Metric | (1) Exact: files that bun fmt formats differently from Prettier, among files with a Prettier parser, by file type. (2) Format gate wall time, in seconds. |
| Before | Not measured yet (agent in the repo, Step 2b, before any change). CI reference, from the 2026-11-11 milestone review read of the Run Report: 🔍 Lint, format & styles step median 45 s (27–51 s, n = 7, 2026-11-07 to 2026-11-11). That step also runs lint, so the format share is not split out. |
| After | Not measured yet. |
| Condition | A git archive HEAD copy. Named laptop (model, cores, RAM, OS). Bun 1.4.4. Prettier version from bun.lock (3.9.10 at HEAD 0b302b222). Warm runs, no other load. Record whether the #554 Q11 pool is on main. If it lands mid-benchmark, re-take Step 2b. |
| How to run | Step 2b: the gate's Prettier command from scripts/check-ci.ts (the format block) on the gate's file list, n = 5; and bun run check:ci, n = 5. Step 4: bun fmt --list-different on the same list, one exact count. Step 5: bun fmt on the same list, n = 5. Report median and min–max. |
| Pass rule | Adopt only if 0 files differ and the gate saves at least 10 % of the measured check:ci median. Any counted file: do not adopt; take the Decision below. Timing runs in every case. |
| Guard | bun fmt --doctor: every file type formats natively and the Tailwind sort comes from .prettierrc.json. If any file goes back to Prettier, the timing is void. bun fmt --debug-check runs once. |
| Owner | Agent in the repo: Steps 1 to 6 and the Measured comment. Maintainer: the reformat decision. |
| Claim | Adopt: "Formatting the whole docs.plus repo fell from s to s (median of 5, )." Kill: "bun fmt formatted of files differently from Prettier, so docs.plus stays on Prettier." |
Why
Bun 1.4.4 added bun fmt, a formatter that reads our Prettier config. Vendor numbers: 286x faster than Prettier 3.9.10 on the Prettier repo, and 9,648 of 9,731 Prettier tests identical. On real projects only 57 of 74 runs (77%) matched Prettier exactly.
Our Prettier is ^3.9.10 (root package.json), the version Bun tests against. Record the resolved version from bun.lock in Setup. It runs in three places:
- the
formatgate inscripts/check-ci.ts:166-207, on tracked files; bun run format(prettier --check .) in.github/workflows/quality-lint.yml:26;.lintstagedrc.js, on staged files.
.prettierrc.json:14 loads prettier-plugin-tailwindcss. With that plugin listed, the bun fmt Tailwind sort is already on (Bun docs).
Steps
The working tree is often dirty, so work in a copy: git archive HEAD | tar -x -C "$T", then bun install --frozen-lockfile --ignore-scripts in the copy. Never use a branch or a worktree.
- 1. Build the gate's file list in the source repo:
git ls-files -z, without symlinks, asscripts/check-ci.tsdoes withlstat. Check that the count equals the gate's file count. - 2. In the copy, run the gate's own Prettier command (
scripts/check-ci.ts:184-197) on that list. It must pass. - 2b. Before, always. Time that Prettier command 5 times on the gate's list. Also time
bun run check:ci5 times. Report median and min–max for both. - 3. Run
bun fmt --doctoronce. Every file type must be formatted natively, and the Tailwind sort must come from.prettierrc.json. If any file is sent back to Prettier, the timing is void. - 4. Pipe the list to
xargs -0 bun fmt --list-different --ignore-unknown --ignore-path .prettierignore --in the copy.- Count a file only if
prettier --file-info <file>gives a non-nullinferredParser. - List the others, such as the
.tomlfiles andbun.lock, as out of scope, not as differences. - Group the count by file type.
- Count a file only if
- 5. In every case, time
bun fmton the same list, 5 warm runs, median and min–max. Label it "not adoptable" if any file is counted. Runbun fmt --debug-checkonce. - 6. Post a
Measuredcomment in the [Tracking] Bun 1.4.x: release-age guard, bunfig cleanup, and measured bun check, bun fmt and bun test numbers #649 format. State the gate saving and thecheck:cimedian.
Kill rules
The kill rules decide adoption only. Steps 2b and 5 run in every case.
- More than 0 counted files: post the list, and take the decision below.
- 0 counted files, but the gate saves under 10 % of the measured
check:cimedian: close. State both numbers in Measured. - This replaces the fixed 16 s line. That line was 10% of the 163 s local
check:cithat Upgrade Bun to 1.4 and measure test plus backend wins #171 measured on Bun 1.4.0. Type-check packages/email-templates and packages/pad-url in the typecheck gate #658 changedcheck:cisince. [Tracking] Faster, change-aware CI/CD pipeline #554 Q11 (a pool of 4) is not filed or built yet; if it lands mid-benchmark, re-take Step 2b.
Decision (only if files are counted)
- Accept a one-time repo-wide reformat to move to
bun fmt? Recommended: no. Stay on Prettier until the real-project match improves, because a reformat conflicts with every open change.
If adopted later
Change the format scripts, .lintstagedrc.js and the scripts/check-ci.ts gate in one change. quality-lint.yml calls bun run format, so the script change covers it. Remove prettier-plugin-tailwindcss only after that.
Activity
HMarzban commentedon Nov 12, 2026
Measured, 2026-11-12
Question: Does
bun fmtformat any gate file differently from Prettier, and does the format gate save at least 10 % of the measuredcheck:cimedian?Setup
cfac48d87(the issue names0b302b222; HEAD moved before the run). Every copy was pinned to it.prettier-plugin-tailwindcss0.8.1 (both frombun.lock)cfac48d87outside the repo, thenbun install --frozen-lockfile --ignore-scripts,bun x prisma generateandbash scripts/build-extensions.sh. No env files.scripts/check-ci.tscallsgit ls-files. A baregit archivecopy fails the format gate and skips bothbuild:cigates. The clone has the same files asgit archive cfac48d87, plus.git.origin/mainset tocfac48d87in the clone, so the extension matrix is "none". The tree stayed clean before and after every run.main.check-ci.tsruns its gates one after another.The #654 Measured draft came first, as ruling 3 on #649 sets the order.
Method
git ls-tree -r -z cfac48d87, without mode 120000 entries. That gives 3,108 of 3,116 tracked files (8 symlinks out). It equalsgit ls-filesin the clone withoutlstatsymlinks, file for file.xargs -0 node_modules/.bin/prettier --check --ignore-unknown --ignore-path .prettierignore --on that list. It passed.bun run check:ci. 1 discarded warm-up each, then 5 timed runs with/usr/bin/time -l. Everycheck:cirun printed PASS with bothbuild:cigates passing.bun fmt --doctor --no-script, once.xargs -0 bun fmt --list-different --ignore-unknown --ignore-path .prettierignore --no-script --on the list. Prettier'sgetFileInfo(the API form of--file-info) set the scope: files that are not ignored and have a parser.xargs -0 bun fmt --check --ignore-unknown --ignore-path .prettierignore --no-script --on the list. It ran in turn with the Prettier command, 1 discarded warm-up, then 5 runs. Thenbun fmt --debug-checkonce.bun fmt". With no flag,bun fmtwrites files, so the timed command is--check, to match the gate'sprettier --check..ts,.tsx(Tailwind class order),.md,package.json,.scssand.yml.Result: differences (Steps 3 and 4)
.prettierignorebun fmtfiles selectedbun fmt --doctor: formatted nativelybun fmtformats differentlybun fmt --debug-checkIn scope by Prettier parser, 0 differences in each:
.ts,.tsx).js,.mjs,.cjs)package.jsonand similar).sql, 55.png, 25.sh, 4.toml,bun.lockand 77 others, such as images, fonts, Git hooks and ignore files.package.json. It runsprettier-plugin-tailwindcssas a built-in plugin and sends no file to Prettier. The timing is valid.className="p-4 flex"to"flex p-4".bun fmtin the second clone printed "Formatted 0 files, 2541 unchanged", before the seeds.Result: timing (Steps 2b and 5)
n = 5 each, 1 warm-up discarded:
bun fmt --check, same listbun run check:ci(Prettier gate)check:cimedian: 9.03 s. The saving is 11.6 % of 90.34 s.Raw data
Attached:
655-format.jsonl,655-checkci.jsonl,655-fileinfo.json,655-doctor.json,655-list-different.txt(empty),655-positive-control.txt. Each timing line holds the load average and free memory at its start.Not measured
bun run format(prettier --check .) inquality-lint.yml, and.lintstagedrc.json staged files.check:cirun withbun fmtin the gate. The saving comes from the two standalone commands.bun fmtin CI. The CI reference step also runs lint, so it cannot isolate the format share.Verdict
Adopt rule met: 0 of 2,541 files differ, and the gate saves 10.46 s, 11.6 % of the 90.34 s
check:cimedian. The maintainer rules the swap.HMarzban commentedon Nov 14, 2026
Ruling, 2026-11-14: adopt
The maintainer ruled the swap at the v2.3.6 release audit. The adopt rule passed: 0 of 2,541 files differ, and the gate saves 10.46 s, 11.6 % of the 90.34 s
check:cimedian (Measured).The swap is #795, a child of #554. It changes the
formatscripts,.lintstagedrc.jsand thescripts/check-ci.tsgate in one commit. Prettier stays installed until a later change removes it.Closing as completed.