diff --git a/AGENTS.md b/AGENTS.md index 89d3d4e..3dadddd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,10 +25,11 @@ first-action facts. Do not restate evolving prose here — it will drift. Don't silence the type system to force a green run. As an agent these are forbidden: - `// @ts-nocheck`, `// @ts-ignore`, `// @ts-expect-error` -- `// oxlint-disable` / `// oxlint-disable-next-line` — the sole exception is the fixed file-level `typescript/no-floating-promises` header at the top of a `*.test.ts` file, spelled exactly as [CONTRIBUTING.md § Rules the tools don't enforce](./CONTRIBUTING.md#rules-the-tools-dont-enforce) prescribes +- `// oxlint-disable` / `// oxlint-disable-next-line` +- editing `.oxlintrc.json` to silence a finding (e.g. turning `typescript/no-floating-promises` off) - `as` casts used to push an expression through (type-aware oxlint already flags unsafe assertions) -Fix the root cause with the type system instead — narrowing, generics, `satisfies`, conditional / mapped types, utility types (`NonNullable`, `Exclude`, …). TypeScript can express it; that's the intended tool. The `oxlint-disable`-location rule in [CONTRIBUTING.md § Rules the tools don't enforce](./CONTRIBUTING.md#rules-the-tools-dont-enforce) is a **human** last-resort convention (so a reviewer can spot a deliberate suppression) — it is not permission for you to add one, except the one fixed `*.test.ts` file-level header named there. If the types genuinely cannot express something, stop and surface the conflict (commit message / handover) rather than suppress it. +Fix the root cause with the type system instead — narrowing, generics, `satisfies`, conditional / mapped types, utility types (`NonNullable`, `Exclude`, …). TypeScript can express it; that's the intended tool. Suppressions — a source `oxlint-disable` **or** a `.oxlintrc.json` entry — are a **human** last resort, not a tool for you. If the types genuinely cannot express something, stop and surface the conflict (commit message / handover) rather than suppress it. The same applies to the checks themselves: **never `git commit --no-verify`** (or otherwise skip a pre-commit / pre-push hook). The checks are fast and offline, so a redundant run is fine — bypassing a hook to get green is the identical anti-pattern. If a commit already skipped a hook, redo it through one: `git reset --soft HEAD~1 && git commit -C `. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9a882c..52c1928 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -155,12 +155,9 @@ reaches for by default: [Script prefix convention](#script-prefix-convention). - **`oxlint-disable` directives live in source, not `.oxlintrc.json`.** The trade-off must sit next to the code it silences. This is a _human_ last-resort - convention; agents must not add these — see - [AGENTS.md § Never do](./AGENTS.md#never-do). The sole agent exception is the - fixed file-level header at the top of a `*.test.ts` file, spelled exactly: - `/* oxlint-disable typescript/no-floating-promises -- expectTypeOf() is a sync -type-assertion library that the type-aware linter misidentifies as a promise -*/` — any other suppression stays human-last-resort. (why: + convention; agents must not add one, nor edit `.oxlintrc.json` to silence a + finding (e.g. `typescript/no-floating-promises`) — see + [AGENTS.md § Never do](./AGENTS.md#never-do). (why: [development/tooling.md](./development/tooling.md#oxlint-disable-directives-live-next-to-the-code)) - **Don't put slow / network / whole-project scans in `check` or pre-commit.** Advisory scans are not correctness gates; they belong under `maintain:`. (why: diff --git a/development/testing.md b/development/testing.md index edcd407..0a2926f 100644 --- a/development/testing.md +++ b/development/testing.md @@ -167,8 +167,8 @@ the CLI is for manual inspection. ## Known issues -- The type-aware linter misidentifies `expectTypeOf()` as a floating promise, so - test files that use it (`src/primitive.test.ts`) carry a file-level - `oxlint-disable typescript/no-floating-promises` with an explanatory comment. - It is a known false positive, not a rule worth disabling project-wide (see +- The type-aware linter misidentifies `expectTypeOf()` as a floating promise. + It is a known false positive, so `typescript/no-floating-promises` is off for + `**/*.test.ts` in the `.oxlintrc.json` override rather than repeated as a + file-level header (see [tooling.md § oxlint-disable directives live next to the code](./tooling.md#oxlint-disable-directives-live-next-to-the-code)). diff --git a/development/tooling.md b/development/tooling.md index 53d3637..7bc39bd 100644 --- a/development/tooling.md +++ b/development/tooling.md @@ -106,26 +106,34 @@ Type-aware oxlint is enabled via `options.typeAware: true` in `.oxlintrc.json` #### Decision (2026-09) -A type-aware rule that false-positives is silenced with a source-level -`oxlint-disable` directive (see `src/primitive.ts`, -`src/primitive.test.ts`), not by turning the rule off in `.oxlintrc.json`. +A type-aware rule that false-positives **at one site** is silenced with a +source-level `oxlint-disable` directive (see `src/primitive.ts`). A rule that is +wrong for a whole **file class** is turned off in a `.oxlintrc.json` `overrides` +entry instead — e.g. `typescript/no-floating-promises` (synchronous +`expectTypeOf` reads as an unhandled promise) and `unicorn/no-null` (intentional +`null` inputs) for `**/*.test.ts`. The same exemption is not repeated as a +file-level header in every affected file. #### Why -- The disable sits next to the code it silences, visible to anyone reading the - source. -- The rule stays on everywhere else, so only the mis-firing line is exempted. +- A one-site disable sits next to the code it silences, visible to anyone + reading the source, and the rule stays on everywhere else. +- A file-class rule is a property of the file class, not of one line; the + override states it once, where the rest of the file-class config lives. #### Rejected -- A project-wide disable in `.oxlintrc.json` for a false positive: it hides the - exemption from the reader of the affected code and switches the rule off - repo-wide for a one-site problem. +- A project-wide disable in `.oxlintrc.json` for a one-site false positive: it + hides the exemption from the reader of the affected code and switches the rule + off repo-wide for a one-site problem. +- A repeated file-level `oxlint-disable` header for a file-class false positive: + the copies drift and scatter one config decision across the tree. #### Known issue -- A source-level disable is a _human_ last resort. AI agents must not add one; - they fix the type at its root (see [AGENTS.md § Never do](../AGENTS.md#never-do)). +- Both placements are _human_ last resorts. AI agents must neither add a source + disable nor edit `.oxlintrc.json`; they fix the type at its root (see + [AGENTS.md § Never do](../AGENTS.md#never-do)). ### Unwanted stylistic rules are turned off in the config