Skip to content

chore(lint): warn on type-erasing assertions (as any/never/unknown) via Biome plugin#624

Merged
coderdan merged 6 commits into
feat/eql-v3-text-search-schemafrom
chore/biome-no-type-erasing-assertions
Jul 12, 2026
Merged

chore(lint): warn on type-erasing assertions (as any/never/unknown) via Biome plugin#624
coderdan merged 6 commits into
feat/eql-v3-text-search-schemafrom
chore/biome-no-type-erasing-assertions

Conversation

@coderdan

@coderdan coderdan commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

What

A Biome GritQL lint plugin (biome-plugins/no-type-erasing-assertions.grit) that warns on type-erasing assertions in source:

  • x as any, x as never, x as unknown (the last also catches the inner half of x as unknown as T).

These silence the type checker instead of narrowing a value, so a real type mismatch can hide behind them. Came out of the #621 review, where as never casts kept appearing.

What it does NOT flag (deliberately)

  • x as const — a widening-freeze, not an erasure.
  • x as SpecificType — a normal, checked assertion.
  • param: nevernever as a type annotation (e.g. a contravariant parameter) is a legitimate technique, not erasure.

Design decisions

  • warn, not error. Biome isn't a CI gate in this repo (the only invocation is the local pnpm code:fix), and there's a small existing backlog — 17 occurrences in src across all packages. This is a ratchet to keep new erasures visible in the editor and code:fix output, not a hard block. Verified that plugin warnings don't change biome check's exit code, so code:fix is unaffected.
  • Tests exempt. **/__tests__/**, **/*.test.ts, **/*.test-d.ts, **/integration/**, **/tests/**, **/*.spec.ts are exempted via an overrides entry — test doubles legitimately force-cast. A deliberate src case takes a // biome-ignore lint/plugin: <reason> suppression.
  • Known limitation: matches only the bare forms, not compound casts like as never[] / as any[]. Easy to extend later if wanted.

To make it a hard gate later

Add a CI step running biome check (or biome lint --error-on-warnings), and/or flip severity to error after burning down the 17 src occurrences. Both are follow-ups, not part of this prototype.

Verification

  • Flags exactly the three bare forms; leaves as const / as Foo / never annotations / as never[] alone.
  • Test/integration files show zero hits (override works).
  • biome check exit code unchanged by the plugin.

https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w

Summary by CodeRabbit

  • New Features
    • Added lint warnings for type-erasing assertions like as any, as never, and as unknown.
  • Documentation
    • Updated development workflow guidance with instructions on fixing types, allowed exceptions, and how to intentionally suppress only deliberate cases.
  • Chores
    • Updated lint configuration so the rule applies to relevant source and example code while avoiding test/integration coverage.

Adds `biome-plugins/no-type-erasing-assertions.grit`, wired into biome.json,
that warns on `as any` / `as never` / `as unknown` in source — assertions that
punch through the type system instead of narrowing (a real mismatch can hide
behind them). `as const`, plain `as SpecificType`, and `never` as a type
annotation are NOT flagged. `as unknown` also catches the inner half of an
`as unknown as T` double-cast.

- severity `warn`: Biome is not a CI gate here (only local `code:fix`), and
  there's a small existing backlog (~17 in src) — this is a ratchet to keep NEW
  erasures visible, not a hard block. Warnings don't change `biome check`'s exit
  code (verified).
- test/integration/*.test-d.ts files are exempt via an `overrides` entry — test
  doubles legitimately force-cast; suppress a deliberate src case with
  `// biome-ignore lint/plugin: <reason>`.
- Known limitation (documented in the plugin): matches only the bare forms, not
  compound casts like `as never[]`.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
@coderdan coderdan requested a review from a team as a code owner July 12, 2026 09:28
@changeset-bot

changeset-bot Bot commented Jul 12, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 3f4adeb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Biome now enables a local GritQL lint rule that warns on as any, as never, and as unknown assertions. Test and integration paths disable plugins through overrides, and AGENTS.md documents remediation and suppression guidance.

Changes

Type-erasing assertion linting

Layer / File(s) Summary
Type-erasing assertion rule
biome-plugins/no-type-erasing-assertions.grit
Adds warnings for as any, as never, and as unknown, with guidance for fixing or deliberately suppressing matches.
Plugin configuration and workflow guidance
biome.json, AGENTS.md
Excludes GritQL files from normal matching, enables the local plugin for selected source and example paths while excluding test and integration paths, and documents the rule’s scope and suppression syntax.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a Biome plugin to warn on type-erasing assertions.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/biome-no-type-erasing-assertions

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
biome-plugins/no-type-erasing-assertions.grit (1)

16-26: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Highlight the full assertion span (biome-plugins/no-type-erasing-assertions.grit:21-24)
Bind the full cast expression in span instead of $e so the warning underline matches the as any / as never / as unknown text.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@biome-plugins/no-type-erasing-assertions.grit` around lines 16 - 26, Update
the diagnostic span in the assertion patterns within register_diagnostic to bind
the full cast expression, including the as any, as never, or as unknown suffix,
instead of only $e. Keep the existing patterns and warning message unchanged so
the underline covers the complete type-erasing assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@biome-plugins/no-type-erasing-assertions.grit`:
- Around line 16-26: Update the diagnostic span in the assertion patterns within
register_diagnostic to bind the full cast expression, including the as any, as
never, or as unknown suffix, instead of only $e. Keep the existing patterns and
warning message unchanged so the underline covers the complete type-erasing
assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f9486c1-86cc-438c-8a36-999f1215aa0f

📥 Commits

Reviewing files that changed from the base of the PR and between e9e81e6 and 15b246b.

📒 Files selected for processing (3)
  • AGENTS.md
  • biome-plugins/no-type-erasing-assertions.grit
  • biome.json

coderdan added 2 commits July 12, 2026 19:41
…obal+exempt

The original wiring (top-level `plugins` + an `overrides` entry with
`plugins: []` for tests) did NOT exempt tests: Biome runs top-level plugins on
every file and `overrides[].plugins: []` does not disable them — verified 158
test-file hits leaking through. Enable the plugin only via an `overrides` entry
whose `includes` matches source and negates the test globs instead. Now: 82
source hits, 0 test-path leaks (verified).

Also ignore `**/*.grit` in files.includes so Biome stops trying to format the
plugin file itself.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
…rated files

Level 1 of making Biome a CI gate (errors only; warnings allowed):

- Add a `code:check` script (`biome check`, read-only) and run it in tests.yml.
  `biome check` exits non-zero on ERRORS and zero on warnings, so this gates
  format/lint/organizeImports errors while the `no-type-erasing-assertions`
  plugin (and the ~500 pre-existing warnings) stay visible but non-blocking.
- Ignore checked-in GENERATED artifacts in biome (prisma-next `contract.*` /
  `end-contract.*` / `*.generated.ts`, and migration `*.json` / `refs`) — they
  carry `DO NOT EDIT` and would re-drift on regeneration, so CI must not gate on
  their formatting. This dropped the error count 36 → 15.
- `biome check --write` the 15 remaining errors in AUTHORED files
  (format + organizeImports only — no logic changes). `biome check` now exits 0.

Tightening the gate to fail on warnings (level 3) is tracked as a follow-up.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
@coderdan

Copy link
Copy Markdown
Contributor Author

Level 1 gate added (per discussion)

  • New pnpm run code:check (biome check, read-only) now runs in tests.yml, gating on errors only — warnings stay visible but non-blocking, so the no-type-erasing-assertions plugin surfaces new casts without blocking merges.
  • Cleared the auto-fixable error backlog: ignored checked-in generated artifacts (prisma-next contract.*/*.generated.ts, migration *.json/refs) that carry DO NOT EDIT and would re-drift (36 → 15 errors), then code:fix'd the 15 remaining authored files (format + organizeImports only). biome check now exits 0.
  • Also fixed the earlier bug where the plugin's test exemption didn't work (Biome ignores overrides[].plugins: []) — it's now scoped to source via an include-override.

Tightening the gate to fail on warnings (burn down the ~521-warning backlog) is tracked in #625 (assigned, before next release).

coderdan added 3 commits July 12, 2026 19:56
Was a step inside the matrixed "Run Tests" job (ran per Node leg, no distinct
check line). Split into a standalone `lint` job — no DB/credentials, single
Node, so it surfaces as its own "Lint (Biome)" check and runs once. Still gates
on errors only (warnings allowed); #625 tracks tightening.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
The dedicated lint job hardcoded Node 24, which trips the supply-chain gate
(e2e/tests/supply-chain.e2e.test.ts) requiring every pnpm-using job to pin
Node 22 (literal or a matrix including 22). Lint is runtime-agnostic, so pin 22.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
…into chore/biome-no-type-erasing-assertions

# Conflicts:
#	packages/stack/__tests__/v3-matrix/catalog.ts
#	packages/stack/src/eql/v3/types.ts
@coderdan coderdan changed the base branch from main to feat/eql-v3-text-search-schema July 12, 2026 13:41
@coderdan coderdan merged commit ebbb143 into feat/eql-v3-text-search-schema Jul 12, 2026
17 checks passed
@coderdan coderdan deleted the chore/biome-no-type-erasing-assertions branch July 12, 2026 13:45
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