Skip to content

chore(deps): take Biome 2, with the migration corrected by hand and pinned - #7

Merged
nzneit merged 1 commit into
mainfrom
chore/biome-2
Aug 1, 2026
Merged

chore(deps): take Biome 2, with the migration corrected by hand and pinned#7
nzneit merged 1 commit into
mainfrom
chore/biome-2

Conversation

@nzneit

@nzneit nzneit commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Raises @biomejs/biome from ^1.9.0 to ^2.5.6, discharging D-021's second deferred obligation. Recorded as D-023. This was the one deferred item that genuinely needed its own PR, and the reason is below.

⚠️ The migration is not taken as biome migrate produced it

On the v1 config, biome migrate rewrites

- "rules": { "recommended": true }
+ "rules": { "preset": "none" }

which does not port the rule set, it deletes it.

Verified by planting a violation rather than by reading the command's output: a file containing any, == and an unused var draws zero diagnostics under the migrated config, and three (noExplicitAny, noDoubleEquals, noUnusedVariables) once preset is corrected to "recommended".

The failure mode is the dangerous kind. biome check . exits 0 in the broken state, CI stays green, and the repo lints nothing. Nothing about the symptom points at the cause.

So the corrected config is pinned by a test

test/lint-gate.test.ts asserts the preset is "recommended" and that the transport-isolation override is still error for aedes/aedes-server-factory under **/src/** and off under **/src/broker/**. Its negative control is verified: setting preset back to "none" makes it exit 1.

It carries no R-### arrow tag, following test/import-style.test.ts (D-013) — it pins a decision, not a requirement.

It deliberately asserts config shape rather than end-to-end gate liveness. Probing liveness for real needs a violating file under src/, which would race test/transport-isolation.test.ts's walk of that same directory. So liveness stays a manual check (recorded in AGENTS.md) and the automated guard covers the one regression actually observed.

The transport-isolation rule also survives the group move out of nursery into style, re-verified by hand: exit 1 on an aedes import outside src/broker/, exit 0 on the same file inside it. The regex gate in test/transport-isolation.test.ts remains the independent second layer — that one catches an offending import, this one catches the rule going missing.

One of Biome's "safe" fixes was not safe

noUselessEscapeInRegex rewrote MQTT_EXTENSION_KEY:

- /^x-[\w\d\.\x2d_]+$/
+ /^x-[\w\d.\x2d_]+$/

A no-op to the regex engine, and a real defect here. D-019 transcribes that pattern character-for-character from the upstream @asyncapi/specs schema key, and test/upstream-drift.test.ts:92 compares .source byte-for-byte against it.

The full suite caught it (1 fail, 431 pass). The fix is reverted and the rule suppressed inline with that reason, so a future --write cannot silently re-apply it. Worth internalising: the test suite caught this one, but a less-covered invariant would have slipped through, which is why --write output gets read here rather than trusted.

The 34 findings, all resolved

count rule
17 assist/source/organizeImports (named-import sorting, auto-fixed)
14 correctness/noUnsafeOptionalChaining
2 complexity/useOptionalChain
1 correctness/noUnusedFunctionParameters
1 complexity/noUselessEscapeInRegex (suppressed, above)

The 14 optional-chaining sites were all the same defect: (x?.y as T).z, a ?. guard immediately dereferenced, so an absent value produced a TypeError instead of a clean assertion diff. Fixed by continuing the chain through the cast, (x?.y as T | undefined)?.z — chosen over a non-null assertion because that spelling is clean under both tsc and Biome, while x!.y trips style/noNonNullAssertion. Both alternatives were probed before picking rather than assumed.

One of those sites then failed tsc, because the result fed toContain, whose parameter is string. That site extracts the value and wraps it in String() so an absent payload still fails readably as "undefined".

Deliberately not done

createServer(config, caps) in src/control-plane/index.ts has a genuinely unused first parameter. It is underscored to _config rather than removed, because dropping it changes an exported function's arity — a refactor, not part of a dependency bump. Recorded in D-023 as an optional follow-up.

Gates

check-docs, lint, typecheck, demo-app:build and full bun test all exit 0.

With this merged, the only item still open from the D-021 dependency review is aedes 1.x, which stays deferred behind R-006/R-007.

…inned

Raise @biomejs/biome from ^1.9.0 to ^2.5.6, discharging D-021's second
deferred obligation. Recorded as D-023.

The migration is NOT taken as `biome migrate` produced it. On the v1
config it rewrites

  "rules": { "recommended": true }  ->  "rules": { "preset": "none" }

which does not port the rule set, it deletes it. Verified by planting
rather than by reading the output: a file containing any, == and an
unused var draws zero diagnostics under the migrated config and three
(noExplicitAny, noDoubleEquals, noUnusedVariables) once preset is
corrected to "recommended". `biome check .` exits 0 in the broken state,
so nothing about the symptom points at the cause.

test/lint-gate.test.ts now pins the corrected config: it asserts the
preset is "recommended" and that the transport-isolation override is
still error for aedes/aedes-server-factory under **/src/** and off under
**/src/broker/**. Negative control verified - setting preset back to
"none" makes it exit 1. It carries no R-### tag, following
test/import-style.test.ts (D-013): it pins a decision, not a requirement.

The transport-isolation rule survives the group move out of nursery into
style, re-verified by hand: exit 1 on an aedes import outside src/broker/,
exit 0 on the same file inside it.

34 findings on the existing tree, all resolved:

- 17 assist/source/organizeImports (named-import sorting, auto-fixed)
- 14 correctness/noUnsafeOptionalChaining
-  2 complexity/useOptionalChain
-  1 correctness/noUnusedFunctionParameters
-  1 complexity/noUselessEscapeInRegex

One of Biome's "safe" fixes was not safe. noUselessEscapeInRegex rewrote
MQTT_EXTENSION_KEY from /^x-[\w\d\.\x2d_]+$/ to /^x-[\w\d.\x2d_]+$/. That
is a no-op to the regex engine and a real defect here: D-019 transcribes
that pattern character-for-character from the upstream @asyncapi/specs
schema key, and test/upstream-drift.test.ts compares .source byte-for-byte
against it. The full suite caught it (1 fail, 431 pass); the fix is
reverted and the rule suppressed inline with that reason so a future
--write cannot silently re-apply it.

The 14 noUnsafeOptionalChaining sites were all the same defect: (x?.y as
T).z, a ?. guard immediately dereferenced, so an absent value produced a
TypeError instead of a clean assertion diff. Fixed by continuing the chain
through the cast, (x?.y as T | undefined)?.z, chosen over a non-null
assertion because that spelling is clean under both tsc and Biome while
x!.y trips style/noNonNullAssertion. Both were probed before picking.

createServer(config, caps) in src/control-plane/index.ts has a genuinely
unused first parameter. It is underscored to _config rather than removed,
because dropping it changes an exported function's arity, which is a
refactor and not part of a dependency bump. Left as an optional follow-up.

Gates: check-docs, lint, typecheck, demo-app:build and full bun test all
exit 0.
@nzneit
nzneit merged commit 6e67336 into main Aug 1, 2026
1 check passed
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.

1 participant