From 10078f3fe90946624b20661f8c98fa56b0b645c9 Mon Sep 17 00:00:00 2001 From: norvalbv Date: Sun, 16 Aug 2026 05:00:38 +0100 Subject: [PATCH] feat(oxc): dogfood the assembled quality stack (sc-1681) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Dogfood the assembled Oxc quality stack inside Devkit itself after the capability and anti-slop baseline work in #401. - make self-host init/upgrade/doctor own Oxc and anti-slop as recorded capabilities - run anti-slop against the exact staged Git index in pre-commit, including staged config, managed plugin, and baseline bytes - enforce base-to-candidate baseline monotonicity in CI, with only a one-time bootstrap exception and durable same-commit handling for Git renames - commit Devkit's generated managed Oxc/anti-slop state and deterministic 1,677-finding / 1,543-fingerprint baseline - recommend the official Oxc editor extension while keeping CLI/CI authoritative - save the reproducible assembled-stack benchmark, raw samples, diagnostic ownership table, and migration rationale ## Why this is a mixed stack The preceding parity studies found responsibilities that should not move merely to reduce process count: - Oxfmt owns formatting. - Biome owns JS/TS/JSON/CSS lint and assist diagnostics. - Oxlint owns the 15 vendored anti-slop rules. - ESLint owns filesystem topology, Electron topology, empty-directory checks, and import walls. - `tsc` owns TypeScript 6 diagnostics and JavaScript build emission. This PR adds no duplicate lint responsibility: the managed Oxlint base enables only anti-slop, Biome formatting is disabled, and ESLint is topology-only. ## Exact staged and baseline semantics `anti-slop check --staged` materializes `git write-tree` into a temporary mirror. It therefore evaluates staged source postimages—not working-tree bytes—and also sees the staged root config, managed config/plugin, package metadata, lockfile, and baseline. Config or baseline changes force a full scan; unrelated staged files no-op. CI uses `anti-slop check --base "$ANTI_SLOP_BASE"`. Candidate baseline counts may only shrink relative to the merge base. A repository with no base baseline gets the sole bootstrap exception. A debt-bearing Git rename must persist the regenerated baseline in the same commit; checks reject a stale old-path fingerprint, then verify the new-path count did not grow. Adding a violation and enlarging the baseline still fails. ## Benchmark Saved at `docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/` with the harness, raw 10-sample results, host/runtime provenance, exact measurement tree, and interpretation. Supported Node 24.19 / Apple M4 results: | Lane | Metric | Control median | Candidate median | Delta | | --- | --- | ---: | ---: | ---: | | local deterministic quality segment | CPU | 10.500 s | 10.190 s | -3.0% | | local deterministic quality segment | wall | 5.344 s | 5.436 s | +1.7% | | local deterministic quality segment | process-tree RSS | 218.4 MiB | 212.5 MiB | -2.7% | | full repository static-quality segment | CPU | 8.335 s | 11.620 s | +39.4% | | full repository static-quality segment | wall | 2.236 s | 3.737 s | +67.1% | | full repository static-quality segment | process-tree RSS | 469.4 MiB | 500.1 MiB | +6.5% | The hot agent loop is effectively CPU-neutral/slightly better while adding all 15 anti-slop rules. The full CI lane is intentionally heavier because it adds a second full-tree policy family, a separate format check, and typechecks the vendored source. That is a costed compatibility boundary, not evidence for removing Biome, ESLint, or `tsc`. Frink must repeat the assembled benchmark on its own staged and full scopes before adoption. ## Validation - `bun run format:check` — 573 files, green - `bun run lint` — 575 files, green - `bun run lint:structure` — green - `bun run typecheck` — green - `bun run benchmarks:check -- --mode staged` — green - `node cli/index.mts anti-slop check --staged` — 1,677 current findings, 0 ready to prune - focused unit/integration tests — 71/71 pre-review plus 14/14 reviewer-fix regressions green - packed anti-slop E2E — 7/7 green, including partial staging, baseline laundering, CI base comparison, durable rename persistence, and a post-merge check - pre-review full suite — 221 files passed / 1 skipped; 3,847 tests passed / 5 skipped - post-review full rerun — 220 files and 3,850 tests passed; only known #1711 parallel timing assertion failed, then passed 1/1 isolated - manual self-host doctor — managed Oxc/anti-slop, baseline, hook, and runner checks green - final GitNexus staged analysis — 73 files, 36 indexed symbols, 9 affected processes, HIGH as expected for self-host init/doctor paths; all affected direct paths are covered above ## Merge order This PR targets `codex/sc-1676-anti-slop-baselines` (#401), which targets the Oxfmt adoption in #400. The evidence-only responsibility studies are #397, #398, and #399. Merge/retarget in epic order. Shortcut: SC-1681 --- .anti-slop-baseline.json | 12350 ++++++++++++++++ .devkit/agent-hooks-manifest.json | 26 +- .devkit/agents-manifest.json | 46 +- .devkit/anti-slop/.oxlintrc.json | 8 + .devkit/anti-slop/LICENSE | 21 + .devkit/anti-slop/manifest.json | 26 + .devkit/anti-slop/oxlint.json | 60 + .devkit/anti-slop/plugin/index.ts | 41 + .../plugin/oxlint-plugins-api/LICENSE | 22 + .../plugin/oxlint-plugins-api/README.md | 95 + .../plugin/oxlint-plugins-api/index.cjs | 357 + .../plugin/oxlint-plugins-api/index.d.ts | 4346 ++++++ .../plugin/oxlint-plugins-api/index.js | 357 + .../plugin/oxlint-plugins-api/package.json | 43 + .devkit/anti-slop/plugin/package.json | 7 + .../rules/no-chained-type-assertions.ts | 77 + .../no-conditional-empty-object-spread.ts | 49 + .../plugin/rules/no-known-value-widening.ts | 247 + .../plugin/rules/no-module-mocking.ts | 91 + .../plugin/rules/no-object-parameters.ts | 126 + .../plugin/rules/no-reflect-apply.ts | 28 + .../anti-slop/plugin/rules/no-reflect-get.ts | 28 + .../plugin/rules/no-runtime-typeof.ts | 67 + .../plugin/rules/no-shape-in-symbol-names.ts | 39 + .../plugin/rules/no-unknown-parameters.ts | 83 + .../plugin/rules/no-unknown-returns.ts | 115 + .../plugin/rules/no-unknown-type-aliases.ts | 70 + .../plugin/rules/no-unsafe-dictionary-type.ts | 134 + .../plugin/rules/no-widen-then-assert.ts | 366 + ...quire-safety-comment-for-type-assertion.ts | 62 + .../plugin/shared/dictionary-types.ts | 502 + .../plugin/shared/lexical-type-parameters.ts | 61 + .../anti-slop/plugin/shared/reflect-method.ts | 35 + .devkit/anti-slop/probe.ts | 1 + .devkit/config.json | 5 +- .devkit/oxc/manifest.json | 19 + .devkit/oxc/oxlint.base.json | 16 + .devkit/skills-manifest.json | 84 +- .github/workflows/gate.yml | 12 + .husky/pre-commit | 2 +- .oxlintrc.json | 8 + .vscode/extensions.json | 3 + README.md | 10 + cli/__tests__/apply-init.test.mts | 8 +- cli/__tests__/self-host.test.mts | 6 + cli/commands/init.mts | 12 +- cli/commands/oxc/anti-slop.mts | 90 +- cli/lib/doctor/self-host-doctor.mts | 57 +- cli/lib/husky/self-host.mts | 5 + cli/lib/install/anti-slop/baseline.mts | 68 +- cli/lib/install/anti-slop/baseline.test.mts | 40 +- cli/lib/install/anti-slop/git-snapshot.mts | 225 + .../install/anti-slop/git-snapshot.test.mts | 129 + cli/lib/install/anti-slop/lifecycle.mts | 2 +- cli/lib/install/oxc/lifecycle.mts | 2 +- dist/README.md | 10 + dist/cli/commands/init.mjs | 11 +- dist/cli/commands/oxc/anti-slop.mjs | 76 +- dist/cli/lib/doctor/self-host-doctor.mjs | 38 +- dist/cli/lib/husky/self-host.mjs | 5 + dist/cli/lib/install/anti-slop/baseline.mjs | 51 +- .../lib/install/anti-slop/git-snapshot.mjs | 183 + dist/cli/lib/install/anti-slop/lifecycle.mjs | 2 +- dist/cli/lib/install/oxc/lifecycle.mjs | 2 +- dist/package.json | 1 + docs/anti-slop.md | 19 +- .../2026-08-16-oxc-devkit-dogfood/README.md | 158 + .../benchmark.mjs | 295 + .../results.json | 483 + docs/decisions/oxc-toolchain-migration.md | 1 + e2e/anti-slop.e2e.test.mts | 62 + package.json | 1 + 72 files changed, 22112 insertions(+), 75 deletions(-) create mode 100644 .anti-slop-baseline.json create mode 100644 .devkit/anti-slop/.oxlintrc.json create mode 100644 .devkit/anti-slop/LICENSE create mode 100644 .devkit/anti-slop/manifest.json create mode 100644 .devkit/anti-slop/oxlint.json create mode 100644 .devkit/anti-slop/plugin/index.ts create mode 100644 .devkit/anti-slop/plugin/oxlint-plugins-api/LICENSE create mode 100644 .devkit/anti-slop/plugin/oxlint-plugins-api/README.md create mode 100644 .devkit/anti-slop/plugin/oxlint-plugins-api/index.cjs create mode 100644 .devkit/anti-slop/plugin/oxlint-plugins-api/index.d.ts create mode 100644 .devkit/anti-slop/plugin/oxlint-plugins-api/index.js create mode 100644 .devkit/anti-slop/plugin/oxlint-plugins-api/package.json create mode 100644 .devkit/anti-slop/plugin/package.json create mode 100644 .devkit/anti-slop/plugin/rules/no-chained-type-assertions.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-conditional-empty-object-spread.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-known-value-widening.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-module-mocking.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-object-parameters.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-reflect-apply.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-reflect-get.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-runtime-typeof.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-shape-in-symbol-names.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-unknown-parameters.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-unknown-returns.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-unknown-type-aliases.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-unsafe-dictionary-type.ts create mode 100644 .devkit/anti-slop/plugin/rules/no-widen-then-assert.ts create mode 100644 .devkit/anti-slop/plugin/rules/require-safety-comment-for-type-assertion.ts create mode 100644 .devkit/anti-slop/plugin/shared/dictionary-types.ts create mode 100644 .devkit/anti-slop/plugin/shared/lexical-type-parameters.ts create mode 100644 .devkit/anti-slop/plugin/shared/reflect-method.ts create mode 100644 .devkit/anti-slop/probe.ts create mode 100644 .devkit/oxc/manifest.json create mode 100644 .devkit/oxc/oxlint.base.json create mode 100644 .oxlintrc.json create mode 100644 .vscode/extensions.json create mode 100644 cli/lib/install/anti-slop/git-snapshot.mts create mode 100644 cli/lib/install/anti-slop/git-snapshot.test.mts create mode 100644 dist/cli/lib/install/anti-slop/git-snapshot.mjs create mode 100644 docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/README.md create mode 100644 docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/benchmark.mjs create mode 100644 docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/results.json diff --git a/.anti-slop-baseline.json b/.anti-slop-baseline.json new file mode 100644 index 0000000..5f31593 --- /dev/null +++ b/.anti-slop-baseline.json @@ -0,0 +1,12350 @@ +{ + "schemaVersion": 1, + "upstreamCommit": "446268e5d15baa968eaec669ff65358d36ae6259", + "entries": [ + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function boundedArray(value: unknown, path: string, max: number): unknown[] {", + "fingerprint": "0056c2d93899fdf49f4dcee8bdb7aa0a3d74aec1a8929af654215730b745c487", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/husky/self-host.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return Object.fromEntries(", + "fingerprint": "00e038859ee039cf8cc2ddad3971935e33bc5d5d5b2d45bf368058bad6033942", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/update.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8')) as {", + "fingerprint": "00e41fcfa750e8eee93c56dc72766c388e7b6d2668642a1c678b540690e7318a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "Parameter `error` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function codeOf(error: unknown): string | undefined {", + "fingerprint": "01274ba3b54ca500770459004749c2e24063da7e7eec7ae44522400dde28007f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value === 'string' && value.includes('\\0'))", + "fingerprint": "015b744375246810fa6923e3d7caae17d2269b3fbdc2a42b5f90446e81fdc797", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.checkpoint.sha256 !== 'string' ||", + "fingerprint": "019ad5ce79d2f7fcccdbd14f23ceed57d0ef2d620ba1f81fbd027b15b6c9eac5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/cases.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!(PRIOR_ART_VERDICTS as readonly string[]).includes(verdict))", + "fingerprint": "01cbf2ec955cbdb1736828fe63b089303523168d358e646281a6a4f7eb92d47b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseRisk(value: unknown, path: string): PlanCritiqueRisk {", + "fingerprint": "01d93a2857e77a68eab1c4578d9ccb7a93ede284703ded61dc493b0d0913f156", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/__tests__/tracker-fixtures.mts", + "diagnostic": "The explicit open dictionary type on return value of `readableSnapshot` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return files;", + "fingerprint": "01f8d078d354d71bd0bf42997aa536fb3192cce4f9605b4c3c9bd3d0dff84bef", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/doctor/pin-checks.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const pkg: Record = { name: 'consumer', version: '1.0.0', ...o.pkgExtra };", + "fingerprint": "02566e33705ee280532576e40b493ac7b53a9949a6d762d63424df58126db81e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "The explicit anonymous object type on binding `changingScope` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const changingScope: { cwd: string; workId?: string } = { cwd: repository };", + "fingerprint": "0272eae68e18a471ae849fefbd2d05ec8ca8501624aa0d1e80926fcea0ec4f23", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "perClass: Object.fromEntries(", + "fingerprint": "02a6e16800799dc50778114f2ec43d073a78b331ee40ac22d299ec1818890b63", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "anti-slop/src/shared/lexical-type-parameters.ts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const record = node as unknown as Readonly>;", + "fingerprint": "02dee1fd44472b99bc7709955ee748d493e79c8fb8afefa0c7a91d1d57a8eda9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/upgrade-gate-offer.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const guards = (root: string) => config(root).components.guards as string[];", + "fingerprint": "0301f708f7073dd4cd2569efcf3e9031bfe02a9deaa7efccc6b66afa5220c353", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/review/baseline-fallow-paths.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const rewritten: Record = {};", + "fingerprint": "0316bd31cfbaad8ce0b572251fff8d0bdb8e80d27187bb52806b487f8d12cf6d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-reflect-apply", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "Replace `Reflect.apply` with a typed function call. Model dynamic dispatch behind a named interface.", + "context": "Reflect.apply(Uint8Array.prototype.set, snapshot, [value]);", + "fingerprint": "035b7ba93b26dac9230c69edc9bfd78ce7f5f27c611cfe16276bd049fa05b52d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/capture-normalizer.mts", + "diagnostic": "The explicit anonymous object type on return value of `deriveResponseEvidence` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!parsed.ok) return { contract: invalidContract(parsed.error.code, parsed.error.path) };", + "fingerprint": "03a89f9d63a19bd15179b75b4b453fd46659da3356be1ef5b628aec407815356", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "hooks: Record | null;", + "fingerprint": "03ac4f41181f00628aeb1dbb780d4af10a8ffdd797c94fcb42548389caacab83", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const reordered = Object.fromEntries(", + "fingerprint": "03d5c97cb86e8bcf6f6001d0fd7d653aae9d93d14122cfdd7c01ccc6bfea0d07", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/commit-message.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(loadCommitMessage(env as NodeJS.ProcessEnv)).toBeNull();", + "fingerprint": "03f622d0d6194035c6c9aa438717c86dc07e472317b5cceb1b18f6fc2680c875", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/conventions-eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const bad = makeRow({ note: '' as unknown as string });", + "fingerprint": "03f98b2350a6dfc1cd459ed61eaaeed4a51f5fc253bb3d8dffa76d85db09c45c", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "...(components as Partial),", + "fingerprint": "0434b844c7930af9380f81ed8915d98f2682ff66a7a8735d14d18364ddf00590", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/completeness.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof sticky.duration_ms === 'number' ? sticky.duration_ms : undefined;", + "fingerprint": "043f3d2305989aed0fc4a8e250d92d26f7a9870dd082790ffac23ae3c67ac73e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/process/process-table.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "identity: match[4] as string,", + "fingerprint": "04465d7cde88f1fdeb753b236ac243fe8c6071307baf03b5af635bc7ff647772", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "root: Record;", + "fingerprint": "04506195d50b96325a870d23ffbc22fb9fe0c8a6083e6ec7be9ef0516309f378", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/capture-normalizer.mts", + "diagnostic": "The explicit anonymous object type on return value of `deriveResponseEvidence` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "0454087dde59cc98fdaf455b23301390cc3deca8d2085ba25ba965a0ac068b4b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/source-projection.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const segment = segments[index] as string;", + "fingerprint": "04c3d4fc77f22976dfdd7ff6679e145bb6aaeded0755d7bb14e5120d0c0eac15", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const manifest = JSON.parse(readFileSync(join(dirname(entry), 'package.json'), 'utf8')) as {", + "fingerprint": "05791b96c4e0947634f1ebdf701d920c0629f52cfa325fa8a6ce55b6ec86b854", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const value = entry.destinationRelativePath as string;", + "fingerprint": "065dc3265e2b78b10d7db2674ee29c3e53fc7624f09b0f2240404325f121f5bb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as NodeJS.ErrnoException).code === 'EPERM') return true;", + "fingerprint": "06c059c7c39c2686b074444a4fa8157e3cd14d323f6cc6835fd3e3a0f3dea035", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/shared/common.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "return value as Record;", + "fingerprint": "06f4cd509b958b46cbe29a4d01869e6bda77e38e8f0ea4d46119f1e01c67b26b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/release.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ".map(([, args]) => args as string[]);", + "fingerprint": "071f370ad48e651b47aab2f33200df42429869569e734619b94fa2640531727d", + "count": 2 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "Rename symbol \"PATH_SHAPED_RE\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "if (typeof ff !== 'string' || !PATH_SHAPED_RE.test(ff))", + "fingerprint": "07ec7440215ee51fa74ac64eb0327a2e0b232ede84840a9093dda694c2c4d457", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/qavis-advisory/__tests__/qavis-advisory.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "(console.error as unknown as ReturnType).mock.calls", + "fingerprint": "0811dece7a77fbfecf8bce704a84181fc52f5bdbf864acf9cb4740946e6187fe", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/__tests__/review-fixes.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "fs.openSync = ((...args: Parameters) => {", + "fingerprint": "08186e60db9e59e8ab00142ed513a910656dde81f285369a4c315ac929cf75cb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof key !== 'string') throw new Error(`${label} cannot have symbol fields`);", + "fingerprint": "0842e38d484d89375a9e93032615fea882a871a49a5fe89fecc5df60f5966c7f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/history.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function sorted(value: unknown): unknown {", + "fingerprint": "0854d561ce4b6e8f8f181ac3b0e2380cf4bc66f12a1b3e3b8986346c352d0099", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof manifest.selfHash !== 'string' ||", + "fingerprint": "08706d133b7f659504bb61f916e831ccb782709c7fdd1433773ff74b0ac3c634", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value[key] !== 'string' || !value[key]) errors.push(`${location}: missing ${key}`);", + "fingerprint": "0878a91bcda37a22e391b148a43b1bf4ee4ae10cf65cecb008821af5c5f09530", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof raw.selfHash !== 'string'", + "fingerprint": "087fccab26c191cdea249e74b1b11322765dc73b8ad0463343b83b225efa955d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const directory = bindingDirectory(context, true) as string;", + "fingerprint": "08ca89e7207e47dbc2c018d6b111a55169416d30cc1c175d41c4bbbc5fb08a89", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "agents-hooks/decision-edit-guard.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "else if (item && typeof item === \"object\") collectPaths(item, out);", + "fingerprint": "08f38769bfc7b874a42b48d40368bd3ffa1c4933eab2689eb51e5f4ca80c0dc0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const { content: newBlock, removed } = removeFragment(block, id as string);", + "fingerprint": "09072e1b0b4ea92c42b69df79a74b4b2a64741bf8c109c0fddbef2334e0436ba", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "if (typeof value === 'object') return value as Record;", + "fingerprint": "095133eabfa3d8709568dbcf6fd00840f204cb3bbceed7e8a148a0d661a156b1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "value !== null && typeof value === 'object' && !Array.isArray(value);", + "fingerprint": "099eca67054c190e484c8dfe71ed613bdc7a4ec0d14d5ba64872c9b490d65ce7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(result.signalLatencyMs as number).toBeLessThan(20_000);", + "fingerprint": "09ba81fa5bac1fb4fde3c14899382a4bc9c0517e4b093a1c3c4c4c8e9ddf47ef", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function takeoverOwner(value: unknown): TakeoverOwner | undefined {", + "fingerprint": "09f33c0d99786e78c5f09dcfaedf37f0fc6432704c3d3d172796bab968fb0a20", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "{ ...noDeps, critic, runs: 3, execIntrinsic: (async () => outs[k++]) as never },", + "fingerprint": "09fe312ccde8c781cc6e038485dca434d37d94a3d0f87239cd0ef564d016fc73", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "{", + "fingerprint": "0a1509a9b57ec24397bca39a7b48e7b7188f59a8790e5bc87a024f22e12e69ad", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "The explicit open dictionary type on return value of `computePercentages` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "0a5a4947cd25976d330842b0c310be47f8835c9c154d6e351b444d1323c1360b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/upgrade.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const runningVersion = (readJson(join(packageDir(), 'package.json')) as PackageManifest | null)", + "fingerprint": "0a650e6e0b4d14b8f598438e2e889e09f09336d916ea047adbaa7cc801d9f47c", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/diff-archive.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const ref1 = archiveFailedDiff(diffText) as string;", + "fingerprint": "0a7805d6952ff475f942cad2662a7f8210ae7bfcc568a891050228859888a47c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const labels = parseCasesText(labelsText) as { caseId: string; slotId: string; match: string }[];", + "fingerprint": "0a7d8ef085fecf4f065714432fab1281cf501fc36852c8039043bc7a721b7fc2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "The explicit anonymous object type on binding `tag` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const tag: { provenance: Record; holdout: number; variants: number } = {", + "fingerprint": "0a8c4e31d935f35744b1388c4593ba20369aed15c74f34f78476262c43e5d8d2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-manifest-format.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function isReviewSetupHash(value: unknown): value is string {", + "fingerprint": "0a9b5b5660d6e7cbfa82abbeca9bcf8e5e271009b694b246a9110af7a79786a8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/__tests__/verdict-store.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "entries: Record;", + "fingerprint": "0ad45ea92a660f6385194a3801348f7a78300a05d093a5384ac0f355b6c998e7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "parsed = JSON.parse(line) as unknown;", + "fingerprint": "0af6e3550869458bc746ac7e29b7545a4ea8b50be078e23eca6d85ed3e652ade", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "console.error(` ${m}: ${computed[m]}% (min ${coverage[m] as number}%)`);", + "fingerprint": "0afccd4d5a143eb3f5a06559cc3acc03672981c87fd85f8ce9347b0921337d7f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "return value as Record;", + "fingerprint": "0b052052dc2e7a05c614aca8cab6e00904fb8e1559754a7a6c43decdc20ee33d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function comparisonErrors(value: unknown, location: string): string[] {", + "fingerprint": "0b6b301ca321da6801e92f1c0f85ac01016c94452e90109e5b514ca934cd54c5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "throw new Error(`${HISTORY_PATH}:${index + 1}: invalid JSON: ${(error as Error).message}`);", + "fingerprint": "0bbee7ab00ef41fe5448803bea804809dcd98e25e9f2d2cb8abe4e5135198d43", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/__tests__/judge-exec-telemetry.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof ev.transcript_ref).toBe('string');", + "fingerprint": "0bc1e48ad59b221e26db6c0e769d0a19af4c58041483f2254ec5ef2459c89336", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-run-result.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ".map((line) => JSON.parse(line) as Record);", + "fingerprint": "0bc57f670b908e6ac9ccb1261b2b0ffe0304b85d66626e2ac74fc5a93b115389", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(record.execution as unknown as Record).unexpected = true;", + "fingerprint": "0bd682cba4f1d8624314735ef80ab9d285b37e067354f30e6f4d3121165f4b6e", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.recordedAt === 'string' && Number.isNaN(Date.parse(value.recordedAt)))", + "fingerprint": "0bfad958d554c5d70ea37ae273781d1356918f5af6b7d9f490000804d2c637ef", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "The explicit anonymous object type on assertion discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const m = merged as unknown as { itemCount: number; itemTally: Record };", + "fingerprint": "0c2189ae08c27b0e5637558a91fb791ce1697328f545f926423a9dd7280750db", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "(record.execution as unknown as Record).unexpected = true;", + "fingerprint": "0c4d7aa80d79073fbb6c8b13c29de1a10bb5ac6d20cd25e60199886f82d4294b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/diff-archive.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const abs = path.join(dir, ref as string);", + "fingerprint": "0c60fe5986b30da6969bc22bbd3814bb79306890b253d8caf85728241b603001", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (fields.has('generatedAt') && typeof generatedAt !== 'string')", + "fingerprint": "0cce94bdf34f3e9c89e98db5b8c468c004582a2a8bf1083cb4bd8f79586e5015", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/agent-asset-lock.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "fs.writeFileSync = ((file, ...args) => {", + "fingerprint": "0ce9caa567cc28d69c603956dae245ef146cb97872d83b3939bbf1a68e2cd722", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(parts.some((p) => p.retried) ? { retried: true, retry_phase: 'deferred' } : {}),", + "fingerprint": "0cf1724c6ff85893c6b5f0e38a7274863cc6b5194dba6b0f014ceb662792e75d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/diagnostics.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const line = typeof span?.line === 'number' && span.line > 0 ? span.line : 1;", + "fingerprint": "0d114128042f839deb9351e3fd43f1bbe5ea01423d3611960bba9ad57286fa5d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "Parameter `issue` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": ".map((issue: unknown) => String(issue).slice(0, ISSUE_CHARS));", + "fingerprint": "0d9493ff7b5362da182ee6520be91f6973728ff343b90e24484c8db41cdf2b60", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "process.exit(error.code as number);", + "fingerprint": "0ddc44e0f0e674bc24ba2456c2d3e1a73f81317da38ba40dd834f1854288e11f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/completeness.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const cachedDuration = typeof hit.duration_ms === 'number' ? hit.duration_ms : undefined;", + "fingerprint": "0df79388c78daa4de69f2f4dfece273cfeae3de46e5086b53aff86851fb128da", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/dist-integrity.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `repo` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { base: git(root, 'rev-parse', 'HEAD'), root };", + "fingerprint": "0e28501d89ef46754dd03100e6c53dd34b1669a3f48e15aa7433ceec856374c2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "...(typeof envelope.session_id === 'string' && envelope.session_id", + "fingerprint": "0e3b5e5929d2ed4b6ce1de5b1d4c24b880eb69c05a8d637c2cdf720613d35792", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/standalone.mts", + "diagnostic": "Parameter `e` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export const firstLine = (e: unknown): string => {", + "fingerprint": "0e7af7d7d9e1051b1bc15500d184129ce8de29e6049dcf0c4f44dff9f5b031f9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const snap = e.snapshot as { items?: unknown[] } | null;", + "fingerprint": "0f027f401e169efe9105a5e00e3926f7185f010d390944c7276b35bb08863473", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.pins?.oxfmt === 'string' &&", + "fingerprint": "0f29625a92f450661f02e540a35ce3318693b679336ce555a71737298212b76c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/components.mts", + "diagnostic": "The explicit anonymous object type on return value of `newBundledGates` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "0f2ceef1d547e8488f0d60303bdf1dbfdba7e7f16a34a775ac153cc3b84e9f2c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/plain-data.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const record: Record = {};", + "fingerprint": "0f8f19ba8ee67d557218b02d1187ef0578b00812792d6f6a5c2e08101ededbba", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "for (const arms of Object.values((file.b ?? {}) as Record)) {", + "fingerprint": "0f98819ceefbfed91c9f9cf5a2e54268cb3c64dd1ec9105952b225c89f5b1a5b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/agent-assets/agent-assets.mts", + "diagnostic": "The explicit unknown type on return value of `parsePlainScalar` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!value) return '';", + "fingerprint": "105ad8bb23748a224543189c260e70ff82c10bce78b17492ac80817085e22425", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/baseline-fallow-paths.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value === 'string') return rewriteFallowPathToken(value, mappings);", + "fingerprint": "10613a2c7048c15cba8b4c3a12e0aa8236cdc8351a810f568b716e2ef4b190eb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as NodeJS.ErrnoException).code === 'ENOENT') return true;", + "fingerprint": "1088a0fc3c1cb7248a991eeedf9e4eec3dfe2268baaabad521c31ce36385dd0f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/dependency-preflight.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "dependencies?: Record;", + "fingerprint": "10a392b9f1866486fd33fd88539eb097bb49c2fc5295637829185ee2dd6b03af", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.token !== 'string' ||", + "fingerprint": "10e2d3590ea3199ba057c808ed6ec3850eaa7b466b7098ea63eeaef7ce71afcc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/baseline.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof entry.ruleId !== 'string' ||", + "fingerprint": "10ed61aea94030ca5e5d71cb26d439b3fa995b34a168320a6edc5e411479c42b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const reordered = Object.fromEntries(", + "fingerprint": "11869bd98b873a466a648f574ffb573c2cb3cec676c0b8e55b8943926a791b0e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const m = merged as unknown as { itemCount: number; items: unknown[] };", + "fingerprint": "11890637f043ac786c1931bb170ef4cf5ca31610849ba2de669bf5b6fc7e7a73", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/diff-evidence.mts", + "diagnostic": "The explicit anonymous object type on return value of `capNamedSegments` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { kept, omitted, truncated };", + "fingerprint": "1196035466788dd0c1f478b28ef63f42e94ae59d583e32f58c8b5e42b54a9f84", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/catalog.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "catalog = JSON.parse(raw) as BenchmarkCatalog;", + "fingerprint": "11f57d8e178e47defda73f40fe30f70998567ecc8f3a5d2793684958e9db4444", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const file = entry as FileCoverage;", + "fingerprint": "12001d1ec3a26da4a14e2501f6f5430b673a87a3c33c7d4999dbee149d527b45", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function validateTimestamps(value: unknown): string {", + "fingerprint": "1200f92d0de8f00c22213aa0a15a222b3c42dea81dee600ebf8b2d4eb5750dd5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/suite-adapters/deterministic.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const rows = input.rows && typeof input.rows === 'object' ? (input.rows as Json) : {};", + "fingerprint": "122654cbf2cb2ec70838fd2709b29d36c1cf54cd31dfc6760fca761e0885c8c0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "allRows[`${key}:${rowId}`] = typeof ok === 'boolean' ? { ...native, ok } : row;", + "fingerprint": "122fb19c6a1cce7227d0e9d5ae350fe36884135d9f57e9fa4a4f0ec79f16ede8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/co-occurrence/allowlist-cli.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const line = (v: typeof s) => (typeof v === 'object' && v !== null ? v.line : v);", + "fingerprint": "124ae15962246cc1a539e91e58fed346c0e9e364754ebe2014b856159d4ca202", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "gate-engine/review/evidence/commit-message.mts", + "diagnostic": "Rename symbol \"INSTRUCTION_SHAPED_LINE\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const INSTRUCTION_SHAPED_LINE = /^\\s*(?:#{1,6}\\s|[\\s>*#-]*\\**(?:VERDICT|OFFENDING|VIOLATION)\\b)/i;", + "fingerprint": "124be3bcf2fd32f73f9514dd3fa0851e10894912767eddb6ef013dc8c88fec39", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function verifyRequiredEntryString(entry: Record, name: string): void {", + "fingerprint": "126a6aa6029f61b707a8695cf178b52c0702e536f72a106685d595b300552168", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/sources.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof s === 'string' && s.length > n ? `${s.slice(0, n)}\\n…[truncated]` : s;", + "fingerprint": "12c9763a108033899a27ae78260fb7d6d4ed3ad14d9c105eb2c69ae35dc524a7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return objectValue(", + "fingerprint": "12ecb89b86e5ba05b3520b81109bcdd3fe365ae20d753475bf559940e9ae5652", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/transcript-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(readTranscript(ref as string)).toBe('evidence\\n--- VERDICT: ROUTINE ---\\nROUTINE');", + "fingerprint": "132803d2d76494183198f2c20e38cdac72010cd760cde9ef17fc37bbb7f14dcd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/eval/conventions/bench.mts", + "diagnostic": "The explicit anonymous object type on binding `tag` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "} = { provenance: {}, holdout: 0, variants: 0, decoyKinds: {} };", + "fingerprint": "132898b98d5d58eebf4b3d9ddaadc5f87bedc100ccba920a986f3a75018fe7a7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(superseded ? { supersedes: superseded.id } : {}),", + "fingerprint": "1352c07d80b7103cb59b9d02921615d0901e6dd99e563577b7926d2fc2359af8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/prefix-cache/config-fingerprint.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (v === null || typeof v !== 'object') return JSON.stringify(v) ?? 'null';", + "fingerprint": "1385d6b05ca6ee2367801cdd2342f2d3c2cb77026eee902097c9535fbb6018d7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "(typeof repository.head === 'string' && GIT_OBJECT_ID.test(repository.head)),", + "fingerprint": "13e9cce21788aa32b30076dca88c254b8b914134169514085e58cd671818df9e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/overlay.mts", + "diagnostic": "The explicit anonymous object type on return value of `syncOverlayHook` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { missing, drift };", + "fingerprint": "13ff2947f1055061f5ba97fce796a948263dc5cb23d67a15693b1c22bd3b2d52", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "(m) => typeof coverage[m] === 'number' && computed[m] < (coverage[m] as number),", + "fingerprint": "141f0ed62e9bfa51259024119da3e442d3cbb3e9d03de31ab5f621a54887f76c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.id !== 'string' || !EVENT_ID_RE.test(value.id))", + "fingerprint": "1446d83b9ee7aac8c6048fce592bada6f3add51969217f1eae062899e942b0c2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/__tests__/test-subprocess.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return cause !== null && typeof cause === 'object' && 'status' in cause", + "fingerprint": "1455c544236cee2033bd7a325817e1ac30fe9fb3bfef2569af3e94640fb9d4cd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "Parameter `input` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function parseBaseline(adapter: string, input: unknown): ParsedBaseline {", + "fingerprint": "15269c560c2baea15c206f44aa8a691321f7fa5a2c589d4f83883fd19f0bdc77", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/run-review-fixtures.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (trackedDirs.length) rmSync(trackedDirs.pop() as string, { recursive: true, force: true });", + "fingerprint": "156693afb23dff3ad5ed0c416d494788c0f3064731f8cd8499d35d37b5a9db34", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/dependency-preflight.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(parts.length === 1 && !name.startsWith('@') && validPart(parts[0] as string)) ||", + "fingerprint": "15a01dc9c49dd2e4a7bfd90b2d8602a734826d80a9d78b01a6c275c67498e04f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const value = raw as Json;", + "fingerprint": "15e422d3b839ebb2ccb2c55bd468c7b73f172f9fb2371d238e79e9f0d8531247", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/reviewers.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const withTargets = wrapPrompt('body', reviewer as never, ['a.ts'], undefined, undefined, {", + "fingerprint": "15ea9c4050e726176c07d286117b204686c0f6f4912feaaccc93b9dcdd3cd6b3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "The explicit unknown type on return value of `reviewed` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const reviewed = (overrides: Partial = {}): unknown => ({", + "fingerprint": "1605213cc38a498ec75b117881fb4140ec44ff01779819607a68f43c08032f46", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const isObject = (value: unknown): value is Record =>", + "fingerprint": "165857c50601b97f23b129bcf67448eb05146f525160417a1d6de2f7bd268e51", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "value !== null && typeof value === 'object' && !Array.isArray(value);", + "fingerprint": "16e625d51a751d09604ebfb3789680c1ccfa96dda5d15c6731ff92bb06331ae3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof value.configSha256 === 'string' && SHA256.test(value.configSha256);", + "fingerprint": "16e72a049b89ba5d748d360dee988a0f04eeda8a49bbdad473e3cc87c13569bf", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/wizard.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function bail(value: unknown): value is symbol {", + "fingerprint": "16ee71442ca7b8bf31164b79f9b701aeb974a97904b79cda32d022bad64c299d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/eval/reviewers/bench.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(cascade", + "fingerprint": "177b8a979c0bcfc2727e0b9ac2b8cb7c133f24b910ab757956475b7d021c31c5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/structure/load-baseline.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (Object.values(mod)[0] ?? []) as string[];", + "fingerprint": "17d0c3ce1317986e79b70cd83df59a1affd5ae1ae8fa62070cc7b65904891f18", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/plain-data.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function exactData(value: unknown, expected: Record): boolean {", + "fingerprint": "17d1e4ae30ab7dab62a47f5733cd50b9d9a05b34927b0425c8bfc7c56b1fb839", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/decisions/decision-format.mts", + "diagnostic": "The explicit open dictionary type on return value of `parseTargetFields` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return fields;", + "fingerprint": "17de5fefe103b6a17a076a00a8be556d6a1ebe96948754debeb9bf5c9ecdfbf7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof options.root !== 'string' || !options.root || !path.isAbsolute(options.root))", + "fingerprint": "1856642acc81f4add976671f72a4053c14c7bf84713a3f769aa97b5b00ddbef8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/anti-slop/diagnostics.mts", + "diagnostic": "Parameter `code` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function ruleId(code: unknown): string | null {", + "fingerprint": "18ad250db1b4b225340ee8fc3cea3da6dc705cc0acea4732156882e40a4eecd6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.pluginDigest === 'string' &&", + "fingerprint": "18da63aeb51e39161b743db5689bb047287878281b73fb935f3890d5d716bf17", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/_helpers.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "export const testSpawnSync = ((", + "fingerprint": "190c67a758fb017ac2552ef4fa18857fdf2c141f0346305afe54a2ffc3ab3b75", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/suite-adapters/prior-art.mts", + "diagnostic": "This dictionary's any value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "type Json = Record;", + "fingerprint": "191d8a1d747e372c476e2990955e3973a1ba079e637534a4cc40120749fa629a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/cache/root.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "`${reviewCacheRoot(args[0] as string, args[1] as string, {", + "fingerprint": "194365ad7e3fa4a8a07b6ed835806a516222762cd294b1f77e158c08caa7ef9a", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/flags/review-profile.mts", + "diagnostic": "The explicit anonymous object type on return value of `reviewPlanFromFlags` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "19738ed2831e7967e6eb66036b834c1397b3d857b336b7af89208f341afdde19", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/co-occurrence/allowlist-io.mts", + "diagnostic": "The explicit anonymous object type on return value of `loadAllowlist` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!existsSync(path)) return { pairs: [], clones: [] };", + "fingerprint": "19cbd2534e73715a76d5ab5b8f804b7c118cfa6ac025e812748784e7e51eaf50", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "Rename symbol \"validShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "if (!validShape) {", + "fingerprint": "1a2b8fc83669192185d503278a92e9c418cec9dc85c4bee0d7d204867bb3c16e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/anti-slop/baseline.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const entry = value as Partial;", + "fingerprint": "1a42bc53912c6de98400cb9f5cf1df172b20aa43193c47f29cfeaf64bc419a9d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? { got: m.verdict, ok: wantMeta.includes(m.verdict as FrameMeta), stable: m.unanimous }", + "fingerprint": "1a48ea5b0b98f70473f9f81ed81f94079a758faa2cb0c5d71483e063d43b1121", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(record as unknown as Record).unexpected = true;", + "fingerprint": "1a5366c1e64c0ead2270b4bc6f2eb666894c1f3561b9d3f9ae65555cb4511d79", + "count": 2 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/cli.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(disposition !== undefined && DISPOSITIONS.has(disposition) ? { disposition } : {}),", + "fingerprint": "1a9425e43a834c75075ddbbb5823275a874cdc4bfe39335c17c5647ef1585b99", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/commands/reconcile.mts", + "diagnostic": "The explicit anonymous object type on return value of `measureBases` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "1ab58ef625582ac306e8b8de185c19e06db60dd06474dad4581faf6c50b9185f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(() => persistPlanCritiqueWorkQuarantine(invalid as never, { root })).toThrow(", + "fingerprint": "1ac5b59fcfd43f9e3e5d724fad5ca95877bd8f17d399370ddfd183f5f1fd3d96", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/match.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof a === 'string' &&", + "fingerprint": "1b04be51a2310a6afcbf3d5d0a340c773f7ea61c1576fe1535f4aac687e17393", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/commands/init.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(prevConfig?.minDevkit !== undefined ? { minDevkit: prevConfig.minDevkit } : {}),", + "fingerprint": "1b0deb611dcad2c181bc1cfae15859e0eb148d9f88d576fdbae79053667e8bab", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/overlay.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof prev.origHooksPath === 'string'", + "fingerprint": "1b2c1b8e72b1abc2b922d1e8509d8fe525ce483b09b30081721974b0f064614b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/immutable-file.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const directory = managedPath(anchor, ['records'], true) as string;", + "fingerprint": "1b4bbea44d2a11a4b58a7c81a97a97b229fa5b4cf4f38487fd3b00c56843589f", + "count": 8 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "The explicit anonymous object type on return value of `readJudgeOutput` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { text: unwrapClaudeResult(stdout) ?? stdout, usage: parseJudgeUsage(stdout) };", + "fingerprint": "1b6835aad0f754c39ae401494a336722ed8a3fb9543c3200673db1d45ac0b0ef", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof a?.coverage !== 'number') err('diff anchor requires anchor.coverage');", + "fingerprint": "1b98397b42ab09b72b5bfe66b8c18365e7585fa245017b6040757c1e75f0d513", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return sum + (typeof d === 'number' ? d : 0);", + "fingerprint": "1c24ecb196c5688764852fd212765e687fa3f322f0d3ba8f2f6c9420cf8186aa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value !== 'string') fail('invalid projection link state');", + "fingerprint": "1cf136a9573331bfcfd14273271e0f756243512835ff4932fb825ecd3f6f7569", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-submodules.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "readFileSync(join(fx.review, fx.modulePath, fx.nestedPath as string, 'nested.txt'), 'utf8'),", + "fingerprint": "1d139c4b99961d19a24dc1308ae55ceb6c94de889274b3a8ddd9449d75329414", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof value === 'number' && Number.isFinite(value);", + "fingerprint": "1d4232a91212c3ab9819eb6cf37e02a74446890670e8ec04de138596c75cc266", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/agent-asset-lock.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const error = new Error('injected owner write failure') as NodeJS.ErrnoException;", + "fingerprint": "1db38a0aed18cd24e0534205a38ce8c57148a38675c7bbf80119f8c5cc82eae0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "execIntrinsic: (async () => outs[k++]) as never,", + "fingerprint": "1e9ca533af4ffadcaae6f1ced59341e78077e984ade17b2a0714058e246dbf19", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "{ id: 'y', kind: 'recorded-decision', desc: 'c' } as never,", + "fingerprint": "1eab7fa8a1417814c5d0b2f4940f8ac7f732391fd87f7ae4b16a9d5d82f904d3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "anti-slop/src/shared/lexical-type-parameters.ts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const record = node as unknown as Readonly>;", + "fingerprint": "1ed8276108ba0124c9868673c54ceebe472a1860285270afea667ee76d558458", + "count": 2 + }, + { + "ruleId": "anti-slop/no-widen-then-assert", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "Binding \"stored\" discards type evidence and later recreates it with an assertion. Keep the precise type from initialization through use; parse boundary input once.", + "context": "const restored = stored as User;", + "fingerprint": "1f37f78db034607b177731bdf37efcbb72de005c4cfa8e2ec35134b007bcbfcc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "gate-engine/critique/provider-runtime/claude-subagent-stop.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.doMock('node:fs', async (importOriginal) => ({", + "fingerprint": "1f66f942bffcdfca361fd1cf2b0c2d68f46d834c291858c50e210af7ac642a08", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseSetup(value: unknown): ReviewSetupState {", + "fingerprint": "1f8a130dab987d70ca0548edbf85927a9b423cf00a637ac4441e7b5a6d44416e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "The explicit unknown type on return value of `ownedSections` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { ...parsed, sections: Object.fromEntries(owned) };", + "fingerprint": "1f95af611f7c160b2547f1217bfe13f25b4350a42552521b56817c385a55a330", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/run-packaged-script.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((cause as NodeJS.ErrnoException).code === 'EEXIST') return;", + "fingerprint": "1facd1e72bf2e971de0b3b0790b04fe7b2ea1e1e94a152f02a694b9b3e2b8696", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(value.pid as number) <= 0 ||", + "fingerprint": "202e37d33cd267a88a4ec67de89718aeab678aae252b36cee39b7475a3dba90b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(await waitForProcessExit(result.managedPid as number)).toBe(true);", + "fingerprint": "205cd0fbdf2d991deefe606cfa156cca33dc383b3e67e47a859b57a9acd6c064", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/anti-slop/baseline.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function validateEntry(value: unknown): value is BaselineEntry {", + "fingerprint": "2070f19bf689502e2a2bdc33d59547082cbbf49af13dd8b328df4f2f6edd6393", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "expect((merged as unknown as { itemCount?: number }).itemCount).toBeUndefined();", + "fingerprint": "20a30528ca66e4678e35b17546d1634b33ad423c6802d368c336c35c6ef7b6eb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "value: Record,", + "fingerprint": "20aba44dec193226e7b3fbe20fd25a136ddf8505697d75932095b52a32b4ee6f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/__tests__/claude-result.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const envelope = (over: Record = {}) =>", + "fingerprint": "20c18f30558739b7481435ba7c2e9736b92cb8fb7e9af3d200bc932fa782036c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/prefix-cache/prefix-cache.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "...(typeof opts.durationMs === 'number' && Number.isFinite(opts.durationMs)", + "fingerprint": "20f74ee817c914a4461e2b023bfa5bd7705001e1245f899089c2d7fc82c930ce", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function validateLinkedState(state: Record): void {", + "fingerprint": "211ff64d952bad9d311c1c57e14f9ba8e75d5ab2430c9d7b8daf5d4583d21526", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function rows(value: Json): Record {", + "fingerprint": "212fa5eaaf88b94dba92139f874467465a4902b22cec345670825f3d671c58bf", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "Parameter `e` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function judgeErr(e: unknown): JudgeError {", + "fingerprint": "216722ad51d2920ef1bd65aaab80f0f01ba000e87b79360123f222467d940e00", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "Parameter `entry` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "function appendLedger(entry: object) {", + "fingerprint": "2167b07c1be3e9267e2bcba68f564b6abc81b29b1dab2c932fe9f02e0bc43c01", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/immutable-file.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const codeOf = (error: unknown): string | undefined => (error as NodeJS.ErrnoException).code;", + "fingerprint": "219787f0387a099822012124c765a93e54f2695d52f34e2b62f722dce6295ae7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.test.mts", + "diagnostic": "The explicit open dictionary type on return value of `payload` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "21d9baf7318445e87ac0846bb325cc461df462652e4516bdb12e1e39e9f6de79", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/sources.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": ".filter((b) => b.type === 'text' && typeof b.text === 'string')", + "fingerprint": "21e25a8b6a0db088876b34027146780ea120c78a0f84bd612c226ef5f6bcfcea", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "Parameter `document` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function editableDocument(document: unknown): {", + "fingerprint": "220b3ea932687016f91f3e18fe9280bc24365bf5b2dd46047096eca7307f0f05", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "result: undefined as ResolvePlanCritiqueBindingResult | undefined,", + "fingerprint": "2227b4f39e1ee7ed6b37cb898c22825d481d6c0e0f7547a05b3db8a762173ab6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/update.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('node:child_process', () => ({", + "fingerprint": "224afe751d014890e763b9ccdae384996349e43af68a3bb7228d26a101469a03", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/upgrade-offers.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ".map((component) => component.id as string);", + "fingerprint": "22f777acf05023709ffe7ebf216d64c932f6aa8de175f6b92ed59625cbafaa48", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof stopHookActive !== 'boolean') return skipped('continuation_state_unavailable');", + "fingerprint": "2344e433bfdfdaa15591b8800b827986c11d23b265bb730751863b4889e44051", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const mode = (values.mode ?? (values.tree ? 'tree' : 'working')) as TrackerMode;", + "fingerprint": "235f4517eb199b9a6dcb446e1cb4b262ca0ed3f4ec9ba04cf0afe89b356e8950", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/devkit-version.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const manifest = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8')) as {", + "fingerprint": "23634d9af850b727d01e31744da72b1ee542f975d62820efadbac65c38f147d1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/factory.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (v == null || (typeof v === 'string' && !v)) {", + "fingerprint": "2367edc75ef66e21291599eafc330c42d9c7af2cb2446845439147d37bf1593f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/upgrade-optional-component-offer.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(unofferedComponents(declinedAll as Partial)).toEqual([]);", + "fingerprint": "236e4e3c68bfd8a3c095c246509e7026bddbc5cf435040f0fa5315470a7a1af8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "function sorted(value: unknown): unknown {", + "fingerprint": "238dc326a67edd6e2a51cdceae3da17ed10663d57da1692e1ca5291447537169", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "Parameter `document` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "document: unknown,", + "fingerprint": "23b446a127d951db0c8ca740a47da7f2a9e53846354047a5cd15d9a9f0f5b583", + "count": 3 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/clean.mts", + "diagnostic": "Rename symbol \"PackageJsonShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const pkg = readJson(pkgPath) as PackageJsonShape | null;", + "fingerprint": "23e0f6e43fbd5758533646c9ac9e9ee7a464a089a92bc5d778f958e2e83feb5b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return entry as unknown as ReviewSetupRuntimeEntry;", + "fingerprint": "23ef45c0f6b1320f45de450d32499610e2ab38f60132d18aacc4cdf2877aee3c", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "source: verifiedSources[index] as VerifiedSetupSource,", + "fingerprint": "244547a36c0beda2e749032a58600ad7286dced0bc6999357db674a218fd4577", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/extends-checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return JSON.parse(jsoncText(path)) as ConfigWithExtends;", + "fingerprint": "24bc9265c18cb341fefd9b26fdbe71b22daf95b9286fec5222a898d123eda9bd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "value: unknown,", + "fingerprint": "24c86a359385a5ea5b51f4b3d3ae9ca1632e340b22afb42b7b4739a72c3544ae", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/pretooluse-bash-hooks.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `resolveHookScript` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { runner: runner ?? '', script: join(REPO_ROOT, repoRel) };", + "fingerprint": "24d1f6cb0e1cd7c5f2f9d4e28bff46bf3f05f48a549cf1ed68a6ff88fe008861", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/valve/waive.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const who = e.author ?? (typeof e.by === 'string' ? e.by : 'unknown');", + "fingerprint": "24e1caccdc759ee17642c3e9bee019ca7af8a25b889978bc83827b7b5e19ba96", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const devkitPkg = readJson(join(packageDir(), 'package.json')) as {", + "fingerprint": "24f5b04d8bc7a44ff74fb063d4258dd5d65bcaf3eddff91df5a630e1f8cf5a30", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function validateEvidenceRefs(root: Record, capturedAt: string): void {", + "fingerprint": "253236bf3504c9614c00f5e989a6d3dfe92682f2195fccdd3b92f5a77691e3d1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "eventsById.set(value.id, value as unknown as BenchmarkEvent);", + "fingerprint": "2548ff33406dff1585cc1a97269a547bdbd3a73b0a5d74f2625caae0017d27ce", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/overrides.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "reconcile(cwd, 'correctness-reviewer', ['concurrency-races'], 'DIFF-SHARED', NOW, {", + "fingerprint": "2571a71fd96ccdb98849f89e5dec99fc8e781460f55c74dba335a05711783041", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "The explicit anonymous object type on return value of `loadBindings` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { bindings: [], candidates: candidates + 1, malformed: true };", + "fingerprint": "25d2bc57e8352c42f745d94b7cd225080d0e83d2897725dcb3cfe10b76074eba", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/finalize.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const findingObjects = rawFindings.filter((f) => f && typeof f === 'object');", + "fingerprint": "264771879cb5b267a6da3fb348de5f0f848521539577f0c1b9c4a05dcc47dcef", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as NodeJS.ErrnoException).code === 'ESRCH') return false;", + "fingerprint": "266b017ae6fe867bbd839a5d96e59e9fa465bc6a5bb43d4fd76870accbf2c75f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const binding = JSON.parse(readFileSync(file, 'utf8')) as Record;", + "fingerprint": "26889f8e9cf6aa9828e7b486a3ffeb59a891c89d2a534d4f832389539c370caa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/install-fallow.mts", + "diagnostic": "The explicit anonymous object type on return value of `installFallow` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "26cd8dc4cd4c3fa18c95f25f41bad884530b274ee9a94a63fcdd3047215092a7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const isObject = (value: unknown): value is Record =>", + "fingerprint": "26cee967c75a3542e47bd870ce3c378b59e55ebbd43f513321b8bf1aee45b137", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/agent-asset-manifest/reader.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "LEGACY_AGENT_PROVIDERS.includes(target as (typeof LEGACY_AGENT_PROVIDERS)[number]),", + "fingerprint": "26df850ec0079addf710cdce0d9890aab57ddc37671c82323376a5db66b462c8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "([, value]) => value && typeof value === 'object',", + "fingerprint": "279fae4f4e3ed068e650e56a1d181a527af14d278c2210f54e2e9306a4f9850e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "args[3] as string,", + "fingerprint": "27e75e21c9f03e745a4f47d7aafd2cecdcfb65f0d28007a7c984c67e4f19a545", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as Sha256;", + "fingerprint": "28016a686d7265755d6bff35a58eccebd5c4bb09da4421cbd65172128f55db04", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/judge/odb-probe.mts", + "diagnostic": "The explicit open dictionary type on return value of `boundedPayload` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { total: objects.length, omitted: objects.length, truncated: true };", + "fingerprint": "280f6b2d55bd382be479d67398489130bc47720a064b54027ed895a050a87f07", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/factory.mts", + "diagnostic": "Parameter `raw` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "return (raw: unknown) => {", + "fingerprint": "281a149ebe22547f018a136c01e84195ad75bec542564378542cef7070d71c79", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;", + "fingerprint": "2846152eb2ce95c767a50dd98c338e192ac1debf6c4adda583b5e48fe01fd863", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/__tests__/odb-probe.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "let events: Array> = [];", + "fingerprint": "2862f6056afc542ce89ffd05a12bb68b2315d15832b4f69e25ac478236e3212a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/judge/odb-probe.mts", + "diagnostic": "The explicit open dictionary type on return value of `build` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "28abc14614435b80ecd3dd132ec468935b4fbdf1dfe5686f3323f4062922d1d3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/immutable-file.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const directory = managedPath(root, ['records'], true) as string;", + "fingerprint": "28b091e71e3da3299335835904bc387245b18f659b3256c1f0ca7fdecad4633e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/hook-registration-ledger/plain-data.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value !== 'object' ||", + "fingerprint": "28ec2edd62825fe771b6f4e51267d7825fa7eab44c964aa7d3db3c01b4df1329", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/run-packaged-script.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "signal && FORWARDED_SIGNALS.includes(signal as ForwardedSignal)", + "fingerprint": "2905a0f9c8138be39cb96c4ca4b9aab9868c641d1fc7db35066f9b9433100ecd", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/_helpers.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "export const testExecFileSync = ((", + "fingerprint": "29a473fdd15271c26b0e386e8a32828f934754d6f6f63174bf8fef5d18d68feb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/waive.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (dirs.length) rmSync(dirs.pop() as string, { recursive: true, force: true });", + "fingerprint": "29b308b57c2e973c4094d2375eb02cfe9d2b819c3c815282e09c68393cb68b1e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/baseline-gate.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return parsed as EslintResult[];", + "fingerprint": "29cda60b2a3b084608fb5cb5652d5ef5e8982221681feb51bb901229aeea70c8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return identity as unknown as PlanCritiqueWorkQuarantineIdentityV1;", + "fingerprint": "29de408826a6e8bd50501ebced9897e79b4b982a81a9b8dd0e06c78387006835", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "skills/_devkit/review-roots.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const roots = review && typeof review === 'object' ? review[configKey] : undefined;", + "fingerprint": "29efce70385b4a324ff9d3a9b4cc0d66341dd2157b221ad0cff30e6cf743c85f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return fields as unknown as ReviewSetupRuntimeFields;", + "fingerprint": "29f1549905b58edaadcf70f06d4bea76a1383209c2364321bcf5192853eded5e", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "hooks: Record,", + "fingerprint": "2ab3d85f16eda349e097c31254dc3ac0c50593fc8bd39230d69c574c3f6a2edc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/upgrade-offers.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const chosen = new Set(picked as string[]);", + "fingerprint": "2af436fed0c79bdb099fc0249396be407ec02c7484429e9e66b7ad9c000286c8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function exactObject(value: unknown, fields: readonly string[]): Record | null {", + "fingerprint": "2b15754e601ec359d3f4613465367041dc129e7aef19e7b554f88e270645b0b5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/suite-adapters/deterministic.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!metric || typeof metric !== 'object' || typeof metric.id !== 'string') continue;", + "fingerprint": "2b1a126c57be2294a49393c20615b1819051177aab7672ffff3186ea8d539ce6", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/generate/generate-structure-baseline.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const trees = (cfg.structure?.trees ?? []) as StructureTree[];", + "fingerprint": "2b22b9f8d4d1dd2bb495439ee6598713f68692203003108cae8e5006262f0207", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "!guards.every((guard) => typeof guard === 'string' && REVIEWABLE_GUARD_IDS.includes(guard)) ||", + "fingerprint": "2b356407638d592402ce6fe8b3e4ff6d054c5e0d291849146ba11b13a21d0a64", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/gate-events.mts", + "diagnostic": "Parameter `durationMs` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function emitCacheHit(judge: string, model?: unknown, durationMs?: unknown): void {", + "fingerprint": "2b41bfc43bcf78a0ec36dea96f4f9e5746b8bb2055afc1729316c6582cd065c4", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/capture-normalizer.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? { bytes: snapshots.opaqueTranscript, expiresAt: transcript?.expiresAt as string }", + "fingerprint": "2b696a5874b644fc90a5869e6537f3b19d2af8b0768203c044ad3985c9676a95", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/shared/common.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!value || typeof value !== 'object' || Array.isArray(value)) {", + "fingerprint": "2b73c08c8df49060a503d9ca1a91917f0e32808253162dc1d78f7cf25f1a3b15", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/consumer-identity.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const beforeCommitGuard = consumerReviewerIdentity(root, cfg, commitGuard as Reviewer);", + "fingerprint": "2b9cedd07db2bfdbf55321b513961146c9a7a496c0079c45f85a626bc0e812cd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/__tests__/run-context.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof env.repo).toBe('string');", + "fingerprint": "2bbb8f89a9da3fad2bbe1eeba55624dd82e75fbf7e4d7d24e5ffa582d7f07949", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof identity.repositoryFingerprint !== 'string' ||", + "fingerprint": "2bee2f08d36105639635a1b6e24f92658e6083fa83787f2a4d32a75cae5d02e7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const base = correctness as typeof correctness & {", + "fingerprint": "2c3fbbdd255b04b44289c3e61f8f0f69ac30fa47999e03464951e7711fd8f594", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/judge/odb-probe.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(omitted > 0 ? { omitted } : {}),", + "fingerprint": "2c4b09566d659539f7cbf64070bcb2ef144266b205b652d7a2c3d2d8db92e74e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/overrides.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "...(typeof entry.author === 'string' && entry.author.trim()", + "fingerprint": "2ca0052e7773cb75528f7b7dd82ddc46b0b543b70e5553d3094fd7a51bb6db9c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseFields(value: unknown): ReviewSetupRuntimeFields {", + "fingerprint": "2ceca409875d84685249076782fb347bda2152c758fb8123cd291db5fe325e69", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/compatibility.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof previous.generatedAt === 'string' &&", + "fingerprint": "2cf4e4ad87acfd4e098dc0beb34345902733c06a92a0323adbc3abefb19a7ff5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/install/package-json.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(sel.biome ? { '@biomejs/biome': '^2.5.0' } : {}),", + "fingerprint": "2d21bdd976b40a8dcca57dc0e856b5b6db89471a9cdeff138da8964f2b66d9c1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "anti-slop/src/shared/lexical-type-parameters.ts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function isNode(value: unknown): value is ESTree.Node {", + "fingerprint": "2d6ea6a4b963b09a8f6f1a31bafe8d71c66e6714f4e8b727855c11d607cfc8aa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "(candidate.createdDigest === null || typeof candidate.createdDigest === 'string')", + "fingerprint": "2d7afc0c9c78d6dcd5cbd8f598ae22adcd25c4e9635d2e33866641b21b8b2a01", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/config.mts", + "diagnostic": "Parameter `v` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const arr = (v: unknown, fallback: T[]): T[] => (Array.isArray(v) ? v : fallback);", + "fingerprint": "2d9c6d5d1f20b4f72783deac7c3e4b8d13f4c2d56bc39897a36f7247f3745bfb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function validateUnlinkedState(state: Record): void {", + "fingerprint": "2da3c6b764fe49637439875ecd9f695a964ef4dd288630f5f685c8f009a307bd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/plain-data.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function exactData(value: unknown, expected: Record): boolean {", + "fingerprint": "2dae7dc2a321b6ada42596eec876ef4e5ca48e49fbcd0a130dfe8062526e1691", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/eval/matcher.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "severity: m[1] as Severity,", + "fingerprint": "2db3e29e6707c44b8750dda1f55153c66f88b6c8d622eee4c038d0d8b044bdcf", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const canonical = resolvePlanCritiqueEvidenceRoot({ root }, true) as string;", + "fingerprint": "2df9eda7d168e3ab6823885ccd9cc5afed20b8e55d498bd1f879390a93211ecc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/lib/doctor/pin-checks.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('node:child_process', () => ({ execFileSync: vi.fn(() => '') }));", + "fingerprint": "2e155c9427d407f0c53cba212ceae26a1396e3fde9575ee0c49d3dcda073a369", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/dependency-preflight.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(parts[0] as string).startsWith('@') &&", + "fingerprint": "2e29bf5010caa55daa3cb0089b655819c0314afd4b31edc1545b37ebd1bc1eca", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return path.join(directory, names[0] as string);", + "fingerprint": "2e33a4de8c8744ca4d729f2df30477544c7233ab28961b8414ee8b8533bdfdbc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/shared/common.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function objectValue(value: unknown, message: string): Record {", + "fingerprint": "2e34b69677790ddf3f638d34827ea92ccbb6ec0093e151b520c2807e72c1b741", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return mergeLensOutcomes(parts as never, sel.reviewer.name) as R;", + "fingerprint": "2e5b4433fd357a4bbf06c4e4fd458126a7c2b97eb8e2b65e8585204ce52f5ff8", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-snapshot.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const fallbackDir = join(env.XDG_CONFIG_HOME as string, 'git');", + "fingerprint": "2ea8f336e0300e60a3e353fb6e7009f4b72673dfa7ea99340cbbfcdbb7ae9882", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/reconcile-detect-merged.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(e as unknown as { stderr: string }).stderr = 'gh: could not resolve to a Repository';", + "fingerprint": "2f0cef4f452258c4d1fea975180076ca30d9c2b2ad6686b3b9f1616e9ebe41ed", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const userId = value as UserId;", + "fingerprint": "2f166392ab5f2e409380e8b1b44b776ca150ec10a1d7a831f696481716b3af56", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const m = merged as unknown as { items?: unknown[]; itemTally: Record };", + "fingerprint": "2f34deca574e82984db90e05013a0ce4483e29167dfa1487e0e08c29f9f74262", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "gold: [{ id: 'g', class: 'not-a-class' as never, severity: 'CRITICAL', desc: 'x' }],", + "fingerprint": "2f57dd2b62b952947144499762d58d465c6046c6b84ac72941e8c5ba6946b88a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const manifest = parsed as DependencyRuntimeManifest;", + "fingerprint": "2f6167f9a6e34fe9b862050638ea0dc2368e247e0cc140b5e587e6a9a89fa9ee", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "Parameter `e` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function isJudgeTimeout(e: unknown): boolean {", + "fingerprint": "2fd4b2cc28290afad07040e68497da10eae65d51b1a0ae6a673f2c1bdefe37ba", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "itemCount: typeof e.itemCount === 'number' ? e.itemCount : undefined,", + "fingerprint": "30048bf0f2fbf3a49308a2b558651b04cd8e870065f211e135fe731dbad31ad7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "Object.entries(tierRows as Record).map(([id, row]) => [", + "fingerprint": "305546f5f52f09bbb8c240bdbe1eb9a56ad229f9fe870a98d652b78b10b4faed", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/mine-cases.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof content === 'string') return content.slice(0, PROMPT_CAP);", + "fingerprint": "30d278810af2317b927164d4c616aab852578020d760b16aa6ab818c1d9b0e0c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const canonical = resolvePlanCritiqueEvidenceRoot({ root: real }, true) as string;", + "fingerprint": "312690c9af64898cebfe31163895d54c291f82d23063a6f578e87fb110b8f40d", + "count": 4 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as Record;", + "fingerprint": "3127be48133b241834bf2dceabcc6d7dfdb93cef84f08252555854fd35a85589", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/generate/generate-structure-baseline.mts", + "diagnostic": "The explicit open dictionary type on binding `roots` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const roots: Record = { ...DEFAULT_ROOTS, ...(opts.roots ?? {}) };", + "fingerprint": "313493e3fb10997e1af2ae9a8d6dfaacaf01d9cc75eb02850927ea7991a9f167", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/runtime-fingerprint.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const size = typeof value === 'string' ? Buffer.byteLength(value) : value.byteLength;", + "fingerprint": "313ed9ca4be65d9597322384464c63169cd167061dba331a3a49d58f5699d063", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-assets/agent-assets.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value !== 'string' || !value.trim())", + "fingerprint": "31764186dc881493e9484eba4fcd8190752362e37a20984d592a1d82aeac56c3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(merged.waivers?.length ? { waivers: merged.waivers } : {}),", + "fingerprint": "31c5977bf50d0b83d0810f488aa4dd77ee2f856975514651ff05563be209820c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/__tests__/integrity-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const row = { ...base, mutation: 'not-a-real-check' as unknown as 'none' };", + "fingerprint": "31e5c7fb4e61365d1356addd0a8891725d0d3592f0a08be24784be94dc82ce18", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "function ownDataValue(record: Record, key: string): unknown {", + "fingerprint": "31fa4af8dcecd0e5854ad914ad38f7afd4fa6bc023fb654a64641446443c3f4f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value === 'string' &&", + "fingerprint": "32510a298595884d5e028c3ad1614b0c2661fc27f907c188183686fca1805333", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "cfg = JSON.parse(readFileSync(cfgPath, 'utf8')) as Record;", + "fingerprint": "3275a22a55cb6a9d075128e02cfacc1363dd5354525f86cffa08aa1e1c392bf3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/upgrade-version-step.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../commands/update.mts', async (importOriginal) => ({", + "fingerprint": "329ca5b720841e7db3a4e0a3dbf33d870baa74a134dd557228dc43798c90992e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/install/package-json.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(sel.husky ? { prepare: PREPARE_SCRIPT } : {}),", + "fingerprint": "32a5978dfee121034bae0bd5acb22a09368133c11304349ed44646e39942f097", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "The explicit open dictionary type on binding `DESTINATION` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const DESTINATION: Record> = {", + "fingerprint": "33114603273808ed7ec324b0affe835545f2f561e18d0ff6907d1ade01cfc574", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "owner = takeoverOwner(JSON.parse(snapshot.bytes.toString('utf8')) as unknown);", + "fingerprint": "3325f46489dcbbaed917d83d418e73b4dc9253584d074369c5226b55188d5b91", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/upgrade-version-step.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../commands/migrate-config.mts', () => ({ computeMigration: vi.fn(() => []) }));", + "fingerprint": "334bb773114ab0a5cda9b717e3e5290ed1e13de0ddbe9fdde95a79f371b62be7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "The explicit unknown type on return value of `neutral` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const neutral = (status: 'wrong_phase' | 'aborted', routing: string | null): unknown => ({", + "fingerprint": "335be33ea1901977c6961d3794c1e6b52ca0961a1b945da413d9fca1ecc13322", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "The explicit anonymous object type on return value of `pluginSource` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (existsSync(join(root, 'index.js'))) return { root, entry: './plugin/index.js' };", + "fingerprint": "33886a9afa347117173fae09511d49478388d97459b579690fea3bca742becbc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return summarize(rows, results as never);", + "fingerprint": "339cdd71d144fa4ffffeba0044b95dcf015a9f19ffc284611590e0e43c6fe405", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/baseline-gate.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (roots.length) rmSync(roots.pop() as string, { recursive: true, force: true });", + "fingerprint": "33f01c636b9da3ec57451f21038be4df1dba7c1c365e68839fabcf006b3b104c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!(CHANGE_TYPES as readonly string[]).includes(requestedChangeType))", + "fingerprint": "33f4f365610a6759ef0b11722aea6674cfa2ef815883bee37591b9b784d6366a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function exactObject(value: unknown, fields: readonly string[]): Record | null {", + "fingerprint": "3448b25b833608eca9cf9fd0e88d9e76d7af82e570bc26946a0213d4fe16910f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/runtime-fingerprint.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const target = pairs[index + 1] as string;", + "fingerprint": "3465c943c9f22472132a6f00fb102ff423ab4bf97d35bda7fffffa078b615380", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/reconcile.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "e instanceof Error && 'stderr' in e ? String((e as { stderr?: unknown }).stderr ?? '') : '';", + "fingerprint": "346df9ae977e5192d0201d104a2e666a1e8b0052875b48b16b3723ce8a3a3386", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/decision-scope-brief.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function run(toolInput: Record, toolName = 'Edit', session?: string) {", + "fingerprint": "34bb99a79f7490e28df8ca7de625d1639a8be878ba10168aa66afe50da7fea5d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/update.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "JSON.parse(readFileSync(join(cwd, '.devkit', 'config.json'), 'utf8')) as {", + "fingerprint": "358ef9dd3751e4e8c6d7a1c3165c2bfa9e9b13d04a5cb8d1fceec1fc121b5e42", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.probeConfigDigest === 'string'", + "fingerprint": "35abe7363b19ea561eb3ccdfe94b7f0adab64ca906067959279b1e360d8148f4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/history.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "isRecord(value) && typeof value.id === 'string' && value.id", + "fingerprint": "35bd02c0d306f402b7a4a324391b403980bcd4650a7734144f69a7cb430e0db3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/commands/init.mts", + "diagnostic": "Parameter `e` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function firstLine(e: unknown): string {", + "fingerprint": "35bf2713e4d40963aa69103ddc0afb4ffb653e66d2d0189632c63a1e8e6c6c7c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(record.execution as { provider: string }).provider = 'unknown';", + "fingerprint": "35d89c98b2e981ddb5cb9ae89b3eb3d436b271e14959245ee6f81cf93711e504", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function boundedArray(value: unknown, path: string, max: number): unknown[] {", + "fingerprint": "35fc57d94d002b709ba68bc4d707da0e91fd7ebbb7600d8f1470e0d2b9a0137f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-submodules.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(fields[5]).toContain(fx.nestedPath as string);", + "fingerprint": "363d01ea70179b1b92a5b0ad092d370d833e0a4cfa55e4f8caef443e119b0451", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/history.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (isRecord(value) && typeof value.id === 'string')", + "fingerprint": "366b2df35118d502587003d549945799eaf730baa0a9d18a5783f5c72577945c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "...itemFields(merged as never),", + "fingerprint": "366b3dd410b57cf9206d4a6bd79f808617ca3f205264883eefeea7b13fee9c78", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "return fields as unknown as ReviewSetupRuntimeFields;", + "fingerprint": "36abd765de7237cd7318d80c82d27b4c92b8517eaf1d840e7543ca66ed989028", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/upgrade-gate-offer.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "cfg.components.guards = (cfg.components.guards as string[]).filter(", + "fingerprint": "36bc8440c5137b940233c27df88b31b691ffa8dd03c9efa3fa6c2ff94fa57608", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/install/package-json.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(electronPreset ? { 'lint:structure': 'eslint src' } : {}),", + "fingerprint": "36da93e872ef12dabf301e066e693fed1305c691994417cab5bbd94209a77652", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/_helpers.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "argsOrOptions?: readonly string[] | Record,", + "fingerprint": "36e5e8bc45857b791bc91871811a67b5760d9094b4ea64357dec340283f649f5", + "count": 2 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const m = merged as unknown as { itemCount: number; itemTally: Record };", + "fingerprint": "36f7b28020e711c26dc97e021b896a2ca052699b6fff02b71819f4948777344f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "requireValue(typeof value === 'string' && allowed.includes(value), at);", + "fingerprint": "373334b2ab4065f1ad51a768695e5cb8f5d85ed70a3c83e1b9e892b9b8242ec5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/husky/husky-block.mts", + "diagnostic": "The explicit anonymous object type on return value of `removeGuardBlock` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (start === -1 || end === -1) return { content: hookContent, removed: false };", + "fingerprint": "3762b7846724e2c59fdb693a7f4dbef866c205324f6687cfeb63ca879a00627b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ".update(readAsset(brief as string))", + "fingerprint": "379a7c2c599e69be970bf0a757eb2f121bf7be55640190b753b13f1a1141e5ee", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value !== 'object' ||", + "fingerprint": "37b0826d54d51c10faa49858c5235fd54a856001683a6728c9b45d6e0573f5d2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function validateLinkState(state: Record, linked: boolean): void {", + "fingerprint": "38475a814cec5f9edabd1e1840d382e2ea0ee3898392ec58eb91344efdcab724", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "execIntrinsic: (async () => null) as never,", + "fingerprint": "385a26267b8bcea2d3986e5e4b5277db80ee364ec466a3353ebe6290530f6d43", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/doctor.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cfg = readJson(join(cwd, '.devkit', 'config.json')) as DevkitConfig | null;", + "fingerprint": "3860ad6b6853113d417b834f82fb0063f84b6c1f380f003abb0d4766e2a4c6a6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/eval/conventions/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const labels = parseCasesText(labelsText) as { caseId: string; slotId: string; match: string }[];", + "fingerprint": "3862850e6463364aab5938ee47c2d54e758725b47c13d619a0c128f82710ea00", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(typeof generatedAt === 'string' ? { generatedAt } : {}),", + "fingerprint": "38cc458bccc080d3b8bab2022c22d7bb7c54a192b1a998a2a751cd9a7f39baac", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.pins?.oxlint === 'string' &&", + "fingerprint": "38d22e73e8933b209615ac8417d6f28e95e2d1dd389ea9ceb5eeec7a20d44656", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/standalone.mts", + "diagnostic": "The explicit unknown type on binding `raw` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "let raw: unknown = '';", + "fingerprint": "38d67af4f4b99340b4541126178d2783352dd41007bfa446caecb65916f6e310", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return result as ReturnType;", + "fingerprint": "390985d5d8751bc20047bf680c7d0c43e2ccd329e107873657104e0191aedfc0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "cli/__tests__/doctor-hook-runner.test.mts", + "diagnostic": "Parameter `cfg: object = HUSKY_CFG` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "async function runnerCheck(root: string, cfg: object = HUSKY_CFG) {", + "fingerprint": "390df27b948b4a25bea5c2d24cb052f6c0ad7460db63060f53e3909dc2091407", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/upgrade.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "readJson(join(cwd, 'node_modules', DEP, 'package.json')) as PackageManifest | null", + "fingerprint": "398ec73a8cc7a55ca5f1d7158c9e0cf18812e5912af492bea471617918cdc93a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(recordedHusky === undefined ? {} : { husky: recordedHusky }),", + "fingerprint": "399b5a6796d19d68d3a3b14ce42f29abb3c2193f9739736d362fcdfb58308d39", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "skills/_devkit/review-roots.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return config && typeof config === 'object' ? config : null;", + "fingerprint": "39ad4d1c5f6caadb02d97fed62038587d7d578fd9f800c429766f8e6ca40e15a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/install-fallow.mts", + "diagnostic": "The explicit anonymous object type on return value of `detectFallow` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (status === 0 && version) return { available: true, version };", + "fingerprint": "39d82271be120a0883df47fed3cc2b24bad8e493d7b510eb8a5db01fb95a6782", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/source.mts", + "diagnostic": "The explicit anonymous object type on return value of `repositoryPath` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { absolute, relative: repoPath };", + "fingerprint": "39eabd1f4e4153d992c736defd1725feadb149dd3718364233b9776c0112f4a3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/doctor/pin-checks.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const pkg = readJson(join(cwd, 'package.json')) as Record | null;", + "fingerprint": "3abe198f9146c7e4217f3268c4878b326b67ae428bd44461fb2a8ac4522c5167", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/baseline.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof entry.diagnostic !== 'string' ||", + "fingerprint": "3b1aebd7f10a3508f225df6e91ce7f2dad2b819a0a7ce534d0726b358d273fbe", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.checkpoint.path !== 'string'", + "fingerprint": "3b23e7c05972867bfcd31ab09e4b066655f0814f584481811d4f7a4e3cdb56eb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/prefix-cache/config-fingerprint.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const obj = v as Record;", + "fingerprint": "3b4cc1e4b2f8c4731273ed4cab69e590206c690a3a1cf3860618c76054b0cbe5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/cache/session.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!(REVIEW_CACHE_STORE_NAMES as readonly string[]).includes(name)) {", + "fingerprint": "3b7a08de0fc3b601d446a41551383379077b4f4441b3f4607da039e4ee52fe70", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const summary = (value.metrics ?? value) as Json;", + "fingerprint": "3bc54629c571837810a78853dc9194c640cb4a4b3ed4da3eeef59e060b441418", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "verifyReviewSetupRuntime(args[1] as string, args[2] as string);", + "fingerprint": "3bd36b5ea05996957c66e07b9da58e1fe10992dba1fce8bdb5c201e8b2a7bf48", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.inferenceUnit !== 'string' || !value.inferenceUnit)", + "fingerprint": "3be020bfebc42ff8717ff13a5bf26138df9e67cb325382e97462f3ce9f794607", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-gate-supervisor.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "process.kill = ((pid: number, signal?: string | number) => {", + "fingerprint": "3c1280373b167635b5b9456ddbfadb7162365cd9f641efa38d4c84bfaed4a9f1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof manifest.destinationRoot === 'string',", + "fingerprint": "3c17e4f3c50926d58c44e7e5fc14161a5a82ff15149b12a6050fabe761d5db7b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const parsed = JSON.parse(raw) as { sections?: Record };", + "fingerprint": "3c1b1ea4c86fc32117fbb3019d5100738e7eea5114a230241f5b3dfa083953de", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "Parameter `e` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "main(process.argv.slice(2)).catch((e: unknown) => {", + "fingerprint": "3c291b3cabe993a2b5e8996717f6cba1b8b299214c182e5256912ac5ef0cb4da", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const lockedRoot = managedPath(location.parent, [location.basename], true) as string;", + "fingerprint": "3c5434d45bb85e6dd72c3f70f8003e885d24b512e61a529b70e871e8e8a6c60f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/reconcile.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const m = JSON.parse(readFileSync(manifestFile(mainRepo), 'utf8')) as ReconcileManifest;", + "fingerprint": "3ca4283aea2921d7cdbe5be96963dfb30e9a237172b438ca5b7416feba6b38ca", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "return value as Record;", + "fingerprint": "3ca86d978af3b44906f9b22f849063d34979ecff82de2727de3f5ddc7befc6fa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function validatePlanCritiqueRecord(value: unknown): asserts value is PlanCritiqueRecordV1 {", + "fingerprint": "3cbb34f9a89a0498712108e01c0010408d4e59d21d0df9b676dd4af2839b2e72", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(p.res.model ? { model: p.res.model } : {}),", + "fingerprint": "3d3b143b66e62710eac353dda785d27d6d554fc105ad191283ca67e3866cc0f1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value === null || typeof value !== 'object' || Array.isArray(value))", + "fingerprint": "3d4b4e2811fd00517536c285a5aa05fbb82e7e77a3b2ee3b818aa859438092cd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit anonymous object type on return value of `status` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { mark: '·', label: 'evidence-only', tone: 'info' };", + "fingerprint": "3d4d1c082832905804a148d39d9b9623d62d6fefa18d3687e92da906996ff39d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/decisions/detect.mts", + "diagnostic": "The explicit anonymous object type on return value of `judgeWithClaude` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { verdict: parseVerdict(raw), raw };", + "fingerprint": "3e22cdfb5d9e91b767555884c47e4ddbf73a95de74e00542aacd87641fef0c53", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const profile = setupValue.profile as Record;", + "fingerprint": "3e24e7ef906db190a0c100d5a02c2677910a7cc72e5e84c436825676568432f7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/qavis-advisory/__tests__/qavis-advisory.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "execFileSync(executable as string, args, { cwd: repo });", + "fingerprint": "3e56edf6beef522a11696f5e90dfe61ccebc89590a44595e703198e24102f024", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "let release: (value?: unknown) => void;", + "fingerprint": "3e585702365facccc683a093d9b803700e21a020c566ccf8a8c5054596d8bffe", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.id !== 'string' || !value.id) errors.push(`${location}: missing metric id`);", + "fingerprint": "3e600a68516eba3d4079ba8b9e4d3335972636818ba6ea7cbf7437eaed2fe6e5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function nonnegativeInteger(value: unknown, at: string, max = Number.MAX_SAFE_INTEGER): number {", + "fingerprint": "3e65348a481d4683feca98d6b39b3097f0008fe8dd7ceac19f1c5e53b8b80189", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof repository.head !== 'string' ||", + "fingerprint": "3eab6e16cfdaf22cc327c6fb998d594b3894211e85cd1a7a4934cc8b42472879", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/diagnostics.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const column = typeof span?.column === 'number' && span.column > 0 ? span.column : 1;", + "fingerprint": "3ec8ef0bac8f41fcd7ddeb92ec4e432be4c72ac2df7a8ce807905f311bf4a65b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/review/baseline-fallow-paths.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "value: unknown,", + "fingerprint": "3ecf49d9e8497f4ef9fa66d0b487efbc19760a6caa4d8be2cb3419a7cd535780", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/__tests__/allowlist-integration.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const err = e as { status: number; stdout?: string };", + "fingerprint": "3ee745884edca42328cf9c90dc248ce939b7dad80adf7b9c827d57410fa97948", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!INSTALL_SCOPES.has(entry.installScope as HookInstallScope))", + "fingerprint": "3f00f5c9d5b83ba39cd5116edbeb8fbed92a2de698771bafdbc875010473b148", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "({", + "fingerprint": "3f1b043fdb52676a15d98986a3a203644468cafc43fea3e0ed8f3d3d3c0f6755", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/ship/review/cache/root.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(args[2] === undefined ? {} : { cacheBase: args[2] }),", + "fingerprint": "3f1c0ac1deb877fd64a836daf824b40a4352ea360f4715132adb901c7f96b1aa", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const legacyConfig = config(false) as Record;", + "fingerprint": "3f298d86f67956af864f0201115f3792231ede723811b50eb61a7fd72a07b667", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/catalog.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "Array.isArray(suite.hashes[key as keyof typeof suite.hashes]),", + "fingerprint": "3f2e1d777b24a685d05ed93139017e8bde8350a0051dcf9b8f87797df36e78ad", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "Object.entries(value as Record)", + "fingerprint": "3fc082b0d94b963cd803fa92f8a4cfc4c31dde7c9134cea9351904b5d1e7e3a7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "The explicit anonymous object type on return value of `probeIntegration` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "3fd0a912e6e5bfffa6600701d7e62b28118afe320b8519eb7ba08bb8f6947d82", + "count": 6 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const setupValue = malformed.setup as Record;", + "fingerprint": "40494cfda21d42314e9359b9a7335c512a6b5b67e9b72f1adb383abdc11a3682", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function exactObject(value: unknown, fields: readonly string[]): Record | null {", + "fingerprint": "405bd6b8707d92a39cc4e92f43b5452e7677a33fd0b5d0b3cab94b99ff83eb9a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "The explicit anonymous object type on assertion discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const m = merged as unknown as { items?: unknown[]; itemTally: Record };", + "fingerprint": "407bd57a5478ade0ae933b44d354cc655406737f5da700114b7ee0ede7fccd6e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/consumer-identity.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(consumerReviewerIdentity(root, cfg, commitGuard as Reviewer)).not.toBe(", + "fingerprint": "40a7980bcac51a26de9a9c3c2a85afffb63d81b5b8180dcd19af9556d3782eb7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/sources.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": ": typeof b.content === 'string'", + "fingerprint": "40b8564989fcb804aca5bc6fbaddb06beea1ab940b62747b921f0c086c1feb92", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "The explicit anonymous object type on return value of `editableDocument` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (document === null || document === undefined) return { root: {}, hooks: {} };", + "fingerprint": "40ec1cbb6a434a7b5970aebb7e8e66aaae19890c334e547be77271ebe0782dd4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/__tests__/review-fixes.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const owner = JSON.parse(readFileSync(lockPath, 'utf8')) as Record;", + "fingerprint": "4132f4c5e4be993ca66df3303c77c9ffd141f6f3fdaa0085ea55c8846ec63c98", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/immutable-file.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pendingDirectory = managedPath(directory, [PENDING_DIRECTORY], true) as string;", + "fingerprint": "413d15f244c93c06980374554d924e0b99edd6692ffe900cd0ca48b0e8ab4e26", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const object = value as Record;", + "fingerprint": "4159f96030bdcf094a0376b182038f362ed65281e82b1e0cf2893fa2e5d2fae3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/evidence/diff-archive.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((e as { code?: string }).code !== 'EEXIST') throw e;", + "fingerprint": "415dae8a6d179892d825330ee0d6745411095c194e1b1f9df82186bacb3c0ce8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const err = e as ExecError;", + "fingerprint": "4169b999805b2bcb3cea64935bed184fb0a14aa06a3de7c3a12f788c14bcb381", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": ".filter((row) => row && typeof row === 'object' && typeof row.id === 'string')", + "fingerprint": "417353959f8025e89808ab88c0068c312956df47a2197e376771da1e8e166a57", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof a?.summary !== 'string' || !a.summary) err('anchor.summary required');", + "fingerprint": "41b1f72c849a30f472e7f279655a2ce9f3b62501aa332c5e5efca300d7ab44ef", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "byteLength = Reflect.apply(byteLengthGetter, value, []) as number;", + "fingerprint": "41c6b9c9558e849bde3fdaa1debacf6ca23a4729a3c20a66a2571676c2565900", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.test.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function list(value: unknown): unknown[] {", + "fingerprint": "41de2a3e529040db8e918506467fe1cbbab09b4f67a3e2f59fa9274c5482ded9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/eval/mine-cases.mts", + "diagnostic": "The explicit anonymous object type on return value of `extractOutput` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { text: out.slice(0, OUTPUT_CAP), ts };", + "fingerprint": "4241d0a5744e35bf162004e238eb585356247b1c97a5a7f4b93f4d72ea0e6ac6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/clean.mts", + "diagnostic": "Rename symbol \"SettingsShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "interface SettingsShape {", + "fingerprint": "42588b59ea9f40559aad77b361eb934e529c50e781dfe34b734b3b3d4fdf1fb0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/folder-fanout.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? ((JSON.parse(readFileSync(baselineFile, 'utf8')) as FanoutBaseline).dirs ?? {})", + "fingerprint": "4287ce2ca6a5fd181c4c2f6f877da693c5fffa4e9583e968470a9537df849506", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/review/__tests__/cache.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "entries: Record;", + "fingerprint": "428dbfd2ba8f5501716207850b34345ec809a8e5fcb5c804906939c914f8c6da", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/doctor/pin-checks.test.mts", + "diagnostic": "The explicit open dictionary type on binding `pkg` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const pkg: Record = { name: 'consumer', version: '1.0.0', ...o.pkgExtra };", + "fingerprint": "42dbb40d70a6a5c7ba50df34394a57b1a044a6f73a952df830e24fa04db44b77", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const { lo, hi } = wilson(k, n) as { lo: number; hi: number };", + "fingerprint": "431b428fb602667aa34c969f554bf844660be3abfe4233883856b7b37b17a253", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value === 'string' &&", + "fingerprint": "4370d54dca08dccbb04f733f9d76641a139de9eeaa981b1e3b6698c71181ecb7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "anti-slop/src/shared/lexical-type-parameters.ts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.type === \"string\"", + "fingerprint": "43aacba9c4ecec3b636ec13695f3df939ca643dbdac5e88523aff39cef55643e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/judge/gate-events.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(model ? { model } : {}),", + "fingerprint": "43ad097c34b81a47e12db2b3865d18ff75126717ccfffaa0ac41d2e00d3056a3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "execWorkflow: wfOut(`${RESPONSE_OK}\\n${RESPONSE_OK}`) as never,", + "fingerprint": "43ffcca95140f6094b5d0c5049e532c352580ba53bb8dd9691498a84c673eff5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "res: {", + "fingerprint": "44348038e6efa902e99f1d4dabe77c20fa41d7fa3202809145f779d1e7a3c447", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/index.mts", + "diagnostic": "The explicit open dictionary type on binding `COMMANDS` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const COMMANDS: Record = {", + "fingerprint": "44a1199c817591b162d737385eff1d1a46f145c36398d604cf9c45111ed90dc8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/config.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof file.maxLines === 'number' && Number.isFinite(file.maxLines)", + "fingerprint": "44cd4beac62c3bfd29cc7e7bd4c2e54f8d2c865bb18fffe527a0b442f045676b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const beforeOk = (prior as { ok?: unknown }).ok;", + "fingerprint": "44ce56271694366f685602725bcd16d427e0d1202115b931844e1079c4c32666", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const raw = (value: unknown): string => JSON.stringify(value);", + "fingerprint": "450b5b8cac9d562f7c65d241921152b253ecd97f58974620450a2bda4ac4692e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "skills/_devkit/review-roots.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof root !== 'string')", + "fingerprint": "4542a81a975f9c4b07552507a0e5991a9538852e92fd338e3e2b71f0b20e658a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof digest !== 'string' || !SHA256_RE.test(digest))", + "fingerprint": "456d23c6c8c895104f88ff2d2c030dbc997433c7791f85c5bf5b320c74a284eb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function eventErrors(value: unknown, location: string): string[] {", + "fingerprint": "4584df927bfbba110734727ba2a4bfb072cc975fe6276aae18d085cbffd86dc1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function canonicalPlanCritiqueRecordJson(value: unknown): string {", + "fingerprint": "4605499b062f04f087c44f611fd726862cb95c038de49b9f470be6d7f017657c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/baseline-gate.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as ReviewBaselineMetadata;", + "fingerprint": "4621190de17e24e2efe37de865c0f332999e709c27ece5f8215eb835dea7ff0f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(r.items.every((i) => typeof i.lens === 'string' && i.lens !== '(finding)')).toBe(true);", + "fingerprint": "465de97841103771a1b31bef5f2e25d30112c4e496f42798abde16bf068f788e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof raw !== 'string')", + "fingerprint": "467784ac426530768f59b5b2a5c16dceacd7dfc460909c3cc19f36dec10e6cb1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function reviewRepositoryManifestHash(value: unknown): string {", + "fingerprint": "46d8a35f6e927b0f8b187b2ff2ef822fb85cee4fe33e1d0e3163f4cec0ec7c0c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const merged = mergeLensOutcomes(", + "fingerprint": "47138c0f5b7bebba2172a2060beea2bdff9b5e33f68a1e1e33393b07731f3a24", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/upgrade.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cfg = readJson(join(cwd, '.devkit', 'config.json')) as DevkitConfig | null;", + "fingerprint": "471bd1984080a9edc5b952cf86bb17abaebc9e76df1c882745c15449ac688dd7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.provenance.source !== 'string' ||", + "fingerprint": "4729a7eda43833ccc615b73f282552ffaae133409ee2bc11782a85674e39e94c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/lib/install/anti-slop/removal-lock.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../oxc/lifecycle.mts', () => ({", + "fingerprint": "4763d6c552a19b4d680f74d80d0994cabece834578a2ce96a6957edcbdcf4428", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('./store');", + "fingerprint": "47668666e5642340cf57e5d6c8d25740d095b149d28c91ea2fc642eeb4481a08", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function boundedString(value: unknown, path: string, allowBlank = false): string {", + "fingerprint": "476a837e3c4ba99bf07dcb0e8de87cb630cf0e4984747ba64b06806b1d4e1f0c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/clean.mts", + "diagnostic": "Rename symbol \"PackageJsonShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "interface PackageJsonShape {", + "fingerprint": "47b6186a53e97cef3e933a22e080d9aa05bdd26da361c0274ac19383e2a8b562", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "The explicit anonymous object type on return value of `enableLineGrowth` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { enabled: true, grandfathered: freezeLines(cwd) };", + "fingerprint": "47d941ba2b0a15fe8ddd608e870ac1ba5024f1d0bd688ece530821b5a40b5307", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/cache/session.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const checkpoints = prepareReviewCacheSession(args[1] as string, args[2] as string);", + "fingerprint": "47dea18f6256cbd28d9078b1bab5cd6d606fb6c50a2bfc2b7ecfe5d4c2e7f1c1", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const code = (error as NodeJS.ErrnoException).code;", + "fingerprint": "48175f167f1e336c4068fa658d00d67aeb9919d89adce60cf9ddf7e459f480b0", + "count": 3 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/extends-checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "parsed = JSON.parse(jsoncText(path)) as ConfigWithExtends;", + "fingerprint": "4829624a0b8441767e8150114d2a3316a750a60ea2a9cede42905acb22221dd0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "Parameter `v` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const isRecord = (v: unknown): v is Record =>", + "fingerprint": "4879f99a743a445a728cc0c20c3fb26380e8624ec1cdc4e9b8da55591a14e43e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "for (const arms of Object.values((file.b ?? {}) as Record)) {", + "fingerprint": "488273c1e1b57f621e27b4bd9060eab7df93f75080f27edce69534ee8d327c96", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function resignManifest(value: Record): void {", + "fingerprint": "4885c79b16f020fd2d376abf0e9d93a5abe47ccf599a9e1a1fa87f17c34e1d9f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as T[number];", + "fingerprint": "489fac052b22440f73188ea810aa939fc660ef5761dc5df66b0aa73e15a428c6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/co-occurrence/clone-detector.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof v === 'number' ? v : v.line;", + "fingerprint": "48e3651562345047ac100788fe11ef1a8d0c12ffbf41c7687763d0dba30f0c7f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof generatedAt !== 'string')", + "fingerprint": "48f328b815b80e643681a58f580ff865317ac810f2339571972b2c99dc2cd25b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit anonymous object type on return value of `status` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { mark: '·', label: 'external', tone: 'info' };", + "fingerprint": "4906063c9132399a7be20dc20dde5dbb1b40f7ae5650eae1b398bf40968418b8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "): Record {", + "fingerprint": "4907d2126b446e6851ba3c4e68e971d9e33173bd44048d358b1bb5a4ce09abb9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(lensDisposition === 'waived' && rationale", + "fingerprint": "4912fef1754779641c02cda95b61cf4f4be04c78d4e216c91aeb17caa94a31fb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/baseline.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!value || typeof value !== 'object') return false;", + "fingerprint": "4913d737ce76d236d93d41d98a2961e1d8926a33ba4e3fd3b4fc7ad5617362f1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value === 'object' && value !== null && !Array.isArray(value);", + "fingerprint": "49291061080f2532eea58b38565da5979c1da2267bb3869a6c3f741340378f24", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "class: (s as GoldSlot).class,", + "fingerprint": "498712ee3ccda8706358439f7a894d5f621a5fff7be0863efc11c9bb2a42da93", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/recovery/settle.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(retried ? { retried: true, retry_phase: 'deferred' } : {}),", + "fingerprint": "498b2c61c21f78ffa227b57480096d757967d8da62994979266c3bf7089e08af", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/clean.mts", + "diagnostic": "Rename symbol \"SettingsShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const claude = readJson(claudeP) as SettingsShape | null;", + "fingerprint": "49d013d5142ba95f7bfcb874e8d7a7e3b2a56289b00d5be2f850a9e91f885a37", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!meta || typeof meta !== 'object' || Array.isArray(meta)) return null;", + "fingerprint": "49d3bbade63c45361197d49a1d67d1cf0b47895a2c661b89746b7ed91f1b5f74", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const parts = rows[0].lens_parts as { lens: string; retried?: boolean; status: string }[];", + "fingerprint": "4a2fc9fac63bc5e1e03d0bcdc0cc2fce158a5365632cf9638bc7eba2e3e23fcb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "selection = result.selection as Selection;", + "fingerprint": "4a52a6066fff8cb3a543f67ed255cdba115972bc9d1d85a1e28114382b3d6fb5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/doctor-review-topology.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(drifted([check('ok', 'OK', ''), advisory as ReturnType])).toBe(false);", + "fingerprint": "4a637a37eabaec6bf34455e92c14c89ff7d148786286d179c1b55fa452000a34", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/conventions-eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "got: baseGot as 'hit' | 'miss',", + "fingerprint": "4a9acd2f627ef25e80bcf7f1efab39aa11e1b20fb4d56cfa3615bd3499eb91a2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.probeDigest === 'string' &&", + "fingerprint": "4b07e255fc47bf70a28b712b905b43a4725ac5e799ee08372a041bf814d93977", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/qavis-advisory/__tests__/qavis-advisory.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(console.error as unknown as ReturnType).mock.calls", + "fingerprint": "4b0caf1c76cd7a97dd02303a0bade95652e8e9341a2c2cc627a953af75c751ed", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/review/setup-manifest.mts", + "diagnostic": "The explicit anonymous object type on return value of `captureOverlayChain` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { chain: { path, sourcePath }, paths, present };", + "fingerprint": "4b3942584e44e0aa943cd50ac4f09784ad1627009b7fcc43d3aff7bce3730c89", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/wizard.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('@clack/prompts', () => ({", + "fingerprint": "4b598b9ce958a42b6823c6051f9c1c818da3016139253ca7b643938f8faffc9b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/update.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = JSON.parse(pkgRaw) as {", + "fingerprint": "4b83b7b78d666a3d51d0a7cd9af0388fa170f33758c4c9de3ba44b69a7e394d1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseManifestHeader(value: unknown): ParsedManifestHeader {", + "fingerprint": "4bcf302af23b4f9557847967ca3a87cdc7e9b1736276e73459637b979ff9719a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return { value: JSON.parse(line) as unknown, line, lineNumber: index + 1 };", + "fingerprint": "4be0b48c894d2a73f2d312b6389f495461d3d9db8557df7418d7fcd3559d34f8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/dist-integrity.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const packageJson = JSON.parse(", + "fingerprint": "4be82facc65eb84bf2507989825a19d1064d9e048522cc59be0278b996f9a6df", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/qavis-advisory/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "console.error(`guard-qavis-advisory: ${(e as Error)?.message ?? e}`);", + "fingerprint": "4bf53e2308f8e3d8c2a3ba5e419d0f04b999b5096b062cc322d72fb76e29f49a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "agents-hooks/prior-art-gate.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof text === \"string\" && text.includes(ACK_TOKEN)) return null;", + "fingerprint": "4c09898c2977db1745647b53ff14f891811cd1bbc4a8473854137b3a8a8a0de3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/mine-cases.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": ": typeof content === 'string'", + "fingerprint": "4c1d5f904b9e78d5a3f1f169696265f03e331a6ad076dbf0656c7b2f68620f37", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/eval/conventions/matcher.mts", + "diagnostic": "The explicit anonymous object type on return value of `splitQuoteAndLoc` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (idx === -1) return { quote: cleanQuote(text), loc: LOC_UNSPECIFIED };", + "fingerprint": "4c2caca938ea645969f36e77dd234e382459dd86faaf4307f7afafa58306626a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/transcript-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((e as { code?: string }).code !== 'EEXIST') throw e;", + "fingerprint": "4c34d64bafe56b4076216595a455a4b4ca2f61325f1ecce603e7401dbec94f8e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "legs: legs as never,", + "fingerprint": "4c4a0f35e7fdf8091e34cdbcd03c47443675e52f12040a82f197f52796fae8a3", + "count": 4 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/oxc/runtime.mts", + "diagnostic": "The explicit open dictionary type on binding `TOOL_PACKAGES` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const TOOL_PACKAGES: Record = {", + "fingerprint": "4c89be3f9402ac1afd7d6600cfa55ada7940a964a8826843fdfb40fbd4c8b512", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/__tests__/review-setup-runtime.test.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(overlay ? { origHooksPath: '.git/hooks' } : {}),", + "fingerprint": "4cb13ea6ec8c0e0aaa8a05d03b67c0bcb905a58a46e425da4a9aaa2d9c42fd29", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/review-gate-supervisor.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `backgroundFixture` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { script, ready, signal };", + "fingerprint": "4d165c2cd237d70fc9f162aa29e295e702fb4b588f519ab7056d83131650c6a7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/agent-assets/agent-providers.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const selected = new Set(values as AgentProvider[]);", + "fingerprint": "4d947d740524697aa6c205ed0636f4301d688bbd9cfd9f5f76b64dd52f2aa6d6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/structure/load-baseline.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (mod.structureExempt?.[name] ?? []) as string[];", + "fingerprint": "4dc7136ca559d0986d9d6157992e5036bd217f5720ebc24e2b571fc83fab64c0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/diff-archive.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(existsSync(path.join(dir, refA as string))).toBe(true);", + "fingerprint": "4de4d0bb6ab159810caac85409dfcc96d533f25c62bdf565a33ccf9b068f963a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "gate-engine/prefix-cache/__tests__/config-fingerprint.test.mts", + "diagnostic": "Parameter `config` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "const repo = (config?: object) => {", + "fingerprint": "4dfae6e20a77a283abd570cc6ce42ec14bad4844775730d84f0bd36f9cc6118b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/decisions/verdict-cache.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "...(typeof durationMs === 'number' && Number.isFinite(durationMs)", + "fingerprint": "4e15375ea0e541c1ba8612addbfc176af720b64292e4e4732c2e2bf9868eadda", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/recall/embeddings.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return JSON.parse(readFileSync(p.vecIndexPath, 'utf8')) as VecIndex;", + "fingerprint": "4e21b738066aac2251a4b0f90225d14df7812a567b14dd3121a7d9daf07fe8f4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/plain-data.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function dataRecord(value: unknown): Record | null {", + "fingerprint": "4e374b34ffec03c216cbee66c6da17e5b51e9e9b838f8375b0b0f141780c9926", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(errorCodeOf(reviewed({ legs: shuffled as never }))).toBe('INVALID_VALUE');", + "fingerprint": "4e90cd4f87db56e1448d198c3cfca3491c26a110d5c1c0be95a09c444806732b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit open dictionary type on return value of `generatedOutputs` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "4ea0eca9606c165324ddb5975f2af08ce57abb606551e704b8ed56f02533f501", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/recall/category-report.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "axes: byCategory.get(category) as CategorizedAxis[],", + "fingerprint": "4ebee896a399efa95bdd90b9cbba47c426699ed22e7878408d6f25f5c39145b8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function itemFields(res: ReviewOutcome): Record {", + "fingerprint": "4eeedfeab1753dbb9610a8435a2fd3bbf682e5b929ecf98aae320726c4898a8b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const parsed = JSON.parse(raw) as { sections?: Record };", + "fingerprint": "4f73923f027f9023bb99118f38fbf130d950b0fbb51fd78ad2040dc1308fa21b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/backfill.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const candidates: Array> = [];", + "fingerprint": "4fcdc505662cdaa81924cd7635231747a667b79afc3319562054d1cbad65522a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const perClass = Object.fromEntries(", + "fingerprint": "4fd642889bf6decbefebf46cbbbfcb94fb4a2869f7586e609420cf424bec8cdf", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "return value as Record;", + "fingerprint": "4fe27f035fa58330023f570f9fb7acad985c0a01195d27be53158d4613d21892", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "The explicit anonymous object type on return value of `pluginSource` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (existsSync(join(root, 'index.ts'))) return { root, entry: './plugin/index.ts' };", + "fingerprint": "4fe7b38763c994bea4a1bc6b93715d721356cb5fdf33aaca40a8ab70d4d67ff4", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/capture-normalizer.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return { bytes: projection, value: JSON.parse(projection.toString('utf8')) as StoredProjection };", + "fingerprint": "5074acbd4d8343d30b33736f0907bb1d1d34defe6c603f082f98b3852a6703b8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(getPlanCritiqueWorkQuarantine(revocable.proxy as never, { root })).toEqual({", + "fingerprint": "50cae425a2f6106b3ed98c94d08cf8d68e0f14981a2c740b8b9d2be74c7cfa66", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "The explicit anonymous object type on assertion discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "expect((merged as unknown as { itemCount?: number }).itemCount).toBeUndefined();", + "fingerprint": "50fa191936fd41cb849d477ca6046222a6eb77494d167843f57069cd7cb34c3b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof (value as { then?: unknown }).then === 'function'", + "fingerprint": "50fb9e18d10085b22d4e0a623efa4675c0862ec6041107b45300418fd5eadddb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(errorCodeOf(reviewed({ legs: legs as never }))).toBe('INVALID_STATUS_COMBINATION');", + "fingerprint": "51109af75e71d0494e182be6186bcd10c958dc6674ba566ffbf14058b3e390a6", + "count": 3 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/cli.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(reason ? { disposition_reason: reason } : {}),", + "fingerprint": "51b0a00a306b61c8775a7b0ea6e15334fe113b813469f85e94d6fd9f3a0b4719", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.sourceCommit === 'string' && !COMMIT_RE.test(value.sourceCommit))", + "fingerprint": "51c1c3b69cc6aacb82caa182b91540f13e9e886601cdd562af183f9f4a41a802", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-gate-supervisor.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const paths = Object.fromEntries(", + "fingerprint": "51ceee57bf93d24e485f3d5b5cc873f8fe2698379fc5442cb85dc778137a26fc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(p.retried ? { retried: true } : {}),", + "fingerprint": "51ef25f5667df5362fc002307ba192143721b667277fa50194cefcd0f4467da6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/__tests__/atomic-write-lock.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof p.pid !== 'number') throw new Error('could not obtain a pid');", + "fingerprint": "51f18372ee5591792b02ead4a75724b33908a33b2ab8330fa33a951dea65299f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const opaqueAsync = (async () => {", + "fingerprint": "5211de86b98198c028a18534cf4f066714bf1d3a1c0d93d171f371f13e95f7ea", + "count": 2 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "Rename symbol \"reshape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const reshape = (n: number) => {", + "fingerprint": "525e566bc6d22ed081b43e9a96cec187b6b9c28dffaf81d9f2bec65b4653b766", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/overrides.mts", + "diagnostic": "The explicit anonymous object type on return value of `domainExclusivityDrop` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { kept, dropped };", + "fingerprint": "5316a4fec5a4b28d194d6ca8d35ba9beb2a57507c16997b144fbca869e81fb92", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "!PLAN_CRITIQUE_FRAME_METAS.includes(value.frameMeta as never) ||", + "fingerprint": "5346cb0251b50ac2ef4ba29bcff1793122a0983d3e13b42063a738381cee9b8a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function isOwnership(value: unknown): value is ConfigOwnership {", + "fingerprint": "536665c92037751efef80a170f403d48ad652e5e972eec97b6b4efdd845febcf", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const recorded = readJson(join(cwd, '.devkit', 'config.json')) as DevkitConfig | null;", + "fingerprint": "536b80613fa334184d87299dc04d460710244f48bd54ef195e34888c4da5998a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/recovery/settle.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(transcriptRef ? { transcript_ref: transcriptRef } : {}),", + "fingerprint": "542b66e00677c2c4fd42d758f2c289bb2b2f9520e317a06c160e280472682725", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/judge-exec-telemetry.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(readTranscript(ref as string)).toContain('{\"verdict\":\"DISSOLVE_FRAME\"}');", + "fingerprint": "543efaf4d64c2f0b967b8255f2bd14dcc8842f9101db9dfb4e2681030a68f5dc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/upgrade.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "console.log(` ✓ added gate(s): ${(picked as string[]).join(', ')}`);", + "fingerprint": "548944ce6531d91a59a1bc5475b3ab7aa73f93c2782f39338abd4d10395962ad", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/commands/clean.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "[key: string]: unknown;", + "fingerprint": "548d5f75c29f20f66b6d18b12417a76c19cdbd62203b273fb832a80c979fbf62", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof envelope.result === 'string' &&", + "fingerprint": "549a65aa4a826dfec1f00fb75c1ed842248253fd903bca3faa096e7251400d1e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function isPresentStateType(value: unknown): value is (typeof PRESENT_STATE_TYPES)[number] {", + "fingerprint": "550eadd0ec20ab5b6906abcbc1932dd5a2470ef4a0c02cbd677e4c4427823a63", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function verifyBooleanField(fields: Record, name: string): void {", + "fingerprint": "554c17b5293dc8464dbe5be1859cacf3ed6ccdb30573ce045a936718e7858bf2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/provider-runtime/claude-subagent-stop.mts", + "diagnostic": "Parameter `payload` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function captureHookPayload(payload: unknown): void {", + "fingerprint": "555ca9f2f578a51af0fd468e932f626079d837b73a495dcdf091783c69090002", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/_helpers.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "argsOrOptions: readonly string[] | Record | undefined,", + "fingerprint": "556393cbb0cc82f8dfcffbfbe6602cf56eecf5205c95904f0c1dbc68371806c4", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/dependency-preflight.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (section === null || typeof section !== 'object' || Array.isArray(section)) {", + "fingerprint": "55726409b20dd7e2b3bbf9a0e12b654b1326d8aba915f3bb3e39fef1623b489a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store-internal.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const blobs = managedPath(canonicalRoot, ['blobs', 'sha256'], true) as string;", + "fingerprint": "55c7cb54a409d8f7c984808c6e20edaba4d38e9c084bd273d22eac9d41e93c57", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "mergeItemVectors(merged, [{ name: 'correctness-reviewer' } as never]);", + "fingerprint": "56a6d0379d2e8d29308926ec8f493c1cbbc2a8fdb6fd2b8fd70a3b728b5da614", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/matcher.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const { pairs: labels } = JSON.parse(readFileSync(labelsPath, 'utf8')) as { pairs: Label[] };", + "fingerprint": "56b732848f9a70c64adddc844438df2f753f5a5181caec5f7f0e23f2347d391c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/guard/protected-branch-guard.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (s && typeof s.command === 'string') {", + "fingerprint": "56befb2eab2d93f6c0cc37f6e2cbc9c5cdaa9e8cc550ab5ac8140d44f02c686a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/judge-exec-telemetry.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const stored = readFileSync(path.join(path.dirname(sink), ev.transcript_ref as string), 'utf8');", + "fingerprint": "56c931bd9e143069ed2b7d5ab5ffd45e87800a605a30c37cc74d6877e665b329", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as unknown as TakeoverOwner;", + "fingerprint": "56edf7890f436c1b964f869d27da8cc64df036f3705f1a8d06c21d11cefe7a87", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/shared/common.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as Record;", + "fingerprint": "56f63500cbf62e111a61fc16d96fb07a3710884a69a801bafe1432cfe46b0bbd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "skills/correctness/scripts/checklist.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!c || typeof c !== 'object') c = {};", + "fingerprint": "5721c9a1c77059686d3dbb15627374e473109d2dfd33b57b7ea5f072876c2e58", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/transcript-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const abs = path.join(dir, ref as string);", + "fingerprint": "576b519e6a87be72be219da9bccef607c1214e82e80af1c4cd85c9ddf73339c3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const profile = setupValue.profile as Record;", + "fingerprint": "581db62cd640f7a085c3d349a41d956b4ee8d42be86d860f635337c9cefafe06", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/stats.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof current === 'object' && current !== null ? current.rowHash : current;", + "fingerprint": "5820098b62a1f54660bbdc89350e1f03019aaa55e747ba17863f41a2d34bed03", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/cache/session.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const encodedGeneration = args[4] as string;", + "fingerprint": "58381556d5545ac673cfeaea4ced68a47055e613ce14949d7dde372efb85072a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/suite-adapters/deterministic.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const declared = Array.isArray(input.metrics) ? (input.metrics as Json[]) : [];", + "fingerprint": "5864c3a65f9a800093ba9842e44c2cd782392dbd2c7e114c107ee2aa7b8080bf", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "const options = { ...(value ? { value } : {}) };", + "fingerprint": "58d86dcb16b7cb0ee8efaf09691cf5bef97ffbc431998b711fea6ba6acf296b8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (typeof value === 'object') return value as Record;", + "fingerprint": "590687744c663467fb196c3535c16dd37d6bbd58a51b683ca1ff50cfce74b523", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof raw !== 'string')", + "fingerprint": "5921a09acceb61358b945f24855c228d2f5024499536f12300d40f1f08158182", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return selected.source.physicalPath as string;", + "fingerprint": "5990eaf3e4ddb84d6ca268f3ba9d0583f62803dff4be5bbf14a0ac156b3438a3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "The explicit anonymous object type on return value of `pluginSource` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (existsSync(join(root, 'index.mjs'))) return { root, entry: './plugin/index.mjs' };", + "fingerprint": "5997492b197aa48be1b832ea97dffb32b3928955d4f46c4094edca1fea088757", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const isObject = (value: unknown): value is Record =>", + "fingerprint": "5998ff3fd12fe0af3b00e614aad5a4daf31b4cc0267131861d14a402d7cee7d9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof candidate.path === 'string' &&", + "fingerprint": "5999af0a9560b5f0c2d07f380d8ce1cb344ddcd898d8a74e1238761a118979ac", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const out = await runMatcher(GOLD, DECOYS, [], { exec: exec as never });", + "fingerprint": "59ccea20e3f7cd56d9a26a2f1c233cc0b3639bb85c066b9cd9245ac59b31455f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/read-stdin-body.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `seedReshipRepo` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "59e7cd484b51119af6265fcf5845c4c31ecf86028b894df2a58684dd287e365a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const out = await runMatcher([GOLD[0]], [], FINDINGS, { runs: 1, exec: exec as never });", + "fingerprint": "5ab4e98790efb8dace82e52d1b2caad0e50bdca3ca3fd2c62319dc33566fe39c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "function ownedSections(raw: string, suiteId: string, sections?: string[]): unknown {", + "fingerprint": "5af2c19ebf2fb24636fb2c1a1bd7c078bee5b87a466b4e9f361ace1a998a577d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseScope(value: unknown, path: string): PlanCritiqueScope {", + "fingerprint": "5b2f16ee517b717c9ac52df8b135c0dae3a5f779c629d4f25a5bca5f39b70ea5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as Record;", + "fingerprint": "5b4299f01278dd12d09704453179959c795ee29b14ffd01dd65536a4c1d60feb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/plain-data.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function dataRecord(value: unknown): Record | null {", + "fingerprint": "5badc8f46cd05d8aae70284508a1029065c2476586ca76cfdca4b8b9b7ec572c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/review/cache/session.mts", + "diagnostic": "The explicit anonymous object type on return value of `stableEntries` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (before === after) return { entries, generation: before };", + "fingerprint": "5bb4899cc55f81c899f953416ff552227985278f0a8ae8b4bd570c8e70b281bb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/judge-exec-telemetry.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const refs = evs.map((e) => e.transcript_ref as string);", + "fingerprint": "5bbba304530e4b23700e98b6335c4d0b867c9bb704e2a9e15485c415911a4f95", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/__tests__/review-fixes.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const withoutCheckpoint = { ...event, checkpoint: undefined } as BenchmarkEvent;", + "fingerprint": "5c05c9bccefdc35f1306a0801396a4a8dca8b629c3ef1bebc4efeffd84e5f559", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/guard-config-doc-sync.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(JSON.parse(readFileSync(join(ROOT, rel), 'utf8')) as Record)['//review'];", + "fingerprint": "5c1d0e0f89bae9212589929a3d1104607b43aac33d473f5a3df0d6d4f9a29a86", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/qavis-advisory/check.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const err = e as NodeJS.ErrnoException;", + "fingerprint": "5c20f0165d11295e9eaa02f7455a450794434527942ac620cf17d63b8138093c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/size-preflight.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const parsed = JSON.parse(readFileSync(file, 'utf8')) as Partial;", + "fingerprint": "5c61beb1b93a0de062ab38c695607489c4064b63e4943cfdf4ad7f6d06da7be6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/install-support.mts", + "diagnostic": "Parameter `document` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "document: unknown,", + "fingerprint": "5c6e3cc751a80bca13401a0ec4e44be24617c524a1280cd48729e7eac509b65c", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.token !== 'string' ||", + "fingerprint": "5c97ede3d1ea87ba0bfa79f18f602bfaa13a406b5f80571fa2f3fa03be4f93a8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(issues.length > 0 ? { issues } : {}),", + "fingerprint": "5ce34f2049e9c56d8c306e9a5158b4deff65c154455b9dbb610ca2d3307b0ff3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function privacyErrors(value: unknown, location: string, errors: string[]): void {", + "fingerprint": "5cf024a58c2f083a036b1e6bed1bc7d7843df4ee1dbc480f036ed83af726a7de", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/install/package-json.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(sel.guards?.includes('fanout') || sel.guards?.includes('size')", + "fingerprint": "5cfcb844d6829ce87086e83bc7bf2c0914c9efca7abcae611bcfa00435739c87", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof manifest.sourceFingerprint === 'string',", + "fingerprint": "5d05204cec923dbb536ec7a86375da3b41de668e609cabc48215cbd77653a611", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/cache/session.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const result = promoteReviewCacheStore(args[1] as string, args[2] as string, name, generation);", + "fingerprint": "5d195db6f3804a257b49019731971d088ad34f3c4d1eb79a7b6246af1075882a", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const prevConfig = readJson(join(cwd, '.devkit', 'config.json')) as DevkitConfig | null;", + "fingerprint": "5d1cd6db349dc32290e05f0e9899beacee4d47c5e40da77fd829719ccdf89f43", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "join(target.root, '.devkit/review-runs', logs(target.root)[0] as string),", + "fingerprint": "5da148e1e6170827cf96912ab5ebbb51e7d85c1c5015e76cf23004c3e2e54433", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "execWorkflow: wfOut(null) as never,", + "fingerprint": "5daf579af98e3d8addb60b885a51e47038bcd1409571d014308c27409a864be5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "The explicit anonymous object type on return value of `clear` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { state: 'removed' };", + "fingerprint": "5e32d43275cf43c4db4153083dcea031cd61ed21361ca38b6369d827d75dc9ca", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return state as unknown as ProjectionState;", + "fingerprint": "5e4160074b4553b47be46d7b6967b43475898852022db7cb9222806cf8e9fc85", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(record.repository as { fingerprintSource: string }).fingerprintSource = 'origin';", + "fingerprint": "5e4b553a132fbedd8dc0150d9ec5b7501b0b84e79ca92127c0d26042ed322f38", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const key = `OVERRIDE_${(m as RegExpMatchArray)[1]}_RATIONALE`;", + "fingerprint": "5e51557f2c15e9eef60c1801f39c088474cda1ac955a31c24399accc3b84155d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/clone-detector.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const report = JSON.parse(readFileSync(reportPath, 'utf8')) as JscpdReport;", + "fingerprint": "5e7cffd875497c32e3fc625623d624cf7be3d21a04b951638070fff360eeac6a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const value = JSON.parse(readFileSync(file, 'utf8')) as Record;", + "fingerprint": "5eaad4c65de13a0073193417cbe9cb5421abc062a233482048b8fb0413f12913", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/commands/init.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "[key: string]: unknown;", + "fingerprint": "5f0840e8560d29b87781250e24d098064c09a635a3b3fca6fbab14a6a26a0dec", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/evidence-store-internal.mts", + "diagnostic": "The explicit anonymous object type on return value of `persistPlanCritiqueRecordAtRoot` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { state: 'existing', record: existing };", + "fingerprint": "5f24ef63801a1294fe735de24823c82926e6822d4d68f9670152e4cabe360423", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "!PLAN_CRITIQUE_PROVIDERS.includes(identity.provider as PlanCritiqueProvider) ||", + "fingerprint": "5f28842ebd29d4ad2a36976b67eaa651d0944e26abba95a7bd630ee1539aebdb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/search-tool/tools.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof v === 'string' && v.trim() ? v.trim() : undefined;", + "fingerprint": "5f68fb1a42884ae0e467cdb1f5fe94f73ff1d4ef97809bc2337618d3aff73915", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parsePath(value: unknown, index: number): ReviewSetupPath {", + "fingerprint": "5f91db83654b48e46f5cbc01be247708b842e4c2537ec034cfe14e4b9fc260af", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const framingVote = majorityVerdict(runs.map((run) => run.framing)) as { verdict: string };", + "fingerprint": "5fbac50d0229d1c58ac30e6921ff39fab89162201a0a3b5ccf6155458323da53", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return e && typeof e === 'object' ? (e as JudgeError) : {};", + "fingerprint": "5fbb3e630022f63e575a0f075b1c0a1dd22005c9d588d38b627461ed85901615", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/diff-archive.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return events.find((e) => e.type === 'review_scope' && e.reviewer === reviewer)", + "fingerprint": "5fc29abc1340f4bd5daa95dac12b8afe10732b6a872dabb7d0bcaf038c19bb75", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "The explicit anonymous object type on return value of `probeIntegration` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { ok: false, detail: error instanceof Error ? error.message : String(error) };", + "fingerprint": "5fc82aba16c20c81588dc142afd8b171866e67a2ce34b0569dbd3e0626ee1eea", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/decisions/detect.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof cachedVerdict.duration_ms === 'number' ? cachedVerdict.duration_ms : undefined;", + "fingerprint": "5fe21831007e6406b07d25b8a9125a624019b4829f5b9677a722df2676bced45", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const isRecord = (value: unknown): value is Record =>", + "fingerprint": "5ffa9e44fcff979b83e245d898c2cb397d367f9524c6714e43de2bf31b1a5894", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value !== 'string' || !value) return false;", + "fingerprint": "60127bf314b03cec9b4a365ee446c0bcd4058380c778b60d9ba81c9c98d67e4b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "The explicit anonymous object type on return value of `loadBindings` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { bindings, candidates, malformed: false };", + "fingerprint": "60357a1ae429575a4d4a2c315800b07828c3fa5935294d71fb47bde0e4642660", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "fail([(error as Error).message]);", + "fingerprint": "603cc038fac0cf110e17a8fe0ba206ea14ee8169daa555a14b2b429975cbe698", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "...(typeof generatedAt === 'string' ? { generatedAt } : {}),", + "fingerprint": "6046e599d715c4a9584e0ae79a124915c7ebd9c5b9d8e044633a16f5fbba8284", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/corpus.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (row.caseId !== undefined && typeof row.caseId !== 'string')", + "fingerprint": "60977211e057004766d80ae5ed67a254d62114a3278e29d28133eec841faa051", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null;", + "fingerprint": "60a9df10d3bb802ee95563751291ee9ba82c1be15ae6a5b4eb339f362f8cbecf", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/__tests__/scoped-targets.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "vi.mocked(rankAxes).mockResolvedValue({ rows: [{ slug: 'bar' }, { slug: 'foo' }] } as never);", + "fingerprint": "60f42d540b938eb1d1716be23275c9dc847d3e3761fe35479c891599cc965403", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "The explicit open dictionary type on return value of `itemFields` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "610a5234c49ba0e7b0431479a4b574d8b08cb98101f35b0303c4f3167d895d11", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/doctor.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = readJson(join(packageDir(), 'package.json')) as { version?: string } | null;", + "fingerprint": "611f62517f8f61ad60e00cf5819bd64fccbadef3972dd3396f864a3edf23a46b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/baseline-gate.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(kind === 'R' ? { basePath: oldPath } : {}),", + "fingerprint": "6126559010acec374560135dfd9f4e8e25693763de5b9b75a1c31c6f439d2d18", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "gate-engine/review/__tests__/commit-message.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../../decisions/scoped-targets.mts', async (importOriginal) => {", + "fingerprint": "613afb62ddf38885010de42f11a2b3554db1f011eecdc678fa2264d1a6d4045b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/history.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof event.checkpoint.sha256 !== 'string' ||", + "fingerprint": "61c2bff37f4d8906ba294d11ec1fdf0e8e1a0ccea29c4b818a32fa2c1a0ca303", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!prior || typeof prior !== 'object' || !current || typeof current !== 'object') continue;", + "fingerprint": "61c3ed578e21a2194c44f5c93127d1063e8387850be6ca9e9bede9fb9ce87a32", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "type PersistenceAction = (canonicalRoot: string) => unknown;", + "fingerprint": "61fc74b30f535450f9a599af80e2eec5a50809a8ba17ff2ca7a936279c187404", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/decisions/decision-format.mts", + "diagnostic": "The explicit anonymous object type on return value of `parseDecision` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { fm, body: match[2] };", + "fingerprint": "62080fc5fcb9224bfff4952834f9bb1ebe25f1079a7a6a72f9b1c0e046d8aa2b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/test-subprocess.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "options: Record,", + "fingerprint": "6217a13e2d6a79ca6175f23f8c6f1c25c175a0eb73382e72501afd9ee320b7cf", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/baseline-gate.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const parsed = JSON.parse(stdout) as unknown;", + "fingerprint": "6247ed0b2592542c0359c0f46df13adfe2299d1e6955c443efeb212b94e8e1a0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/config.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return parsed as RawGuardConfigFile;", + "fingerprint": "629fb328feb9fbf6f90d4d50aa7e120fd42bef4e1281ff474d7484bad25ae922", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof profile.enabled !== 'boolean' ||", + "fingerprint": "62a2403fab1d19cbdcf13d6cfc771a8f5f668a50f4f8eb51a92ff0193ecc2dcd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "skills/_devkit/review-roots.d.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function isNonEmptyStringArray(value: unknown): value is string[];", + "fingerprint": "62a6400b949c3dbe78ec269684e33a2adca38f10863e9988a2e919563bf2deed", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = readJson(pkgPath) as PackageJson | null;", + "fingerprint": "62c3b1f355d5d26b58d871698b934c219bfb321b4d1a343ef2df36438ac0bb72", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.test.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function data(value: unknown): Record {", + "fingerprint": "62e03bfbbe65a0d307e483dd9a1571cd842bd2fe3b6f02344aa1dd5848583739", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return value.rows && typeof value.rows === 'object' ? value.rows : {};", + "fingerprint": "636340f8aa74687684f18fa7f127645e89b74a22416974566498041b3dd0afcd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "skills/_devkit/review-roots.d.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function normalizeReviewRoots(value: unknown, name: string): string[];", + "fingerprint": "637228accf417501e2477217b9bb6aa0d548f3f5fbb8b86a0faa5daca9b2784c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function recordValue(value: unknown, message: string): Record {", + "fingerprint": "638147516f4093d7cfa1294dc480c1e0c2b645b6d3b1883059df196fd5f129a4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseFinding(value: unknown, path: string): PlanCritiqueFinding {", + "fingerprint": "645d30d5fa01d018685a42b49f5fd26dc79b77cf8baa7396003b5fc5b7182495", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value !== undefined && typeof value !== 'boolean')", + "fingerprint": "645f1dd91da0e79b54c9626d20d5a0a8a9c7b2b35b1fb7bb6344b907409e7cb7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/clean.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const codex = readJson(codexP) as SettingsShape | null;", + "fingerprint": "64b0e09cdb31b1f8c212cf42aaa60585271dceeb8b169b518451eddd87de7ec4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/flags/review-profile.mts", + "diagnostic": "The explicit anonymous object type on return value of `reviewPlanFromFlags` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {};", + "fingerprint": "64ddb0630ca2d847014c208e2494d11f8dc480d46ac0958099647fa1d859b2c4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof value === 'string' && values.includes(value);", + "fingerprint": "65310b5b548a69b1d546dffd6b9f986a7ab12593db53dbccfe2cd61d5e48f103", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value !== 'string' || !value || value.includes('\\0'))", + "fingerprint": "6539ca245600995ee5bd7bb0abef287bbb670fd08f1fbf01de57ba017ad8fbb3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/agent-asset-manifest/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return [[source.logicalRel, sourceShas.get(source.logicalRel) as string]];", + "fingerprint": "654fcaad972a0a65c0858af87cfeebc147c9f5eca902eabb58a20e21c46df44a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof f?.text !== 'string' || !f.text) err(`${fid}: missing text`);", + "fingerprint": "656f07ce935d6d45dbbb1a17e49ad4ab2648196eac98403c42e7a5f9706674ce", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/clean.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cursor = readJson(cursorP) as SettingsShape | null;", + "fingerprint": "65ab999ebefc3846486bbf6027137eb1f6d1eea337166c62a5a3e6239f1ed683", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/run-context.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function runEnvelope(): Record {", + "fingerprint": "66074ef05f581531cf4d603ad40c649bfac406ae578d8a0659efb215ef29be7b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/verdict-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const persisted = JSON.parse(readFileSync(file, 'utf8')) as {", + "fingerprint": "660b92517a456601f52ec111728847cc85d20fa297ef4e43fdca9a555769c20c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(lensDisposition ? { disposition: lensDisposition } : {}),", + "fingerprint": "661ff85e398f5ccc9ba39d34bcdede97f389622de9c05a053d107c52ea41d564", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "Parameter `condition` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function assertPlanCritiqueRecordValue(condition: unknown, at: string): asserts condition {", + "fingerprint": "663f8e4b460bc06847cda99b072fd128997d1a6b7adbfb8b939df95fff613dc8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof state.fingerprint !== 'string' ||", + "fingerprint": "66632d2fc108f24c21684e4f6d065f4a8d1ea1cd8077c50f9507c8ad2a1c0010", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "execWorkflow: (async () => {", + "fingerprint": "667f4eedcc1b0d571d2fe976ebf2b987d598e7c0258957a24c23ab5f23bf6382", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseQuestion(value: unknown, path: string, expected: string): PriorArtQuestion {", + "fingerprint": "6695d3965a48dbe896b6155403615eafc20cfdb1373593bc84357828b0cb3165", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-manifest-format.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function reviewSetupHash(value: unknown): string {", + "fingerprint": "66bb76da8f1650e5a30d187152cb16e725fd1719dda0218ff1172f066ed8e637", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/wizard.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "selection.lineGrowth = (guards as string[]).includes(LINE_GROWTH_ID);", + "fingerprint": "66c8487351d874d25f11aa8efd826bd1c3ea8f55cfe062769f46f5f1c499812c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "): Record {", + "fingerprint": "6767c1a304009776ae7917ec999f58334125794b6dceec30cee09fcb2532905a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/asset-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const result = materializeReviewAssetRuntime(args[0] as string, args[1] as string);", + "fingerprint": "6799937479a8bac877e40316a0de95d327022dc073396ff5c5a7bd156f52d887", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "agents-hooks/prior-art-gate.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof sessionId === \"string\" && sessionId.length > 0", + "fingerprint": "67c70bab497e5e3530371fa22741cc4673c4df22ddf270d41e49bd3a9af1b8d4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const actual = JSON.parse(readFileSync(result, 'utf8')) as Record;", + "fingerprint": "67fbf473908034416e74f0152d17eeae7afae649301db8ca57980821ad58b164", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/doctor/guard-config-checks.mts", + "diagnostic": "The explicit open dictionary type on binding `roots` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const roots: Record = {", + "fingerprint": "68126b22bfa4a7270ded978141d546e2a8fd2860bdeb84b66f85cb0a98f18733", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/deterministic/run.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (e && typeof e === 'object' && 'status' in e && typeof e.status === 'number') {", + "fingerprint": "682b15f60d16789c86edf600fea6fd003ed0f588c5c57050fe20e72ac13edc5b", + "count": 2 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/install/package-json.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(sel.biome ? { lint: 'biome check .', format: 'biome check --write .' } : {}),", + "fingerprint": "684fd04d43b2d5cbc3cd0165ae05b84860c8214447478efb4ac8d06fbd88e72e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function runtimeRecord(value: unknown, label: string): Record {", + "fingerprint": "685685c9b5312f95132f819a50cccc2f41bc72c6938790e070c5c47ee8ebe70d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/overrides.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((e as { code?: string }).code !== 'EEXIST') throw e;", + "fingerprint": "688825b1fc866341c7026357caac75c2dc96d88138025021ca3bd2d0f54d3b49", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const envelope = JSON.parse(raw) as unknown;", + "fingerprint": "68b4609a064b58250955a9157e28465192374511f18468c0824500439cde63a7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "): Record {", + "fingerprint": "68d0ffbef4913608e9a66d629a7a6ec2f26294abd67feb225192fde1ebcb9f1b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/co-occurrence/index-refresh.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "let rows: Record[];", + "fingerprint": "691ea362d0b2a012cd78cebdac8f6fee792e04cb3022732a8feaf47eb527513f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const allRows: Record = {};", + "fingerprint": "69256c5d27e9ce4adb93c29ce620ffdfe4410a121e20da9c8db8fc78179c5e5a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "const neutral = (status: 'wrong_phase' | 'aborted', routing: string | null): unknown => ({", + "fingerprint": "6947bc88db678b1fbe42ad6cb964c75576b2b2c07d398fedaaf7c20306d388b1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!parsed || typeof parsed !== 'object') return fail('dependency runtime manifest is invalid');", + "fingerprint": "694d0d65aa387b2837ef1bda5ec7c9f929637a26714bfa698e794b2bb352c93a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/commands/update.mts", + "diagnostic": "The explicit anonymous object type on return value of `fetchLatestTag` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { latest: latestTag(output ?? '') };", + "fingerprint": "695fc41db14875ed1fb477f9f6bbe1e513d251a6c2a86e279659007b7d1da90f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/asset-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "writeCapturedAsset(runtime, assetPath, before.get(assetPath) as CapturedAsset);", + "fingerprint": "69674d15cf99d192fe1486022ea79a0d5d43187af441ea6ec3e061ead8f1d6d1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.capturedAt === 'string' && Number.isNaN(Date.parse(value.capturedAt)))", + "fingerprint": "698425d1b6f6bbf70efc17b7a3678664e87ae5f6f7e3b9c039219bf7e1aff1c8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/ship-branch.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(block as RegExpExecArray)[1]", + "fingerprint": "69ecd15e70735e628b65a0bbf6cca5e9bd0bbd938e1f60bd39af146b64606cd2", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/catalog.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!(EVIDENCE_MODES as readonly string[]).includes(subject.evidence))", + "fingerprint": "6a1bfebff9875db858b17c51d455ccd43ad5472acec90f0d547d4eb3dd0e5d00", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "Rename symbol \"reshape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "reshape(3); // a DIFFERENT branch: neither key covers it", + "fingerprint": "6a2056a6e52b10a41b2a08639b9af4eb54b9d60292aae72a88146873d7beb092", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/overrides.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof entry.by === 'string' && entry.by.trim().length > 0 ? entry.by.trim() : 'file',", + "fingerprint": "6a2721e93216b28a2c73d42cfd4a7e0970862532beb1f592ee54a6f23bd7ebe1", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/cases.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "rows = parseCasesText(readFileSync(casesPath, 'utf8')) as Row[];", + "fingerprint": "6a6b83b15a37b6f4af72f40b6a3d65a7e784557b779095963836bb96cf6d6c18", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const candidate = value as Partial;", + "fingerprint": "6aa6021ca53125a0a9bf05c54c36532574693070fc7c80fed972aaa3d73a5b06", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/dependency-preflight.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as PackageManifest;", + "fingerprint": "6ac376c8d912ea74fc235eca98aa07398ce7b87f9c28ad540409be20f1213e0e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "!PLAN_CRITIQUE_VERDICTS.includes(value.verdict as never) ||", + "fingerprint": "6acc72f5adb1f93664af0aabe6db5d8dc149cafda3a1f3fbc43f3f37f359b5b6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const enforced = METRICS.filter((m) => typeof coverage[m] === 'number');", + "fingerprint": "6ae1916ffe8c3bf28c627d4eadbab2dbbab067f4bb61b41671c55db08f1653e6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/agent-assets/agent-assets.mts", + "diagnostic": "The explicit unknown type on return value of `parsePlainScalar` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (raw.startsWith('#')) return '';", + "fingerprint": "6b252a2da7885cc82be59bf8d13bc36305e81267266c3561a40372e23578a869", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "The explicit open dictionary type on binding `ADAPTERS` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const ADAPTERS: Record ParsedBaseline> = {", + "fingerprint": "6b376694d686b8a0a56ad992307d64b311165922b537ac7d69c5dc734d5cef75", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const checkpoint = parsedCheckpoint as unknown as CheckpointEnvelope;", + "fingerprint": "6b4e0a01b4081be70326194385dd29d9d066c2197a37c8634c47051dc508ed70", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/judge/matcher-core.mts", + "diagnostic": "The explicit anonymous object type on return value of `voteSlot` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { match: 0, stable: false, outage: allNull };", + "fingerprint": "6b6771ecd7ac83d4bb6fdfdd8f494a014cfc33e78a18d30fe68196d2f4e119a2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "The explicit anonymous object type on return value of `enableLineGrowth` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!setMaxLines(cwd) && !hasLineCap(cwd)) return { enabled: false, grandfathered: 0 };", + "fingerprint": "6ba3a4d637dfec6c1c2566d935cd17a874c01c65c9953bf889411893fb79a1f6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-reflect-get", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "Replace `Reflect.get` with typed property access. Parse dynamic input into a named domain type before reading it.", + "context": "Reflect.get(owner, key);", + "fingerprint": "6bb7a352394ae8f7617ee0beb067776bf45492f96592e1bd39d60300defa1994", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value !== undefined && typeof value !== 'string')", + "fingerprint": "6bddd797485fb8bf0800d44e83a9e34356af7a96addd3d0e0cb23f192077e896", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof setup.overlay !== 'boolean' ||", + "fingerprint": "6c12971118ff5e862ef9b26b89d5795e9f917df8ba4104e1b4c869a8bcf8b78e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "cli/lib/install/agent-assets/agent-assets.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "function parseFrontmatterScalar(raw: string, key: string): unknown {", + "fingerprint": "6c1f52a6ec634af5fc226dcde681575384ef768a401abf05fb6c312e1e7e406a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/prefix-cache/prefix-cache.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(typeof opts.durationMs === 'number' && Number.isFinite(opts.durationMs)", + "fingerprint": "6c5bd13643111b7e8b3779eafd5f02e57891d36a1e307813f272f990212d2773", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "agents-hooks/decision-scope-brief.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "for (const k of PATH_KEYS) if (typeof ti[k] === 'string' && ti[k].trim()) return ti[k];", + "fingerprint": "6c60763bd75be0c4024322ab42eae9cff94b7e097f2f3007b6cb465170ae74af", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const value = Object.create(null) as Record;", + "fingerprint": "6c6134bd09541ae351ddb809df0227da9ad21b895a2b8dc6a98183f44fd4558b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function metadataText(value: unknown, at: string): string {", + "fingerprint": "6c89a01ae56c2dbc7464a9cdcf60d80c8132854189b5e7341ad5ec6a0a4131e5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/run-packaged-script.mts", + "diagnostic": "The explicit open dictionary type on binding `SIGNAL_STATUS` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const SIGNAL_STATUS: Record = {", + "fingerprint": "6c96c8a08f44d8a5be19052b493a3c2cfac570eaef4b469e5d53419b7395f9e4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const isRecord = (value: unknown): value is Record =>", + "fingerprint": "6d5d29a17d29094432b9735dd6c8566cbf8ce18d01d03e5b3d3db4c8525c4a6c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "cause && typeof cause === 'object' && 'stderr' in cause ? String(cause.stderr).trim() : '';", + "fingerprint": "6da64d69e7a2816dce853f52dc529eb3e92729f7e0009033b1370b2fb6565519", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store-internal.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "record.lineage.pass === 1 ? null : readRecord(record.lineage.parentCritiqueId as string);", + "fingerprint": "6de72e3b0f816b6799928e985f988d76f5f9ed5ebd51005a253e5bfe54b27992", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-private-dependencies.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const captured = JSON.parse(readFileSync(baselineManifest, 'utf8')) as {", + "fingerprint": "6de8b685c358357b3333ab6f9d71de82bf4389431e59081b5473345d386b60f2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/doctor-review-topology.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function repo(pkg: Record, review: ReviewRoots | null) {", + "fingerprint": "6deb714d135bb551a1bb50901816127449351f52570b8461d9d213d0298a656d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/sentry/__tests__/verdict-cache.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (dirs.length) rmSync(dirs.pop() as string, { recursive: true, force: true });", + "fingerprint": "6e6b87be39881c188c17701cc49f3e2879f6fc7b095001439cb70609d8b1e2ba", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/update.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(call) => (call[1] as string[] | undefined)?.join(' ') === 'pm cache rm',", + "fingerprint": "6ea734de390194302a45bdf891f2e609bd5a95a0061e774e553d3d346879db8d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/config.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": ": file.coverage && typeof file.coverage === 'object' && !Array.isArray(file.coverage)", + "fingerprint": "6edf036732148d660ea6a4961b3a2634d2964925b3b9da0243b3708424522fc8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/overrides.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const env = {", + "fingerprint": "6f0e88642c41f6f99ae08ffaf053b68f0408278c8b838bb98471585840d76476", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/review/__tests__/record-agent-cli.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function events(): Record[] {", + "fingerprint": "6f6c84d0d51b42142b77ca64fc63d81f0b1ed60b7c1fe889a343a643a28e0c40", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? (e.itemTally as Record)", + "fingerprint": "6f93d209e58d5d119dba56330e834ee1519bec817281b7e2342a6bcca8b28fc0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-capture-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? { ...blobRef(payloads.opaqueTranscript), expiresAt: transcriptExpiresAt as string }", + "fingerprint": "6f93fd52dcbcda71e9a4d8d66e592cb4663d237688fa057a13a7816f394b1476", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/shared/common.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function objectValue(value: unknown, message: string): Record {", + "fingerprint": "6f9b0b61a5e8ea04906a429969b0dfc843fc2e85860080840d1fc8dc75282092", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "value: unknown,", + "fingerprint": "6fb7ae1a202552d6bc42fc06d1d22542bf4491ab822b044def0b73b0787f2716", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value === 'object') return value as Record;", + "fingerprint": "6fc5e9d51de1869b396f1c67083cc2d6919bfee9bbbf66f4fd3986d19e7aa4da", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "return value as unknown as TakeoverOwner;", + "fingerprint": "700d5f8988cda79a0e7b61a615b4f48d681a8d374d1ccbd6ec831acf946837dc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(() => persistPlanCritiqueWorkQuarantine(revocable.proxy as never, { root })).toThrow(", + "fingerprint": "701371eea715dab0e083e8c6f3bc4442f88e6b10ce31e2f7e7969c2537c4b79a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/folder-fanout.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? (JSON.parse(readFileSync(baselineFile, 'utf8')) as FanoutBaseline)", + "fingerprint": "701962ddf061c1df5f23e8463eff6e52c4f1e0449193b7568dec9c9aef4366c3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/run-packaged-script.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? (signal as ForwardedSignal)", + "fingerprint": "703db8dc75d0e2289b235fdb8af83282b99a0a22ef77d5bed2259731a9e55ace", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function validateRepository(value: unknown): void {", + "fingerprint": "704a94e93f2f653f507b1cdd03c5c8defe133b60c81a02999d2a3fb538610896", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof c?.promptVariant !== 'string' || !c.promptVariant) err('missing promptVariant');", + "fingerprint": "704e8309a5bf1d63309827459dbc165cbcbe01242a0c66a2b512c3c6a4ccea74", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "fs.unlinkSync = ((...args: Parameters) => {", + "fingerprint": "70697870ed5f27748c565c05c326581f5caa9d115184beab3f4216e75ca91f06", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "The explicit open dictionary type on return value of `cachedLensFields` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { items: res.items, itemCount: res.itemCount, itemTally: res.itemTally };", + "fingerprint": "70ae806eaf69434906019553b6c8e428cc90904beb34c5874678e6e32ef48de0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype) as object;", + "fingerprint": "70d77c9d660e20ee17223bcce7856d4908d6cfb3394a5ba8e7b882604c47082a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cfg = JSON.parse(readFileSync(cfgPath, 'utf8')) as {", + "fingerprint": "712b3f1c4e84c2ccc7e9cf04c866d737d559ec9143fb8f69c11af668a42059bc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function opaqueIdentifier(value: unknown): value is string {", + "fingerprint": "716cb0f7b5ed5484461795b4e4f32e54d58efe4062658b7b3348556b21105b89", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "args[3] as string,", + "fingerprint": "71835d47667de64357bf081a58f5a814aa98371e959abc02213204ad63a3d116", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "args[1] as string,", + "fingerprint": "718b853dca2ef282cc29657c2e1b1a0269aa34eb9019623496a2ea7f44314b6d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/test-subprocess.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "timeoutStatus: (command: string, args: readonly string[], options: Record) =>", + "fingerprint": "7193677b83f659320174d8fbaca496c493cebd75ef90af383db006345404a682", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "cli/lib/install/hook-registration-ledger/install-support.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "export function providerDocument(root: string, provider: AgentProvider, rel: string): unknown {", + "fingerprint": "720c70f38a75252a4bc0c2a4ad9d11fceed1b6f0b53ce7288cf23073c14ca6c4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/eval/conventions/bench.mts", + "diagnostic": "The explicit anonymous object type on return value of `validateRow` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { problems };", + "fingerprint": "7218f020030907f2dec6cf523064d4a0ce88532ec60a90bcf74f5180f8616993", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof path.required !== 'boolean' ||", + "fingerprint": "724ff7fb181290db9147a095035ef8c9b00eb7a305efa0b2c9bb84b053163bd3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/asset-checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const manifest = readJson(manifestPath) as Manifest | null;", + "fingerprint": "728f612741f3079c102edefba4dda7c339f1ee29e6db8833b15067bdfb51df05", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function verifyStringField(fields: Record, name: string): void {", + "fingerprint": "72dc1723b89ef25d8f3fd68f0f3ca012e8c6942a775be9c5aaff90894485fa34", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!value || typeof value !== 'object' || Array.isArray(value)) return null;", + "fingerprint": "72f10f89928f130f1e291a086ef14b2b7b01699e99baebb48d99f3a7fa503796", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "cli/lib/install/agent-assets/agent-assets.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "function parsePlainScalar(raw: string): unknown {", + "fingerprint": "73083e064a3a4a02810283c9b788b5b80912808b6a06af1278e7aa9c5e4a444b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "process.stdout.write(dependencyRuntimeSourceFingerprint(args[1] as string));", + "fingerprint": "730908003d0d563d7ec852853d37b1f298546a8a953c61d88399160dd9c5c507", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function isRecord(value: unknown): value is Record {", + "fingerprint": "733904b98ead714e5b22df493f01a0b9ee6fa9cacb2af964d74e990ea91137ce", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const promiseAction = (() => Promise.resolve('async')) as unknown as () => string;", + "fingerprint": "733cc0c3bcd7acf992101e97575feec922ccfbc3f7d7e0f0ccc687e55150f065", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/pin-checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return !!v && typeof v === 'object' && DEP in (v as Record);", + "fingerprint": "73a0448f85d32d292563a3e6c28f1114b9977def74e52795bbc59022aa5d05ef", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const items = projectResponse(run.raw as string);", + "fingerprint": "7401c37d8def85069c2a83f5029191a8befebe9f5d0caac91fb6a5d6cfde26ce", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/sentry/check-sentry.mts", + "diagnostic": "Parameter `raw` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function cleanMessage(raw: unknown): string {", + "fingerprint": "7433072fb674b1a8756bbe72239023c39a4c163aed8849cf7be2973cfba64942", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/overrides.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const env = { [`OVERRIDE_${fp}_RATIONALE`]: 'ok' } as NodeJS.ProcessEnv;", + "fingerprint": "74bc3abe8cec7b7eba7dfbf75223b95439b72b4df97f372158cd0f4bcf505a78", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "state: Record,", + "fingerprint": "74fc46bc4e1af1afbfec46fc3a5fb6096c83d3cabfa1d86ba323d97b0cc2a0c1", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/upgrade-optional-component-offer.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(unofferedComponents(acceptedAll as Partial)).toEqual([]);", + "fingerprint": "7503b6964bdfd7f76ddc1ba4597250ec69f2fdebdb830ef5a0f9aeb79af5a783", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/co-occurrence/allowlist-io.mts", + "diagnostic": "The explicit anonymous object type on return value of `loadAllowlist` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "750f6625d1d75c1868b9bbff52425ce32c3d7dedd4fde7b7a95778bf39b706f2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "agents-hooks/decision-edit-guard.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof parsed.decisionsDir === \"string\" && parsed.decisionsDir.trim()", + "fingerprint": "75546c5cf700fd10bf9b164b8835d52e4bd9c7335a29aeeea288c1e6589a60b5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const fp = (m as RegExpMatchArray)[1];", + "fingerprint": "75727c8f9996a13351cc5b2e74b9ab3d521ceb5d5c90fcaae98d978ad7ca646e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/config.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "coverage: Object.freeze({}) as CoverageConfig,", + "fingerprint": "75a6f357ce464d38e6a48af26693c8c29d83cf44128b88f5b03a8958c0dcadc0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/__tests__/tracker.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const baseline = JSON.parse(source.read(baselinePath) ?? '') as {", + "fingerprint": "75d2df8e61622bcc698ad37b085cd4d0a25d35ec9d06096e831fc85206ba6bb0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "guards: guards as string[],", + "fingerprint": "75f377f39c3b10ed92f2979b8b8f3ebcbeffce21aa28706beeef419159f910fd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "(record as unknown as Record).unexpected = true;", + "fingerprint": "76206cb787e962a002162137acf71103b356d7fbb7c97852291d008e457c2739", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prefix-cache/__tests__/config-fingerprint.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (dirs.length) rmSync(dirs.pop() as string, { recursive: true, force: true });", + "fingerprint": "762d2ff9b281c3216a059ce0ae678d307637dad0acf921ef9841067730a91d86", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/reconcile-detect-merged.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const args = mockExec.mock.calls[0]?.[1] as string[];", + "fingerprint": "76cdfe030518c0772a7c1ca4cbd2a42433c5bc66edf90e736ba36270d0c3f0cd", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/guard/protected-branch-guard.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cfg = JSON.parse(", + "fingerprint": "76d98658fb2cbbee31fcea6e8c9897cc62a038ac50c089aeffc0adb7ac061f6a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/decisions/verdict-cache.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(typeof durationMs === 'number' && Number.isFinite(durationMs)", + "fingerprint": "76dfdcc6c0d862e1ac299b14463ba4f63210baa9225035c42d5834b90d6db638", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/consumer-identity.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const beforeOther = consumerReviewerIdentity(root, cfg, other as Reviewer);", + "fingerprint": "76f63c536bcef6ba2631da3afb5a4c23c4f6c4df3c34b93243e749aecde36105", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/review/__tests__/checklist-store.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function harness(overrides: Record = {}) {", + "fingerprint": "774ea2422a837c64763d4ce92fafebc18fe8286bbb278abab4200fac0c4c0dc0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/diagnostics.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof code !== 'string') return null;", + "fingerprint": "77de9070601ad40cde4998acbb90166519580a7de184c38f62626831c1232716", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-submodules.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const sourceNested = join(sourceModule, fx.nestedPath as string);", + "fingerprint": "77dfdfc3aa479714e76290a53449189935859bfd74d9193277e4a3acaa2c8344", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.interval.method !== 'string' ||", + "fingerprint": "77e15d842ff012010a0f01663a598f8b393e503a47f0029af1889a8c082594e3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-reflect-apply", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "Replace `Reflect.apply` with a typed function call. Model dynamic dispatch behind a named interface.", + "context": "Reflect.apply(operation, owner, args);", + "fingerprint": "77eb0d80ec465806fd679b9a7838720c37846815b4c72d1af17678cb916a57b6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.pid !== 'number' ||", + "fingerprint": "782ee416eba5817be94efe9947646cab9bd119dc03a32be842ad1ecfcf4b320d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/recall/markdown.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "depth: (node as { depth: number }).depth,", + "fingerprint": "784874d50af1b3dc2d0a53ce3a96744a89c4305f9f620400091b936c5f2304fa", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "sel: { ...sel, reviewer: deriveLensReviewer(sel.reviewer as ChecklistReviewer, g) },", + "fingerprint": "7868579073c354437aec97e27f946903d3fef2d7534e2d5b866282f08d756f61", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/config.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof file.maxTestLines === 'number' && Number.isFinite(file.maxTestLines)", + "fingerprint": "788f2693708a2d260a529934b67d740b75db1e839729142c633803c1681c312c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "declare const operation: (...args: unknown[]) => unknown;", + "fingerprint": "78978071bf3abff98ea4c09f5d0d72aa40e3e3aa126c2278c4bf041e282b6330", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const value = Object.create(null) as Record;", + "fingerprint": "78a0aeee21e6c5710949b401975ddf3087a81182f6c787444b6a08b6955e9a28", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as number;", + "fingerprint": "78ce9f22b522939fffcfb10704eed6bdf51b00e379bdb9e6c5b48b0ef031a0b4", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseFeasibility(value: unknown, path: string): PlanCritiqueFeasibility {", + "fingerprint": "78f9cde7c9a047939d889c0c175841ca412af9980d54c41d3fb26592ecbba262", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? ({ ...value, antiSlop: value.antiSlop === true } as OxcManifest)", + "fingerprint": "7906295382c1a1672855d5b34bfa6216dc5c3f65995de5b168bbe93e637ca47d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return raw as unknown as ParsedManifestHeader;", + "fingerprint": "790ed254de5aa4a17d53f6b9439fac33f5127241a47423e1beb3c06d0008d800", + "count": 2 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/cli.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(Number.isFinite(duration) && duration >= 0 ? { durationMs: duration } : {}),", + "fingerprint": "794383f546e1e25dac375df2c3100f19d4a6019b29bdc9650fd0341d5ef4d718", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/anti-slop/baseline.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const baseline = value as Partial;", + "fingerprint": "79c6d2fe810fa39adb20283a71b974f52d9126df2b28ba4129e010dd7d3deed5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/doctor/extends-checks.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const old = list.find((v) => typeof v === 'string' && v.includes('devkit'));", + "fingerprint": "79ca92f53d1cb01cb2acbcca1949f4ce5cfe016fef814dd19dd81810f952e231", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "((typeof value === 'object' && value !== null) || typeof value === 'function') &&", + "fingerprint": "79ea6644d46ad4f4a12fcc9a85e944dae2c18e532a0451cbcf5d5753c4080b7a", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/baseline-gate.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.finalWorktree !== 'string' ||", + "fingerprint": "79f934cc9cd7956f244012c5cad99ccedb721e8c530df15d2dcb15112105454e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/reconcile-detect-merged.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(call?.[1] as string[]).toEqual([", + "fingerprint": "7a01e8e2e7bc2f2b4c9641eafb016b89830659f70e6025c7d6f3716f62783189", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "The explicit anonymous object type on return value of `planReviewWork` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { tasks, scope, fullyCached, cachedLines, splitParts };", + "fingerprint": "7a3cc6cebe59abcb719957d9fcb15cbb729330350a17d4aa0ac4c41d2ff28499", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/decisions/__tests__/integrity-bench.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const row = { ...base, mutation: 'not-a-real-check' as unknown as 'none' };", + "fingerprint": "7a43099439802164d55515133b01b23e199c0ac79762279c39d71d1dbe007391", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/overrides.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "recorded_at: typeof entry.at === 'string' ? entry.at : null,", + "fingerprint": "7a4ca19eb64898bcdf212460a9dd7ce6adca20af36ad4acdecba6cfd1c7733b5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/__tests__/chunk-index.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return { status: e.status as number, stdout: `${e.stdout ?? ''}` };", + "fingerprint": "7a9b23c8b95daac0643b4116c93dafd43408a2a109b367be093c4b929a88acb7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof manifest.fingerprint === 'string',", + "fingerprint": "7aabdbeea3a296b4d18f30181414d7f1d80f266fb1df8e4d05dba6d31bd783bb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/clean.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cfg = readJson(join(cwd, '.devkit', 'config.json')) as DevkitConfig | null;", + "fingerprint": "7b88b3b2a5af14a0828fa8e5783dc195c6e9b0078cc1605ae7304925dd724a87", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!(allowed as readonly string[]).includes(text))", + "fingerprint": "7ba1959f9752159f7900425f356c4296e40a20065066df71576c2137a98a4af3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/husky/husky-block.mts", + "diagnostic": "The explicit anonymous object type on return value of `removeFragment` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { content: hookContent.slice(0, from) + hookContent.slice(to), removed: true };", + "fingerprint": "7bb2944728b0aacdfcd882a68c2d8c3fbe707f3e08f14a842eba8472148f6868", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/__tests__/eval-bench.test.mts", + "diagnostic": "The explicit open dictionary type on binding `transcripts` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const transcripts: Record = {", + "fingerprint": "7bbd13f24e5674169f65382824fa7c1b089e61b0bd2fb014f031f9ac4a73ebf6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? (value as AntiSlopManifest)", + "fingerprint": "7bc7d316f05278b159d34b2c95205c3d73f76e5608458af5bdf9d2606396b255", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!Array.isArray(value.subjectIds) || value.subjectIds.some((id) => typeof id !== 'string'))", + "fingerprint": "7bcdd7a619e3b81709d3f49a01091d05085bdf93387831b2c4f20b52b7f80223", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/repository/state.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "verifyReviewRepositoryState(args[1] as string, args[2] as string);", + "fingerprint": "7c27e408d43ff3ad5254828f7383403e70928bbf3046a8ac3c5e6fdcd858e83e", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/anti-slop/diagnostics.mts", + "diagnostic": "The explicit anonymous object type on return value of `repositoryFile` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { absolute, relative: rel.split(sep).join('/') };", + "fingerprint": "7c636944d8775ea87ba8951dd2fd432942dbac99ba1e51b23158aea7765a2a1e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/update.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cacheCwd = (cacheCall?.[2] as { cwd?: string } | undefined)?.cwd;", + "fingerprint": "7c779c2b4cf0a9324e1a2a127d022669f6ad8d7674fc85e9f247236efc5be2c9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/decisions/__tests__/integrity-bench.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const row = { ...base, provenance: 'real' as unknown as 'adapted' };", + "fingerprint": "7ca4155975f395210d6a0d3d2675d0083616cb8c2b8545b31754bdb468df36cc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "legs: darkLegs as never,", + "fingerprint": "7cf59bb74a96ea70267cece33891c04a11a79e2eb00ac32b95198721ae1fb701", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.processStart !== 'string' ||", + "fingerprint": "7d01f8a945b862edd35df6e80c76752a51090850b78343a02ce6c6eefea98deb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect((merged as unknown as { itemCount?: number }).itemCount).toBeUndefined();", + "fingerprint": "7d0e952728e372a46924c2780a9f2039118137ecbb903719ea54793b68050883", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/gate-events.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function emitGateInfraFailure(ev: Record & { gate: string }): void {", + "fingerprint": "7d1f9ff5b1d710d5953091af836624ac5ff861f1dc2af7759a2785f22b3d7173", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/commands/init.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof e === 'string' && e.startsWith('@norvalbv/devkit/tsconfig');", + "fingerprint": "7d3471ee0455274661d1405430a906e69b28a4f1edc95bf0c49de3456b1c918c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "gate-engine/review/evidence/commit-message.mts", + "diagnostic": "Rename symbol \"INSTRUCTION_SHAPED_LINE\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": ".map((line) => (INSTRUCTION_SHAPED_LINE.test(line) ? `¦ ${line}` : line))", + "fingerprint": "7d5abe8e7beaa2368d3430ccf4973f730e419ee3e5b4b318d0582b7517453e70", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/wizard.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "reviewGuards = (picked as string[]).filter((guard) => REVIEWABLE_GUARD_IDS.includes(guard));", + "fingerprint": "7db8de9d8d2ddaa32872d28961b1370d4c1580d82c7f0d791afd48d328b6e8ba", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "value: unknown,", + "fingerprint": "7dd3c2ff0c305f67437f1ca5958a2b465fc6a6cc6464bda1abb706c6380ceeb6", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof c?.sourceRef !== 'string' || !c.sourceRef) err('missing sourceRef');", + "fingerprint": "7e4383157ac63946c868d42e2b693620484f0f1a50dab2e3e33e38699b527088", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "The explicit anonymous object type on return value of `majorityBool` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { got: t * 2 > xs.length, stable: t === 0 || t === xs.length };", + "fingerprint": "7e506cfc5814ed95f8313a0bcf6365ae1620dfbfe287145edf61b117f1d73643", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "cache: Record,", + "fingerprint": "7e89959fa94d6c239913cc50e21cdee951d22883065ecc828946c5876a8bd5dc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const directory = managedPath(root, QUARANTINE_PATH, true) as string;", + "fingerprint": "7ebadc54af9811314e77e019fd737d011ca6150700f3d91156778914938fcbb8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This dictionary's any value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "type Json = Record;", + "fingerprint": "7ee4d5a9ea611112ac78c40475e4294a6553037ce64ee4499b3973a16651dfb5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/flags/init-flags.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const recorded = readJson(join(cwd, '.devkit', 'config.json')) as {", + "fingerprint": "7f10972b26c74339db6f5b01f5c38b1272f55b61f0dcf629a5374aa8f09b0957", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/co-occurrence/chunk-index.mts", + "diagnostic": "The explicit anonymous object type on return value of `partitionFresh` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "7f50bf8262d2301b5256edd176d70d18599f3a76199fb98c850e7fc679d54771", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/install/package-json.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(electronPreset", + "fingerprint": "7f60a6f8961c867ea968bd4929e0b7e08f8d2f87f5c31185cad8f62a9987007e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-reflect-apply", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "Replace `Reflect.apply` with a typed function call. Model dynamic dispatch behind a named interface.", + "context": "byteLength = Reflect.apply(byteLengthGetter, value, []) as number;", + "fingerprint": "7f8afef8fd864777cba616730ba36a6f18ba4e61c0b9bdafd697f2386754ee70", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/hook-registration-ledger/codec.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "entries: [entry({ provider: 'other' as 'claude' })],", + "fingerprint": "7fdd3f8304ca024cffd1d47c2a1f0ed970d364e8cfd16420469f92ea3d629fa1", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/run-context.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (repos.length) rmSync(repos.pop() as string, { recursive: true, force: true });", + "fingerprint": "801d6057e87778ce2cf12fd1dfde2930245617c2732c9d2167e6c24fb5738a50", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/conventions-eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const bad = makeRow({ difficulty: 'impossible' as ConventionsCase['difficulty'] });", + "fingerprint": "802f7eb5830af14dffb377abaa27452cbac54a060830ca38180310f3888f13ea", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/manifest/validation.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "): value is Record & ReviewManifestRoots {", + "fingerprint": "804a962edc08071ce0fccdcc360a2284b6d7e851e382bca3265f672b56e5d9b8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/commands/init.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const cfg: Record = (readJson(path) as Record | null) ?? {};", + "fingerprint": "805c6244b3c6fcac74eb76a4abc78e3478adcc30fe4dd2f4c8584f64f8533506", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/reconcile-manifest-write.mts", + "diagnostic": "Parameter `m` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const isValidV1 = (m: unknown): m is ReconcileManifest =>", + "fingerprint": "809749627e39d111dac2d267aadb4a273b52834e6b5225ec2ec1c02122af0bfa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "The explicit anonymous object type on return value of `editableDocument` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!Object.hasOwn(root, 'hooks')) return { root, hooks: {} };", + "fingerprint": "80a44bcd2823976312abd887b5b9511c2e61770f559c1d1ecdc2bb5219a05581", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof candidate.path !== 'string' || typeof candidate.mutable !== 'boolean') {", + "fingerprint": "80b4674c68df15d574484c947da93e8fd1e2e2d2bbbe336305ff3f92d65d1cfc", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/sources.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof o === 'string' ? o : `${o?.stdout ?? ''}${o?.stderr ? `\\n${o.stderr}` : ''}`;", + "fingerprint": "80d0f3436f29311f0c64638f069e9e702b4fa65e3da2d0197c29c4d68565052e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "cfg = JSON.parse(readFileSync(cfgPath, 'utf8')) as Record;", + "fingerprint": "80f2f73a9dbed9d0def60a804ac5bde05c7ce0bec4e2db4da0d9f956cdee8622", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function verdictEntries(value: unknown): Record | null {", + "fingerprint": "8107ec44b5d37a18fc2e38f341cd97eaca43c6417a5eef317138ecd6c7dae7eb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/eval/save-quality/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const rows = parseCasesText(readFileSync(CASES, 'utf8')) as SaveQualityCase[];", + "fingerprint": "81634eef1bc873a903ac746989fc6d46244ea84d5d1812785791b3fbe22274cf", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function payload(overrides: Record = {}): Record {", + "fingerprint": "8182a1883c38d8b066a443ac170f0b76f95326dfd2b60e03b22a5ee284ce4486", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "The explicit anonymous object type on return value of `rowFlipStats` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { shared, positive, negative };", + "fingerprint": "81e07b70fd1c2be31be4a8256fb4be625e862e046a12f9e22e412e6f5fb4b461", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "The explicit open dictionary type on binding `CURSOR_EVENT` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const CURSOR_EVENT: Readonly>>> = {", + "fingerprint": "81e0d46c23ddee8cb834d86d334f61821205f8bd882d7b05685f61c02e18c532", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const isRecord = (v: unknown): v is Record =>", + "fingerprint": "81e424a5747ef4f9049b859759005e42cb8af40d5ea18e2cacd5aa043ee5e8c4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!value || typeof value !== 'object') return false;", + "fingerprint": "8203192943f8e0d09a592ab1bb7f503ba47e661cbef0adea753482cdc62ec6cd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/ratchets/folder-fanout.mts", + "diagnostic": "The explicit open dictionary type on return value of `tallyDirs` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return counts;", + "fingerprint": "82061c908d83a9d95d3f3d31965f639676c18f8a779922fad951c90213443561", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "The explicit open dictionary type on binding `handlers` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const handlers: Record = { start: startHandler };", + "fingerprint": "82291a8ba08812c9878ce8933c7c7e76478049b3259de94340a50450f6f4e41a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "(row) => row !== null && typeof row === 'object' && (row as Json).stable === true,", + "fingerprint": "8239c3bc076c888cde8e06a9d70dfbf2eb8999141f353c70c8348a015eb31c21", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "({ verdict, frameMeta: meta }) as never;", + "fingerprint": "824458135dea4cd1cd9055507e50bff32f129effa1455e766cbef8fc57b8f597", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const malformed = JSON.parse(readFileSync(manifest, 'utf8')) as Record;", + "fingerprint": "829c6b3c33d4ff336a385b1c52c1f622a7cbef013337709d4ba19a3866588999", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/scrub.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value === 'string') return scrub(value);", + "fingerprint": "829f1595b3011eb5bc77c736715cc95d96626fb050c3c430188c70bc3d157bfb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/suite-adapters/prior-art.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "helpers: { ratio: Ratio; rows: (value: Json) => Record },", + "fingerprint": "82a8ed57f975fa59b6b4dcd4ce0b833a5f821ddc1eceaf81a5b38293d19b6bb1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/history.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function canonicalJson(value: unknown): string {", + "fingerprint": "82c94ab7cd3a7dc38dc0a00ff38241c3c5b83bd23fe711d780aa1fefd52204d8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(() => clearPlanCritiqueWorkQuarantine(invalid as never, { root })).toThrow(", + "fingerprint": "82d598fc64450f3446afe246c18319aabe24562ee9d4ca031512ff720e530d06", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/review-cache-session.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `roots` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "8307ea3efb63ca636c872232d748f6df0554f2aaacd0fc69779cfa638fb88fff", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/__tests__/_ship-branch-fixture.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "return { ...seedShipRepo({ origin: bare, ...(hookBody ? { hookBody } : {}) }), bare };", + "fingerprint": "837705fc0ff7064ddfe80b746f9992313fafc0392084d476e82bb5fdd286dbfb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return text as T[number];", + "fingerprint": "837b49e5e93e50ed58bf66a2a8219f72339966128e2d8ee11afaab9f5713afa0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(deriveLensReviewer(base, ['b', 'a'] as string[]).stateFile).toBe(", + "fingerprint": "83bd8b5ccd7ce3267a6e6a292f8da0dcc37a8d8778f098e0dc38f5729047531f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/baseline.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof entry.fingerprint !== 'string' ||", + "fingerprint": "83c394182f0fbf6be8c97a7e29431f9418317411a4b7ece76d05f4bae64ddd22", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.fenced !== 'boolean' ||", + "fingerprint": "83e3e9d8c86469c5a06f275f5497a96821517b18eedd63841ee316b865e4315a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "deriveLensReviewer(base, ['a', 'b'] as string[]).stateFile,", + "fingerprint": "83f771a497f8a56dfab5b90b756a68f36cbde8dc47d3476ee10d5538c4c3b238", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ": selection[c.id as keyof Selection] && !(c.id === 'structure' && !isStructure),", + "fingerprint": "84043a13bb19eb033ac4888693aea176fb56ebebc9475d0459a448dc19966ea8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.configDigest === 'string' &&", + "fingerprint": "8419d9ab8a54df5fc82694e1e9f88622292fbf9259b96b7402e6636360866a62", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/commands/init.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "configOverrides?: Record;", + "fingerprint": "846e252b408974af3df23df0122ea3c2c63e05642e8e034229b55ca9673aa67a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function checkpointErrors(value: unknown, location: string): string[] {", + "fingerprint": "848840ba5a72eb232dd8933d6960190967dd3df8cb903d5f2658ef1a9b776457", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/response-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const noSummary = { ...REVIEWED_RESPONSE } as Record;", + "fingerprint": "84cd0e7f725023e8d755eae979bca19b57bbfab0483daa477e2bbd29370dd7fb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "workId: workId as unknown as string,", + "fingerprint": "84e9d690d1d46eda6512d57ccc8a21d58e64618dc1dc61d59bb87805f12a16c0", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "Parameter `cov` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function computePercentages(cov: unknown): Record {", + "fingerprint": "8500ebd18d0c3d6590e07a6151ea4fe5241adc5bbecb408d0e662d720d5ed8d0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/reconcile-manifest-write.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof m.branches === 'object' &&", + "fingerprint": "853177bb18428f5c207565f5c858c44d6d1b9fb265472bf8bf2760786a95cb84", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/types.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "rows: Record;", + "fingerprint": "85395a22c9a544f85841de6bbeb3d45c9cab350b4ad786ccab73e14ffe31a64b", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/doctor-extends-checks.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `withConfig` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { root, path };", + "fingerprint": "855ff0db83b6552e1786969b668f45d12ece1f4dba19b01e9d44bbff8c6d2815", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/__tests__/gate-config-projections.test.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(purpose === 'review' || purpose === 'review-baseline'", + "fingerprint": "858d66af0be8f11ef7f8895feaef894cf4fdf4e23e76ee5680ecbb2f2b9bd15e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const legacyConfig = config(false) as Record;", + "fingerprint": "859f110abff0a52bf944c066affa0cd4a857691e99a2b396391b80d7d2f699b6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof manifest.sourceRoot === 'string',", + "fingerprint": "85a02fc1505a458881268d2ef2b9e7170777b8513192273a21dc33249f0f28ef", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/suite-adapters/deterministic.mts", + "diagnostic": "This dictionary's any value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "type Json = Record;", + "fingerprint": "85fe299c3320a7eb2c02123cdb724e155d683f17c545001495fd3eed66a8738d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-assets/agent-providers.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof value === 'string' && SUPPORTED_AGENT_PROVIDER_NAMES.has(value);", + "fingerprint": "8621d3baa70270ef0471c215ccaf4ad0266fca019edfee9126e0e7ddd1d0916f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/commands/init.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "} as Record,", + "fingerprint": "8622c7f770a4c12bdea100a2c9ac3c38f908983f3e14ad227e5d446b04b097c3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/move.mts", + "diagnostic": "Rename symbol \"TsconfigShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "interface TsconfigShape {", + "fingerprint": "8680e9d4e593cc0be3e13c65f84e8615c8851fa8a3e7133d2b51120395f6378b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/review/source-projection.mts", + "diagnostic": "The explicit anonymous object type on return value of `traverseSegment` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { traversal: next, exists: true };", + "fingerprint": "869a6305f22ffa630294c3ff17a5266a75457bf9d446cce156ffea2d3a3a9554", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/oxc/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const bin = typeof manifest.bin === 'string' ? manifest.bin : manifest.bin?.[descriptor.binName];", + "fingerprint": "86cdd7dcb2b54080b1792f9bd3dd2a7ceb61363833f570480f3aea3ec432b5e3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/overrides.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "reconcile(cwd, 'conventions-reviewer', ['app/handler.ts:4'], 'DIFF-SHARED', NOW, {", + "fingerprint": "86f6046c52da9b8279ea18fd9ccf890e56dc7a3015993ed3e54fa1c57540eb99", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "The explicit anonymous object type on return value of `readDisableBaseline` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (raw?.files) return { grandfathered: raw.files, legacy: false };", + "fingerprint": "8713e701f785a698d3c3c866c39ef4daf2cd238de06aa5ad0eaf0633444391d5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/asset-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "verifyReviewAssetRuntime(args[1] as string, args[2] as string, args[3] as string);", + "fingerprint": "874c4e589919daca5f0591fc5065245bfd08a270e1565a89c50c2462adf43d9a", + "count": 3 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/process/gate-supervisor.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const timeoutMs = timeoutMilliseconds(args[0] as string);", + "fingerprint": "878091fc4e0a80cc6ab41f99acc441dfbe5b7ea50122a085d0df00c54a9c86d0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/cases.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!LEG_STATUSES.includes(row?.legs?.[leg] as string))", + "fingerprint": "87e3c3f3013457e9a3eb2f51f153fab3fcdf100d03ed02c24b1202f488fed952", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/agent-assets/agent-providers.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function isAgentProvider(value: unknown): value is AgentProvider {", + "fingerprint": "87f8f6c514685fb993f76fe4a4e1faca88b6337fc669e961ad08f63310fcda9c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/mine-bots-lib.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof login === 'string' && BOT_BASE_LOGINS.has(baseLogin(login));", + "fingerprint": "87fb83bc9435c0452c57061cd83ff5ed7d5a92cfc0bf511f6f1244aabf3bee98", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value !== 'boolean') fail('invalid setup runtime fields.');", + "fingerprint": "880e8d10bb2de11dc2eaa8e57058e5d11338229aaa22bb6639ffcf212e6a9b6d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-manifest.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof config.origHooksPath === 'string'", + "fingerprint": "88583a5f23bed2e58207d8fa1f23084f7d967c83d373e94e7c91fd2e548270ee", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const raw = parsed as Record;", + "fingerprint": "8894ff6062215b70a6329d13397c8cbcd95536413f7a0e5a7dac8f2697f36483", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "The explicit anonymous object type on return value of `readDisableBaseline` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { grandfathered: {}, legacy: true };", + "fingerprint": "88ae9f362bed0c67bfb1704682aae6713ef09d5d6ae948b9b723077b7ec42d6d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "await scoreRow(row, runsByRow.get(row.id) as RunRecord[], outagesByRow.get(row.id) ?? 0),", + "fingerprint": "88b9460bde83674a9fe60f057e96432d58db1e18c1cf74eebd95dbabc46f4b80", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/wizard.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "selection.guards = (guards as string[]).filter((g) => g !== LINE_GROWTH_ID);", + "fingerprint": "88e8c7797b388f719896efd8e38f5b8aed91d863751c7fa4c1f9f6b04f7acd5f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "The explicit anonymous object type on return value of `readDisableBaseline` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!existsSync(baselineFile)) return { grandfathered: {}, legacy: false };", + "fingerprint": "88f0df470777635ec3cfc79f586a027c3230607d6a6adc53f17946f00e328d6f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (a?.kind === 'diff' && (typeof a?.nameStatus !== 'string' || !a.nameStatus.trim()))", + "fingerprint": "893462d026aa8470d02e9cba8bb19593bf8c8dcf4723c3b3f3230837ef3153b8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/_helpers.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "maybeOptions?: Record,", + "fingerprint": "8a00c1f36fbed2db2495b0fc9320140824e0d7ca5625a8d225fe3ef250f04062", + "count": 2 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(overlay ? { origHooksPath: '.git/hooks' } : {}),", + "fingerprint": "8a0298c62ba4e61ca64ed09a3eef3f87c13e71c2a2aaa7a8b5669e337f24d898", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/__tests__/allowlist-integration.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const tokens = shellSplit((line as string).trim()).slice(1);", + "fingerprint": "8a0e151681d7deb7556570046fe4d77f71f75247e5aacf65503bdb6c27d1d4c9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const object = value as Record;", + "fingerprint": "8a1443faf4ccd5363cc245ffeddf5c48afbcc8c4f3270f0a4365266e8b5d4a75", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/decisions/__tests__/decisions.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof env.cost.ms).toBe('number');", + "fingerprint": "8a221fa56f93f115681b76ecb0a8ff966a27c58ee118e5ad568b27a6987ebbc3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(typeof envelope.session_id === 'string' && envelope.session_id", + "fingerprint": "8a42218f9f80e150b89455185f85316585d6a04abec724467bfaec9f6525332a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const s = summarize([row], results as never);", + "fingerprint": "8a422fc01288a6375ac2152317d4b31e748c3f518f035508606ed8c34ef76365", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseObject(value: unknown): PriorArtResponseV1 {", + "fingerprint": "8a6ad18ea18ae1cf6852ec55555083bfd306e0e1e64c24f12e409a15ecb73f5e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/odb-probe.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "): Record {", + "fingerprint": "8a6ee88760cc2a64c0f9113d6e3dfc71b0fec9adbb350e54389b665946f8b981", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "Object.entries(value as Record)", + "fingerprint": "8a6f71b5697bc8ab0b0b1a1465aa32711d41006e833a285d6f456ddffa12eb92", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof generatedAt === 'string')", + "fingerprint": "8a9597abe2cf8a05ab1bdde91fec1a31d24fda2fa82ebf46de77aa9d46009fe9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const count = (value: unknown): number => (typeof value === 'number' && value >= 0 ? value : 0);", + "fingerprint": "8a9f97819e91145d4859633ad0a5b66ac3af848ed8eef69a878978d6193dc076", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/cascade/reviewer.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return { ...res, status: 'inconclusive', reason, retryable: reason } as CascadeResult;", + "fingerprint": "8ac7e4dc48772b5b5404f02c4ae385947703dc9aec165725a6dbc1c3cd1a2f9f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const binding = value as PlanCritiqueBindingV1;", + "fingerprint": "8aef79bf8630fa14e900e4306b20924bced5cb9c0b65c04ba0d322fdbd3ef1d7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/reviewers.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const checklist = wrapPrompt('body', reviewer as never, ['a.ts'], undefined, undefined, extras);", + "fingerprint": "8afab611577a670e84082f59c34931ddedbbdf47b3f1c45368cc26ed18e2f18f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/pretooluse-bash-hooks.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `armedRepo` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { dir, binDir };", + "fingerprint": "8b35f412c2d5901b2281855d5c9c381bc5ba06ebf20932284122f5d47b9a6523", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/structure/eslint-config.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const trees = (cfg.structure?.trees ?? []) as TreeSpec[];", + "fingerprint": "8b83482ce57a808c2419d29cded69334a235d7ced391a2b64edb24eab1f5f8d0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/components.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (previous?.[id as ComponentToggleId] === undefined) delete components[id];", + "fingerprint": "8bcdbd4350a23b824a081854cd538063f2bfb0c42a01d5b3038600f8fe51ad0b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "match: matchStub as never,", + "fingerprint": "8c293bcbb422d4ba300d5c47d029d1040b9daa09f20124fd849ebae7687bb797", + "count": 4 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof finalMessage !== 'string') return skipped('final_message_unavailable');", + "fingerprint": "8c31b4ca8a1beefa2e068951d5a995057b87a9990f7f74c0a16571840675e310", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const merged = { name: 'correctness-reviewer' } as never;", + "fingerprint": "8c4cf553eff5e6e3fb661725739fdbe2444fd5fd37a8e7852b31849620766c16", + "count": 5 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/search-tool/search-tool-guard.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "payload = JSON.parse(readFileSync(0, 'utf8')) as PreToolUsePayload;", + "fingerprint": "8c5f65ca1542b532c8eccd4fef8ee58c656136759ddbc76db1404b939498950d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseAction(value: unknown, path: string): PlanCritiqueAction {", + "fingerprint": "8c8dc6089a587edbfd763670e56597827ab28e4114f50b51d78e6e0cb738b564", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "requireValue(typeof eligibility.eligible === 'boolean', '$.contract.eligibility.eligible');", + "fingerprint": "8c9330c93b241281b0e1f8712eb8c0f1745ecc1a0ab698d570e9a2e51df0cb76", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-manifest.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "captureReviewSetup(args[1] as string, args[2] as string);", + "fingerprint": "8ca415671e2477eb085218cf0d8f88657c4bf864700bbf75658d886c051389dd", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/gate-events.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "...(typeof durationMs === 'number' && Number.isFinite(durationMs)", + "fingerprint": "8cbdc135ca2d485042f90d94f289fc97b127fc4b8f27c36952128ab0320a7a47", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/_helpers.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "maybeOptions: Record | undefined,", + "fingerprint": "8d6a5c10640fefc13600e383cdf55b52a04ac87ac6ddd68b5e80732edf81308f", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function isRecord(value: unknown): value is Record {", + "fingerprint": "8d7b653de11589690f29281ced414537e5cfaa07cfc4cfc3a8a9e0368e331ca7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/eval/reviewers/bench.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(CASCADE ? { blockRecall: pooled.blockRecall, cleanPass: pooled.cleanPass } : {}),", + "fingerprint": "8d7f9eac881ea8183b37a3e441a9e82228dc114a757613bc9654971dca71319d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseState(value: unknown): ProjectionState {", + "fingerprint": "8d8a1cc57db5bd7ffe31b8ccb86f579dafd530b672c8a0e0254e6ec1333f4d1a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-manifest-format.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof value === 'string' && SHA256.test(value);", + "fingerprint": "8da711c93c840cefcc972b6cbae99ee85059001727a20a587569cc0f7e86ed9f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/decisions/decision-format.mts", + "diagnostic": "The explicit anonymous object type on return value of `parseDecision` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!match) return { fm: {}, body: markdown };", + "fingerprint": "8dc07bdf734824f6bea51561f1cc426c7adf7f854e9cb925cf450c99ca139d48", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return text as T[number];", + "fingerprint": "8dcdf41b5072cd46ddb55d29e2dc523531e68e517c52dd1677afa47927968c6d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/statistics.mts", + "diagnostic": "The explicit anonymous object type on return value of `wilsonScoreInterval` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (total <= 0) return { lower: 0, upper: 1 };", + "fingerprint": "8dfb329d9381673b93fc124e1aaa44806bf325f52529d0f65aa690fac2b3a13f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/sentry/__tests__/sentry-hard-defaults.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (stubs.length) rmSync(stubs.pop() as string, { recursive: true, force: true });", + "fingerprint": "8e07d1bcf8b82091858e9a22b1e6d939de5da0c1cd9c5e69d2f25f05f237562a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const errorCodeOf = (value: unknown): string => {", + "fingerprint": "8e341d0802fddc5f3233af6a9116d65f1cad82a725f2589d976ac6523f4db218", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof value === 'boolean' ? value : fail('INVALID_TYPE', path, 'expected a boolean');", + "fingerprint": "8e3bbda7fd6246cb33ace20e593e2256c3004ae2933fc9e6ba8a42223e142603", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "gate-engine/decisions/__tests__/scoped-targets.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../decisions.mts', async (importOriginal) => {", + "fingerprint": "8e905e9e7f67f68b19e6a3e507c08ac508c117bc2c98094acd8a9e82fec81363", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/doctor/guard-config-checks.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const raw = readJson>(join(cwd, 'guard.config.json'));", + "fingerprint": "8ead0ecf9bb666f0ff29e263a652b9c8100cabcec55bd6ac2b561037e27745f8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "): value is Record & ReviewRepositoryState {", + "fingerprint": "8ee737a6efc079ca470cc3d85e752e5ba1085c33567f81681f3ee1b115dc5ab8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/install-support.mts", + "diagnostic": "The explicit open dictionary type on binding `RETIRED_COMMANDS` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "{", + "fingerprint": "8f08ed0284d66ba3f3642431dae782d449f4c77c542f333a856f45547cb8cafc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseEdgeCase(value: unknown, path: string): PlanCritiqueEdgeCase {", + "fingerprint": "8f15539e8d2ba56586187e0f748624a391f207b6d18c5d53539359eab1a61af5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/folder-fanout.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const over = inCommit ? overCap(indexCounts as FanoutCounts, cap) : offenders;", + "fingerprint": "8f29c726e41a3e55ae6e39f179922b0aeca9e3dc27b7630386e1e1508e6e4c2e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "verifyDependencyRuntime(args[1] as string, args[2] as string);", + "fingerprint": "8f2caf1a5d3159183814abfee2c850e928860f28d5e34041d91c460c5aa8af0c", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "match: (async () => {", + "fingerprint": "8f324ec96aa3d0cc6e2f9bf1a66df1a471f60316ed93ffe660bf007daf9e5e52", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/run-packaged-script.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((cause as NodeJS.ErrnoException).code === 'ESRCH') return;", + "fingerprint": "8f4cbb382a13c51ac4c86992ea5351fdc8aeb5c564174401fb91627bee28ca57", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(value.interval.lower as number) > (value.interval.upper as number)", + "fingerprint": "8fc9da023f361028b1bb2be7046279119d866413b19e299f5139e335fbf325ce", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/statistics.mts", + "diagnostic": "The explicit anonymous object type on return value of `wilsonScoreInterval` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "9004b19055e33ec7eba04045b5c7ebecdbe04d94b51adb7b4ba1449b590082a2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof beforeOk !== 'boolean' || typeof afterOk !== 'boolean') continue;", + "fingerprint": "901b653ca7e889be5eae8f5843fbf24fb292c5062e9571a29af17922b1c444d9", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/search-tool/search-tool-counter.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return JSON.parse(readFileSync(stateFile, 'utf8')) as SearchState;", + "fingerprint": "9046d6dbe9ad0b5f0c5888a96e1610120e61d6d96300229d554e7d7fcd4650bc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/__tests__/review-fixes.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ".map((line) => JSON.parse(line) as BenchmarkEvent);", + "fingerprint": "905c704f7e12fcb0f8e51c0e5605f314f2aad3ba82642d7cdf4e5323a1acb231", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "args[2] as string,", + "fingerprint": "9071ef8ff3c9c78850847cd7a76cd55009cb1db6f02b99e2c34e613d3c003ce1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "extra?: Record;", + "fingerprint": "90791dbbd035e4386c41e0eb27f8d31c16fc6802453bae4d66388cf7b0300fe1", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/immutable-file.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const records = managedPath(anchor, ['records'], true) as string;", + "fingerprint": "90a2190cc2776bdcac8ce157e0c4175d515fbc4940b8031f99167c43cafe69c5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/decisions/detect.mts", + "diagnostic": "The explicit anonymous object type on return value of `judgeWithClaude` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (raw === null) return { verdict: 'OUTAGE', raw: null };", + "fingerprint": "90b17a8f97ccc5c27da6495a7c579d9130c7bdb1c90a859bbdc3152136a80b99", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return e && typeof e === 'object' ? (e as JudgeError) : {};", + "fingerprint": "90eba1da09aefcd06754e1b682df53421d75e303696c516893db4ad3ac716a2a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "fs.unlinkSync = ((...args: Parameters) => {", + "fingerprint": "90fe7bd6c2b3c11ead67b3125bf27384f9351efe01c5c24b16cacb4ee0b6ba02", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/husky/husky-block.mts", + "diagnostic": "The explicit anonymous object type on return value of `removeFragment` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (start === -1 || end === -1) return { content: hookContent, removed: false };", + "fingerprint": "9107c6a35b23df580a618a05b86cd47d1f9643233a9e7b7708d3aae0d1abc633", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ".map((line) => JSON.parse(line) as Record);", + "fingerprint": "913cd0ee36f23d7ca55f3964d49785f94c9c61259f31f858fd0c9ecd710d32b2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value !== 'string' ||", + "fingerprint": "9197026aadad16bd04ad89765f5ff8fad16434da5b09d365a34de6c46b62d8f3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/reconcile-manifest-write.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof m === 'object' && m !== null && 'version' in m ? m.version : undefined;", + "fingerprint": "91b0471b8b462024710e2a16396e8a69644553fae290d6cafc5ad1e7e2764c41", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/compatibility.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "(target) => typeof target !== 'string' || !LEGACY_TARGETS.has(target),", + "fingerprint": "91e3ca15d3c506444c73581321862d49c306b2570d9299b8fb8855ea4831a8ae", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(errorCodeOf(reviewed({ routing: 'route_feature_critique' as never }))).toBe(", + "fingerprint": "91f06df0ba0579e465efe2295972e43f56753c12186943d29c62937e471ccc1c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/overlay.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof prev === 'object' &&", + "fingerprint": "91f7ee66a5d60e2691e84b4f37ff487156500b74092de075ccdc2b2baae7487a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/baseline-gate.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "changes.push({ status, ...(kind === 'M' ? { basePath: path } : {}), finalPath: path });", + "fingerprint": "91f919f0242ed8ac7b11818f55e98a5443b7a92b791aed0c2cf04f32e91504d6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/overrides.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(typeof entry.author === 'string' && entry.author.trim()", + "fingerprint": "9270f610853c221cfdaf0b7e896a7fcdf6a393ae473c280cc110745f25fef3ad", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-submodules.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(fields[7]).toContain(fx.nestedPath as string);", + "fingerprint": "929228dfb21203324f6a6b4209dc8fe0ab7284a5b676384189e1385c3189a97a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(id === 'guards' ? selection.guards.length > 0 : selection[id as keyof Selection]);", + "fingerprint": "92beb237016b02f8c1ec41e5f81d5ada5215cd62091db0d562222e59d0d1a30f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof root.critiqueId !== 'string' || !CRITIQUE_ID.test(root.critiqueId)) return null;", + "fingerprint": "92cbf8ef1fb781d3e665be14481be537827452eb8fecf2c6a4b5ba80ae10258f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/commands/init.mts", + "diagnostic": "The explicit open dictionary type on assertion discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "{", + "fingerprint": "92e4cec3fbdc05212210809dddc69b3012901edee3952675ad12cb81f9159de7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "The explicit anonymous object type on assertion discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const m = merged as unknown as { itemCount: number; items: unknown[] };", + "fingerprint": "930f52fa9c3036e2c7b71128e6c6496131d86b9b64d8efc88f32839611baea96", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/upgrade-offers.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const ids = unoffered.map((c) => c.id as string);", + "fingerprint": "93281b4975ffe3965a980504b808dbd5a94513b628ae847b2850366d572d3f20", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/decisions/detect.mts", + "diagnostic": "The explicit anonymous object type on return value of `judgeWithClaude` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (noLlm || !diff) return { verdict: null, raw: null };", + "fingerprint": "93b29bcd607642d28dd4258d0386bc3a01b53efbe08e3efe358b3316ec7649be", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/odb-probe.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const oids = ev.oids as string[];", + "fingerprint": "93c0856312882242dc40385a08307248a44bffb432c37b66a1cae1b168002fa0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.headOid !== 'string' || !REVIEW_REPOSITORY_OBJECT_ID.test(value.headOid)) {", + "fingerprint": "94027bcb47ab694dae14329abc5854fd8e515f2618de75092522e42e979878d0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "execWorkflow: wfOut(RESPONSE_OK) as never,", + "fingerprint": "940775f8c58d2a66a62e4df5d04681145d7d109cd30973f767bf68d5ec44c349", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/manifest/validation.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function isSafeManifestAbsolutePath(value: unknown): value is string {", + "fingerprint": "9408714387634f1089195c54a54f717f003a0bb582d1933d311c8690c77d1fea", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/recall/markdown.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "item as { position?: { start?: { offset?: number }; end?: { offset?: number } } }", + "fingerprint": "943ee626189674d042cebebf390f0e885ad413b3677dbc41228c93c6596c526a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/review/baseline-fallow-paths.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "): unknown {", + "fingerprint": "94543c58ea63ececf82bfdb97a8887e5a4263c8012527069a4ca9d33176952cf", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/cache/session.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return name as ReviewCacheStoreName;", + "fingerprint": "94616154b2048691e75980780917d7ec18330c39283b6ad579bc3c2265b473f7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "function readManifestValue(path: string): unknown {", + "fingerprint": "946e104be22d56bbdd8057ec730a7e38d987f2bb4894e4a3fbd40567cb01dfe5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/allowlist-io.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "v = JSON.parse(readFileSync(path, 'utf8')) as RawAllowlist;", + "fingerprint": "94adfdf000792bfa3ff31ef1c90ba1beafe9c4a34209936b210c26140d07fd41", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/progress.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return JSON.parse(readFileSync(file, 'utf8')) as Progress;", + "fingerprint": "94be41dab78b244e73631ac1c2a3fd2d2830a93389dc94eb02218ecc0c5fb1c0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return readFileSync(join(root, '.devkit/review-runs', fresh[0] as string), 'utf8');", + "fingerprint": "94e046259f7db5c20a903131f6cd0104f3ddeac106d4d11b72cd8cf26fbd6b69", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/strict-bounded-file-read.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (error as NodeJS.ErrnoException).code;", + "fingerprint": "9518b1fa1008dca8ce76003d03de2a5cbfe0cd4dabe83e02f1d0e18bd5e292e3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/suite-adapters/deterministic.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const rows = input.rows && typeof input.rows === 'object' ? (input.rows as Json) : {};", + "fingerprint": "9520822704a0d5a6019bab3b6169724f414d7517673cfda195f026621d026717", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as string | undefined;", + "fingerprint": "955be7846bf37bc8e4e436a9f77d029e825dfc06acbdaffa3ab4e21f7d2ce06f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.refsSha256 !== 'string' || !SHA256.test(value.refsSha256)) return false;", + "fingerprint": "95733d2e5fe00979a024f526a50f236bb536256f72b7d85c0c15a94a32273d45", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/suite-adapters/deterministic.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "else if (typeof metric.value === 'number')", + "fingerprint": "957345ed7961fc9f0839c72c7199c679d336ddb6b094036463ed424c1affb657", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/odb-probe.mts", + "diagnostic": "Parameter `err` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "err: unknown,", + "fingerprint": "958be66df7ec16ca3b6d823aee35913262a533c2bf98f2cd535b428a9cd921ae", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/record-agent-cli.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ".map((l) => JSON.parse(l) as Record);", + "fingerprint": "95c591c964d6d8ea2d452a5bd233a43ac730d4525bd50a4883b86f3b03b04814", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/generate/generate-import-wall-baseline.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return JSON.parse(r.stdout) as EslintFileReport[];", + "fingerprint": "95cfe8cee8fc9c17cd3555148efba331da83587563c67392bda60d36e646b133", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/search-tool/tools.mts", + "diagnostic": "Parameter `v` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const nonEmpty = (v: unknown): string | undefined =>", + "fingerprint": "95f0baeafade5d40e2203eb9ff4b4ac67e299827af5d635b44eded0e717f5530", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/structure/compile.mts", + "diagnostic": "The explicit open dictionary type on return value of `buildRegexParameters` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return params;", + "fingerprint": "95f6a6b45d35596c529256fdc59506bc18c1bca816be2eb5c0f6ab8ca40e9159", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as string;", + "fingerprint": "961a8817d0eaa4364e8866e9c90f9eb1ba7d7d33a38b902c85776171a0bbfbbc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const s = summarize([row], [", + "fingerprint": "9638a3a9f55212e5c8381bf25be64c0d6461c8114ac3b981d7627c859c2f76b8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/co-occurrence/allowlist-io.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!v || typeof v !== 'object') {", + "fingerprint": "963d9d41605c177c1eb9985061e1ba682bea722296d15895dbe9b594f85f434b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/baseline-fallow-paths.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (parts as string[]).sort().join('|');", + "fingerprint": "966b598cd23eaeb7da172fefe6b7a62d7f70f678bd94b087315bdf846626d260", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "anti-slop/src/rules/no-runtime-typeof.ts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof option === \"object\" &&", + "fingerprint": "969d3b43d7c47f4cc70373feb320bd226402bca16cd96fd157cd710777d72410", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof cfg.maxTestLines === 'number' &&", + "fingerprint": "96c41e97ab49438125def6e553d92f0c2e3e15399369989035b798da41351b2e", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/__tests__/tracker.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ".map((line) => JSON.parse(line) as BenchmarkEvent);", + "fingerprint": "96c9fb1aebcfd119a072fd662c0bb3c544f5e29e25e89948e11b48bfb2c906d4", + "count": 3 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/verdict-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "rmSync(tempRoots.pop() as string, { recursive: true, force: true });", + "fingerprint": "96ffd8f4a11301e374d042b3dcefd867cdb78638077dcd459dc1f7d5032ffb1c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "cost_usd: typeof cost === 'number' && cost >= 0 ? cost : 0,", + "fingerprint": "97552ddd29dfbd619af250bef53c5703d5429474d254a79eae80c65359909caf", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof c?.repo !== 'string' || !c.repo) err('missing repo');", + "fingerprint": "9768ff6bff886f0a3652cb4f6bad2ace29a61601d55fde6415cb0116597bf3dc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const part = (lens: string, status: string, extra: Record = {}) =>", + "fingerprint": "978250588fa6885b5ba14565f78eb6cb2a0d8bbaeed16ba1782261d43d9458e9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/strict-bounded-file-read.mts", + "diagnostic": "Parameter `error` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function codeOf(error: unknown): string | undefined {", + "fingerprint": "979c889d0f2eecca80f575007b589f9c765cfccbc28edbc685e7159af94241d0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "function readManifestJson(path: string): unknown {", + "fingerprint": "97a5dc9f3381f6e2ece9b61ad2017f746904e32320583624cfcfa8613c46009b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function boundedString(value: unknown, path: string, allowBlank = false): string {", + "fingerprint": "97d472c3348da5eb117dc478fb2d2f2257636a122b62568312c17244288dc91e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/flags/review-profile.mts", + "diagnostic": "The explicit anonymous object type on return value of `reviewPlanFromFlags` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { error: `devkit init: ${modifiers.join(' and ')} require --review.` };", + "fingerprint": "97fe9c91d0abcbd2c21e094cc75b0860d847b2e432d24737485cd1ac788de5bc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function stringField(value: unknown, label: string): string | undefined {", + "fingerprint": "9859aac45ba258fe694893af56d8ef11ef0549542bc6e5c8d7c51f11c1c2a934", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/install-hooks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const devkitPkg = readJson(join(packageDir(), 'package.json')) as { version?: string } | null;", + "fingerprint": "9866b7e43017697ebfa352b47b74a93c053bfb3f6f9add7c18c4b983664379e1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/wizard.mts", + "diagnostic": "The explicit open dictionary type on binding `AGENT_SURFACE_SETS` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const AGENT_SURFACE_SETS: Record = {", + "fingerprint": "98ab0719c24e7b8f1110c7bf1b791b49c935213a5982dec9869c557a73d96cbd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function reviewSetupRuntimeHash(value: unknown): string {", + "fingerprint": "98ab4d533ab8680f133a9e72c4520562ab14e394ed121f6b0882b63fd6c528cb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "Parameter `record` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "function save(record: object) {", + "fingerprint": "98b02c179800fbedab969b58f71171449729a27996da606fd354b3e590a2e64c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "value.verdict === 'PROCEED_WITH_CHANGES' ? 'PROCEED WITH CHANGES' : (value.verdict as Verdict);", + "fingerprint": "98dcd9b9aebae7b8a4319801b953c82411e92f641c374e94be6236e31eee8583", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/dist-integrity.mts", + "diagnostic": "The explicit anonymous object type on return value of `parseArgs` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { base, paths: argv.slice(i), root };", + "fingerprint": "99225119bec9059a106e1c5bbc470589ddd3a6b6f8dad58c72c351c8b3f61422", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/__tests__/remedy-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8')) as {", + "fingerprint": "994432ebb3e2077152df710bc21c7bbf7b223adec83de09cc7df403f928327b7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function manifestRelativePath(value: unknown, label: string): string {", + "fingerprint": "994f2b46c7ac85b1b6a0c1d840eed5b0b3fae8d1427340e14e248ef717750a55", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/conventions-eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "got: variantGot as 'hit' | 'miss',", + "fingerprint": "996fb95f9cb266f5132e80516146bcc1e2db5cb94b311f85656d25a42c59aa2a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function ownDataValue(record: Record, key: string): unknown {", + "fingerprint": "99d7595ef806dfaa6986fa29025268a71f2ac57a7d3d110f48dc7f29c31bbac1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/history.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof event.checkpoint.path !== 'string'", + "fingerprint": "99e8eb8668034e394b3bfac3f758d1be1a3de57ba963c812cea834c77ca342d1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "agents-hooks/decision-edit-guard.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!value || typeof value !== \"object\") return out;", + "fingerprint": "9a33286e5986878bc4457b0b9830d9b0a99e31550ce8acfd0e0e6e48c3ca2585", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value === 'object' && value !== null && !Array.isArray(value);", + "fingerprint": "9a9d7e00158682a5e3cc72134291b0b27938d43a5b070a75b6ba52e04b4b870b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/commands/update.mts", + "diagnostic": "The explicit anonymous object type on return value of `lsRemote` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { error: `could not reach the git remote (${lsUrl})` };", + "fingerprint": "9af2ca05a0b31da653635c4616e72a333f8a316303ef357e2aa59320855e4c2e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-submodules.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "git(join(fx.review, fx.modulePath, fx.nestedPath as string), 'rev-parse', 'HEAD').trim(),", + "fingerprint": "9b12852aa3edc0f8578fc31bdd6ac26542e85b7a130c95ca8fc6b168bfff6446", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/overrides.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return raw && typeof raw === 'object' ? raw : {};", + "fingerprint": "9b2b890c33b38ff203ccd9104b48bae0d7fde98b94ee2f1104c5e07b2a23be75", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/process/gate-supervisor.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return cause !== null && typeof cause === 'object' && 'code' in cause", + "fingerprint": "9b7fc2a568f028e6acabd9c1c41998d050b0980bae2e36da5de019f2a7277b11", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "Parameter `error` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function missing(error: unknown): boolean {", + "fingerprint": "9b8ebfc79271742c7310c64db86eb8dd73394c7194fded7f5b7d5c3c90f378af", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const m = merged as unknown as {", + "fingerprint": "9bec7cccdfc7101702652028d7b557d6dce384b5b3f086ad933f2bcd0fcabca0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/__tests__/gate-events.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof first.ts).toBe('string');", + "fingerprint": "9c35a00a7e1868562b2cdbf4379f879265edbdaa0607211de448378243baaec5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "eventsById.set(value.id, value as unknown as BenchmarkEvent);", + "fingerprint": "9c51a3b3a465ff30979dafe9cd1dd5a1472645f4e16b747f1f13512be64e3e77", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const m = merged as unknown as {", + "fingerprint": "9c54ad8f03913205350bc2015bcaa939e19e091175b0b5dabdc9205f6d1ae8d3", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit open dictionary type on binding `ASSESSMENT_MARK` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const ASSESSMENT_MARK: Record = {", + "fingerprint": "9c646cb64c37a387631930d4d8f6d0c5ece0b99da6d7e120cc5366da934c780f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const setupValue = malformed.setup as Record;", + "fingerprint": "9ca7711084f8fc5873cdd99118ea1e5d0894b9f61cc5f169b9885a96f0254fc9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "const nextMessage = (): Promise =>", + "fingerprint": "9cc0a6c13a2260af5893c12460c5230d896d45a0e0d0b45dcea7583ebe65d0ce", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/corpus.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (row.sourcePr !== undefined && typeof row.sourcePr !== 'number')", + "fingerprint": "9d7644e2b5eadfca7649fdb40ccfb828a388e83bd1383e32973108b9f2bbb05b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/review-run-result.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": ".map((line) => JSON.parse(line) as Record);", + "fingerprint": "9d7b8d957924215ea7e68de309eb7df548cea7e8efc8d4fa7139ad24ab3615cf", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const existing = parsed as unknown as BenchmarkEvent;", + "fingerprint": "9db9f6b290479ab8fe386cc077e0a255ae1badc574677b912588155eab42fea7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/__tests__/review-fixes.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const owner = JSON.parse(readFileSync(lockPath, 'utf8')) as Record;", + "fingerprint": "9df061e01c22dab6306a872b0154249fd6d5fc8aaf76472de5ef27d4db22210f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(hits.every((e) => typeof e.duration_ms === 'number')).toBe(true);", + "fingerprint": "9dff30c0c3f6dbcbe3470d3054e3a142424dda3564493c8a0e4369aaf4080b31", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function countValue(value: unknown, path: string): number {", + "fingerprint": "9e127b023b5555b59452889e940a95cb0d4b6078357b462816304731226c8e0d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "match: (async (...args: Parameters) => {", + "fingerprint": "9e22152d49590f8932bc0e877cf647004cf2b54fc3c224a2c027fbf3e3bc7b3a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "rows: Record,", + "fingerprint": "9e3a600e93bc15f24f4752c98af129f14794450e8f06b30a5a71eec3a78b21c0", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof guard !== 'string') fail('invalid setup runtime fields.');", + "fingerprint": "9e99303214f73ccef1eec8f69e73ece0ae9f8e727ccf3e815d0bf7fbfd2ef151", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const record = value as PlanCritiqueRecordV1;", + "fingerprint": "9e994fe69fc0f3ec03bac9f15e2153c25d2e6dfe238fd6442aa782b8964f21b7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/pin-checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = readJson(join(cwd, 'package.json')) as Record | null;", + "fingerprint": "9ececc2f009318631000508e9c3137b4ced413fc13928951515e5f1c90410c24", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const parsed = JSON.parse(readFileSync(path, 'utf8')) as { extends?: unknown };", + "fingerprint": "9ef97188539e67f337d834ef11fe506b010f5c038a22a5e5fd4c88f61ab2a00a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/history.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!isRecord(parsed) || typeof parsed.id !== 'string')", + "fingerprint": "9efda09ee30c56bb38946af8ead5e347b5c678f8572aa3778145e3c075e68719", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseEvidence(value: unknown, path: string): PriorArtEvidence {", + "fingerprint": "9effaba69dd10552577f82e326e5a119c54f2039cb1caf473853d46f146d5e22", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "verifyReviewSetupSource(args[1] as string, args[2] as string);", + "fingerprint": "9f1bfdbe330efed2ff43de7d23b26c5e3ab2e0c49fd56ebc646a9556c30337f5", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "value: unknown,", + "fingerprint": "9f1e7399c8b42871bdbf2c3a7335e96e80d37c4f6602f88b9e4781f6888fb4ce", + "count": 4 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/baseline-gate.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.baseWorktree !== 'string' ||", + "fingerprint": "9f3bb34484601af061f68f01706477abae3d2c1336f15c31e352fb26c48b6eee", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/reviewers.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const without = wrapPrompt('body', reviewer as never, ['a.ts']);", + "fingerprint": "9f41a00a2b3f2f900c61f41b4bec0e78aab212bb9f54a632ab1017ac735e202e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/amend.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const [oldText, newText] = options.noteReplace as [string, string];", + "fingerprint": "9f76a4d0380d115e3ac0f595c14d00e30220cf2f61e242fd2077dd4d75c8da74", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseChain(value: unknown): ReviewSetupState['chain'] {", + "fingerprint": "9f7727d08b94a55c03f78c273f8b0367456a803fca775b755e759fbbb4fd1694", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/asset-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const expected = (before.get(assetPath) as CapturedAsset).fingerprint;", + "fingerprint": "9fd41a81640161381559f9c055e9fc22ebf4811256718ff4a05c2aa01df13e4a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/provider-runtime/claude-subagent-stop.test.mts", + "diagnostic": "The explicit open dictionary type on return value of `payload` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "9fdb5f0dca87e7ef76069ff0113ce7d79aa0e910b13c178dd0cd2f0319beb88f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "Rename symbol \"validShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const validShape = [", + "fingerprint": "a02407faab2222adfe726c1175fb2e7bfd470986fc7c404885de2df45aa61fe6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "await run({ ...sel, reviewer: deriveLensReviewer(sel.reviewer as ChecklistReviewer, g) }),", + "fingerprint": "a03d68a58bd2e2268a1ed4d98b95e530afeb4cf40b04d6e5b8a864be95a6dc48", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/review/source-projection.mts", + "diagnostic": "The explicit anonymous object type on return value of `traverseSegment` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (stat === undefined) return { traversal: next, exists: false };", + "fingerprint": "a07cbb631031a8bf64d0336de79ccff2776898d74f37da5a285048ea6b921a4b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "The explicit anonymous object type on return value of `persist` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { state, quarantine };", + "fingerprint": "a0946808cefc7dd3baf4179d86851365a907ba71537b167f591073215d9e989a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(lstatSync(files[0] as string).mode & 0o777).toBe(0o600);", + "fingerprint": "a0ccd9aa9886e29b1d0c8d292b2ac268f80aa5d5948df9349c6079a713a3dc33", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "e.itemTally && typeof e.itemTally === 'object' && !Array.isArray(e.itemTally)", + "fingerprint": "a0fb584ded13c34e0812e60db3f473d6883845df9f5ae4ba5d217d866018c047", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function decodeEntry(value: unknown, index: number): HookRegistrationOwnershipV1 {", + "fingerprint": "a13ba15a7393f2f69866ab1a7f42afb9e9f73ce315adf748cbc5d0ab6a25f136", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/clean.mts", + "diagnostic": "Rename symbol \"SettingsShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const onlyEmptyHooks = (obj: SettingsShape, allowed: string[]): boolean =>", + "fingerprint": "a1afd8043eb228602248919089972283b8a1302d3a7a8acb01779740efcde358", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as boolean | undefined;", + "fingerprint": "a1f675a4374d2c7ace2c6dcafeed651ff2ada17f935b9af3ab155d605b73959a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value === 'string') {", + "fingerprint": "a24d3a694fa66f647f14743b3242ca6f82c018d907179a32a33fcdecff3ad79c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "errors.push((error as Error).message);", + "fingerprint": "a25ec209854245909cf6c7bc517c6b1dd87193014ae0215a635095a311a77c86", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "e2e/anti-slop.e2e.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const composedPayload = JSON.parse(composed.stdout) as {", + "fingerprint": "a26604cb4915c3d97115b71767d7152eaf07b7bf03c7d717adcd7588fa37145f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "The explicit anonymous object type on return value of `clear` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!directory) return { state: 'absent' };", + "fingerprint": "a291f6cf46f3e198ee73f7a69fed7045b8ae6393df331b2263e04b3b8834486b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/doctor-search-index.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return { root, sel: (cfg as { components: Record }).components };", + "fingerprint": "a29cfbe947844372b159697a7b325a12e93abcb3b0b9f07c641f4aebee8f29d4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "? value.results.filter((row: unknown): row is Json => Boolean(row && typeof row === 'object'))", + "fingerprint": "a305d71c1b159794e9f9e72ff6cc4be683dd4aa90eb2bf153f702f4bd37390d9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/git-tracked.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as { status?: number }).status === 1) return false;", + "fingerprint": "a33a3d4833ccdf1835abd084d5633dc08f0ea1e5175478c3eec5fa2e22e23330", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/husky/commit-msg-block.mts", + "diagnostic": "The explicit open dictionary type on binding `FRAGMENT_ID` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const FRAGMENT_ID: Record = {", + "fingerprint": "a3ad8430cb9fa1c2207075a9f536aeedbe393056d2311e867a9df6dad769bcb5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function exactObject(value: unknown, fields: readonly string[]): Record | null {", + "fingerprint": "a3c72077201eff8e655a29b78dcbb361fca1ed13bd8ddcabb3e9b8e2347a8e6a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "Parameter `err` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const fail = (err: unknown) => {", + "fingerprint": "a3f53abe7b2f227a77f981a80bc493dc3b6e0ebc42843282c42d9012eb2870cc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(runsByRow.get(row.id) as RunRecord[])[run] = recordRun(raw);", + "fingerprint": "a479cbf36ce29d3c2f387d5e4d714f67e477917ce60d0fd6afe28cd7e43acc7b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/capture-normalizer.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof identity !== 'string' ||", + "fingerprint": "a4813270304755d504e5aea4887612dd8cb925a3ee7105ccc9342528e82af582", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/review/source-projection.mts", + "diagnostic": "The explicit anonymous object type on return value of `traverseSegment` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "a4a7f8c5a19c106fd489bcec39479e208f61587be999b7e832dbec478c9592e4", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? (JSON.parse(readFileSync(linesBaselineFile, 'utf8')) as LinesBaseline).files", + "fingerprint": "a4c98ddfe7c53e3c8d8e2ad074c4c3278564e5c309c615581b79b700a528339a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/config.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof file.fanoutCap === 'number' && Number.isFinite(file.fanoutCap)", + "fingerprint": "a4d9ce390f6d2f25bdc0d77ff30d3b8728ed19ab1036351f5d95bd09e9b62048", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/repository/manifest.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function canonicalBase64(value: unknown): value is string {", + "fingerprint": "a4dc5b2b40fe937742316fd151c0d3d8662718e831159286be39f3c169c1fa8e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/commands/update.mts", + "diagnostic": "The explicit anonymous object type on return value of `lsRemote` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "a4e64b7be94967ad495183aa7f4cc467ef6be910a84e3075dcf57b95ce63d876", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/co-occurrence/chunk-index.mts", + "diagnostic": "The explicit anonymous object type on return value of `buildVectors` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { dim, codeV, descV };", + "fingerprint": "a507ea75964e02e2d957a4739b30ae9d1e2053f822e83b4b47e7dcc9a675076e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function manifestHash(value: unknown): string {", + "fingerprint": "a51736df8513b99a403848e38b39d2ae0c982206e5c02bb55a8d30c88c9ee03c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function validateContractShape(value: unknown): void {", + "fingerprint": "a525527884135711af21438ab9ce85eb273bd026b7449e6a0476591de3dcc390", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/lifecycle/work-quarantine.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const identity = (overrides: Record = {}) => ({", + "fingerprint": "a5670b26ac7cba4c74953aede5f6650860eb4873e63e1a8b0b65189fad19eb81", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "Object.entries(tierRows as Record).map(([id, row]) => [", + "fingerprint": "a57c051adce0a2ec6d07619b2b7b72a9f40edae44d26cf1b3bb2c7d7069301dd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function dataFields(value: unknown, label: string, budget: DecodeBudget): Map {", + "fingerprint": "a5e003a997460f0d14f9e467c01dc829f62965f181414ecd2631d268a45355b5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Rename symbol \"validateContractShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "function validateContractShape(value: unknown): void {", + "fingerprint": "a5e464bef1bf4b2c1d8adb3f278d992216d34e362dd42700aec2a3af4bf4a9eb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/hook-registration-ledger/plain-data.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof key !== 'string') return null;", + "fingerprint": "a628b3eabf42cc6df1d3f51cb356112fc71d45f0b09bae2c9381c6c499154fa7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/run-packaged-script.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((cause as NodeJS.ErrnoException).code !== 'ESRCH') throw cause;", + "fingerprint": "a6c046f0831309ec41d070d8a2639c0ae5ba06b8d0e540cf54c7f3fe85bb5d52", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/components.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof partial?.decisionsDir === 'string' && partial.decisionsDir.trim()", + "fingerprint": "a6ee625fdc83b70fa8b0d026421ada6522433f0a76b1a097bb6a353676b6f668", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "existingReview: (readJson(join(cwd, '.devkit', 'config.json')) as DevkitConfig | null)", + "fingerprint": "a75094d647abe991a09fad80de730623f17ac98c6d50db3706550a967676c3f4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "findings.push(candidate as unknown as BenchmarkFinding);", + "fingerprint": "a7563b0eefd1f77df61b783d05fa2d9356272555b35dce230f824a49feb0b497", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "const opaqueAsync: (root: string) => unknown = async () => undefined;", + "fingerprint": "a76bc18883e0b40ba010a4ed17bc8ac5797a6e12b3be92b1d8db930394fbbb44", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof path.executable !== 'boolean'", + "fingerprint": "a794042817f822acfb803a2cf5862a76dbf2156d9938bfd51563763fca22c74c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/oxc/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return JSON.parse(readFileSync(path, 'utf8')) as PackageManifest;", + "fingerprint": "a7a703bbc8ec645dab945c882407c0bc32bb3c221037c3126620641cf7af14d3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/finalize.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!row.reviewer || typeof row.reviewer !== 'string') {", + "fingerprint": "a7b5e7a6928fad8f21ebf7d4e92377b03fc4bfe6bd6086fd7dd4aaf02d5323cb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "anti-slop/src/shared/lexical-type-parameters.ts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const record = node as unknown as Readonly>;", + "fingerprint": "a7bb899072b9ab517eaa3edb047a2cd068cd992791bb0bcdaca1e99df66a1db2", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/repository/state.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "captureReviewRepositoryState(args[1] as string, args[2] as string);", + "fingerprint": "a7d0d09f06ac9a73ffe09b57267e46060fc3d38ad67739830771da750ffe4362", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/mine-telemetry-lib.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof a === 'string' && typeof b === 'string' && a.length > 0 && a === b;", + "fingerprint": "a7e0b4e78442c15ca1dba73e2664dfa47ad6eacfc3b8845577f6b5fbb8c4c267", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/eval/conventions/bench.mts", + "diagnostic": "The explicit open dictionary type on return value of `buildAssets` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "a7ed66d8fc4497b682f8f655cf33ffba1446e3e1a81a15c6f1c0a105cc91e929", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/corpus.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value && typeof value === 'object') {", + "fingerprint": "a84aaa639a7316315c1b88964fadd8cbbbef5149c88212861b7dc727c745878b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/baseline.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof entry.context !== 'string' ||", + "fingerprint": "a8d904f1a31cd5bc6fc22c667eb0475bbf4c7a7a5e819bc5b6a998b76fb2fdd5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/catalog.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const bins = (JSON.parse(packageRaw) as { bin?: Record }).bin ?? {};", + "fingerprint": "a8e79f1a3d1292192efa5dc3a403c2c4966b21208e576287dfb261a819c4cae4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof e.transcript_ref).toBe('string');", + "fingerprint": "a8f2e1167aa1d0e51a6115349edd9688b40130d6689990993ac0237887394ec2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/gate-events.mts", + "diagnostic": "Parameter `model` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function emitCacheHit(judge: string, model?: unknown, durationMs?: unknown): void {", + "fingerprint": "a9154eb4e8959652d93d0bca1981c85f0a1ddb7405b0297f84a9539f747c28d6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function positiveInteger(value: unknown, at: string): number {", + "fingerprint": "a956f5eaa14546fb53b9e7f0ec6f440bb9ea6f3ae9a5cbde50f6d3afa7557749", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function timestamp(value: unknown, at: string): string {", + "fingerprint": "a958ca582813862b333ca2279581381a0a9c14faa2d30a79ee18c89834b68415", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/deterministic/run.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof cachedPrefix?.duration_ms === 'number' ? cachedPrefix.duration_ms : undefined;", + "fingerprint": "a960d30549c2dd413c500e3f879ff62af6d73453d72397597889b636b87eeac0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/upgrade.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "sel.guards = [...sel.guards, ...(picked as string[])];", + "fingerprint": "a96e04b09d0837a7e968fe71388379eb71a12b6c8c07362be3937825c6fb018b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-gate-supervisor.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return realKill(pid, signal as NodeJS.Signals);", + "fingerprint": "a9967dfe2519edd5125c1a0b7843331f4324f007567fa3762f9ba5823ce247e3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function recordValue(value: unknown, message: string): Record {", + "fingerprint": "a9c87277fdea5f6f678fc3ef93f8f829df86c40668753f74045fb7585c2e70f8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "assessment = verdict as Assessment;", + "fingerprint": "aa08b0af392f2205ba948a676b9a1c771b82ba0d55c2193232fc3c06e7d36a93", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/mine-telemetry-lib.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof reviewReason === 'string' && reviewReason.trim() ? reviewReason : null;", + "fingerprint": "aa27b972a41d7f8b085c773f29d1be7a63fae5a92da8ca86b9f3b30e36d61fbb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof raw.destinationGitRoot !== 'string' ||", + "fingerprint": "aa2b772bb7252921fb93427a11f28c5878415d59639bf303f46fb509d9c741e7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/catalog.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!(LIFECYCLES as readonly string[]).includes(subject.lifecycle))", + "fingerprint": "aa3a6800b241e1c0478e7a1bc0b428d5ba9708e3126c6a184a7d0dd90880b8d6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "Parameter `payload` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function handle(payload: unknown) {", + "fingerprint": "aa5459e37946828a19750ee58dfeb44a881e8b7ed282e94d699847e66b856095", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof repository.fingerprint !== 'string' ||", + "fingerprint": "aa60c5e4a05e011cb6420a56723fc8aa986c98b18adbca172aac018386aeb2bd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function runtimeRecord(value: unknown, label: string): Record {", + "fingerprint": "aa6d2477b71ed66341428da68f51d52451762dfb2b58ae713d5db9c26d5d3dac", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const chained = input as object as User;", + "fingerprint": "aa802d7c82ef6d151a9f997f6efae7d6a5087de9597f3b24832180f657df8a49", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const chained = input as object as User;", + "fingerprint": "aa914cbda8e3804869aae45dfddc15372bd6305b74205bc1217c74e085255436", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function hashErrors(value: unknown, location: string): string[] {", + "fingerprint": "aac13a052ff94d3b35f6ffec72e098d84571a69ac100dc9194fdf326c9c8d46c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/gate-events.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function emitGateEvent(ev: Record): void {", + "fingerprint": "ab2d8fb0d40bd3ebd79410853bdf233bffc881ce426942b3181c1b6ff2859e2a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "verifyProjectionRuntime(args[1] as string, args[2] as string, args[3] as string);", + "fingerprint": "ab5ec182322bcfefa0afd295daa94f11e05ec28fc76cbf8a1ce581620bbed1c5", + "count": 3 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/clean.mts", + "diagnostic": "Rename symbol \"SettingsShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const cursor = readJson(cursorP) as SettingsShape | null;", + "fingerprint": "ab6847d3d520a00099754daf11b7610786460ff8e14544925617b1f788789369", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "cli/__tests__/reconcile-detect-merged.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "(e as unknown as { stderr: string }).stderr = 'gh: could not resolve to a Repository';", + "fingerprint": "ab7982e13d1ed5db524983c0f9180fc77df17693032f1cdff35ee7a3356b631d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/sources.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof content === 'string') return content;", + "fingerprint": "ab9407ec53ccbddd17ba0bb45b227bb87ca0290f07beb5e40633b4ed0ef7cdb4", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "args[3] as string,", + "fingerprint": "ab97fd8a0a5ab75b38a2ed3a4962ce1c2e038369039f825d3490ccd4b67128ec", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "function loadUser(): unknown {", + "fingerprint": "aba45beba8bfa9d2f4a1ab6948179a8c8faad10b4c838d0a8df00af90fe64bd4", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/immutable-file.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pending = managedPath(directory, ['.pending'], true) as string;", + "fingerprint": "aba62a40a54f3b076189840e28b849c109e92cb6683c0208b874ebbb4e244b6d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function sha256(value: unknown, at: string): Sha256 {", + "fingerprint": "abf8dab211573bfaa1b7e0ee1eaf7845b80ef6be219bc187411621d18abf69c6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof state?.skipped === 'string' &&", + "fingerprint": "abfb568ca50fce4b973b633b4208110b8518110698d119f8426c7e57e4496cb0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof v === 'object' && v !== null && !Array.isArray(v);", + "fingerprint": "ac14ce618f7827ca849bd35188efdd7eaa8365f5706620a76e369368e172d485", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "The explicit anonymous object type on return value of `partitionLedger` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { authorized, untrusted };", + "fingerprint": "ac4ea6be8806b2b4a45a1f9586f8a3b7d0aeef20efccb101ea2dad7f21a148a3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/overlay.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../commands/update.mts', async (importOriginal) => ({", + "fingerprint": "ac5cbbe72572c5cd4f8ba3a705ee60c0c05bd3a98c5d546baceecaeb5a3a682f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "record.lineage.parentCritiqueId as string,", + "fingerprint": "ac867eb6857d4436464dccf0080739242d1705ffa564e605ccfc3819c55c78ce", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/evidence-store-internal.mts", + "diagnostic": "The explicit anonymous object type on return value of `persistPlanCritiqueRecordAtRoot` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { state, record };", + "fingerprint": "ac8f84735f75fa645b152b04fe74640ed259421c436822fb9357e39c0e8ba10a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit anonymous object type on return value of `status` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (view.event.lifecycle === 'no-ship') return { mark: '×', label: 'no ship', tone: 'info' };", + "fingerprint": "acd1aa0a8a98418777d4943eae329b03acb1c60c814d7ce17208dbb6101083a8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/claude-result.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const count = (value: unknown): number => (typeof value === 'number' && value >= 0 ? value : 0);", + "fingerprint": "ad467b9edc2516081c1380c265fffe35f0afc1a9c4cdea1c735796499e18ddca", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "Rename symbol \"reshape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "reshape(2); // same branch, same claim, reshaped diff → sticky hit", + "fingerprint": "ad66b38519aebe87069a86a613cdf597809570d45ce34c17be143b3e926045fd", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/cache/session.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const name = cacheStoreName(args[3] as string);", + "fingerprint": "ad79d985310cbb48b2ebbec2a849831d7a7e878dc795968d93df0544a35854e0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/review.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": ".map((line) => JSON.parse(line) as Record);", + "fingerprint": "ad9928aa9e2f938a8cb2c284c1d8280cd23573f9b2e9166ab27f6af5b8b525af", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/clean.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = readJson(pkgPath) as PackageJsonShape | null;", + "fingerprint": "adcf4756210ed3ac7838ef320fd8069c3ea9de340b775896e7761fc9662f8509", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const isObject = (value: unknown): value is Record =>", + "fingerprint": "add3e8635f229633d6223887d678bcc27638669c3ec43fb5ce90c6e948cae584", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/provider-runtime/claude-subagent-stop.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return JSON.parse(UTF8.decode(buffer.subarray(0, bytesRead))) as unknown;", + "fingerprint": "ade8becb4d66510da016c0c7392d2718bb8f84b5ce0fa37b098edf07d29bf127", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/mine-telemetry-lib.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof diffText !== 'string') return { diffText: null, diffPath: null };", + "fingerprint": "adf3c287f82825d4e77139348ac3069cccd52788e4094e83c18036585da18704", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function parseRequestedGuards(settings: Record, installed: string[]): string[] {", + "fingerprint": "ae0adc63a914c92b8e0a6bcc99c04abc0e3c82ed24b02f6c3e0bef58426a0ca0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/agent-assets/agent-assets.mts", + "diagnostic": "The explicit unknown type on return value of `parsePlainScalar` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (value === '~' || NULL_RE.test(value)) return null;", + "fingerprint": "ae841fc44db5c920e8546b7ad71679724c0f8cd10ffe3703d6732f3a62f2450c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function promiseLike(value: unknown): value is PromiseLike {", + "fingerprint": "aeec6f07faf56fef401dd683fe7a24342b6b9456f61ec5e047c30e9c9e90fb3f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/capture-normalizer.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof identity === 'string' &&", + "fingerprint": "af4b7e6710eef62b64badf2395e4969330dcf8d0c8fe2e724d0ef3e5dace17b6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "value: unknown,", + "fingerprint": "af57f6b3b623361b517d791f665bda52ddb1ca0fb1679863339626518e3be618", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "for (const [key, child] of Object.entries(value as Record)) {", + "fingerprint": "af5b5ff6d22f13e749e8b659629a67c61b993ca9860cf91ade1eb02c702abff7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/install-fallow.mts", + "diagnostic": "The explicit anonymous object type on return value of `installFallow` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { ok: false, method: null, message: 'no package manager could install fallow' };", + "fingerprint": "af5f4c85178fa63ad217f6d7c880a503c053aa047893c60f1d618e27ce0d8eac", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "[key: string]: unknown;", + "fingerprint": "af6ab777284251dbf10e744c415c330f8872687bfbe1593c50b27d99792efcd5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/eval/reviewers/finalize.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((e as { code?: string }).code !== 'EEXIST') throw e;", + "fingerprint": "afa5b3b470190738c01e2df96b0f10cd3813d2c51792352df0861b43ee52b15a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "requireValue(typeof value === 'string' && SHA.test(value), at);", + "fingerprint": "afabfc73faa534be8b9fb644143cf0afb32f3be017135975bf964ed0ec1efa75", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const { researchReferences: _dropped, ...withoutRefs } = reviewed() as Record;", + "fingerprint": "afafe1caba1727e1f4e93d7252d94a2775c429b72ab4a848f8724c4d8470256f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseConfigurationRow(value: unknown, path: string): PlanCritiqueConfigurationRow {", + "fingerprint": "afb540bdcc24c2d0512b0117e08d3eeb2ffa267f82ed8897218cdaee6b92d4ce", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ": (value.verdict as Verdict | null),", + "fingerprint": "afda75f8b77ad265e07ded2ff81ca6e9d80000aad390df128bd654ac8a784c9b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "throw new Error(`Adapter rejected ${suiteId}: ${(error as Error).message}`);", + "fingerprint": "b00a3c7886bd88af2bdb96efe82a0416b03ad9a33386a1b15390430c79a5a4e1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/reconcile-manifest-write.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof v === 'string' ? v : undefined;", + "fingerprint": "b02c90b66c0ed5327d9828561235af1876da99ae26d71e41c54dabda61c87fb2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.label !== 'string' || !value.label)", + "fingerprint": "b06f92289dd96d43118b43c33814a6c50018c1ed7471f76bb80b4da6ab10cd94", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit anonymous object type on return value of `status` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { mark: '·', label: view.event.evidence, tone: 'info' };", + "fingerprint": "b0724d33a913e69cabe6710e3ddfca851cc6f1c91d5531d22d89382189f667a9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function data(value: unknown): Record {", + "fingerprint": "b0a38691cfe125d76f2cf414dae22379e0bca637f10eb05def52f9b505d2d077", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/history.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value && typeof value === 'object') {", + "fingerprint": "b0c127275d417028f5a9fb10c0e918eea1840644ccfb2d96bc76add8f8d3e13b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/__tests__/response-contract.test.mts", + "diagnostic": "The explicit open dictionary type on assertion discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const noSummary = { ...REVIEWED_RESPONSE } as Record;", + "fingerprint": "b0cf56d3b3bdcf45558510238043a8f5d30b231d87e7e900d17618a87b1435e9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/hook-registration-ledger/install-support.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!componentIds || !LEGACY_AGENT_PROVIDERS.includes(provider as never)) return entries;", + "fingerprint": "b1062ecbe526f00e098e43c3b3b4a1b29a04d52ae65e24e34162f416ce8e79cb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/wizard-optional-defaults.test.mts", + "diagnostic": "The explicit open dictionary type on binding `selectAnswers` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const selectAnswers: Record = {", + "fingerprint": "b106e3a12366b9442b853491e11841829d2f950b848684219c552f93b89328eb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "Parameter `this` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "value(this: unknown) {", + "fingerprint": "b158c4beb189673216e03a21205581c87e580f0b2bdce79eb9fd5dd1f9f8ddf2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "The explicit anonymous object type on return value of `checkSnapshot` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { errors, mode: source.mode, ...(source.ref ? { ref: source.ref } : {}) };", + "fingerprint": "b1a77e71f80f2b8686d1210886429a1dba16ef073a82b65ac2df7560cb2f706f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/judge/odb-probe.mts", + "diagnostic": "The explicit open dictionary type on return value of `odbEnvironment` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "b217d193568042c54eeec08fac577e7db2411bb2641f855693d086a06365ce6c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const restored = stored as User;", + "fingerprint": "b21938992b9e8c7fc8d4fe5bd068a0eddbaa487942632345c78aa4b9b12458d0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function decodeSyncManifest(value: unknown, kind: AgentAssetKind): DecodedSyncManifest {", + "fingerprint": "b2215d82fa1a3a39be45db35f77dd13d397639ffe46d12a51eb8d25ce79f6436", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cfg: Record = (readJson(path) as Record | null) ?? {};", + "fingerprint": "b2270649aabbd10ec67f0d29331d6283e1bc9b0ce349c3af7cd38662d7aea1fe", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseLeg(value: unknown, path: string, expected: PriorArtLegName): PriorArtLeg {", + "fingerprint": "b25a285f665e136f10211349ea62324bd0751b0260dbab119b3191dbbd24367b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "keys.every((key) => typeof key === 'string' && allowed.includes(key)),", + "fingerprint": "b262ff71674c046c4b2bd92a04412bba40ea585a64e734879260352d6d7da1f4", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/move.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "JSON.parse(", + "fingerprint": "b274d31caf3e3a920d08d82478dc7e33a57d36bb99cc12643cf6fb0d3a66f15b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "{ ...baseRow, id: 'r3', expectVerdict: ['MAYBE' as never] },", + "fingerprint": "b28e0c6336018552f8eb6577e4da01d436b14dce6e4f68df8cc7b7809cbf08e5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/review/__tests__/conventions-eval-bench.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const bad = makeRow({ note: '' as unknown as string });", + "fingerprint": "b28fcdc8fbb3147ce4da583e5b00c3fd4e73b4972ae4255bf5b1a4d80f36833d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "): Record {", + "fingerprint": "b29488522d5fb8495214266683c73f5a24a8e50ff227d206b8b0856d8c897fcf", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "requireValue(typeof key === 'string', at);", + "fingerprint": "b2bb8d9baabffa0a8fe158de64a294a226373f9d92ddd8a1b30bc0cf4122cee8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/eval/recall/scoring.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const goldRank = hits.length ? Math.min(...hits.map((g) => rankOf(g) as number)) : null;", + "fingerprint": "b2f00bf62c1818c0476ef6a7e49b9d96d347cc8efff2cbf431e2a9255abf2c2c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/reconcile-detect-merged.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(call?.[1] as string[]).not.toContain('--head');", + "fingerprint": "b308a54b869dd8a8c34d390ba0e663a943434a153a2052cc317d55a210167a78", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function config(overlay: boolean, overrides: Record = {}) {", + "fingerprint": "b320c6b816c1ca4902683c2e5dbbb325bf98a8ea0a150f7bb67600f7b280f4f4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "The explicit anonymous object type on return value of `loadBindings` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { bindings: [], candidates, malformed: true };", + "fingerprint": "b36cda8f0be24f0f28c67ef7b3024a83bb1dbf7325205516363f7dd6d87cdc0c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as NodeJS.ErrnoException).code === 'EEXIST') return false;", + "fingerprint": "b39e004484430f701adf1cbec95f5a66bab27f1cb905e61df67862a203d3cd6b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(row) => row !== null && typeof row === 'object' && (row as Json).stable === true,", + "fingerprint": "b3ce407790166920a7f89e01d197ddfd0438f1e1ba5ea4a962a9b3b0a4f5c0ef", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const location = rootLocation(options, true) as EvidenceRootLocation;", + "fingerprint": "b3d1581722332a59380b47aa6c6f14367f4ff2fc91ff2608bfd05be8314b9808", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/upgrade-version-step.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const V = JSON.parse(", + "fingerprint": "b3e54865f3f35bff3dc2f8824203b68c81a4e089b323036b064d2db907c846c3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/anti-slop/diagnostics.mts", + "diagnostic": "Parameter `filename` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function repositoryFile(cwd: string, filename: unknown): { absolute: string; relative: string } {", + "fingerprint": "b4183f4ac777e3eaf20cceb5f9d6f4f8cd700353e28f98dccdffbaa5d8d4b587", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/telemetry/run-result.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const logPath = args[3] as string;", + "fingerprint": "b4679623515f3d9411a600840b4a836a7e94f82c260a45bb05d3653d0aed88c3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const s = summarize([row, makeRow({ id: 'other' })], [", + "fingerprint": "b4aacc58f2b026953521548037a1043f48d73a3f1bd1b049e24cfe7851ea83b2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "The explicit anonymous object type on return value of `experimentHashes` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "b54db09e5c866c7b366b58c8fa5442fba8e0236c7a59cdd9d151b38a57945031", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const actual = JSON.parse(readFileSync(result, 'utf8')) as Record;", + "fingerprint": "b54efe81dc6de15cb2b3c383985d8a84e1c950cea5c8dc778464c0fffd953759", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof descriptor.value === 'string')", + "fingerprint": "b588bce8657fa5cb945d3e7866f53287a85dafdf42e503aaba78da5dfec2faba", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseReference(value: unknown, path: string): { title: string; url: string } {", + "fingerprint": "b5a27c45155d6ec0075a7394c3a2e917968f7c711594902307ebbce448004497", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/__tests__/consumer-identity.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `consumerFixture` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { root, packaged };", + "fingerprint": "b5a368e7f2cb74c3c034b42597a11db99f8f770e29b900391656f3d5fc7fd195", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const isRecord = (value: unknown): value is Record =>", + "fingerprint": "b5c96296c6c0d8200d4f9dfe70564ffb395d550140a2f4e61b2ba8dafab03220", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(await (contender as Promise)).toEqual({ code: 0, stderr: '' });", + "fingerprint": "b5cde2cf4be24093e7c22ca8c72efcc15e745abf0d42ca32be60c775d7ee3395", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof input === 'string') console.log(input);", + "fingerprint": "b5d6d648501bbe36d4ebeb6b7743067f4ae98f4bb0d8e0ff0fab244f82e32535", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/search-tool/search-tool-lib.mts", + "diagnostic": "The explicit anonymous object type on return value of `classifyOperands` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { patternValues, positionals };", + "fingerprint": "b5ec976a020d5b36777598c5d343272b97982faff19dd1b9e3d2287293f3a0a4", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/anti-slop/lifecycle.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const base = JSON.parse(readFileSync(join(cwd, '.devkit/oxc/oxlint.base.json'), 'utf8')) as {", + "fingerprint": "b62c8bc9d583bc708548cb034090534166226ef2896e050807b6c227f4585a47", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(devkitRef !== undefined ? { devkitRef } : {}),", + "fingerprint": "b63762037a1a4391f18aba02a3476c591673b63b6c34b9a51aa330f5ed45e72e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/eval/conventions/matcher.mts", + "diagnostic": "The explicit anonymous object type on return value of `splitQuoteAndLoc` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { quote: cleanQuote(text.slice(0, idx)), loc: loc || LOC_UNSPECIFIED };", + "fingerprint": "b6385cf22c74ae282f73460b4bd63592263907590f8b39daf3ee8f28ac8e7255", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/claude-md.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (dirs.length) rmSync(dirs.pop() as string, { recursive: true, force: true });", + "fingerprint": "b645caf3e8630e018350489fd5157b5c2aef42c4ae74bfa8978e963da29606a2", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const entry = JSON.parse(lineText) as {", + "fingerprint": "b66735964e459db39f518cf9abe6363dd01b330bdb65ecadfb2db0a265182ff6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/commands/update.mts", + "diagnostic": "The explicit anonymous object type on return value of `fetchLatestTag` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "b718714439c9f8831813f493cd83a1b505fa1cff81e244d1aab2dd9ca3a56183", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "gate-engine/critique/provider-runtime/claude-subagent-stop.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.doMock('node:tty', () => ({ isatty: inputIsTTY }));", + "fingerprint": "b7429c878ce4205b857ec5c2ac59860b386f35dbb17bb88d77ce5dc3a626102c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/doctor/pin-checks.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return !!v && typeof v === 'object' && DEP in (v as Record);", + "fingerprint": "b757c69bb8951b20f3925e5ba1496c88abfcee54dd859791dda93862e78e6c34", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.predecessorEventId !== 'string' || !value.predecessorEventId)", + "fingerprint": "b77711914ad6c647c2064c17f54b91415043c09fdde7afd40ea4dc21311f2acb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/process/gate-supervisor.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const handlers = Object.fromEntries(", + "fingerprint": "b7ab2b569e30c87fd52f500879756abe2377f192f3fc0e2aa704e707e8131ab9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/review/baseline-fallow-paths.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "): unknown | typeof DROP_FALLOW_VALUE {", + "fingerprint": "b7bddd55d486f436cb9123f88037d143a5e9d323317057b84db3ebd0194cde9c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/upgrade-optional-component-offer.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(unofferedComponents({ [id]: false } as Partial).map((c) => c.id)).toEqual(", + "fingerprint": "b7c28c54eaf8703ca21fc2e9d6d3d6c6a9ffac61496f5daf035fff98a1b11235", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/install-support.mts", + "diagnostic": "The explicit anonymous object type on return value of `stripRetiredRegistrations` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!root || !hooks) return { document, changed: false };", + "fingerprint": "b7eb668e1ab081c58927a04ce955f860fbd86c5b403e2b27b1e8ee3295300533", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const event = value as unknown as BenchmarkEvent;", + "fingerprint": "b892ea7c2b731920d7533438574420167ebd4de9927542144e59a02b276dcf5a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function stringArray(value: unknown, path: string): string[] {", + "fingerprint": "b8fefe49f960cd7ecbf9f2e5d2770472f205f64257066af85b5ad32ce0b0a07f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/__tests__/allowlist-cli.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const err = e as { status: number; stdout?: string; stderr?: string };", + "fingerprint": "b8ff007b6c5c18911028c3c62f427784c2596edaf9f5901ee6876fa9d338bfa9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/commands/init.mts", + "diagnostic": "Parameter `e` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const isDevkit = (e: unknown): boolean =>", + "fingerprint": "b9041683f932748117e0abd1f374a3fa7f2680a1ee393c02a1d16733b1bdf6c8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/__tests__/factory.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof g.run).toBe('function');", + "fingerprint": "b96e5b6431eef3b54b9259dd8098567bc879b0bc21474da6b2a81fc1ec95aa68", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseIdentity(value: unknown): PlanCritiqueWorkQuarantineIdentityV1 | null {", + "fingerprint": "b97a054f678789c75a60cfd819958051bdfbebf6b0f81be27f398f87d2812875", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/judge/gate-events.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(typeof durationMs === 'number' && Number.isFinite(durationMs)", + "fingerprint": "b99bbb8c84ab6402f63fef125b736e5ca7bd02acfec4d514270f89cae907cd72", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/lib/install/install-fallow.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('node:child_process', () => ({ spawnSync: (...a) => spawnSync(...a) }));", + "fingerprint": "b9a8eb7d3cab22e8fde3eccf64a8e890a3104c8d8f0bb88afa2cddee7b042d4f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/conventions/bench.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof content === 'string' && INJECTION_RE.test(content))", + "fingerprint": "b9c839abdcca43466ff3c9dfb32b526d6140b1494741f1c9d822dc6221264af3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/overrides.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const env = { [`OVERRIDE_${fp}_RATIONALE`]: 'a different env rationale' } as NodeJS.ProcessEnv;", + "fingerprint": "b9ec55f1d9299aa3dac2c9883621bf1951e25ee38c888ba1d3d130779adbb6dd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/flags/review-profile.mts", + "diagnostic": "The explicit anonymous object type on return value of `reviewPlanFromFlags` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { error: `devkit init: invalid --review-guards (${details}).` };", + "fingerprint": "ba265d9151e29e4cdb4fa86592c1a1acff5426874b2a9e61232260546cbdb30d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/move.mts", + "diagnostic": "Rename symbol \"TsconfigShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const readJson = (f: string): TsconfigShape =>", + "fingerprint": "ba486dab56f19b02e065569ce8ac1e9b82b3ebb77f0e9403d5ca752b15232c27", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/clean.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const claude = readJson(claudeP) as SettingsShape | null;", + "fingerprint": "baa442bcdcf64391908f9c82b4fa8e4322c736505de197771ae19ae60927e96d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "frameMeta: value.frameMeta as FrameMeta,", + "fingerprint": "bab5fa3861867e5b87f30efe4fd07c9a29af1a20283837e3b6e61d0c0802662f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "(record.execution as unknown as Record).unexpected = true;", + "fingerprint": "bad510b2d978957c2e2cda5fb0e9fbf33391cd69685bc62ac3068cfab42bb743", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/immutable-file.mts", + "diagnostic": "Parameter `error` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const codeOf = (error: unknown): string | undefined => (error as NodeJS.ErrnoException).code;", + "fingerprint": "baf91deaf99704591d153ad1f40f2023325da6e8a7c62248151a68d55b34efb3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/anti-slop/diagnostics.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "payload = JSON.parse(json) as RawPayload;", + "fingerprint": "bb0319fd9b62813860b9642ea31f5f74f92d7bebbeceac39e8adeedc5afd0b4d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "!LEGACY_AGENT_PROVIDERS.includes(target as (typeof LEGACY_AGENT_PROVIDERS)[number])", + "fingerprint": "bb043c4cc6e11187bb9f05126a43639a3bc2392d261e3aed9495aa8e93d27444", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const m = merged as unknown as { itemCount: number; itemTally: Record };", + "fingerprint": "bb33f303af751cda01e0a9dc778b672118037a061d6deff36eee2d8366a754b2", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/guard-config-checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "mod = (await import(", + "fingerprint": "bb9b67b713a4f031022854c141940d62ba8debe65bbc609982c1a9ba452e51c2", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/hook-registration-ledger/codec.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(() => hookRegistrationDestination('claude', 'other' as 'shared')).toThrow(/scope/);", + "fingerprint": "bbbe5d97f2f8fca16265656d04cb67a528b527ed1a6c3c4ac74a662ef13db572", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/transcript-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const ref = saveTranscript('review/../../etc', 'x') as string;", + "fingerprint": "bc1c00e0236e0d6c4c15c7a7d7e11d68d3d598f5ae3f926398f7c182c4ded2f5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/reconcile-detect-merged.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect((mockExec.mock.calls[0]?.[2] as { stdio?: unknown } | undefined)?.stdio).toEqual([", + "fingerprint": "bc2e4c4fcc15c183c44868c470f7076a0ab782900fe0df80e02ad3ff336bf14f", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value !== 'string' ||", + "fingerprint": "bc36819499a23587ad45f60d1dc0264ae01f165562ddeaf8464ded0f4977127c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/review/__tests__/record-agent-cli.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": ".map((l) => JSON.parse(l) as Record);", + "fingerprint": "bca1b75e33e912dbbe003b0dd7a532ece175ab2baac12de155fb7dcb2ab373ed", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!Array.isArray(value) || !value.every((entry) => typeof entry === 'string')) {", + "fingerprint": "bca9e5c9cd5e8c522b7ba522411a616260ce53e91d9fd6137e0278b791702653", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function booleanField(value: unknown, label: string): boolean | undefined {", + "fingerprint": "bcdc35edd184693823ebb6153b85121d526de9bfda0abca4ec8053cafd064ae7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "args[1] as string,", + "fingerprint": "bcde36a0d690b8f30fb54f5f297b5a1f792e651eb417890b5b2f8f87d85a2f78", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value === null || typeof value !== 'object') return null;", + "fingerprint": "bcf3a8d86efb7512b4e3ee29cf3a3d4d77370857b30a3bbc277c34d4d226fbbb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "join(environment.HOME as string, '.devkit', 'telemetry', 'gate-events.jsonl'),", + "fingerprint": "bd1a2c88d39826a8ee81c1b63c24a3ac57c59c12740e165daee1751bef4c1b78", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "cli/__tests__/line-growth.test.mts", + "diagnostic": "Parameter `cfg` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "const writeConfig = (root: string, cfg: object) =>", + "fingerprint": "bd34da8b01cc792365ebdf5a488807f9610c963ea0ce98db7c36429df55070ef", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/decisions/__tests__/detect.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof ev.transcript_ref).toBe('string');", + "fingerprint": "bd364bfd5cb91baaacb2edd182f7229870565c4a2d1d7f5081673f06b33e60d6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const installScope = entry.installScope as HookInstallScope;", + "fingerprint": "bd3699184ccb81c07b7bf9955d97726063d6ec87e999f652d2b8f677adddb1dd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const promiseAction = (() => Promise.resolve('async')) as unknown as () => string;", + "fingerprint": "bd3df0b3d02e867a52919b295022ae758c7e1997b6e3cdf00b86e00ac1c99daa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/review/process/gate-supervisor.mts", + "diagnostic": "The explicit open dictionary type on binding `SIGNAL_EXIT_CODES` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const SIGNAL_EXIT_CODES: Record = {", + "fingerprint": "bd49ef29047f027e93d52fecc814a2d59216b7ae832ec3e68e0a50db3a63000d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/diagnostics.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof diagnostic.message === 'string' ? normalizeText(diagnostic.message) : 'diagnostic';", + "fingerprint": "bd785f61ff93aeb577e2ecf447bf56f2d4bbab4d1502d0ebfc2e83850d7933e0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/reconcile-detect-merged.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('node:child_process', () => ({ execFileSync: vi.fn() }));", + "fingerprint": "bda23603a6272502eea5abf62f85c641e46256394474c9d43ec463672a7c2a50", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/structure/__tests__/run.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof guardConfig === 'string' ? guardConfig : JSON.stringify(guardConfig),", + "fingerprint": "bdbe4e650666e9b04f5abee8c5e509b292f053e44c98fe0a16b67237152428ed", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const isRecord = (value: unknown): value is Record =>", + "fingerprint": "bdeeed3afccc1671e5bd1375c9cb27de53ade997ae2bf51204d16fdf7e91b8c2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "skills/correctness/scripts/checklist.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const review = typeof c.review === 'object' && c.review !== null ? c.review : {};", + "fingerprint": "be2aab86bbfed0cc13e2d51feef9998d519191701fce2111f14c00adc0f669c1", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/__tests__/tracker-fixtures.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as Error).message.startsWith('Path escapes repository:')) continue;", + "fingerprint": "be45cebd58148f3b0bdfd47363c4472ad46ca5b372406c3aa12381b664f597cd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "e2e/agents-hooks.e2e.test.mts", + "diagnostic": "Parameter `payload` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "const runHook = (fx: Fixture, hook: string, payload: object) => {", + "fingerprint": "be5c5dd2b73f2920253bd110b71b62f82efa7852140d99c6bc2c466d4def93e8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/dependency-preflight.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(parts[0] as string).length > 1 &&", + "fingerprint": "be5e8f8cdf34b89af3b0e76e4484f9d6932ddbe9318728ee8d351b97812036d1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/__tests__/review-setup-runtime.test.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(pkgRel ? { pkgRel } : {}),", + "fingerprint": "be648abda75ae071793a8bb4d97a021092b9820ff893a41282e00121ecb926ec", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/co-occurrence/chunk-index.mts", + "diagnostic": "The explicit anonymous object type on return value of `partitionFresh` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!verifier.enabled) return { fresh: pairs, dropped: [] };", + "fingerprint": "beb8ef605a83edf8926b3f323646845e3b4e875d5a00b74aabace30767540b81", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.mts", + "diagnostic": "Parameter `payload` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "payload: unknown,", + "fingerprint": "bedda1f13e11964cca6cb39dfa43cca52f729ad51755e7ca826f84299fde84dc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/upgrade.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "} else if ((picked as string[]).length) {", + "fingerprint": "bf504f9da76602ee534b7632c36b39e90c5024db2b9a2714dcd7fa8de761623b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof raw.sourceRoot !== 'string' ||", + "fingerprint": "bf94a8148d1fc3b8c4d74c2fab231424036aa8cb03d071babc75e4c86f46b434", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-type-aliases", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "Type alias `ExternalValue` hides `unknown`. Keep `unknown` explicit at the parsing boundary or on an allowed `cause` field; otherwise use the parsed owner type.", + "context": "type ExternalValue = unknown;", + "fingerprint": "bfd443c27e859991187c128a34f1fdc304c92b8ca396a586227d0b896c6ab28c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "got: majorityVerdict(tiers).verdict as FindingSeverity,", + "fingerprint": "bfff3a59975ae2a88b1e13bac117715e00014e8166def83c1b63150c44c0ef07", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/decisions/decisions.mts", + "diagnostic": "The explicit open dictionary type on binding `fm` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "fm = { slug, created: date };", + "fingerprint": "c0397858487d565be362b71ca12d94628957c19e97abce9d487fa80c46289fef", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "return state as unknown as ProjectionState;", + "fingerprint": "c039c7fe199651c3f4294e49a4ba8a7b625859446c9ae301a03a092df78e9a57", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/odb-probe.mts", + "diagnostic": "Parameter `e` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function message(e: unknown): string {", + "fingerprint": "c0664709b66e9df444f7131e9b6f7f128bd7105281a44acf38a50f991b6633cb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "typeof (value as { then?: unknown }).then === 'function'", + "fingerprint": "c093c1a7f8808c71f078d2ae5fb8ff911e28eb071f6014175d3ecf705277a623", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/clean.mts", + "diagnostic": "Rename symbol \"SettingsShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const codex = readJson(codexP) as SettingsShape | null;", + "fingerprint": "c0a8030d4c95d9ca5bcfec43f10bbf91e583ac44308ddc7be89afe6f4f7b0c42", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "workId: workId as unknown as string,", + "fingerprint": "c15997c01258210eecf2d1be0e04127fcb098407ca0665b3a603ad8e80b8972d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "return { errors, mode: source.mode, ...(source.ref ? { ref: source.ref } : {}) };", + "fingerprint": "c19202f9f4eed8faa582a0b96b60127000ae6ce49e6c84ca7d7b21ccd1a87d23", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Rename symbol \"validateContractShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "validateContractShape(root.contract);", + "fingerprint": "c1a2f583ff1b39e9e4c0d514bb94962a6c04282fbb06292682b6b3b4cb60ed4e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? buildGoldPrompt(r.slot as GoldSlot, r.findings)", + "fingerprint": "c1d4e5ceae0ae95d28b3b878c60ae4c5b228066c512fddcba07b1d8996b4b329", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prefix-cache/config-fingerprint.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const obj = v as Record;", + "fingerprint": "c1ec7e62438b0f3b2dadd422a6b6ab4f4851e66b8b35eed3d31d7e50d1e24ca9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "The explicit anonymous object type on return value of `editableDocument` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { root, hooks: dataRecord(root.hooks) };", + "fingerprint": "c1f28ab72284dbfa9752cb349cb11f1380be8904a71ae00d1a9ab3413df3ebc4", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "owner = JSON.parse(snapshot.bytes.toString('utf8')) as unknown;", + "fingerprint": "c216aa13e74487a5302732b70c49b72e4f14e602d1991ba98ae741dea4e57fbb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseProfile(value: unknown): ReviewProfile {", + "fingerprint": "c2d5daf12676f651e745c46259c74902c305416334679a0432350df47f34aeac", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/runtime.mts", + "diagnostic": "The explicit anonymous object type on return value of `resolveReviewerIdentities` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (reviewMode) return { identities: identitySalts, cacheSalts: identitySalts };", + "fingerprint": "c2e1d2ee22a9f272bf31bf1d821c2ed96a43a9283fb7ce5311a39673e43d1928", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof cfg.maxLines === 'number' &&", + "fingerprint": "c3297fc58e11a215e678cab5bdb9c70d46ff7f6a65c52523c2d61c02c3d72e22", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof c !== 'object' || c === null) return undefined;", + "fingerprint": "c338b3933f7a865ca82b4fbda22956011eb9eb921e622afc07240e2ccb89c892", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/pre-push.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `seedRepository` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "c360e90361455b70604aaf3608c8b7e2d1da925d5d0d8edc4e8ebd9997dc64db", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as number;", + "fingerprint": "c368fbdd6183cb3b221b1d1e0547bfdb0e960bdcd49931affb5e071ae3f99be7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/runtime.mts", + "diagnostic": "The explicit anonymous object type on return value of `resolveReviewerIdentities` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { identities, cacheSalts };", + "fingerprint": "c3806acd47ecb6f7ca98a8f15134982d9448a693cf2fc33da4e0c9c6bfe24a3e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/update.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "bunCalls().some((c) => (c[1] as string[] | undefined)?.[0] === 'install');", + "fingerprint": "c38663e95255adae0dac92baec42fc4bc4f1b29dbc0833887874f0156938da20", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return JSON.parse(", + "fingerprint": "c3921fd56e33333af0f7a8507b3084894f79cc286c4d91a6b453d9041a30f3c0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return raw ? (JSON.parse(raw) as CheckpointEnvelope) : undefined;", + "fingerprint": "c3c845e4c5e21d6a16120ef90d86e244d0398a1b4c4cb33e3ebfbd05e7f1bc8b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const existing = parsed as unknown as BenchmarkEvent;", + "fingerprint": "c3d932ba42f99a318d25f95a2ec5ce81903b3237b38d9df90ca220ec5d96de62", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/doctor/pin-checks.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "return !!v && typeof v === 'object' && DEP in (v as Record);", + "fingerprint": "c41112926aa76706cfd4e4d8da8faab0ce4209dee2931d76729b270ab3a44104", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/hook-registration-ledger/codec.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(() => hookRegistrationDestination('other' as 'claude', 'shared')).toThrow(/provider/);", + "fingerprint": "c41a8a96fe6b0366f64012ed5be2a9f21a4fd7bacca1d4b43191bb8d10d376d5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/release.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('node:child_process', () => ({ execFileSync: vi.fn() }));", + "fingerprint": "c43c7d4d6f0b428c58fad92fc6db2a1f3a21cb4cc46270eb0d0f15c939e4fb97", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.generation === 'string' &&", + "fingerprint": "c51fd24fc1d4e19d86e6c311135b03b6a65da0efd8d9bf15356207bd2cd91597", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/search-tool/search-tool-counter.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "payload = JSON.parse(readFileSync(0, 'utf8')) as PostToolUsePayload;", + "fingerprint": "c52d269bf6d7fed3fe48e69fbc69ced09c7f106dfa33da908034bbccb78ac8fa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/sentry/verdict-cache.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (hit && typeof hit.verdict === 'string' && CACHEABLE.has(hit.verdict)) {", + "fingerprint": "c55a8270f9cec0a6dfd99e5291a747f72e4b055997738f7893bbb1bef652b609", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const object = value as Record;", + "fingerprint": "c56f24db25ced5227c1f091623a04d366aaf346576e129613927b251449e4c4c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "!(ASSESSMENTS as readonly string[]).includes(requestedAssessment)", + "fingerprint": "c5937bfecddb8c14b36279103b92444e861483606e7f13745d646bfd2b7d4b40", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function oneOf(values: readonly string[], value: unknown): boolean {", + "fingerprint": "c6148eefd0053418dbe013628e93278a7373bd030cf7fefd30b8adc0f358f1dc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/dependency-preflight.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "devDependencies?: Record;", + "fingerprint": "c63009cf1996ec1c8f360af5a7ed860ce448996602405e93d4823e7a00efd776", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/baseline-gate.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const value = parsed as Partial;", + "fingerprint": "c63e58d0a26083ae2e4a9d59b9fa6a07183580843c3e9624ea40c6c52393b826", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/diff-archive.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(existsSync(path.join(dir, refB as string))).toBe(true);", + "fingerprint": "c66cea68b31c1734288f0ccc88f7da4e2e097527d1e3e963a429210f692c6391", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "args[1] as string,", + "fingerprint": "c6cbfd0ee8a092486a6faa42eb298d89003fe0a0e132036bdc8c346a433330cd", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "questions: questions as never,", + "fingerprint": "c6cdbe77dd1505fa71c520a1388f4a1199f088b91d6a764331c29a06eecf4da6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const baseline = JSON.parse(baselineRaw) as Summary;", + "fingerprint": "c6d93c65252fa177d0eb88a070553ac3656b674610e204f0ee69f9a6244fc2f3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/provider-adapters/claude-subagent-stop.test.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const adapt = (value: unknown) => adaptClaudeFeatureCritiqueSubagentStop(value, { repository });", + "fingerprint": "c6df427ff31e4ebee1e05f555fdd69066bc468797758e88655491a9f63677dac", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function verifyRelativeEntryPath(entry: Record): void {", + "fingerprint": "c70db19c8ab129041d9ce0e8227169ad4424dfcd86cbca955f933f92c7f16469", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value.method !== 'string' || !value.method)", + "fingerprint": "c71204f304ef879a1637fb6c6a9c425f26b635b01aeabc377072612670d7463b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(res.itemsRef ? { items_ref: res.itemsRef } : {}),", + "fingerprint": "c72cdc9f482201229f70cce473db9610190c13b4cee1fb93db28f02d4b3cc3a0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const verdictOk = row.expectVerdict.includes(v.verdict as Verdict);", + "fingerprint": "c72e8e1e5d1e1ac834436c3d5e5894f7441f5ce32d2654b5e2bdb5181dc2f6b6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-gate-supervisor.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect((result.cause as Error).message).toMatch(/inspection unavailable/);", + "fingerprint": "c73482cc5ba4041a56165dbb973fef11864a935645502982dae0d21ec2f0e09d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/__tests__/judge-exec-telemetry.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function events(): Record[] {", + "fingerprint": "c73623813b1cc81e2a3b42cb2022eb0fc297f119d334fec49fe6c341c423d2d7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value !== null && typeof value !== 'string')", + "fingerprint": "c752a86c7fbc06d2e4f1d57b0961899f7384ed1af8766b394db9633308efecef", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/doctor-search-index.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "guardConfig?: Record;", + "fingerprint": "c77e84def00822597fc666acd4f45a3f25678735f373f4624e525b4178ba94cb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const spoofed = {", + "fingerprint": "c786feaf830969c8ed035d86f3e88c3302f38ee39fcc270e9078e5912bf2ee42", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/sources.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": ".filter((p) => p.type === 'text' && typeof p.text === 'string')", + "fingerprint": "c798cb6bbd0f7dd2d9b06abb36d4388ba76edb27cfc7cf3e26194a83d876c7d3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "skills/_devkit/checklist-store.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const filePath = () => (typeof path === 'function' ? path() : path);", + "fingerprint": "c7b8a39f0cdd3592835623aeda6a695f8f70290a869c80c6cf8c3bc848ad7be9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const binding = JSON.parse(readFileSync(file, 'utf8')) as Record;", + "fingerprint": "c7d6474c3d83474b1d7e6731e9556037b34992f3a34c92e7dc81bfbd9f22af99", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const { importWallExempt = [] } = (await import(pathToFileURL(file).href)) as ExemptModule;", + "fingerprint": "c7e4d19f810db93ec762ba4fe5cb8da8253919854e4ed66893f092c14b305680", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseEntry(value: unknown): ProjectionEntry {", + "fingerprint": "c7e56775f57c0f16a5af3386a9babd5e96cba35bc3bc62463e9eed040f9b7196", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "The explicit anonymous object type on return value of `loadBindings` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!directory) return { bindings: [], candidates: 0, malformed: false };", + "fingerprint": "c7ee058232850734e8a9c59d474534331f25fa5651b047cbfff6d92864f9d2db", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/components.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function dropUndecided>(", + "fingerprint": "c8043c557060b3074a2e0e886cc156ea0bc5c8bd9856d6c57c77555f9731ba3c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/run-review.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "emitCacheHit(`review:${c.name}`, c.model as string, c.duration);", + "fingerprint": "c813d5e48cee47a27d80fdcb04960f731f666e1550b1279da35bad673172a34e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseEntry(value: unknown): ReviewSetupRuntimeEntry {", + "fingerprint": "c82d0881c587340b9b9abccd9787ae4fec91d5ce1fde560ee171534a50e577c6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "(record as unknown as Record).unexpected = true;", + "fingerprint": "c92b482cf040e7fc53cf4220091785f23f902da05138da654f6dbbaa9033dc6e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function verifyEntryFingerprint(entry: Record, name: string): void {", + "fingerprint": "c92eb0b9186afbd6c11163bc48763bd410be938cbbe2ba9a94bccb5147eed8b9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/decisions/decisions.mts", + "diagnostic": "The explicit open dictionary type on binding `fm` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "fm = { slug, created: parsed.fm.created || date };", + "fingerprint": "c935ca267813dea43324795ee7c9e84e326b7071d6fa58f319efe59afea638d9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/immutable-file.mts", + "diagnostic": "The explicit anonymous object type on return value of `filePath` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { directory: identity, file: path.join(identity.realPath, name) };", + "fingerprint": "c94809c1f22b4d548d8be643abf5ec9f30a3f7572ee6b3b9dc492661ef473a89", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as Record;", + "fingerprint": "c95f6c4843d0670ea737481bc9797f60c2e11cdd37da7a4867b9b724704e7696", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const parsed = JSON.parse(source) as Record;", + "fingerprint": "c9874ef79d07e2cfcc31007ce76a44541a98e22df67184c82a684c3d9d927f2e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/asset-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const result = materializeReviewAssetRuntime(args[1] as string, args[2] as string);", + "fingerprint": "c99e52b441c8fb0f4bc131bbf9f0bac9bb5c68e985f43434fbabb0a33555b0d0", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "const reviewed = (overrides: Partial = {}): unknown => ({", + "fingerprint": "c9b372fa40f36f1527bb53d160f42d699e8857e0a33ee677b72352933accf764", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/cache/root.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((cause as NodeJS.ErrnoException).code !== 'EEXIST') {", + "fingerprint": "c9ca4eee3b6f7cb11eeb524d57668e1c2f30646f6be039557c4ca935d336b3b6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/scrub.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value && typeof value === 'object')", + "fingerprint": "c9cf722660a8930646c31f326b3855386f25df6bb69617d0d37df3ff9c87f577", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/verdict-cache.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = JSON.parse(", + "fingerprint": "c9d19b8b761d1f025a6a7c2faef2df1063c9c7ba776298477cd952886d53e094", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const raw = JSON.parse(readFileSync(baselineFile, 'utf8')) as Partial;", + "fingerprint": "c9e294c2218040bba6c4857d9cc7a92dc906c22bac710036fa565ec6f1889e80", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prefix-cache/prefix-cache.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = JSON.parse(", + "fingerprint": "ca79c244f536327199799b9ca4d43f28425f0a20393b9626618cfe69bbfc3cf5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/doctor-version.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('node:child_process', () => ({ execFileSync: vi.fn() }));", + "fingerprint": "ca802d437d2d2520e73ccb96ff71c2ba65692a822c5a5d883fde90354c6bda14", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.acceptance.reason !== 'string'", + "fingerprint": "cb2f7ab0948d4b1cb85522c58337e6d57a49ab635573c81d307d8257cabab310", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (cause as NodeJS.ErrnoException).code !== 'ESRCH';", + "fingerprint": "cb40fb3c1ac2a31456e1bc2f4b1b73975b4f20c9add61d7846a14fa52800875a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/hook-registration-ledger/lifecycle.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "): { group: Record; hooks: unknown[] | null } | null {", + "fingerprint": "cb62abc75de68160901452397132efa042dd383d569d18b677d7579e2dbfebd1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "type Metadata = Record;", + "fingerprint": "cb72b4a5a7aaf50432e65b019a03580271e579454cc21b2a8874c4b6afcae6fd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/commands/init.mts", + "diagnostic": "The explicit open dictionary type on binding `map` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const map: Record = {", + "fingerprint": "cb73df0f10909115f8d6ed434048a5e0747d9a1d2b92775bae5ce7ce3ca28c35", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof f?.evidence?.reviewed !== 'boolean')", + "fingerprint": "cc970506124f4ea4590dfd9dd94d1aa1a295e2619a73635bf7eed3d3c3322741", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/recall/embeddings.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const data = (await res.json()) as EmbedResponse | null;", + "fingerprint": "ccac79a86324e3f585e30a13d719bae1a0f2f09dbafafbe46faa9e716edac6e9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "e2e/lib/__tests__/harness.unit.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(out({ stdout: undefined, stderr: undefined } as never)).toBe('');", + "fingerprint": "ccc09ee51a0854a5ec3eaad93b3de8f2b6262c760e5a49b9f05f98b48df80bfd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "Parameter `error` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "main().catch((error: unknown) => {", + "fingerprint": "ccefcac617ec9362aa88677b6e892f496f68a288394592e726f971096099a7a6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/pin-checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = readJson(join(cwd, 'package.json')) as {", + "fingerprint": "ccf1084b0e80a09caaaee57ce7ec40ef34aff91d94c3d391e2f97ea64328cf46", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "value: unknown,", + "fingerprint": "cd2c8be03c8db0e316cc57a92b1d81b409c9cc75e74c33f2f8e20ed29d7aef3e", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/co-occurrence/__tests__/index-refresh.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function freshnessDb(rows: Record[]): IndexFreshnessDb {", + "fingerprint": "cd51cef68d97b7613b5986c2dbd616797c618bdb6e55b1a66010f1158200e296", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-repository-state.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const tampered = JSON.parse(readFileSync(first.manifest, 'utf8')) as {", + "fingerprint": "cd52da57f52a460e2c74e997a41de41ad9124080fc3191ef747a427371ce7129", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-repository-state.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(Buffer.from(attached.state.headSymrefBase64 as string, 'base64').toString()).toBe(", + "fingerprint": "cd836f6884432f98b58cb71675b24b08b67fc946810eed2d3837b3c2dd31c042", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/doctor-bundle-completeness.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const m = JSON.parse(readFileSync(p, 'utf8')) as {", + "fingerprint": "cd9059b4b347ea5fce16f9ba38742a62aec132183dcc45a6f697f29281955d65", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/__tests__/waive.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof stored.at).toBe('string');", + "fingerprint": "cd9ebbcaf86ab55961722d2258551d495f55a948bd17f8b41b0561cc8f9149a5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const checkpoint = parsedCheckpoint as unknown as CheckpointEnvelope;", + "fingerprint": "cd9fc55ff96c49ac649677fed73f5a71deba3e7b7025195593271faaa17f9fe7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value !== 'string') fail('invalid setup runtime entry.');", + "fingerprint": "cddb332a83980c30f8ff99a9187d17592138c31968bf146d1748853dee24fdac", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit anonymous object type on return value of `status` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (view.event.evidence === 'accepted') return { mark: '✓', label: 'accepted', tone: 'good' };", + "fingerprint": "ce287e1fefb969ec075eb0d3d6b8e1ec16eb37a6b4a96be40158103422a1a381", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "anti-slop/src/shared/lexical-type-parameters.ts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value === \"object\" &&", + "fingerprint": "ce48072c85800cf1c77a167f6c88de7dbc1c647ae67304acef3435f9cfb6b8bd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "requireValue(typeof root.critiqueId === 'string' && ID.test(root.critiqueId), '$.critiqueId');", + "fingerprint": "cea0bfa5525d96f73477d4951e389f3abff4ed7481d4dab8e01d29d5913dfdd9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/__tests__/judge-exec-telemetry.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof ev.duration_ms).toBe('number');", + "fingerprint": "cf1a2c1d7535bf9cb368f68a62db7999dc9f7d090a55fb5bcc99f1c461a62efe", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/install-fallow.mts", + "diagnostic": "The explicit anonymous object type on return value of `wireFallowGate` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { ok: status === 0 };", + "fingerprint": "cf7a6907e55ac3fe9a6ba6bea6e9b3cdb3b6f1dd26ff849b74a7eb4cce299186", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "return raw as unknown as ParsedManifestHeader;", + "fingerprint": "cfa30c8d6365a61616d0d296a6611f82266a059f6e4ae356d0c1df31d48fd5a2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/config.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {", + "fingerprint": "cfa6cf950c2a663d4f0a6402c2273870323e0f04544c2436547b5f97398a5f75", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/overlay.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../lib/install/install-fallow.mts', async (importOriginal) => ({", + "fingerprint": "cfdbc7a5627cbbfc335415d23c91abbe67407240025191505b1440136fb31dae", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/devkit-version.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof manifest.version === 'string' &&", + "fingerprint": "cfea52ea729356dbd4eef4e84d191a331cec733175d28bdb36fff45229ae9fe7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const value = JSON.parse(readFileSync(file, 'utf8')) as Record;", + "fingerprint": "d01e116d329c1392165349bf535b159e2bac4b6309f8a6a1a93d5ed3a2c18a13", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/commands/init.mts", + "diagnostic": "The explicit open dictionary type on binding `STRUCTURE_TEMPLATE_FILES` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const STRUCTURE_TEMPLATE_FILES: Record = {", + "fingerprint": "d08832828826b6563dadde07953dfa20fb5f2a6198877aa45f555e0ad4122f3a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/sentry/check-sentry.mts", + "diagnostic": "Parameter `raw` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function parseSentryVerdict(raw: unknown): string | null {", + "fingerprint": "d0b155f36b5ed609d15f8d4dc2461921b7270d93df4ba39c239ec1e1d26dbb09", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const spoofed = {", + "fingerprint": "d0b3952c763943c1850e380d6ed6b1d910349ff3cb2385823345f0cd87a29bc5", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/doctor.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cfg = (readJson(join(cwd, '.devkit', 'config.json')) ?? {}) as DevkitConfig;", + "fingerprint": "d1025e13b1e97a8121ccecf23f50175d9b21fb078a2f979136d99e26634b67c0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "agents-hooks/decision-edit-guard.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed))", + "fingerprint": "d11f0380020a67f7b85d4ef447fc2d9c1c43b5be0438fcf22d1130635206f944", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))", + "fingerprint": "d1226b96012020e77611891f6f3973d2038b0e4f3f3e21c310f5f1d234b8ba9d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/commands/migrate-config.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const tpl: Record | null = readJson(", + "fingerprint": "d16c11ff214e8e74102875bb34aa7a7f322d1669107fbf28541ff8555076c063", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/__tests__/review-fixes.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ".map((line) => (JSON.parse(line) as BenchmarkEvent).id);", + "fingerprint": "d256c6277755eee17974cf36360c7c957501d8cffc9c7a3ce51ac2bc1b2e5d74", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/read-stdin-body.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `seedShipRepo` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "d26d1afec338ff1b0fc8a57c665a8dcfebc45cb5d531a05412d429303438d709", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/scrub.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof text !== 'string' || !text) return [];", + "fingerprint": "d2d3f946111b069229c6c2a295b3f21ed1dac8af52a67742741afbde311f9ac9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/matcher.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "rows = db", + "fingerprint": "d2fb9389bd3840c25092e8e40d9adcb57890b57d70bef63ece3979d939901006", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return Object.freeze({", + "fingerprint": "d3177fa3e9b980bf0473d356c1016d5e8978561e5e7dff518ec5fc19946c8a91", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "parsedCheckpoint = JSON.parse(content) as unknown;", + "fingerprint": "d33622355262e0c4cf894dd69187d15437735abcdc4528fdb18ef34907681f22", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/eval/recall/scoring.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const base = {", + "fingerprint": "d3ab4e97f9dab4ea5a6f84c20231b1cca634ffb9fc7c9c0ce6517c53fecc5a11", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/mine-telemetry-lib.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof issuesJson === 'string' && issuesJson.trim()) {", + "fingerprint": "d3b58a023e87cd51bb64d678b78f4557fa711dfc889b5460611a0b87e38379b3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/recovery/settle.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(res.waivers?.length ? { waivers: res.waivers } : {}),", + "fingerprint": "d3fe80cb49bc8691f1d8d5da8eff65b99a765d2c2d756090b6d34d9981ed6243", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/match.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof b === 'string' &&", + "fingerprint": "d40be5bfdea4aa2b5e458a6226c41c2fd438b1bc54b5ab49a2a261678ff3dc94", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseAnalysis(value: unknown, path: string, allowBlank: boolean): PlanCritiqueAnalysis {", + "fingerprint": "d41f6c2d81ec4f8be0d2cb0a71aedbe2f185fc9326c8ada95115c956f40ed014", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!item || typeof item !== 'object' || Array.isArray(item)) return item;", + "fingerprint": "d49811d1461ac6866eb033ed8e9bcd1a0a513474fd843eb20eb730c0481eb08a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value === 'object' && value !== null && !Array.isArray(value);", + "fingerprint": "d49be29fe016b34c78e759c5f95fa1b8dc5fe6ded1f1488ab7aac1424d9bbc17", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/release.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = JSON.parse(pkgRaw) as { name: string; version: string };", + "fingerprint": "d4c25c8e78884dd9847b0e78e4ec8ed22d0db619cb46641b6da0f48508a36922", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "execWorkflow: (async () => ({ raw: raws[spawned++] })) as never,", + "fingerprint": "d54232905d3a55ec7fce86ba4dc32817c67304084d8cbeffab9900f607a62299", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/__tests__/run-context.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof env.branch).toBe('string');", + "fingerprint": "d54c3d314f6b51d5996b5fdaabda54668f59344125b487d318a76d03e971947e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "gate-engine/review/eval/bench.mts", + "diagnostic": "Parameter `entry` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "function appendLedger(entry: object) {", + "fingerprint": "d58e8da1519f8c457685085f1bc790e4528f350b81b0655a3d7de6632d7a2220", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/husky/self-host.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = readJson(join(cwd, 'package.json')) as { name?: string } | null;", + "fingerprint": "d597850feb8031dea9a68fe3066a4b98fce8666224cb78854de590a6cc4f2e6d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function cachedLensFields(res: ReviewOutcome): Record {", + "fingerprint": "d5a3b6f601d30fb83dbc4d867013a68416fc5ff72b2d39dc869e5b3e28b93610", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/eval/recall/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const rows = parseCasesText(readFileSync(CASES, 'utf8')) as RecallCase[];", + "fingerprint": "d5c8449e3be3ca40cc903b7fba55cc4bc59fbe4e01e565494b1c3a08d238ed09", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "agents-hooks/decision-edit-guard.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (PATH_KEYS.has(key) && typeof item === \"string\" && item.trim())", + "fingerprint": "d60dd2b11f1e59208a2c20145212a5f7dfce1359888f1ece27139654c1907876", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const native = row as Json;", + "fingerprint": "d634874ddfa0ede1d6e6d16ce16611fe5998ae02c7d3d1a667af0956544cba3f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/package-json.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = readJson(pkgPath) as PackageJson | null;", + "fingerprint": "d640891bb6045bbd2f6345c721dbf6173744ef7d5ca348a183fb47a9dbe7e463", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/integrity/checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "...PROSE_FIELD_KEYS.map((k) => [k, block.fields[k] ?? ''] as [string, string]),", + "fingerprint": "d650f7fcda63e4e557ac460d84d2e8bb0c925df0f5b9c25cf1452d6242d754d0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "state: 'not_started' as 'not_started' | 'running' | 'completed',", + "fingerprint": "d678d7ae1c13802aa6cfb067307a7364e90f58fc4947bd0e0c9fbc1361700f8d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseObject(value: unknown): PlanCritiqueResponseV1 {", + "fingerprint": "d6949dded29b6fc0613d6ddc1a3b13d06eb80f461bbad45ecbf20f5961122b18", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/__tests__/response-contract.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const noSummary = { ...REVIEWED_RESPONSE } as Record;", + "fingerprint": "d6da41131f8fae8163763d233a4fab9f3e72561fb42e4981358ced205b939a99", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!(allowed as readonly string[]).includes(text))", + "fingerprint": "d720cf392b784122ac8dd241726080981d088d125bae0efe99e82c04562d8f20", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return { event: value as BenchmarkEvent, line };", + "fingerprint": "d7cd8aa6a4b7e83ffd830cba09be25bf569b1e8653597ea322a35479af62e17a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/immutable-file.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(lstatSync(directory as string).mode & 0o777).toBe(0o700);", + "fingerprint": "d808964c790fc82a572a5e55cecaa0ff991e28fc1287001d3d28af2a9fc7364e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/agent-asset-manifest/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;", + "fingerprint": "d8120789bbd65880a4113a55013052e72ad91a4e661e97509b8965eab2933f0f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "value.ruleIds.every((id) => typeof id === 'string') &&", + "fingerprint": "d83efdcddeef98eb985e0c24575e20f9901752b595729a900ccdafa3f84cfd3e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const corpus = parseCasesText(", + "fingerprint": "d84a5939cbbc5eb32e2d63fe2b9aa4684222fbe9a8a945c131286e55b5b60acf", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/doctor-version.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "readJson(join(packageDir(), 'package.json')) as { version?: string } | null", + "fingerprint": "d8d35cde216708c471d218765062fc28319db325ef9970edbedf95c2dea445ca", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const m = merged as unknown as { items?: unknown[]; itemTally: Record };", + "fingerprint": "d8dbdd916a6b70d6b7f80ff420b9b25765ef8d3c05777a0c01aa3af91c1346d3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(res.items ? { items: res.items } : {}),", + "fingerprint": "d8fa8b6a4a0f347e1dce8245d307db76a290e9435659e55a5fe5951f9fa17ede", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/husky/husky-block.mts", + "diagnostic": "The explicit anonymous object type on return value of `removeGuardBlock` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { content: hookContent.slice(0, from) + hookContent.slice(to), removed: true };", + "fingerprint": "d8fc63c213ee9718c79a3ebcdb7d08eb7ee1ed228e8f225c2dc8068f7f1fcb67", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value !== 'string') fail('invalid setup runtime fields.');", + "fingerprint": "d932338b1e3dc2afa2331943c812b4888c2a1cab4f8fad861b4a32027b54a7f6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "e2e/anti-slop.e2e.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const recovered = JSON.parse(readFileSync(join(fx.repoDir, '.devkit/config.json'), 'utf8')) as {", + "fingerprint": "d96b1ad4c7ff9212ad468dd91b5d81dfaacbf11114153b17ea801657d6f55669", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/doctor-search-index.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `repo` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "d9e5f66dba44ddce89ea78cb1f50e9097e48ef11ef628f5f13043256f4d347f0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/husky/self-host.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = readJson(join(cwd, 'package.json')) as { bin?: Record } | null;", + "fingerprint": "da173ac0939b9c0675194e966ddda882143b3d84cd028b2de4b7d38e99fbb138", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/__tests__/response-contract.test.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const raw = (value: unknown): string => JSON.stringify(value);", + "fingerprint": "da23ebc28168c998c0923d3ae7cd8bdbdc505887d1eebd8d35a452729b0cfad1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/reconcile-detect-merged.test.mts", + "diagnostic": "The explicit anonymous object type on assertion discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "(e as unknown as { stderr: string }).stderr = 'gh: could not resolve to a Repository';", + "fingerprint": "da2905769a00b192526d24a33350bf128cd46d3f7e22beb145755d9c057567fc", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return value as Record;", + "fingerprint": "da55c4e859951115da11ac5610a23be70c2267492884cb8ed85385d537127b99", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/detect-stack.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = readJson(join(cwd, 'package.json')) as PackageJson | null;", + "fingerprint": "da9b124d74f688d1f29358fe96413fb19caa4b280c15c51831f07e27e847facf", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/agent-assets/agent-surfaces.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const targets = (selection.agentTargets ?? AGENT_TARGETS) as AgentProvider[];", + "fingerprint": "daa7f810f83af9f0af9d5ba02ebd571dd1c289b65fd9db799be926b93f209204", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const event = parsed as BenchmarkEvent;", + "fingerprint": "dadf46edfe981f92fca96ec75431a8a989cbde802ef93cfe61c976c67fd440c7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof identity.provider !== 'string' ||", + "fingerprint": "db033e2c73bea8635d70bd33e919adc0ac56e299f1888b804cc2a18c2dd8a26f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "ms: entries.reduce((sum, e) => sum + (typeof e.ms === 'number' ? e.ms : 0), 0),", + "fingerprint": "db1151c1e9f5f988667fa6b39624e86e3f81ea6decbc54aab266364b8aff0b39", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const cfg = readJson(join(cwd, '.devkit', 'config.json')) as DevkitConfig | null;", + "fingerprint": "db841832e02b20d23d75dd562b18b85c09b3e4885475f46c104ddc22187b6c4e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "process.exit(e.code as number);", + "fingerprint": "db9cdf33f3824cdcf239115fefcfff989501dff2871f04ac88b78efe006b8d59", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function dataArray(value: unknown, label: string, budget: DecodeBudget): unknown[] {", + "fingerprint": "dbfc117ca6bdae83acab1200ca487e5b6a487d726aebd0ca5c3e235a2fcd4f2a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "e2e/agents-hooks.e2e.test.mts", + "diagnostic": "Parameter `payload` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "const runNodeHook = (fx: Fixture, hook: string, payload: object) =>", + "fingerprint": "dc3233d3feb099772c7855c45872aef108da710ebf2ab4aa8adde6f3da8ad4d7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/__tests__/allowlist-integration.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (e as { status: number }).status;", + "fingerprint": "dc770773198b3b6c6d235f51dd2cc3d91df3562c3125149cfb33de646849bfc4", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "The explicit anonymous object type on return value of `clear` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (raw === null) return { state: 'absent' };", + "fingerprint": "dc8ac717f9af1cc9fb5839a23b24ae9d3bc1a9d2289062058aaa13230dd2716d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/overlay.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const prior = readJson(join(cwd, '.devkit', 'config.json')) as {", + "fingerprint": "dca4dd940864acc1fddcf3eabe6fa9864d5a25668a27bf327184c5fa67d348dd", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const payload = JSON.parse(result.stdout) as { diagnostics?: Array<{ code?: unknown }> };", + "fingerprint": "dce2f667605cf91d633ff0fd4309e4e6896665573626e7ebb7e44f074cd6422f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(parsePriorArtResponse(raw(reviewed({ legs: legs as never }))).ok).toBe(true);", + "fingerprint": "dce5e225803a815f9dfa927c28371556b1c1a661ecec0df6d6f416da20ae9448", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/run-review.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "fingerprint: (m as RegExpMatchArray)[1],", + "fingerprint": "dd18d54f8bfd442d589d6711814005648bb5d2d06c91f1862bf0642f8eb9d385", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "mergeItemVectors(merged as never, parts.map((p) => p.res) as never);", + "fingerprint": "dd37c996095f0a76e007e12729d4172b86c28fdceb7dca7d158ebb0190a8412f", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/doctor/guard-config-checks.mts", + "diagnostic": "The explicit open dictionary type on binding `REQUIRED_DOMAINS` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const REQUIRED_DOMAINS: Partial> = {", + "fingerprint": "dde5dc1f5576d823cd843141a7d98bca932b744412135bb1dcf8cd4c7c2b4382", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof cfg.maxLines === 'number' && Number.isFinite(cfg.maxLines) && cfg.maxLines >= 0;", + "fingerprint": "ddf298181b6328348a14554e226c5352fca2071a9de49e1f031c700a2ae8d727", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const parsed = JSON.parse(source) as Record;", + "fingerprint": "ddfef2deeaaf48e65303813b16b88e42ae34c4874228fe27ee29765acc6d4097", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/eval/bench.mts", + "diagnostic": "The explicit anonymous object type on binding `tag` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "} = {", + "fingerprint": "de1982b5dea2bf120e1a52c6a6b059a0d9094a794f590986012e388d3fd78d11", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/diff-archive.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (dirs.length) rmSync(dirs.pop() as string, { recursive: true, force: true });", + "fingerprint": "de1dc91900b3f03e742f1027a777151ed82b428840cf6c53b4480acc83b83d0e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/catalog.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!(LIFECYCLES as readonly string[]).includes(suite.lifecycle))", + "fingerprint": "de843232ae232c495d80eb9796876783e2157f1d80eff0e87896c8f0ca4410ad", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/co-occurrence/chunk-index.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "rawCode: typeof row.raw_code === 'string' ? row.raw_code : null,", + "fingerprint": "de873055fab804532fbe9665b4da32a5aff1cc0d3592d17be5fb414a34ede9bc", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(usage ? { extra: { ...usage } } : {}),", + "fingerprint": "ded0fc08edaaf9cd92a5233f45e3df791ccb5911fe24baec44da8c172158e547", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/evidence/items.mts", + "diagnostic": "The explicit open dictionary type on return value of `tally` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return counts;", + "fingerprint": "defa2ca2ba0a9e9af913dac5f8445f7bf0bfb27a03184169df83768a793e26fd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/capture-normalizer.mts", + "diagnostic": "The explicit anonymous object type on return value of `deriveResponseEvidence` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { contract: invalidContract() };", + "fingerprint": "df16269cc0521211f86ab36773ec14a715a2c80c6c2f14847ecc3dd29cebd03b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/integrity/checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "['positive', block.positive] as [string, string],", + "fingerprint": "df3af8e7a0ff1e628d372141305b21675e1e231cf8a9a77bb0280309bdf373e1", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "args[2] as string,", + "fingerprint": "df3d1facbd66cf37d189f8fd2a541af90f761b4534e7082d086bce63a961b599", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/index.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = JSON.parse(", + "fingerprint": "df401bdf084aa059658561b3370fa0e6a084f412bfa97aa3e6c8d1733596fe24", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value[key] === 'string' && SHA256_RE.test(value[key])", + "fingerprint": "df47b77f5570a59a56c9906451e375dcb1e379a9faf56ac4df5374befba238d6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/sentry/check-sentry.mts", + "diagnostic": "Parameter `raw` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function extractEvidence(raw: unknown): string {", + "fingerprint": "df6e5b58a8009bc783efef73fd42dfb98cb4663fbf6575da69e5c55df389d3a5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function validateExecution(value: unknown): void {", + "fingerprint": "df94b7d230e4a36ff0b5a5f0e6c82b38b30c28e2762dafc136ad56f50e23da8b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "The explicit anonymous object type on assertion discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const m = merged as unknown as {", + "fingerprint": "df97165ad834253cf0235bece2c9221b05d18a83ae24b05d1d00ca4dd17c6005", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/install/package-json.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(sel.husky ? { husky: '^9.1.7' } : {}),", + "fingerprint": "e00719d22ee7e1333eeb6261ec4d278190e1ebd07e5502e6a83f40c6236138b7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "{", + "fingerprint": "e06c24eebf43f561afcc25071415403f8b17958374ee92eb08d50b48abe8e7e3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/anti-slop/vendored-source.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `sourceDigest` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { digest: hash.digest('hex'), files };", + "fingerprint": "e09656872fef60498c97108f564ba1e8da2cdce922e61f74c2ceea28bb4bdf2e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/dependency-runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof manifest.destinationFingerprint === 'string',", + "fingerprint": "e0ec9cdfa1e1e59597c779994952d48e0254bcf77030e2872a3eb397738e6f44", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/size-preflight.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const parsed = JSON.parse(text) as Partial;", + "fingerprint": "e10c0c35ed30d4ad3b000937654c53d276d6676b058d0a09a94e2c3ce1184bb1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/publish-lock.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof pid !== 'number') return 'invalid';", + "fingerprint": "e13b2d3c4544e24eccd9da512d4ae5c2198c73b9adf19f92e31ce57200e152b1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "return identity as unknown as PlanCritiqueWorkQuarantineIdentityV1;", + "fingerprint": "e156d8d38f1c5fc2b7b223623caac997eca394dfb09a2f472b389a16edd9afad", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function metricErrors(value: unknown, location: string): string[] {", + "fingerprint": "e179ca306e88f84f9d49d549aeebe268906bf08803a2c646413db3afefc9cf60", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/runtime-fingerprint.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const expected = pairs[index] as string;", + "fingerprint": "e1a35b101f3b6cbf5be003e63acaf9fa7cf60ee8442633bf94d25f88eb9dc564", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/baseline-fallow-paths.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!value || typeof value !== 'object') return value;", + "fingerprint": "e241882d0dfec00bbbce821693cbc05b6ec386231a9bab045d6755594c385cf9", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof json !== 'string' || Buffer.byteLength(json, 'utf8') > MAX_JSON_BYTES)", + "fingerprint": "e2d19c1130b02001297306eef542537c34d2822f29410ff7238da39f23b3cbc7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function plainRecord(value: unknown): Record | null {", + "fingerprint": "e317066689fc21d7740b6897e58e54e5241b6f3eda5b59c265f53c836dbe4f1b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "Parameter `row` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "? value.results.filter((row: unknown): row is Json => Boolean(row && typeof row === 'object'))", + "fingerprint": "e33bb72d90cf3a75db20caec8959614ba63d33be28025afb5a14dd9fbc7d7005", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/stray-gate-calls.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf8')) as {", + "fingerprint": "e34d089b0b3c108bb0edee2e62753d5193496dee43c9c1d3e94cfc0dab1829b7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (error as NodeJS.ErrnoException).code;", + "fingerprint": "e376f60af2b439d5eec861be12de95ec5eb5399a7ec04becd9556248285627c8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/judge/odb-probe.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const build = (n: number, cap: number): Record => {", + "fingerprint": "e3a6825e967fa60315b410879c2e0875e552d862df9e2cd173107ddae783f1b7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/agent-asset-manifest/lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;", + "fingerprint": "e3eacfffbcdbedb115dcde74a21723308baa25418e27fed59c3725b6aba38be5", + "count": 2 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const opaqueAsync = (async () => {", + "fingerprint": "e3f04c42b7b801006b454ccefd67eceb5cd6cf71b7660084334a497d36dd7fcb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-manifest-parse.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function manifestString(value: unknown, label: string): string {", + "fingerprint": "e3f29651bed3b4cff390276156b9fc16229d0f41d1720631db7d75cecd95ab28", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `aliasRoots` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "e3fdd77f8ef3b56702417896c4ca309936787cfafd39788167553592e27ab92b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/recall/categories.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (CATEGORIES as readonly string[]).includes(value);", + "fingerprint": "e408f3b0c2c2fb93a9fc783c9f0790bd90e7c5acbcb32df2ced415a28c31d8a3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/__tests__/verdict-store.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const owner = JSON.parse(readFileSync(`${file}.lock/owner.json`, 'utf8')) as {", + "fingerprint": "e41c3c3386388020137261520b81b88f8cd830c0b627286f8f845c04a56750c9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "e2e/lib/__tests__/harness.unit.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(out({ stdout: 'a', stderr: 'b' } as never)).toBe('ab');", + "fingerprint": "e446ac92353786136c33637b7349cecb8167a83b84c6742f4578bb03e6d274b7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/diagnostics.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof filename !== 'string' || !filename) throw new Error('diagnostic has no filename');", + "fingerprint": "e482276e35e5aa47d91ab848c6adb24665c07b2faaae90a71f7d588dd3dec3c1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.provenance.sourceCommit !== 'string' ||", + "fingerprint": "e48cf2d7d1de3a94405e1c41d6f607c8b2f656bddb6fdf2d51d5c87bf2b91cd3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(opts.durationMs === undefined ? {} : { duration_ms: opts.durationMs }),", + "fingerprint": "e4d821a982b99b3646ddcdc91ffff819a780d538f67d9467c3b769fe6bb0cb98", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/review-cache-root.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `initRepository` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { gitRoot: realpathSync(gitRoot), target: realpathSync(target) };", + "fingerprint": "e4f84cdd88590943b15d70f4daca691be0fd95a169a183ab4befdf4c931c9ea6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseDecisionLogAlignment(value: unknown, path: string): PlanCritiqueDecisionLogAlignment {", + "fingerprint": "e4faa812f5bc4d46e051bd6014110062beac5942ffbcef3c12b33b38f61150e2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit anonymous object type on return value of `status` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { mark: '!×', label: 'stale no-ship', tone: 'warn' };", + "fingerprint": "e500dd608bd2d74c7ac19aa52032b1111f0f5c22bedd3284dc587989668bd1b7", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/integrity/checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "['negative', block.negative] as [string, string],", + "fingerprint": "e5176854892402c7eb06d316a313bdbbb42ec1076108b6910a1c64e2030665c2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!input || typeof input !== 'object' || Array.isArray(input))", + "fingerprint": "e5301c876314d13f86ec5fc319b21c1204b1044a526450068bf5a7b7c38cac79", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const object = value as Record;", + "fingerprint": "e56d4e9fe23976dad63a872218663b3306d0bfb81170bc029054bcafdf5c26a7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/generate/generate-structure-baseline.mts", + "diagnostic": "The explicit open dictionary type on binding `walkers` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const walkers: Record TreeWalker> = {", + "fingerprint": "e58d06689f879fe00a900b6767dcb6e97564dbbb5992b90b6d4a325f61a4eabb", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/cache.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const persisted = JSON.parse(readFileSync(cachePath(repo), 'utf8')) as {", + "fingerprint": "e58e1b4b48d401439de14fd56020f42efae2c78089472dc5d663cfa3a27a1f8f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (!value || typeof value !== 'object' || Array.isArray(value)) fail(message);", + "fingerprint": "e5a3c8635a2f8c9ca9dbe16dfc62190b273f03bf216b04fba7f8ca058c27b020", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/recall/markdown.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "for (const item of (node as { children?: unknown[] }).children ?? []) {", + "fingerprint": "e5a577492064f9e78299df27f7eb91b1224b704d7a7c45f21536e578bd85aae1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/co-occurrence/index-refresh.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const file = typeof row.file_path === 'string' ? row.file_path.replace(BACKSLASH_RE, '/') : '';", + "fingerprint": "e5b575060653ce1940374f2583f4c167a9ca6f9366e54fca38817aa8400e8453", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/__tests__/response-contract.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const { researchReferences: _dropped, ...withoutRefs } = reviewed() as Record;", + "fingerprint": "e5ba1c7f4d10a359cc03f9e3dc70e36f97933b947abf1b08524389ae20f096f0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "gate-engine/review/eval/conventions/bench.mts", + "diagnostic": "Parameter `entry` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "function appendLedger(entry: object) {", + "fingerprint": "e61400e91a2647287d932f4a05edc7e8faf9b6b5abe534a4a4ee802e424f0ab8", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "for (const path of mutableProjectionRoots(args[1] as string)) process.stdout.write(`${path}\\0`);", + "fingerprint": "e65062e3955ec6ed654418e2b321dae214f3dc1dff7afc566c014faf6eff3c64", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/__tests__/_helpers.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof requestedTimeout === 'number' && requestedTimeout > 0", + "fingerprint": "e66eac4f45c16cacb7d1c28fd8a5c644187a86152a159cce3f8456b4c40b497c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/co-occurrence/index-refresh.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "all(): Record[];", + "fingerprint": "e68b3dec3935fabd89271209f4e098099cacfb21fd17d738505421b3b29c480e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(recordedGuards === undefined ? {} : { guards: recordedGuards }),", + "fingerprint": "e6a25e8d817aac7ee55aae612c6e95c25dedcf74e90d7444cb7e19ee553a6785", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/generate/generate-structure-baseline.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const mod = (await import(pathToFileURL(file).href)) as StructureDomains;", + "fingerprint": "e6f3f923d9d76e25d196659612a3e20b8dee65c261166d4ec836e1c236fb47e3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/__tests__/review-gate-supervisor.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `signalFixture` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { script, leaderReady, descendantReady, leaderSignal, descendantSignal };", + "fingerprint": "e734d4e28605c6a8299c2200bd62bd81009d5301534651dc277b4264451910a2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "value: Record,", + "fingerprint": "e744e291bbf3fbe458fe136d7c0a728246e960e8f832a3dafc07729efd79aa4e", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/consumer-identity.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(consumerReviewerIdentity(root, cfg, other as Reviewer)).toBe(beforeOther);", + "fingerprint": "e78238d5e877778fccda2a637b75ad13939430ce51de1da39e66c526769b8fe7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": ": typeof lineage.parentCritiqueId === 'string' && ID.test(lineage.parentCritiqueId),", + "fingerprint": "e7dcfd7a1c22b214b73c8fb947c8be39db6ee438bc1f120f111f1fa55169dc97", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "rows = parseCasesText(readFileSync(casesPath, 'utf8')) as Row[];", + "fingerprint": "e8737331addca0923aa6be1c66dd3c561992790e9c1f241ab97993cd6e32104c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/install-support.mts", + "diagnostic": "The explicit anonymous object type on return value of `stripRetiredRegistrations` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!commands.size || provider === 'codex') return { document, changed: false };", + "fingerprint": "e873d75c60cabc153c0b3df407776348915b1a4d7e485c8f0c3b7de9f3f9d36b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/scrub.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof text !== 'string' || !text) return text;", + "fingerprint": "e8765b5af9350bf1e01120f811700001fe16b8f3e3c4d7e81d90f872795e4b15", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/ship/review/runtime-fingerprint.mts", + "diagnostic": "The explicit anonymous object type on return value of `readPinnedReviewFile` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { content: readFileSync(descriptor), mode: stat.mode };", + "fingerprint": "e8c8619024d56782e4860a4532737c9791a585db7581a649e2b59650a6abe1b6", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(!Number.isInteger(value[count]) || (value[count] as number) < 0)", + "fingerprint": "e8c8f099b412e17be42e524d391788abd642dabcb7fecb935db6eb85b31d972d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/doctor/extends-checks.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "[key: string]: unknown;", + "fingerprint": "e8d1fa8a7e7f4e051dd26d74dda4f6810c1bd2a36beacb4483a20a2cb2c62b7e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/upgrade-version-step.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../commands/init.mts', () => ({ applyInit: vi.fn(async () => {}) }));", + "fingerprint": "e8dde57376b82b328b8688400ecc3c6d74c96310f8d0d2b097bdf648567d34be", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/mine-bots-lib.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return (texts ?? []).some((t) => typeof t === 'string' && t.includes(ADDRESSED_MARKER));", + "fingerprint": "e8f29fa7cef7e64d2e4945b2595844fb3639179ef1a15e40b810b4ecd0e5a970", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/ratchets/size-disable.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "let cfg: Record;", + "fingerprint": "e947f6b174ca0e9b2c193b5a606abdcd8bae74233b3ece5c8dab1fa8130a53b3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "Parameter `e` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function warnUnavailable(label: string, e: unknown, timeout?: number): void {", + "fingerprint": "ea04f0f4c7a702025a8ca5296652526ee93b87c2db2381c536f1e5535e59a84c", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/json-duplicate-keys.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "key = JSON.parse(raw.slice(start, index + 1)) as string;", + "fingerprint": "ea053cc37fc3ee07da839102d8ce9a44e373ad330f9e94a30e46129ee31770f8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof ff !== 'string' || !PATH_SHAPED_RE.test(ff))", + "fingerprint": "ea24b41ca9f300859d8dab3e36878cfd0a5bf31648e52ae6faf10934f5ce34a5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/manifest/validation.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value !== 'string') return false;", + "fingerprint": "ea438a7a3e285226e62987ae2b97cea810b4ae2f5e6300882a34c011ce28eb96", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/doctor/unguarded-gate-calls.mts", + "diagnostic": "The explicit anonymous object type on return value of `errexitState` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { state: 'in-force', reason: 'the hook sets -e itself' };", + "fingerprint": "ea77d8934f2c16c09b284a968996940482a647305f2717019759c9c931cea5af", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/review/overrides.mts", + "diagnostic": "The explicit open dictionary type on return value of `envOverrides` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return out;", + "fingerprint": "ea99cd959986d307af3150e0663b1fe9ef19ea127af1bae00e518122ec6bf511", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/asset-checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const manifest = readJson(join(gitRoot, '.devkit', 'agents-manifest.json')) as Manifest | null;", + "fingerprint": "eab0ef4e6f6a90d15bcbe11c772b455ce0cb70b17396eedcadfbd023632c3091", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/decisions/__tests__/integrity-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const row = { ...base, provenance: 'real' as unknown as 'adapted' };", + "fingerprint": "eabfb9fd60750dee9303026823da610ef7405b420585632ec8ae9bf679a8ce76", + "count": 2 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/release.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../commands/ship.mts', () => ({ default: vi.fn() }));", + "fingerprint": "ead8b5589955c4472059f8ad9f9cf3b832561dcee0177ff83c021d5afcbed6b9", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/dependency-preflight.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const [manifestPath, nodeModulesPath] = args as [string, string];", + "fingerprint": "eaf83573d2475f4e59ef848f721d62d61b84de6d8aee9044d8c8903367bcad18", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/judge/run-context.mts", + "diagnostic": "The explicit open dictionary type on return value of `runEnvelope` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "eb3a227f39122d4c13895047b439a752bcd16609603af3de967f5696c0a12f21", + "count": 4 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-store-internal.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const recordDirectory = managedPath(canonicalRoot, ['records'], true) as string;", + "fingerprint": "eb77970422bea6964e72aeb532adacf9eeb4754c9a4026664409010ffc87b485", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/__tests__/husky-block-exec.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof t.duration_s).toBe('number');", + "fingerprint": "eb9a9d9036f76925b3bc45700c3c4b8b3c22eb4f05faca00d0a0cfd5966ce6fa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit anonymous object type on return value of `status` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (!view.event) return { mark: '?', label: 'missing', tone: 'bad' };", + "fingerprint": "ebb7a90d813b87d4c0d0fe4a935173dea513c43f7f6cfd7e2448abe400c690d3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof c?.degenerate !== 'boolean') err('degenerate must be boolean');", + "fingerprint": "ec4088f6884c727f78854b232afd9d7a3e93fcb266f74309e41eb0d4edee7f1b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(m) => typeof coverage[m] === 'number' && computed[m] < (coverage[m] as number),", + "fingerprint": "ec7d5e9133394c36fa7c12795791b17664f7d63109a67a2bd3d0a29b0b86c75a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/ratchets/size-lines-freeze.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? (JSON.parse(readFileSync(baselineFile, 'utf8')) as LinesBaseline).files", + "fingerprint": "ece9078b9db00271f5254fb133a08cced3a8ae5375a76a741644aaa9cc96aad2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "gate-engine/review/__tests__/lens-split.test.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "const m = merged as unknown as { itemCount: number; items: unknown[] };", + "fingerprint": "ecee7ce13906761657ab0b0a3df2dcf6f4102f5767f31d05db44659072baa250", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const text = typeof value === 'string' ? value : fail('INVALID_TYPE', path, 'expected a string');", + "fingerprint": "ecf94dc600e48e124776f67fe42fc919b8329e4a165e15da60ab6a54493ef5b8", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof f?.claim !== 'string' || !f.claim) err(`${fid}: missing claim`);", + "fingerprint": "ed086ea23fca701a71fceb136753cab80b37ec191f59b9d649082b1d667048c8", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/upgrade-version-step.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../commands/doctor.mts', () => ({ default: vi.fn(async () => 0) }));", + "fingerprint": "ed41ee3dcd261ceeb1273ebf09fc70a112156bd557a9f587b80a1fc331364ad0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/install-fallow.mts", + "diagnostic": "The explicit anonymous object type on return value of `saveFallowBaselines` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { ok };", + "fingerprint": "ed5f5aa081cbf0bf020efe07ad5fdde860fbafde1acd8863f91b2da184c2ea69", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value === 'object' && value !== null && !Array.isArray(value);", + "fingerprint": "ed7dde09dd4d1094ba6163aed6a16585476197a2fd81b5f05b66beec7bf7a0de", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/standalone.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (e && typeof e === 'object') {", + "fingerprint": "ed9e45b759d2c04eea79dc77fe8ea63991dd01fe9f93cf85be9eb83d61c09d8f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value && typeof value === 'object') {", + "fingerprint": "edadd436c12d59c9186181071dddc81e51197e55ae88d362f353650bd8966dff", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const isRecord = (value: unknown): value is Record =>", + "fingerprint": "ede91c938ae30cdb55ac0ad13ccb666d8ee604154dd92b8f0c1629f38c0b3993", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/review-setup-manifest.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const malformed = JSON.parse(readFileSync(manifest, 'utf8')) as Record;", + "fingerprint": "ee0eef9c8da5974290a018a4f713563cee01b1de79a0ac57ef9a605e0bf688d5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/runtime-fingerprint.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "process.stdout.write(pinReviewRuntimeFile(args[1] as string, args[2] as string));", + "fingerprint": "ee1341b22118aa910fb8592dbe394c2a9552a6e70e520135caea704b8df4c7cc", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof value.baseDigest === 'string' &&", + "fingerprint": "ee3797fa4c2f31292f183e2eabd57f1685c489d721074094b2d884e2f11c4147", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "findings.push(candidate as unknown as BenchmarkFinding);", + "fingerprint": "ee638a0a464fd53ec1ccd5feb72bc6650abc1c1ab7049da897d2c7d445ce972f", + "count": 2 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/apply-init.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('../lib/install/install-fallow.mts', () => fallowSpies);", + "fingerprint": "ee8222acbc29cd073dfce057d403e8e9aa332a4acbb26eb35747dbd51227b859", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const afterOk = (current as { ok?: unknown }).ok;", + "fingerprint": "ee9e6d3bc84e96cd37a7b39f9fa7d47d3b384a0b62e39dbc2389753bcaebd3e7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/provider-runtime/claude-subagent-stop.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "function payload(overrides: Record = {}): Record {", + "fingerprint": "eea42205789981a939e2c9abd3023cd8a4839afc4247c5d3320d70ef79199f0f", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof raw.destinationRoot !== 'string' ||", + "fingerprint": "eebb333c37fe3d3efe99a563af0c8659decc2b43917ce93e0ef26d9b9607230a", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/init.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (e as ExecError).status != null; // non-zero exit → debt; ENOENT (status null) → treat as none", + "fingerprint": "eedfb56925f01e47beb06f631c6ac5e89a5f46cd400ae5f5992b08e41558518a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/lifecycle/work-quarantine.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "keys.some((key) => typeof key !== 'string' || !fields.includes(key))", + "fingerprint": "ef3a43ef584f9275f8d4f5212b48f8c9757bcee172aa12dd10b8e27016202bfa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "gate-engine/coverage/__tests__/run.test.mts", + "diagnostic": "Parameter `cov` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "const writeCoverage = (root: string, cov: object) => {", + "fingerprint": "ef580abb0d240b287374945e216f2307c0fea5c82f9e20a1c39dcaeb530e52e3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/structure/eslint-config.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "createFolderStructure(rule as Parameters[0]),", + "fingerprint": "ef677ad7b02a7ac7733ee6cb745edfd6d8826884cbfd0a5211fe69e3e644d31d", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/capture-normalizer.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(input as { provider: string }).provider = 'other';", + "fingerprint": "ef899a9ce2f89c5162425960f1e243bff48e2bbf17b32df40edf6962c2e5add6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "Rename symbol \"PATH_SHAPED_RE\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "const PATH_SHAPED_RE = /\\/|\\.|^[A-Z][a-z]+file$|^[A-Z][A-Z0-9_-]{2,}$/;", + "fingerprint": "efae931c4c53abcc42911a3372dd01a7b4e416d9fdbe6ef8cdf2083ebb2d717f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/judge/matcher-core.mts", + "diagnostic": "The explicit anonymous object type on return value of `voteSlot` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { match: Number(winner), stable: sorted.length === 1, outage: false };", + "fingerprint": "efb3c17844266977356fff86bf7916e89afaa09fc2e7fa8cdac50b7e0296f98f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/coverage/run.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof line !== 'number') continue;", + "fingerprint": "efbeb07356e8c2acb9cd5e955c84eae8ac4cb0705c50f21dc185c02628f0b54f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const text = typeof value === 'string' ? value : fail('INVALID_TYPE', path, 'expected a string');", + "fingerprint": "f004d99b9d653d920e1b6297ede267fd0c1b9687316f2413e592e4225c760290", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/co-occurrence/allowlist-cli.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof v === 'string' && v.trim() !== '' ? v : undefined;", + "fingerprint": "f0096792d0e9e6b8e8e34e2d7d11156026843e8516408d3a414d3c84bc9244de", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/config.mts", + "diagnostic": "Parameter `v` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function positiveMs(v: unknown): number | undefined {", + "fingerprint": "f03ccc6932213b6cd6d5b5dd85ed6979936a4d348afb6072c4820f735e37b79c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/edge-cases/eval/lib/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof f?.evidence?.detail !== 'string' || !f.evidence.detail)", + "fingerprint": "f0413267c31a35af0b21fa8ad97659b47be6d0e3dba8ecf242ab562fc1d31918", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/catalog.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "errors.push(`Cannot validate baseline ${baselinePath}: ${(error as Error).message}`);", + "fingerprint": "f06aa076f99f385ecd5b43cc3a8b343374a249ec1908e8ab245499bdf303e9da", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "cli/commands/init.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(prevConfig?.configOverrides ? { configOverrides: prevConfig.configOverrides } : {}),", + "fingerprint": "f088807b55d652bbfd5456001c2027246630a82a2766a6dcbdaa85d66a124341", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/judge/__tests__/judge-exec-telemetry.test.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "expect(typeof ev.transcript_ref).toBe('string'); // collected by default", + "fingerprint": "f0b0d276dc73a801c8d8d6bad30c3f4b18e863c3c634ab62dcd1a43475e832cd", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof root.recordCapturedAt !== 'string' ||", + "fingerprint": "f0fb99c451d3d93899494d9b4d17c6c521801d3dbb9886bbd3f727d94c77ac6e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(shared === 0 ? { note: 'No shared row outcomes; quality is not comparable' } : {}),", + "fingerprint": "f129e9ff6cc1b448901c8637457f44bfdb8ceae22ea42de78b6b3d5c9b9d7287", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/commands/update.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "? ((readJson(join(cwd, 'node_modules', DEP, 'package.json')) as { version?: string } | null)", + "fingerprint": "f17c8011ee8550808f54f7f53f038f0da06439da858f56fac6ac4cf19ead45ab", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/lens/split.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(transcriptRef ? { transcript_ref: transcriptRef } : {}),", + "fingerprint": "f19d21a3ef66d8285ea7fcb7991d777b8c062e291e45543ddc18d7d093ff10cf", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const raw = parsed as Record;", + "fingerprint": "f1b30219e343a4f179e19b2ef3c5c1ec0ef8a525065ca9d0a812e5cb30ed77ea", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function verifyGuardFields(value: unknown): void {", + "fingerprint": "f1bf57f4b20f1570d7c9479ad3557a9614ba228fd2f7de5e0654f8ce4740ac3b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/evidence-bindings.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return { status: 'selected', binding: bindings[0] as PlanCritiqueBindingV1, candidates: 1 };", + "fingerprint": "f1c49cdf1ceda5ebc50606fe076758fa520ff60e3de8215dbae97e249d450c27", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "rows = parseCasesText(readFileSync(auditPath, 'utf8')) as AuditRow[];", + "fingerprint": "f1f69d56dd674ad3c7a90ad05816db09bbc6abb309affbd85667acfa72a368d2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/doctor/unguarded-gate-calls.mts", + "diagnostic": "The explicit anonymous object type on return value of `errexitState` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return {", + "fingerprint": "f1fe2e85f5b4146b16c16d23847ddc79c9cbd585860cdd0abac6c743ceef848b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/anti-slop/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const value = JSON.parse(readFileSync(path, 'utf8')) as Partial;", + "fingerprint": "f2340d9823492ed9871e68015c39302e8bf5c402835313690d0cc33458330022", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/persistence-lock.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "fs.openSync = ((...args: Parameters) => {", + "fingerprint": "f239b47bec996e6b237685875897e8aa4cfead0a1655bcfdcdad0d4f4d272b2c", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "The explicit anonymous object type on binding `options` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const options: { cwd?: string; evidenceRoot: string; workId: string } = {", + "fingerprint": "f2697e7c1184aa5040c99e03190b88b3050cbb4b8fdb7e3195f41e50886a8bca", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value !== 'number' || !Number.isInteger(value) || value < 0)", + "fingerprint": "f28daea12c0c4b4aad5005b06fc807946b444d6fe001b26ad49446ca5c9f9ec0", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/judge/verdict-store.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const value = JSON.parse(readFileSync(ownerPath, 'utf8')) as Partial;", + "fingerprint": "f2ea32a55d74a78f63b63c75479e929f00f903930434134f5e86e7912dc9a764", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/catalog.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "throw new Error(`Invalid benchmark catalog JSON: ${(error as Error).message}`);", + "fingerprint": "f3033d75b9577ace5fe4769d6b0b64eb5de15f6c2d5eff74f0d519e8fa0266e5", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/apply-init.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(normalizeSelection({ agentTargets: null as never }).agentTargets).toEqual([", + "fingerprint": "f3076dcc13d9b1b9e90dd4cfb2f570d04c7bb189149dd27750359b211154664b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/ship/review/manifest/validation.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "value: Record,", + "fingerprint": "f30980e3a6eb20387f14b5d529091ee7546468a8a77957973348f4cdfd4fbd09", + "count": 2 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/review/eval/reviewers/mine-telemetry-lib.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const joined = parsed.filter((s) => typeof s === 'string' && s.trim()).join('\\n');", + "fingerprint": "f31757fa476b79f99f10f8cb8a5d7a5686e2d0e20c307e126f98df68155ab916", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/prefix-cache/config-fingerprint.mts", + "diagnostic": "Parameter `v` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function canonicalJSON(v: unknown): string {", + "fingerprint": "f381662b2ba56ebc0cf0d07a043363d4d09e34aa3b613799fc9c084a3aed5371", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "cli/lib/ship/review/setup-profile.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function stringArray(value: unknown, label: string): string[] {", + "fingerprint": "f38981f0aa32fbc970388b3ece6fe9d08845c1f53736bd85f0b0ff48659bc4bb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(ref ? { transcript_ref: ref } : {}),", + "fingerprint": "f3a5a1565c7115adde7817e8984cc891ece38496b1ef3a409d8bc370ee8b4391", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/cascade/reviewer.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return {", + "fingerprint": "f3cbf358342917f3c8afc9330d84c8d87c73ffe884d7a4b8390350290cd1ff58", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/doctor/extends-checks.mts", + "diagnostic": "The explicit open dictionary type on binding `EXTENDS_REPAIRABLE` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "export const EXTENDS_REPAIRABLE: Record = {", + "fingerprint": "f3d396ec00cdfe116b9bfd5bdc071d84361c92b593f0504238d280c67307a7ef", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const isRecord = (value: unknown): value is Record =>", + "fingerprint": "f440bc3a1972d2c8cb994d9ba2428effc1f382a75ed53ae7a9d61872cefcb35f", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/catalog.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const checkpoint = JSON.parse(checkpointRaw) as CheckpointEnvelope;", + "fingerprint": "f45ff9cb32c5b6acb1587f4f99749b8a2e7e4efce16ab4ea8c24af2bf4ff4949", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/history.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const event = value as unknown as BenchmarkEvent;", + "fingerprint": "f4735da3f4e1a460a8c10d6f0236560ee429a2e6731561c5b8945eab07db6b8c", + "count": 2 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/cases.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "if (!(PRIOR_ART_FRAMINGS as readonly string[]).includes(framing))", + "fingerprint": "f4caf5ceb1dc40bdc0f2360a7d39e6b3e0bdbf798e37ec0f0819a0c5fd5bcc88", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/hook-registration-ledger/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (value === null || typeof value !== 'object' || Array.isArray(value))", + "fingerprint": "f4cb626977ea4f4d10a6ba81714016ce271688d2651e66f0c74114d6001c7eba", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/doctor/asset-checks.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const manifest = readJson(", + "fingerprint": "f4dfe156dce2d15c5b02cb432acace658173aadd020e953cc4b1f352a3229966", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/adapters.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return fn(input as Json);", + "fingerprint": "f4e85dec2cb3aa29a2c3b92b7da49acb2af662d190f82184e4ca2d719c450e1f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function booleanValue(value: unknown, path: string): boolean {", + "fingerprint": "f4f228a36aff4b9878487bc869fe9823c291782d3a39a83cd3701463e4a7a5aa", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/prior-art/response-contract.mts", + "diagnostic": "The explicit anonymous object type on return value of `parseReference` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { title: boundedString(object.title, `${path}.title`), url };", + "fingerprint": "f563e7a22483545791cc6c473966d76680e72592d5a9e99ff3e2a3b3823c8a3a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "feasibility: typeof feasibility === 'string' ? feasibility : null,", + "fingerprint": "f5ae56a9aa966deb6c59db999278cdae8bbb3257dc54c6682cc0071531c25a47", + "count": 1 + }, + { + "ruleId": "anti-slop/no-object-parameters", + "file": "gate-engine/coverage/__tests__/run.test.mts", + "diagnostic": "Parameter `cfg` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + "context": "const writeConfig = (root: string, cfg: object) =>", + "fingerprint": "f5f574de901e1fa8f3d07ddc71c4d04e308c7b094838063968359f04a6b8b4c0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/factory.mts", + "diagnostic": "Parameter `raw` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "): (raw: unknown) => string | null {", + "fingerprint": "f6005773d2cc266b3fa4a6eed2fa1f2d13bb569fb7f0d637e33844cacfe39b67", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "e2e/fixtures/anti-slop/all-rules.ts", + "diagnostic": "Rename symbol \"UserShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": "interface UserShape {", + "fingerprint": "f62d8ee8921a5471b14b353b1400883ac93c142163e4f5b540ea0fa1ca9bbc68", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/config.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : undefined;", + "fingerprint": "f632e4304ff266fe29f94742a514da595f7b3e0f1a78c7cc505c8cb67e20b5a7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/suite-adapters/deterministic.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof metric.k === 'number' && typeof metric.n === 'number' && metric.n > 0)", + "fingerprint": "f643a14f887999339a112d02087b49f80867a873885c587c2779e31344a90130", + "count": 2 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/install-fallow.mts", + "diagnostic": "The explicit anonymous object type on return value of `detectFallow` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { available: false, version: null };", + "fingerprint": "f688b6126cd13ba5bf10e9d7db1c45c1249f374983fe648df24cacd5493ba1d5", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "(field) => typeof candidate[field] === 'string' && candidate[field].trim().length > 0,", + "fingerprint": "f6a209bd387dbb7ae9b493eebaa410df6494b866a9265196d0c634ec26444e94", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/projection/runtime.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "args[2] as string,", + "fingerprint": "f6a48d0589c62d44f2f810a07642b53e4d1ae509cdcab07bfc5586be9757a2cb", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/lib/install/package-json.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "[key: string]: unknown;", + "fingerprint": "f6d2cd009236f55479eb7c698ffae85262a882fd9a0523a9377f74f96872ce45", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/install/oxc/lifecycle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const value = JSON.parse(readFileSync(path, 'utf8')) as Partial;", + "fingerprint": "f6ee96824bb53400f18a6e6100091812ca248388ba003990ea74b2a470dfdd87", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/eval/run-critic.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "const isRecord = (value: unknown): value is Record =>", + "fingerprint": "f6f5decc74e2a63776deab786274aa3010a5d0958419eddf6f4b4484d966aab3", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/eval/cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const changeType = requestedChangeType as ChangeType;", + "fingerprint": "f6ffd496bdda7bf8557060f1634cff3e2cdfcfabe5ffad9a67b1cf7e906fbf65", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/anti-slop/baseline.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof entry.file !== 'string' ||", + "fingerprint": "f7aca3deea2d2432b0792796c7d30419315fd8225598c4a7f2266a711d647e2d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/doctor-search-index.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "return { root, sel: (cfg as { components: Record }).components };", + "fingerprint": "f7b1ba77207718ce73fc1a524f799b4eea4616d4b130e9f8687e5790053dab37", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "skills/_devkit/review-roots.mjs", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "value.every((entry) => typeof entry === 'string' && entry.length > 0);", + "fingerprint": "f7cdb6f4fe30333932d7ce72a855aca1e0012c714c35961f2d2c2cf34f29ba73", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/eval-bench.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "exec: exec as never,", + "fingerprint": "f7f4d1481d5217519bbb0a2df47e6c3e47d3b6e70748c7a6f46c73de8d1d879d", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-store.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function validateLineage(value: unknown): void {", + "fingerprint": "f85c0c179848ae8e6414747787c6f4ceda29da1b89d93bd7193e287556e4e860", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/__tests__/overrides.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "while (dirs.length) rmSync(dirs.pop() as string, { recursive: true, force: true });", + "fingerprint": "f87d06bcd83857a4af1144342e7ff455b2cc791e0befc693bf9c0d5227cee926", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/ship/reconcile-manifest-write.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "typeof m === 'object' &&", + "fingerprint": "f8e7df60cc5c506fdd1ef03a13f45075ae7f1c721e4133225439df3a5eed7274", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/hook-registration-ledger/registrations.mts", + "diagnostic": "The explicit open dictionary type on binding `HOOK_REGISTRATIONS` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "export const HOOK_REGISTRATIONS: Record = {", + "fingerprint": "f905f164e971b0723339189af1bcbaff660eed340dffa0c6109f05b40db0695f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/render.mts", + "diagnostic": "The explicit anonymous object type on return value of `status` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "if (view.freshness === 'stale') return { mark: '!', label: 'stale', tone: 'warn' };", + "fingerprint": "f92076ac6261d5b66a0f5ecb049b70e682a714d9bcb2e5c09db5030ae9e5ece0", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function finite(value: unknown): value is number {", + "fingerprint": "f93850ed8f7fbbe1f9770e2d433e6bbc6355101896b4b3f70ea8dac73298df44", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "cli/lib/install/install-fallow.mts", + "diagnostic": "The explicit anonymous object type on return value of `wireFallowHooks` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { ok: git.ok, log };", + "fingerprint": "f953db6ecf8179c9420418e6840daebdbb79c12a401a5740f8248d7927fff19a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function snapshotPayload(value: unknown, at: string, maxBytes: number): Buffer {", + "fingerprint": "f9c246dbb05ba7079b17c368e7158b186f340f9d4d833df7a15aaf279f8998d1", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/critique/__tests__/capture-normalizer.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `storedProjection` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { bytes: projection, value: JSON.parse(projection.toString('utf8')) as StoredProjection };", + "fingerprint": "f9d0ceb2628443bbc6d45297aebeed85c4d0e62e54ee913de17369031e9d2b24", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/__tests__/review-repository-state.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const tamperedAdmin = JSON.parse(readFileSync(first.manifest, 'utf8')) as { gitDir: string };", + "fingerprint": "f9db9c76943da810fee4a0f9d22d02de6a8b966e457dd2deea0db0d8dadf94f4", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/prior-art/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const verdictVote = majorityVerdict(runs.map((run) => run.verdict)) as {", + "fingerprint": "fa15598a3366ac858bbab9594c571910cc320919b67daef21f8ff561b2843af7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/judge/__tests__/verdict-store.test.mts", + "diagnostic": "The explicit anonymous object type on return value of `replacePublishedLock` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { displaced, token };", + "fingerprint": "fa96b0c277b7d9e150dcd958a627985c363a60b1619f0b4596f55d5b332fdd31", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/eval/history.mts", + "diagnostic": "The explicit anonymous object type on return value of `checkpointArtifact` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "return { content, sha256: digest, path: `${CHECKPOINT_DIR}/${digest}.json` };", + "fingerprint": "faa32d112a5006185e2a58ed75c3343b7ca4df00900f92fda57768a03f5bc1c3", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/commands/clean.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "hooks?: Record;", + "fingerprint": "faab1d843d2397d9893bd42e07b2e9524de9ec0392ad9f7e738c3c248859e6ef", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/__tests__/evidence-bindings.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect((await (contenderClosed as ReturnType))[0]).toBe(0);", + "fingerprint": "faacb1392770ea59559a3d460a33fe576ce3906f5be3c890b56b6cdbb789c200", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/review/recovery/settle.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "(res as RecoverableOutcome).retryable;", + "fingerprint": "fb1cce29bce8dbd0a3258d8fe67320c524625ed17b7afffcca342f5709748c6f", + "count": 1 + }, + { + "ruleId": "anti-slop/no-known-value-widening", + "file": "gate-engine/decisions/cli.mts", + "diagnostic": "The explicit open dictionary type on binding `SUB_ENGINES` discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + "context": "const SUB_ENGINES: Record = {", + "fingerprint": "fb4df844b617941983dd72ea7dcadacb52a0a605670b5e8781f5bcf6c30b6c48", + "count": 1 + }, + { + "ruleId": "anti-slop/no-conditional-empty-object-spread", + "file": "gate-engine/review/recovery/settle.mts", + "diagnostic": "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + "context": "...(t.splitOf ? cachedLensFields(res) : {}), // spill-safe lens re-seed (sc-1475)", + "fingerprint": "fbdb425e74888333a2a58f977234260a63c55e20876114d3b7403df2546dfdb7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/judge/run-judge.mts", + "diagnostic": "Parameter `e` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function unavailableMessage(label: string, e: unknown, timeout?: number): string {", + "fingerprint": "fbeaf63898383d698efdb271e684737074c5696c6f2f05902ebc9aa89a4741aa", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup-manifest.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "verifyReviewSetup(args[1] as string, args[2] as string);", + "fingerprint": "fc3df346267ed36e2f40079b0149a097300bdccee038d389ae532753469301e8", + "count": 2 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/__tests__/wizard-optional-defaults.test.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const selectAnswers: Record = {", + "fingerprint": "fc586283d64a53c915c278aaf74a3d52bbefa95b422ddaf11715fc64f615512b", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "cli/commands/migrate-config.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const have: Record = JSON.parse(readFileSync(dest, 'utf8'));", + "fingerprint": "fc59f39f8921b683add2ef1b072f634876bb02a9949e9896aab01a458edc1906", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const parent = managedParentPath(path.dirname(requested), [], false) as string;", + "fingerprint": "fc8d379f205061a28e74814e19e71be578ed9b8ef65d83f660d0b2733a634433", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "cli/lib/ship/review/setup/setup-runtime-copy.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "const code = (cause as NodeJS.ErrnoException).code;", + "fingerprint": "fd16d1cc18f8fcef27cce1cb8ee72d6eab19a202ae23fa61fc6284f0bd47c7c6", + "count": 1 + }, + { + "ruleId": "anti-slop/no-chained-type-assertions", + "file": "cli/lib/ship/review/setup-runtime-format.mts", + "diagnostic": "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + "context": "return entry as unknown as ReviewSetupRuntimeEntry;", + "fingerprint": "fd37f6a2eefcefdfbe5e2788fc153a94e13251ea73d0bab2558ababcf26d7764", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "const isRecord = (value: unknown): value is Record =>", + "fingerprint": "fd42d663186258d84942b35106d82f36d868a8c64259ab2c86a503c49982e359", + "count": 1 + }, + { + "ruleId": "anti-slop/no-shape-in-symbol-names", + "file": "cli/commands/move.mts", + "diagnostic": "Rename symbol \"TsconfigShape\" for its domain role; \"shape\" describes structure rather than ownership.", + "context": ") as TsconfigShape;", + "fingerprint": "fde8aa0ab183994afb71abcbdb26381b33902516d7d6c8a701fdbdb38d80d66b", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/eval/bench.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": ": buildDecoyPrompt(r.slot as DecoySlot, r.findings);", + "fingerprint": "fe4fb87d2dd96704ed3e7b663c47ac5ed2d8145d67cb3ebb951d84fbe6d52351", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/lifecycle/work-quarantine.test.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "expect(getPlanCritiqueWorkQuarantine(invalid as never, { root })).toEqual({", + "fingerprint": "fe96df8e186a3b0ed46268d7ba079d08b5b85c87ed7230eca603c953cdc42688", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/co-occurrence/allowlist-cli.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "scanned = JSON.parse(readFileSync(0, 'utf8')) as ScannedClone[];", + "fingerprint": "febffa2fc9dd06238ce4be2f967fd5e5db70838657d4a6baf4bd547d8c4dab7e", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "return Boolean(value && typeof value === 'object' && !Array.isArray(value));", + "fingerprint": "feeef0e2b8f21c0561c5956e9da9a488059b54a3e82ed54513a41ae33162d381", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "export function plainRecord(value: unknown): Record | null {", + "fingerprint": "fefc7435c18dad0b56e7813494ebb40d80f2a2715f316fc3e3a1eb7c0b80680a", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unsafe-dictionary-type", + "file": "gate-engine/eval/schema.mts", + "diagnostic": "This dictionary's unknown value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + "context": "for (const [key, child] of Object.entries(value as Record)) {", + "fingerprint": "ff376406259d1e4b44cc2a79050ac739daf923101b3ad64b00ffe83b3e5bd3ab", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-returns", + "file": "gate-engine/critique/provider-runtime/claude-subagent-stop.mts", + "diagnostic": "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + "context": "function readHookPayload(): unknown {", + "fingerprint": "ff49b377216e86e6c1c020820f5dd89d433202fb28d065f269edf9fc81e7aeb7", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/commands/doctor.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "const stamped = typeof ref === 'string' && ref.startsWith('v') ? ref.slice(1) : undefined;", + "fingerprint": "ff5952f1b80f8baa31a203f5ebb259ec94088f3e05ae70fce77e50007feafe36", + "count": 1 + }, + { + "ruleId": "anti-slop/require-safety-comment-for-type-assertion", + "file": "gate-engine/critique/persistence-lock.mts", + "diagnostic": "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + "context": "return (error as NodeJS.ErrnoException).code === 'ENOENT';", + "fingerprint": "ff6591dbd5f22fa1eb54e4e755b49e9b5b463289b7a34ffa572e3d4c74269284", + "count": 1 + }, + { + "ruleId": "anti-slop/no-runtime-typeof", + "file": "cli/lib/install/agent-asset-manifest/codec.mts", + "diagnostic": "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + "context": "if (typeof value === 'string') accountText(budget, value, `${label}.${key}`, MAX_METADATA_BYTES);", + "fingerprint": "ff79f9856bda980487b1113910bcfe22a9a6ecafc9f20989aa501903b0518c25", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/response-contract.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "function parseReference(value: unknown, path: string): PlanCritiqueResearchReference {", + "fingerprint": "ffa1f6baf46a1af5b9f718042f1765b3ccaf105116945dc614d2dbc995be9cd2", + "count": 1 + }, + { + "ruleId": "anti-slop/no-module-mocking", + "file": "cli/__tests__/wizard-optional-defaults.test.mts", + "diagnostic": "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + "context": "vi.mock('@clack/prompts', () => ({", + "fingerprint": "ffc70972cd44c9679d16a7db59cccf90773853df5fb114f9dab48508b69a5640", + "count": 1 + }, + { + "ruleId": "anti-slop/no-unknown-parameters", + "file": "gate-engine/critique/evidence-record.mts", + "diagnostic": "Parameter `value` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + "context": "export function validText(value: unknown): value is string {", + "fingerprint": "fff2270d04ebf163acc7766d1abb8a5c127202f509c897de27c1219a7ad16c27", + "count": 1 + } + ] +} diff --git a/.devkit/agent-hooks-manifest.json b/.devkit/agent-hooks-manifest.json index 4baf8d7..ad57a02 100644 --- a/.devkit/agent-hooks-manifest.json +++ b/.devkit/agent-hooks-manifest.json @@ -1,13 +1,27 @@ { - "devkitRef": "v0.49.1", - "generatedAt": "2026-08-07T09:41:05.314Z", - "targets": [ - "claude", - "cursor" - ], + "schemaVersion": 2, + "kind": "hooks", + "devkitRef": "v0.51.1", + "generatedAt": "2026-08-16T02:26:52.089Z", "files": { "adhd-prompt-anchor.mjs": "002e1ee4dd7f10ccef97babb57b7cf0e01c76433a18b4c8be4aa04ab89288504", "adhd-session-start.mjs": "b5257348cb11fe85742178f43bbde30a94d7b58cb8f67281e060c875bbe8bc80", "decision-edit-guard.mjs": "041da116c296a2104f181c285e2cb40343d5e0e20c6265417f734079e16c494d" + }, + "providers": { + "claude": { + "files": { + "adhd-prompt-anchor.mjs": "002e1ee4dd7f10ccef97babb57b7cf0e01c76433a18b4c8be4aa04ab89288504", + "adhd-session-start.mjs": "b5257348cb11fe85742178f43bbde30a94d7b58cb8f67281e060c875bbe8bc80", + "decision-edit-guard.mjs": "041da116c296a2104f181c285e2cb40343d5e0e20c6265417f734079e16c494d" + } + }, + "cursor": { + "files": { + "adhd-prompt-anchor.mjs": "002e1ee4dd7f10ccef97babb57b7cf0e01c76433a18b4c8be4aa04ab89288504", + "adhd-session-start.mjs": "b5257348cb11fe85742178f43bbde30a94d7b58cb8f67281e060c875bbe8bc80", + "decision-edit-guard.mjs": "041da116c296a2104f181c285e2cb40343d5e0e20c6265417f734079e16c494d" + } + } } } diff --git a/.devkit/agents-manifest.json b/.devkit/agents-manifest.json index 8590377..d1266b1 100644 --- a/.devkit/agents-manifest.json +++ b/.devkit/agents-manifest.json @@ -1,16 +1,14 @@ { - "devkitRef": "v0.49.1", - "generatedAt": "2026-08-07T09:41:05.312Z", - "targets": [ - "claude", - "cursor" - ], + "schemaVersion": 2, + "kind": "agents", + "devkitRef": "v0.51.1", + "generatedAt": "2026-08-16T02:26:52.084Z", "files": { "api-security-reviewer.md": "ed7b27dbf49e30f597559baaf153487b2851abf2c6a9482ea9caaa6228ceb420", "backend-performance-reviewer.md": "8aa858861a1afb3e740d371f7cc28d7f22552c25eb28a21fabda19186baca338", "commit-guard.md": "1a996999d7bcd0e5c96d4e78d6b5e67c1e02f3a66ec4ea8d98548260ad511764", "conventions-reviewer.md": "f7329e27571e9abdc6409556e4d2ae291473d001653763790ae72b9db8a8d456", - "correctness-reviewer.md": "227246dbdaea499c97d1857f23910a3c61e5f0ae314442c4a93886e215f8d6bf", + "correctness-reviewer.md": "abdb37e8a43ba1bf7d72269967dd25bc98df988681c5fca182150ce7610aacf0", "feature-completeness-reviewer.md": "0b9a742a2692d0b0ad9b8ff9829d652f7f43c52c163d780ef1b36a3aaeba2c19", "feature-critique.md": "36b77ef31ffd9e7c82147ba0db0b369d20420cea34cbec660db7f7d693dee5f4", "fix-upstream-reviewer.md": "1cff6e45b474dd6900d9e0b159078fdacbb4028ac2d7feb6ba99a58a82da1326", @@ -18,5 +16,39 @@ "frontend-performance-reviewer.md": "66a1777cfe069196b2dc31b8f918deb0e7833d3aa96c72b615351156990731a2", "frontend-security-reviewer.md": "1888e5a6365e4fe2d8881823da6cd2e5c66e6f8457e08295fcc0729247b25d79", "prior-art.md": "64525643e13a9c2180cdea5029ef4335791a5673dbce7f3bbe14e3c4aa30ad40" + }, + "providers": { + "claude": { + "files": { + "api-security-reviewer.md": "ed7b27dbf49e30f597559baaf153487b2851abf2c6a9482ea9caaa6228ceb420", + "backend-performance-reviewer.md": "8aa858861a1afb3e740d371f7cc28d7f22552c25eb28a21fabda19186baca338", + "commit-guard.md": "1a996999d7bcd0e5c96d4e78d6b5e67c1e02f3a66ec4ea8d98548260ad511764", + "conventions-reviewer.md": "f7329e27571e9abdc6409556e4d2ae291473d001653763790ae72b9db8a8d456", + "correctness-reviewer.md": "abdb37e8a43ba1bf7d72269967dd25bc98df988681c5fca182150ce7610aacf0", + "feature-completeness-reviewer.md": "0b9a742a2692d0b0ad9b8ff9829d652f7f43c52c163d780ef1b36a3aaeba2c19", + "feature-critique.md": "36b77ef31ffd9e7c82147ba0db0b369d20420cea34cbec660db7f7d693dee5f4", + "fix-upstream-reviewer.md": "1cff6e45b474dd6900d9e0b159078fdacbb4028ac2d7feb6ba99a58a82da1326", + "frontend-accessibility-reviewer.md": "c0494ea5b15bd288a2d4476dd097cdebe6f267a542ea04efffd4dd8574626232", + "frontend-performance-reviewer.md": "66a1777cfe069196b2dc31b8f918deb0e7833d3aa96c72b615351156990731a2", + "frontend-security-reviewer.md": "1888e5a6365e4fe2d8881823da6cd2e5c66e6f8457e08295fcc0729247b25d79", + "prior-art.md": "64525643e13a9c2180cdea5029ef4335791a5673dbce7f3bbe14e3c4aa30ad40" + } + }, + "cursor": { + "files": { + "api-security-reviewer.md": "ed7b27dbf49e30f597559baaf153487b2851abf2c6a9482ea9caaa6228ceb420", + "backend-performance-reviewer.md": "8aa858861a1afb3e740d371f7cc28d7f22552c25eb28a21fabda19186baca338", + "commit-guard.md": "1a996999d7bcd0e5c96d4e78d6b5e67c1e02f3a66ec4ea8d98548260ad511764", + "conventions-reviewer.md": "f7329e27571e9abdc6409556e4d2ae291473d001653763790ae72b9db8a8d456", + "correctness-reviewer.md": "abdb37e8a43ba1bf7d72269967dd25bc98df988681c5fca182150ce7610aacf0", + "feature-completeness-reviewer.md": "0b9a742a2692d0b0ad9b8ff9829d652f7f43c52c163d780ef1b36a3aaeba2c19", + "feature-critique.md": "36b77ef31ffd9e7c82147ba0db0b369d20420cea34cbec660db7f7d693dee5f4", + "fix-upstream-reviewer.md": "1cff6e45b474dd6900d9e0b159078fdacbb4028ac2d7feb6ba99a58a82da1326", + "frontend-accessibility-reviewer.md": "c0494ea5b15bd288a2d4476dd097cdebe6f267a542ea04efffd4dd8574626232", + "frontend-performance-reviewer.md": "66a1777cfe069196b2dc31b8f918deb0e7833d3aa96c72b615351156990731a2", + "frontend-security-reviewer.md": "1888e5a6365e4fe2d8881823da6cd2e5c66e6f8457e08295fcc0729247b25d79", + "prior-art.md": "64525643e13a9c2180cdea5029ef4335791a5673dbce7f3bbe14e3c4aa30ad40" + } + } } } diff --git a/.devkit/anti-slop/.oxlintrc.json b/.devkit/anti-slop/.oxlintrc.json new file mode 100644 index 0000000..6324d2f --- /dev/null +++ b/.devkit/anti-slop/.oxlintrc.json @@ -0,0 +1,8 @@ +{ + "extends": [ + "../oxc/oxlint.base.json" + ], + "rules": { + "anti-slop/no-object-parameters": "off" + } +} diff --git a/.devkit/anti-slop/LICENSE b/.devkit/anti-slop/LICENSE new file mode 100644 index 0000000..69239ea --- /dev/null +++ b/.devkit/anti-slop/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Dillon Mulroy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.devkit/anti-slop/manifest.json b/.devkit/anti-slop/manifest.json new file mode 100644 index 0000000..0859a5f --- /dev/null +++ b/.devkit/anti-slop/manifest.json @@ -0,0 +1,26 @@ +{ + "schemaVersion": 1, + "upstreamCommit": "446268e5d15baa968eaec669ff65358d36ae6259", + "pluginApiVersion": "1.78.0", + "ruleIds": [ + "anti-slop/no-chained-type-assertions", + "anti-slop/no-conditional-empty-object-spread", + "anti-slop/no-known-value-widening", + "anti-slop/no-module-mocking", + "anti-slop/no-object-parameters", + "anti-slop/no-reflect-apply", + "anti-slop/no-reflect-get", + "anti-slop/no-runtime-typeof", + "anti-slop/no-shape-in-symbol-names", + "anti-slop/no-unknown-parameters", + "anti-slop/no-unknown-returns", + "anti-slop/no-unknown-type-aliases", + "anti-slop/no-unsafe-dictionary-type", + "anti-slop/no-widen-then-assert", + "anti-slop/require-safety-comment-for-type-assertion" + ], + "pluginDigest": "40a480e9670b4c28fed3ec7577e1b1f4321c58ab41ddacd46709fe21a5a15f96", + "configDigest": "a1755ce4c9bd74b4800717f1f316b1047d638dc59d6277c4844b59c55306c496", + "probeDigest": "bf2c2181804ac4004aed98aa41133e080068be9b2e9bf9d47a459ce75c6cdb87", + "probeConfigDigest": "b9bfbd93519b843df6bd175b91f5742bb67be649cac5c82492621e5a7bbd7604" +} diff --git a/.devkit/anti-slop/oxlint.json b/.devkit/anti-slop/oxlint.json new file mode 100644 index 0000000..2452427 --- /dev/null +++ b/.devkit/anti-slop/oxlint.json @@ -0,0 +1,60 @@ +{ + "jsPlugins": [ + { + "name": "anti-slop", + "specifier": "./plugin/index.ts" + } + ], + "overrides": [ + { + "files": [ + ".agent/**", + ".agents/**", + ".claude/**", + ".codex/**", + ".continue/**", + ".cursor/**", + ".devkit/anti-slop/plugin/**", + ".gemini/**", + ".opencode/**", + ".pi/**", + ".roo/**", + ".windsurf/**" + ], + "rules": { + "anti-slop/no-chained-type-assertions": "off", + "anti-slop/no-conditional-empty-object-spread": "off", + "anti-slop/no-known-value-widening": "off", + "anti-slop/no-module-mocking": "off", + "anti-slop/no-object-parameters": "off", + "anti-slop/no-reflect-apply": "off", + "anti-slop/no-reflect-get": "off", + "anti-slop/no-runtime-typeof": "off", + "anti-slop/no-shape-in-symbol-names": "off", + "anti-slop/no-unknown-parameters": "off", + "anti-slop/no-unknown-returns": "off", + "anti-slop/no-unknown-type-aliases": "off", + "anti-slop/no-unsafe-dictionary-type": "off", + "anti-slop/no-widen-then-assert": "off", + "anti-slop/require-safety-comment-for-type-assertion": "off" + } + } + ], + "rules": { + "anti-slop/no-chained-type-assertions": "error", + "anti-slop/no-conditional-empty-object-spread": "error", + "anti-slop/no-known-value-widening": "error", + "anti-slop/no-module-mocking": "error", + "anti-slop/no-object-parameters": "error", + "anti-slop/no-reflect-apply": "error", + "anti-slop/no-reflect-get": "error", + "anti-slop/no-runtime-typeof": "error", + "anti-slop/no-shape-in-symbol-names": "error", + "anti-slop/no-unknown-parameters": "error", + "anti-slop/no-unknown-returns": "error", + "anti-slop/no-unknown-type-aliases": "error", + "anti-slop/no-unsafe-dictionary-type": "error", + "anti-slop/no-widen-then-assert": "error", + "anti-slop/require-safety-comment-for-type-assertion": "error" + } +} diff --git a/.devkit/anti-slop/plugin/index.ts b/.devkit/anti-slop/plugin/index.ts new file mode 100644 index 0000000..05e9407 --- /dev/null +++ b/.devkit/anti-slop/plugin/index.ts @@ -0,0 +1,41 @@ +import { eslintCompatPlugin } from "#oxlint-plugins"; + +import { noChainedTypeAssertionsRule } from "./rules/no-chained-type-assertions.ts"; +import { noConditionalEmptyObjectSpreadRule } from "./rules/no-conditional-empty-object-spread.ts"; +import { noKnownValueWideningRule } from "./rules/no-known-value-widening.ts"; +import { noModuleMockingRule } from "./rules/no-module-mocking.ts"; +import { noObjectParametersRule } from "./rules/no-object-parameters.ts"; +import { noReflectApplyRule } from "./rules/no-reflect-apply.ts"; +import { noReflectGetRule } from "./rules/no-reflect-get.ts"; +import { noRuntimeTypeofRule } from "./rules/no-runtime-typeof.ts"; +import { noForbiddenTermInSymbolNamesRule } from "./rules/no-shape-in-symbol-names.ts"; +import { noUnknownParametersRule } from "./rules/no-unknown-parameters.ts"; +import { noUnknownReturnsRule } from "./rules/no-unknown-returns.ts"; +import { noUnknownTypeAliasesRule } from "./rules/no-unknown-type-aliases.ts"; +import { noUnsafeDictionaryTypeRule } from "./rules/no-unsafe-dictionary-type.ts"; +import { noWidenThenAssertRule } from "./rules/no-widen-then-assert.ts"; +import { requireSafetyCommentForTypeAssertionRule } from "./rules/require-safety-comment-for-type-assertion.ts"; + +/** Generic Oxlint rules that reject low-evidence and low-signal implementation patterns. */ +const antiSlopPlugin = eslintCompatPlugin({ + meta: { name: "anti-slop" }, + rules: { + "no-chained-type-assertions": noChainedTypeAssertionsRule, + "no-conditional-empty-object-spread": noConditionalEmptyObjectSpreadRule, + "no-known-value-widening": noKnownValueWideningRule, + "no-module-mocking": noModuleMockingRule, + "no-object-parameters": noObjectParametersRule, + "no-reflect-apply": noReflectApplyRule, + "no-reflect-get": noReflectGetRule, + "no-runtime-typeof": noRuntimeTypeofRule, + "no-unsafe-dictionary-type": noUnsafeDictionaryTypeRule, + "no-shape-in-symbol-names": noForbiddenTermInSymbolNamesRule, + "no-unknown-parameters": noUnknownParametersRule, + "no-unknown-returns": noUnknownReturnsRule, + "no-unknown-type-aliases": noUnknownTypeAliasesRule, + "no-widen-then-assert": noWidenThenAssertRule, + "require-safety-comment-for-type-assertion": requireSafetyCommentForTypeAssertionRule, + }, +}); + +export default antiSlopPlugin; diff --git a/.devkit/anti-slop/plugin/oxlint-plugins-api/LICENSE b/.devkit/anti-slop/plugin/oxlint-plugins-api/LICENSE new file mode 100644 index 0000000..444bffc --- /dev/null +++ b/.devkit/anti-slop/plugin/oxlint-plugins-api/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2024-present VoidZero Inc. & Contributors +Copyright (c) 2023 Boshen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.devkit/anti-slop/plugin/oxlint-plugins-api/README.md b/.devkit/anti-slop/plugin/oxlint-plugins-api/README.md new file mode 100644 index 0000000..8065871 --- /dev/null +++ b/.devkit/anti-slop/plugin/oxlint-plugins-api/README.md @@ -0,0 +1,95 @@ +# @oxlint/plugins + +Plugin utilities for [Oxlint](https://oxc.rs/docs/guide/usage/linter/js-plugins). + +This package provides optional functions to assist in creating Oxlint JS plugins and rules. + +## Installation + +```bash +npm install @oxlint/plugins +``` + +## Usage + +### Define functions + +Use `definePlugin` and `defineRule` if authoring your plugin in TypeScript for type safety. + +```typescript +import { definePlugin, defineRule } from "@oxlint/plugins"; + +const rule = defineRule({ + create(context) { + return { + Program(node) { + // Rule logic here + }, + }; + }, +}); + +export default definePlugin({ + meta: { name: "oxlint-plugin-amazing" }, + rules: { amazing: rule }, +}); +``` + +### Types + +This package also includes types for plugins and rules. + +```typescript +import type { Context, Rule, ESTree } from "@oxlint/plugins"; + +const rule: Rule = { + create(context: Context) { + return { + Program(node: ESTree.Program) { + // Rule logic here + }, + }; + }, +}; +``` + +### ESLint compatibility + +If your plugin uses Oxlint's [alternative `createOnce` API](https://oxc.rs/docs/guide/usage/linter/js-plugins#alternative-api), +use `eslintCompatPlugin` to convert the plugin so it will also work with ESLint. + +```typescript +import { eslintCompatPlugin } from "@oxlint/plugins"; + +const rule = { + createOnce(context) { + return { + Program(node) { + // Rule logic here + }, + }; + }, +}; + +export default eslintCompatPlugin({ + meta: { name: "oxlint-plugin-amazing" }, + rules: { amazing: rule }, +}); +``` + +## Node.js version + +This package requires Node.js 12.22.0+, 14.17.0+, 16.0.0+, or later. +This matches the minimum Node.js version required by ESLint 8. + +This package provides both ESM and CommonJS entry points. + +So a plugin which depends on `@oxlint/plugins` can be: + +- Used with any version of Oxlint. +- Used with ESLint 8+. +- Published as either ESM or CommonJS. + +## Docs + +For full documentation, see [Oxlint JS Plugins docs](https://oxc.rs/docs/guide/usage/linter/js-plugins). diff --git a/.devkit/anti-slop/plugin/oxlint-plugins-api/index.cjs b/.devkit/anti-slop/plugin/oxlint-plugins-api/index.cjs new file mode 100644 index 0000000..49cd83c --- /dev/null +++ b/.devkit/anti-slop/plugin/oxlint-plugins-api/index.cjs @@ -0,0 +1,357 @@ +Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); +//#region src-js/package/define.ts +/** +* Define a plugin. +* +* No-op function, just to provide type safety. Input is passed through unchanged. +* +* @param plugin - Plugin to define +* @returns Same plugin as passed in +*/ +function definePlugin(plugin) { + return plugin; +} +/** +* Define a rule. +* +* No-op function, just to provide type safety. Input is passed through unchanged. +* +* @param rule - Rule to define +* @returns Same rule as passed in +*/ +function defineRule(rule) { + return rule; +} +//#endregion +//#region src-js/package/compat.ts +const EMPTY_VISITOR = {}; +/** +* Convert a plugin which used Oxlint's `createOnce` API to also work with ESLint. +* +* If any of the plugin's rules use the Oxlint alternative `createOnce` API, +* add ESLint-compatible `create` methods to those rules, which delegate to `createOnce`. +* This makes the plugin compatible with ESLint. +* +* The `plugin` object passed in is mutated in-place. +* +* @param plugin - Plugin to convert +* @returns Plugin with all rules having `create` method +* @throws {Error} If `plugin` is not an object, or `plugin.rules` is not an object +*/ +function eslintCompatPlugin(plugin) { + if (typeof plugin != "object" || !plugin) throw Error("Plugin must be an object"); + let { rules } = plugin; + if (typeof rules != "object" || !rules) throw Error("Plugin must have an object as `rules` property"); + let afterHooksState = new AfterHooksState(); + for (let ruleName in rules) Object.hasOwn(rules, ruleName) && convertRule(rules[ruleName], afterHooksState); + return plugin; +} +/** +* Class containing state for tracking if any `after` hooks for a plugin's rules need to be called. +* +* # Aims +* +* Aims are: +* 1. `after` hook of each rule runs after all other AST visit functions, and CFG event handlers. +* 2. `after` hooks for *all* a plugin's rules run after *all* that plugin's rules have completed visiting AST. +* 3. `after` hooks for *all* a plugin's rules run before *any* of plugin's rules begin linting another file. +* 4. In the case of an error during AST traversal, `after` hooks are always still run. +* +* The above exactly matches the behavior when running a `createOnce` rule in Oxlint. +* +* # Why this is important +* +* All the complication comes from ensuring `after` hooks run even after an error during AST traversal. +* +* In ESLint CLI, an error will crash the process, so it doesn't particularly matter if `after` hooks run or not, +* but language servers will typically swallow errors, and keep the process running. +* +* Rules using `before` and `after` hooks will often rely on both hooks running in a predictable order, +* to maintain some internal state. For example, they may use `before` and `after` hooks to maintain a per-file +* cache of data which is shared between rules. The cache use case is why rule (2) above is important. +* +* Below is an example of using `before` and `after` hooks to maintain a per-file cache, shared between rules. +* It relies on all `before` hooks running before any rule starts visiting the AST, +* and all `after` hooks running after all rules have finished visiting the AST. +* +* ```ts +* let cache: Data | null = null; +* +* let numRunningRules = 0; +* +* const setupCache = (context) => { +* if (cache === null) cache = new Data(context); +* numRunningRules++; +* }; +* +* const teardownCache = () => { +* numRunningRules--; +* if (numRunningRules === 0) cache = null; +* }; +* +* const rule1 = { +* createOnce(context) { +* return { +* before() { +* setupCache(context); +* }, +* Identifier(node) { +* // Use `cache` +* }, +* after: teardownCache, +* }; +* }, +* }; +* +* const rule2 = { +* // Same as above +* }; +* +* const rule3 = { +* // Same as above +* }; +* ``` +* +* If `after` hooks did not always run, the next lint run could get stale state, and malfunction. +* If `after` hooks ran in the wrong order (e.g. after some `before` hooks for next file), +* `numRunningRules` would never get to 0, and cache would never be cleared. +* +* Note that because all rules run together in a single AST traversal, if a rule from plugin X throws an error, +* it can disrupt rules from plugin Y. This would make it hard to debug. +* +* # Mechanism +* +* ## Initialization +* +* Rules with an `after` hook register themselves by: +* +* 1. Calling `registerResetFunction` to register a function to run `after` hook and clean up internal state. +* This call adds the reset fn to `resetFunctions`, and adds `AFTER_HOOK_INACTIVE` to `pendingStates`. +* 2. Adding an `onCodePathEnd` CFG event handler to the visitor which calls `ruleFinished` at end of AST traversal. +* +* ## Per-file setup +* +* Before linting a file, `create` will call `setupAfterHook` which is created by `createContextAndVisitor`. +* This registers that the `after` hook for the rule needs to run, by setting `pendingStates[ruleIndex]` +* to `AFTER_HOOK_PENDING`, and incrementing `pendingCount`. +* +* If a cleanup microtask has not been scheduled yet, one is scheduled now (see reason below). +* +* ## Normal operation +* +* AST traversal for each rule ends with `ruleFinished` hook being called from `onCodePathEnd` CFG event handler. +* It increments `lintFinishedCount`. If `lintFinishedCount` equals `pendingCount`, all rules have finished linting +* the file, and `reset` is called, which calls all the pending `after` hooks. +* +* ## Error handling +* +* If an error is thrown during AST traversal, we ensure that `after` hooks are still run by 2 mechanisms: +* +* ### 1. Next microtick +* +* Before any rules began linting files, a microtask was scheduled, which runs on next micro-tick. +* All language servers we're aware of run each lint task in a separate tick, so this microtask will run in next tick +* after a linting run, before the next lint task starts. +* +* If the linting run completed successfully, the microtask does nothing. +* +* But if an error was thrown during AST traversal, this will be visible from the state of `pendingCount`. +* The microtask will run any `after` hooks which need to be run, and reset state to reflect that there are +* no more pending `after` hooks. +* +* ### 2. Fallback: Next lint run +* +* Before linting any file, the state of `pendingCount` is checked. +* If any `after` hooks are still pending, they are run immediately. +* They're run before the `context` objects in `createOnce` closures are updated to the next file, +* so they run with access to the old `context` object from the last file. +* +* This fallback should not be required, but it's included as "belt and braces", to handle if any language server +* or other environment running ESLint programmatically, does not pause a tick between linting runs. +*/ +var AfterHooksState = class { + resetFunctions = []; + pendingStates = []; + pendingCount = 0; + lintFinishedCount = 0; + resetIsScheduled = !1; + sourceCode = null; + resetMicrotask = this.resetMicrotaskImpl.bind(this); + /** + * Register a function to run `after` hook for a rule, and reset state. + * @param reset - Function to run `after` hook and reset state + * @returns Index of rule + */ + registerResetFunction(reset) { + let { pendingStates } = this, index = pendingStates.length; + return pendingStates.push(0), this.resetFunctions.push(reset), index; + } + /** + * Register that a rule with `after` hook has completed linting a file. + * Called by `onCodePathEnd` CFG event handler which is added to visitor for rules with `after` hooks. + * + * If all rules with an `after` hook which needs to be run have completed linting the file, run all `after` hooks. + */ + ruleFinished() { + this.lintFinishedCount++, this.lintFinishedCount === this.pendingCount && this.reset(!1); + } + /** + * Call all reset functions where corresponding entry in `pendingStates` is `AFTER_HOOK_PENDING`. + * Should only be called when some `after` hooks are pending. + * + * @param ignoreErrors - `true` to catch and silently ignore any errors which occur in `after` hooks. + * `false` to throw them, + * @throws {unknown} If `ignoreErrors` is `false` and an error occurs in any `after` hooks. + */ + reset(ignoreErrors) { + this.pendingCount; + let { resetFunctions, pendingStates } = this, hooksLen = pendingStates.length, hasError = !1, error; + for (let i = 0; i < hooksLen; i++) if (pendingStates[i] !== 0) { + pendingStates[i] = 0; + try { + resetFunctions[i](); + } catch (e) { + hasError === !1 && (hasError = !0, error = e); + } + } + if (this.pendingCount = 0, this.lintFinishedCount = 0, this.sourceCode = null, hasError === !0 && ignoreErrors === !1) throw error; + } + /** + * Schedule a microtask to run `reset` functions. + */ + scheduleReset() { + queueMicrotask(this.resetMicrotask), this.resetIsScheduled = !0; + } + /** + * Function which is scheduled as the cleanup microtask. + * `scheduleReset` uses `resetMicrotask` which is this method bound to `this`. + */ + resetMicrotaskImpl() { + this.resetIsScheduled = !1, this.pendingCount !== 0 && this.reset(!0); + } +}; +/** +* Convert a rule. +* +* The `rule` object passed in is mutated in-place. +* +* @param rule - Rule to convert +* @param afterHooksState - State of `after` hooks +* @throws {Error} If `rule` is not an object +*/ +function convertRule(rule, afterHooksState) { + if (typeof rule != "object" || !rule) throw Error("Rule must be an object"); + if ("create" in rule) return; + let context = null, visitor, beforeHook, setupAfterHook; + rule.create = (eslintContext) => { + context === null && ({context, visitor, beforeHook, setupAfterHook} = createContextAndVisitor(rule, afterHooksState)); + let eslintFileContext = Object.getPrototypeOf(eslintContext); + if (setupAfterHook !== null) { + let { sourceCode } = eslintFileContext; + afterHooksState.sourceCode !== sourceCode && (afterHooksState.sourceCode = sourceCode, afterHooksState.pendingCount !== 0 && afterHooksState.reset(!0)); + } + return Object.defineProperties(context, { + id: { value: eslintContext.id }, + options: { value: eslintContext.options }, + report: { value: eslintContext.report } + }), Object.setPrototypeOf(context, eslintFileContext), beforeHook !== null && beforeHook() === !1 ? EMPTY_VISITOR : (setupAfterHook !== null && (setupAfterHook(eslintFileContext.sourceCode.ast), afterHooksState.resetIsScheduled === !1 && afterHooksState.scheduleReset()), visitor); + }; +} +const FILE_CONTEXT = Object.freeze({ + get filename() { + throw Error("Cannot access `context.filename` in `createOnce`"); + }, + getFilename() { + throw Error("Cannot call `context.getFilename` in `createOnce`"); + }, + get physicalFilename() { + throw Error("Cannot access `context.physicalFilename` in `createOnce`"); + }, + getPhysicalFilename() { + throw Error("Cannot call `context.getPhysicalFilename` in `createOnce`"); + }, + get cwd() { + throw Error("Cannot access `context.cwd` in `createOnce`"); + }, + getCwd() { + throw Error("Cannot call `context.getCwd` in `createOnce`"); + }, + get sourceCode() { + throw Error("Cannot access `context.sourceCode` in `createOnce`"); + }, + getSourceCode() { + throw Error("Cannot call `context.getSourceCode` in `createOnce`"); + }, + get languageOptions() { + throw Error("Cannot access `context.languageOptions` in `createOnce`"); + }, + get settings() { + throw Error("Cannot access `context.settings` in `createOnce`"); + }, + extend(extension) { + return Object.freeze(Object.assign(Object.create(this), extension)); + }, + get parserOptions() { + throw Error("Cannot access `context.parserOptions` in `createOnce`"); + }, + get parserPath() { + throw Error("Cannot access `context.parserPath` in `createOnce`"); + } +}); +/** +* Call `createOnce` method of rule, and return `Context`, `Visitor`, and `beforeHook` (if any). +* +* @param rule - Rule with `createOnce` method +* @param afterHooksState - State of `after` hooks +* @returns Object with `context`, `visitor`, and `beforeHook` properties, +* and `setupAfterHook` function if visitor has an `after` hook +*/ +function createContextAndVisitor(rule, afterHooksState) { + let { createOnce } = rule; + if (createOnce == null) throw Error("Rules must define either a `create` or `createOnce` method"); + if (typeof createOnce != "function") throw Error("Rule `createOnce` property must be a function"); + let context = Object.create(FILE_CONTEXT, { + id: { + value: null, + enumerable: !0, + configurable: !0 + }, + options: { + value: null, + enumerable: !0, + configurable: !0 + }, + report: { + value() { + throw Error("Cannot report errors in `createOnce`"); + }, + enumerable: !0, + configurable: !0 + } + }), { before: beforeHook, after: afterHook, ...visitor } = createOnce.call(rule, context); + if (beforeHook === void 0) beforeHook = null; + else if (beforeHook !== null && typeof beforeHook != "function") throw Error("`before` property of visitor must be a function if defined"); + let setupAfterHook = null; + if (afterHook != null) { + if (typeof afterHook != "function") throw Error("`after` property of visitor must be a function if defined"); + let program = null, ruleIndex = afterHooksState.registerResetFunction(() => { + program = null, afterHook(); + }); + setupAfterHook = (ast) => { + program = ast, afterHooksState.pendingStates[ruleIndex] = 1, afterHooksState.pendingCount++; + }; + let onCodePathEnd = visitor.onCodePathEnd; + visitor.onCodePathEnd = onCodePathEnd == null ? function(_codePath, node) { + node === program && afterHooksState.ruleFinished(); + } : function(codePath, node) { + onCodePathEnd.call(this, codePath, node), node === program && afterHooksState.ruleFinished(); + }; + } + return { + context, + visitor, + beforeHook, + setupAfterHook + }; +} +exports.definePlugin = definePlugin, exports.defineRule = defineRule, exports.eslintCompatPlugin = eslintCompatPlugin; diff --git a/.devkit/anti-slop/plugin/oxlint-plugins-api/index.d.ts b/.devkit/anti-slop/plugin/oxlint-plugins-api/index.d.ts new file mode 100644 index 0000000..68467ba --- /dev/null +++ b/.devkit/anti-slop/plugin/oxlint-plugins-api/index.d.ts @@ -0,0 +1,4346 @@ +//#endregion +//#region src-js/plugins/tokens.d.ts +/** + * AST token type. + */ +type TokenType = BooleanToken | IdentifierToken | JSXIdentifierToken | JSXTextToken | KeywordToken | NullToken | NumericToken | PrivateIdentifierToken | PunctuatorToken | RegularExpressionToken | StringToken | TemplateToken; +interface BaseToken extends Span { + value: string; + regex: undefined; +} +interface BooleanToken extends BaseToken { + type: "Boolean"; +} +interface IdentifierToken extends BaseToken { + type: "Identifier"; +} +interface JSXIdentifierToken extends BaseToken { + type: "JSXIdentifier"; +} +interface JSXTextToken extends BaseToken { + type: "JSXText"; +} +interface KeywordToken extends BaseToken { + type: "Keyword"; +} +interface NullToken extends BaseToken { + type: "Null"; +} +interface NumericToken extends BaseToken { + type: "Numeric"; +} +interface PrivateIdentifierToken extends BaseToken { + type: "PrivateIdentifier"; +} +interface PunctuatorToken extends BaseToken { + type: "Punctuator"; +} +interface RegularExpressionToken extends Span { + type: "RegularExpression"; + value: string; + regex: { + pattern: string; + flags: string; + }; +} +interface StringToken extends BaseToken { + type: "String"; +} +interface TemplateToken extends BaseToken { + type: "Template"; +} +//#endregion +//#region src-js/generated/visitor.d.ts +// To understand why we need the "Bivariance hack", see: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/20219 +// For downsides, see: https://github.com/oxc-project/oxc/issues/18154#issuecomment-4012955607 +type BivarianceHackHandler any> = { + bivarianceHack(...args: Parameters): ReturnType; +}["bivarianceHack"]; +interface StrictVisitorObject { + DebuggerStatement?: (node: DebuggerStatement) => void; + "DebuggerStatement:exit"?: (node: DebuggerStatement) => void; + EmptyStatement?: (node: EmptyStatement) => void; + "EmptyStatement:exit"?: (node: EmptyStatement) => void; + Literal?: (node: BooleanLiteral | NullLiteral | NumericLiteral | StringLiteral | BigIntLiteral | RegExpLiteral) => void; + "Literal:exit"?: (node: BooleanLiteral | NullLiteral | NumericLiteral | StringLiteral | BigIntLiteral | RegExpLiteral) => void; + PrivateIdentifier?: (node: PrivateIdentifier) => void; + "PrivateIdentifier:exit"?: (node: PrivateIdentifier) => void; + Super?: (node: Super) => void; + "Super:exit"?: (node: Super) => void; + TemplateElement?: (node: TemplateElement) => void; + "TemplateElement:exit"?: (node: TemplateElement) => void; + ThisExpression?: (node: ThisExpression) => void; + "ThisExpression:exit"?: (node: ThisExpression) => void; + JSXClosingFragment?: (node: JSXClosingFragment) => void; + "JSXClosingFragment:exit"?: (node: JSXClosingFragment) => void; + JSXEmptyExpression?: (node: JSXEmptyExpression) => void; + "JSXEmptyExpression:exit"?: (node: JSXEmptyExpression) => void; + JSXIdentifier?: (node: JSXIdentifier) => void; + "JSXIdentifier:exit"?: (node: JSXIdentifier) => void; + JSXOpeningFragment?: (node: JSXOpeningFragment) => void; + "JSXOpeningFragment:exit"?: (node: JSXOpeningFragment) => void; + JSXText?: (node: JSXText) => void; + "JSXText:exit"?: (node: JSXText) => void; + TSAnyKeyword?: (node: TSAnyKeyword) => void; + "TSAnyKeyword:exit"?: (node: TSAnyKeyword) => void; + TSBigIntKeyword?: (node: TSBigIntKeyword) => void; + "TSBigIntKeyword:exit"?: (node: TSBigIntKeyword) => void; + TSBooleanKeyword?: (node: TSBooleanKeyword) => void; + "TSBooleanKeyword:exit"?: (node: TSBooleanKeyword) => void; + TSIntrinsicKeyword?: (node: TSIntrinsicKeyword) => void; + "TSIntrinsicKeyword:exit"?: (node: TSIntrinsicKeyword) => void; + TSJSDocUnknownType?: (node: JSDocUnknownType) => void; + "TSJSDocUnknownType:exit"?: (node: JSDocUnknownType) => void; + TSNeverKeyword?: (node: TSNeverKeyword) => void; + "TSNeverKeyword:exit"?: (node: TSNeverKeyword) => void; + TSNullKeyword?: (node: TSNullKeyword) => void; + "TSNullKeyword:exit"?: (node: TSNullKeyword) => void; + TSNumberKeyword?: (node: TSNumberKeyword) => void; + "TSNumberKeyword:exit"?: (node: TSNumberKeyword) => void; + TSObjectKeyword?: (node: TSObjectKeyword) => void; + "TSObjectKeyword:exit"?: (node: TSObjectKeyword) => void; + TSStringKeyword?: (node: TSStringKeyword) => void; + "TSStringKeyword:exit"?: (node: TSStringKeyword) => void; + TSSymbolKeyword?: (node: TSSymbolKeyword) => void; + "TSSymbolKeyword:exit"?: (node: TSSymbolKeyword) => void; + TSThisType?: (node: TSThisType) => void; + "TSThisType:exit"?: (node: TSThisType) => void; + TSUndefinedKeyword?: (node: TSUndefinedKeyword) => void; + "TSUndefinedKeyword:exit"?: (node: TSUndefinedKeyword) => void; + TSUnknownKeyword?: (node: TSUnknownKeyword) => void; + "TSUnknownKeyword:exit"?: (node: TSUnknownKeyword) => void; + TSVoidKeyword?: (node: TSVoidKeyword) => void; + "TSVoidKeyword:exit"?: (node: TSVoidKeyword) => void; + AccessorProperty?: (node: AccessorProperty) => void; + "AccessorProperty:exit"?: (node: AccessorProperty) => void; + ArrayExpression?: (node: ArrayExpression) => void; + "ArrayExpression:exit"?: (node: ArrayExpression) => void; + ArrayPattern?: (node: ArrayPattern) => void; + "ArrayPattern:exit"?: (node: ArrayPattern) => void; + ArrowFunctionExpression?: (node: ArrowFunctionExpression) => void; + "ArrowFunctionExpression:exit"?: (node: ArrowFunctionExpression) => void; + AssignmentExpression?: (node: AssignmentExpression) => void; + "AssignmentExpression:exit"?: (node: AssignmentExpression) => void; + AssignmentPattern?: (node: AssignmentPattern) => void; + "AssignmentPattern:exit"?: (node: AssignmentPattern) => void; + AwaitExpression?: (node: AwaitExpression) => void; + "AwaitExpression:exit"?: (node: AwaitExpression) => void; + BinaryExpression?: (node: BinaryExpression) => void; + "BinaryExpression:exit"?: (node: BinaryExpression) => void; + BlockStatement?: (node: BlockStatement) => void; + "BlockStatement:exit"?: (node: BlockStatement) => void; + BreakStatement?: (node: BreakStatement) => void; + "BreakStatement:exit"?: (node: BreakStatement) => void; + CallExpression?: (node: CallExpression) => void; + "CallExpression:exit"?: (node: CallExpression) => void; + CatchClause?: (node: CatchClause) => void; + "CatchClause:exit"?: (node: CatchClause) => void; + ChainExpression?: (node: ChainExpression) => void; + "ChainExpression:exit"?: (node: ChainExpression) => void; + ClassBody?: (node: ClassBody) => void; + "ClassBody:exit"?: (node: ClassBody) => void; + ClassDeclaration?: (node: Class) => void; + "ClassDeclaration:exit"?: (node: Class) => void; + ClassExpression?: (node: Class) => void; + "ClassExpression:exit"?: (node: Class) => void; + ConditionalExpression?: (node: ConditionalExpression) => void; + "ConditionalExpression:exit"?: (node: ConditionalExpression) => void; + ContinueStatement?: (node: ContinueStatement) => void; + "ContinueStatement:exit"?: (node: ContinueStatement) => void; + Decorator?: (node: Decorator) => void; + "Decorator:exit"?: (node: Decorator) => void; + DoWhileStatement?: (node: DoWhileStatement) => void; + "DoWhileStatement:exit"?: (node: DoWhileStatement) => void; + ExportAllDeclaration?: (node: ExportAllDeclaration) => void; + "ExportAllDeclaration:exit"?: (node: ExportAllDeclaration) => void; + ExportDefaultDeclaration?: (node: ExportDefaultDeclaration) => void; + "ExportDefaultDeclaration:exit"?: (node: ExportDefaultDeclaration) => void; + ExportNamedDeclaration?: (node: ExportNamedDeclaration) => void; + "ExportNamedDeclaration:exit"?: (node: ExportNamedDeclaration) => void; + ExportSpecifier?: (node: ExportSpecifier) => void; + "ExportSpecifier:exit"?: (node: ExportSpecifier) => void; + ExpressionStatement?: (node: ExpressionStatement) => void; + "ExpressionStatement:exit"?: (node: ExpressionStatement) => void; + ForInStatement?: (node: ForInStatement) => void; + "ForInStatement:exit"?: (node: ForInStatement) => void; + ForOfStatement?: (node: ForOfStatement) => void; + "ForOfStatement:exit"?: (node: ForOfStatement) => void; + ForStatement?: (node: ForStatement) => void; + "ForStatement:exit"?: (node: ForStatement) => void; + FunctionDeclaration?: (node: Function$1) => void; + "FunctionDeclaration:exit"?: (node: Function$1) => void; + FunctionExpression?: (node: Function$1) => void; + "FunctionExpression:exit"?: (node: Function$1) => void; + Identifier?: (node: IdentifierName | IdentifierReference | BindingIdentifier | LabelIdentifier | TSThisParameter | TSIndexSignatureName) => void; + "Identifier:exit"?: (node: IdentifierName | IdentifierReference | BindingIdentifier | LabelIdentifier | TSThisParameter | TSIndexSignatureName) => void; + IfStatement?: (node: IfStatement) => void; + "IfStatement:exit"?: (node: IfStatement) => void; + ImportAttribute?: (node: ImportAttribute) => void; + "ImportAttribute:exit"?: (node: ImportAttribute) => void; + ImportDeclaration?: (node: ImportDeclaration) => void; + "ImportDeclaration:exit"?: (node: ImportDeclaration) => void; + ImportDefaultSpecifier?: (node: ImportDefaultSpecifier) => void; + "ImportDefaultSpecifier:exit"?: (node: ImportDefaultSpecifier) => void; + ImportExpression?: (node: ImportExpression) => void; + "ImportExpression:exit"?: (node: ImportExpression) => void; + ImportNamespaceSpecifier?: (node: ImportNamespaceSpecifier) => void; + "ImportNamespaceSpecifier:exit"?: (node: ImportNamespaceSpecifier) => void; + ImportSpecifier?: (node: ImportSpecifier) => void; + "ImportSpecifier:exit"?: (node: ImportSpecifier) => void; + LabeledStatement?: (node: LabeledStatement) => void; + "LabeledStatement:exit"?: (node: LabeledStatement) => void; + LogicalExpression?: (node: LogicalExpression) => void; + "LogicalExpression:exit"?: (node: LogicalExpression) => void; + MemberExpression?: (node: MemberExpression) => void; + "MemberExpression:exit"?: (node: MemberExpression) => void; + MetaProperty?: (node: MetaProperty) => void; + "MetaProperty:exit"?: (node: MetaProperty) => void; + MethodDefinition?: (node: MethodDefinition) => void; + "MethodDefinition:exit"?: (node: MethodDefinition) => void; + NewExpression?: (node: NewExpression) => void; + "NewExpression:exit"?: (node: NewExpression) => void; + ObjectExpression?: (node: ObjectExpression) => void; + "ObjectExpression:exit"?: (node: ObjectExpression) => void; + ObjectPattern?: (node: ObjectPattern) => void; + "ObjectPattern:exit"?: (node: ObjectPattern) => void; + ParenthesizedExpression?: (node: ParenthesizedExpression) => void; + "ParenthesizedExpression:exit"?: (node: ParenthesizedExpression) => void; + Program?: (node: Program) => void; + "Program:exit"?: (node: Program) => void; + Property?: (node: ObjectProperty | AssignmentTargetProperty | AssignmentTargetPropertyProperty | BindingProperty) => void; + "Property:exit"?: (node: ObjectProperty | AssignmentTargetProperty | AssignmentTargetPropertyProperty | BindingProperty) => void; + PropertyDefinition?: (node: PropertyDefinition) => void; + "PropertyDefinition:exit"?: (node: PropertyDefinition) => void; + RestElement?: (node: AssignmentTargetRest | BindingRestElement | FormalParameterRest) => void; + "RestElement:exit"?: (node: AssignmentTargetRest | BindingRestElement | FormalParameterRest) => void; + ReturnStatement?: (node: ReturnStatement) => void; + "ReturnStatement:exit"?: (node: ReturnStatement) => void; + SequenceExpression?: (node: SequenceExpression) => void; + "SequenceExpression:exit"?: (node: SequenceExpression) => void; + SpreadElement?: (node: SpreadElement) => void; + "SpreadElement:exit"?: (node: SpreadElement) => void; + StaticBlock?: (node: StaticBlock) => void; + "StaticBlock:exit"?: (node: StaticBlock) => void; + SwitchCase?: (node: SwitchCase) => void; + "SwitchCase:exit"?: (node: SwitchCase) => void; + SwitchStatement?: (node: SwitchStatement) => void; + "SwitchStatement:exit"?: (node: SwitchStatement) => void; + TaggedTemplateExpression?: (node: TaggedTemplateExpression) => void; + "TaggedTemplateExpression:exit"?: (node: TaggedTemplateExpression) => void; + TemplateLiteral?: (node: TemplateLiteral) => void; + "TemplateLiteral:exit"?: (node: TemplateLiteral) => void; + ThrowStatement?: (node: ThrowStatement) => void; + "ThrowStatement:exit"?: (node: ThrowStatement) => void; + TryStatement?: (node: TryStatement) => void; + "TryStatement:exit"?: (node: TryStatement) => void; + UnaryExpression?: (node: UnaryExpression) => void; + "UnaryExpression:exit"?: (node: UnaryExpression) => void; + UpdateExpression?: (node: UpdateExpression) => void; + "UpdateExpression:exit"?: (node: UpdateExpression) => void; + V8IntrinsicExpression?: (node: V8IntrinsicExpression) => void; + "V8IntrinsicExpression:exit"?: (node: V8IntrinsicExpression) => void; + VariableDeclaration?: (node: VariableDeclaration) => void; + "VariableDeclaration:exit"?: (node: VariableDeclaration) => void; + VariableDeclarator?: (node: VariableDeclarator) => void; + "VariableDeclarator:exit"?: (node: VariableDeclarator) => void; + WhileStatement?: (node: WhileStatement) => void; + "WhileStatement:exit"?: (node: WhileStatement) => void; + WithStatement?: (node: WithStatement) => void; + "WithStatement:exit"?: (node: WithStatement) => void; + YieldExpression?: (node: YieldExpression) => void; + "YieldExpression:exit"?: (node: YieldExpression) => void; + JSXAttribute?: (node: JSXAttribute) => void; + "JSXAttribute:exit"?: (node: JSXAttribute) => void; + JSXClosingElement?: (node: JSXClosingElement) => void; + "JSXClosingElement:exit"?: (node: JSXClosingElement) => void; + JSXElement?: (node: JSXElement) => void; + "JSXElement:exit"?: (node: JSXElement) => void; + JSXExpressionContainer?: (node: JSXExpressionContainer) => void; + "JSXExpressionContainer:exit"?: (node: JSXExpressionContainer) => void; + JSXFragment?: (node: JSXFragment) => void; + "JSXFragment:exit"?: (node: JSXFragment) => void; + JSXMemberExpression?: (node: JSXMemberExpression) => void; + "JSXMemberExpression:exit"?: (node: JSXMemberExpression) => void; + JSXNamespacedName?: (node: JSXNamespacedName) => void; + "JSXNamespacedName:exit"?: (node: JSXNamespacedName) => void; + JSXOpeningElement?: (node: JSXOpeningElement) => void; + "JSXOpeningElement:exit"?: (node: JSXOpeningElement) => void; + JSXSpreadAttribute?: (node: JSXSpreadAttribute) => void; + "JSXSpreadAttribute:exit"?: (node: JSXSpreadAttribute) => void; + JSXSpreadChild?: (node: JSXSpreadChild) => void; + "JSXSpreadChild:exit"?: (node: JSXSpreadChild) => void; + TSAbstractAccessorProperty?: (node: AccessorProperty) => void; + "TSAbstractAccessorProperty:exit"?: (node: AccessorProperty) => void; + TSAbstractMethodDefinition?: (node: MethodDefinition) => void; + "TSAbstractMethodDefinition:exit"?: (node: MethodDefinition) => void; + TSAbstractPropertyDefinition?: (node: PropertyDefinition) => void; + "TSAbstractPropertyDefinition:exit"?: (node: PropertyDefinition) => void; + TSArrayType?: (node: TSArrayType) => void; + "TSArrayType:exit"?: (node: TSArrayType) => void; + TSAsExpression?: (node: TSAsExpression) => void; + "TSAsExpression:exit"?: (node: TSAsExpression) => void; + TSCallSignatureDeclaration?: (node: TSCallSignatureDeclaration) => void; + "TSCallSignatureDeclaration:exit"?: (node: TSCallSignatureDeclaration) => void; + TSClassImplements?: (node: TSClassImplements) => void; + "TSClassImplements:exit"?: (node: TSClassImplements) => void; + TSConditionalType?: (node: TSConditionalType) => void; + "TSConditionalType:exit"?: (node: TSConditionalType) => void; + TSConstructSignatureDeclaration?: (node: TSConstructSignatureDeclaration) => void; + "TSConstructSignatureDeclaration:exit"?: (node: TSConstructSignatureDeclaration) => void; + TSConstructorType?: (node: TSConstructorType) => void; + "TSConstructorType:exit"?: (node: TSConstructorType) => void; + TSDeclareFunction?: (node: Function$1) => void; + "TSDeclareFunction:exit"?: (node: Function$1) => void; + TSEmptyBodyFunctionExpression?: (node: Function$1) => void; + "TSEmptyBodyFunctionExpression:exit"?: (node: Function$1) => void; + TSEnumBody?: (node: TSEnumBody) => void; + "TSEnumBody:exit"?: (node: TSEnumBody) => void; + TSEnumDeclaration?: (node: TSEnumDeclaration) => void; + "TSEnumDeclaration:exit"?: (node: TSEnumDeclaration) => void; + TSEnumMember?: (node: TSEnumMember) => void; + "TSEnumMember:exit"?: (node: TSEnumMember) => void; + TSExportAssignment?: (node: TSExportAssignment) => void; + "TSExportAssignment:exit"?: (node: TSExportAssignment) => void; + TSExternalModuleReference?: (node: TSExternalModuleReference) => void; + "TSExternalModuleReference:exit"?: (node: TSExternalModuleReference) => void; + TSFunctionType?: (node: TSFunctionType) => void; + "TSFunctionType:exit"?: (node: TSFunctionType) => void; + TSImportEqualsDeclaration?: (node: TSImportEqualsDeclaration) => void; + "TSImportEqualsDeclaration:exit"?: (node: TSImportEqualsDeclaration) => void; + TSImportType?: (node: TSImportType) => void; + "TSImportType:exit"?: (node: TSImportType) => void; + TSIndexSignature?: (node: TSIndexSignature) => void; + "TSIndexSignature:exit"?: (node: TSIndexSignature) => void; + TSIndexedAccessType?: (node: TSIndexedAccessType) => void; + "TSIndexedAccessType:exit"?: (node: TSIndexedAccessType) => void; + TSInferType?: (node: TSInferType) => void; + "TSInferType:exit"?: (node: TSInferType) => void; + TSInstantiationExpression?: (node: TSInstantiationExpression) => void; + "TSInstantiationExpression:exit"?: (node: TSInstantiationExpression) => void; + TSInterfaceBody?: (node: TSInterfaceBody) => void; + "TSInterfaceBody:exit"?: (node: TSInterfaceBody) => void; + TSInterfaceDeclaration?: (node: TSInterfaceDeclaration) => void; + "TSInterfaceDeclaration:exit"?: (node: TSInterfaceDeclaration) => void; + TSInterfaceHeritage?: (node: TSInterfaceHeritage) => void; + "TSInterfaceHeritage:exit"?: (node: TSInterfaceHeritage) => void; + TSIntersectionType?: (node: TSIntersectionType) => void; + "TSIntersectionType:exit"?: (node: TSIntersectionType) => void; + TSJSDocNonNullableType?: (node: JSDocNonNullableType) => void; + "TSJSDocNonNullableType:exit"?: (node: JSDocNonNullableType) => void; + TSJSDocNullableType?: (node: JSDocNullableType) => void; + "TSJSDocNullableType:exit"?: (node: JSDocNullableType) => void; + TSLiteralType?: (node: TSLiteralType) => void; + "TSLiteralType:exit"?: (node: TSLiteralType) => void; + TSMappedType?: (node: TSMappedType) => void; + "TSMappedType:exit"?: (node: TSMappedType) => void; + TSMethodSignature?: (node: TSMethodSignature) => void; + "TSMethodSignature:exit"?: (node: TSMethodSignature) => void; + TSModuleBlock?: (node: TSModuleBlock) => void; + "TSModuleBlock:exit"?: (node: TSModuleBlock) => void; + TSModuleDeclaration?: (node: TSModuleDeclaration | TSGlobalDeclaration) => void; + "TSModuleDeclaration:exit"?: (node: TSModuleDeclaration | TSGlobalDeclaration) => void; + TSNamedTupleMember?: (node: TSNamedTupleMember) => void; + "TSNamedTupleMember:exit"?: (node: TSNamedTupleMember) => void; + TSNamespaceExportDeclaration?: (node: TSNamespaceExportDeclaration) => void; + "TSNamespaceExportDeclaration:exit"?: (node: TSNamespaceExportDeclaration) => void; + TSNonNullExpression?: (node: TSNonNullExpression) => void; + "TSNonNullExpression:exit"?: (node: TSNonNullExpression) => void; + TSOptionalType?: (node: TSOptionalType) => void; + "TSOptionalType:exit"?: (node: TSOptionalType) => void; + TSParameterProperty?: (node: TSParameterProperty) => void; + "TSParameterProperty:exit"?: (node: TSParameterProperty) => void; + TSParenthesizedType?: (node: TSParenthesizedType) => void; + "TSParenthesizedType:exit"?: (node: TSParenthesizedType) => void; + TSPropertySignature?: (node: TSPropertySignature) => void; + "TSPropertySignature:exit"?: (node: TSPropertySignature) => void; + TSQualifiedName?: (node: TSQualifiedName) => void; + "TSQualifiedName:exit"?: (node: TSQualifiedName) => void; + TSRestType?: (node: TSRestType) => void; + "TSRestType:exit"?: (node: TSRestType) => void; + TSSatisfiesExpression?: (node: TSSatisfiesExpression) => void; + "TSSatisfiesExpression:exit"?: (node: TSSatisfiesExpression) => void; + TSTemplateLiteralType?: (node: TSTemplateLiteralType) => void; + "TSTemplateLiteralType:exit"?: (node: TSTemplateLiteralType) => void; + TSTupleType?: (node: TSTupleType) => void; + "TSTupleType:exit"?: (node: TSTupleType) => void; + TSTypeAliasDeclaration?: (node: TSTypeAliasDeclaration) => void; + "TSTypeAliasDeclaration:exit"?: (node: TSTypeAliasDeclaration) => void; + TSTypeAnnotation?: (node: TSTypeAnnotation) => void; + "TSTypeAnnotation:exit"?: (node: TSTypeAnnotation) => void; + TSTypeAssertion?: (node: TSTypeAssertion) => void; + "TSTypeAssertion:exit"?: (node: TSTypeAssertion) => void; + TSTypeLiteral?: (node: TSTypeLiteral) => void; + "TSTypeLiteral:exit"?: (node: TSTypeLiteral) => void; + TSTypeOperator?: (node: TSTypeOperator) => void; + "TSTypeOperator:exit"?: (node: TSTypeOperator) => void; + TSTypeParameter?: (node: TSTypeParameter) => void; + "TSTypeParameter:exit"?: (node: TSTypeParameter) => void; + TSTypeParameterDeclaration?: (node: TSTypeParameterDeclaration) => void; + "TSTypeParameterDeclaration:exit"?: (node: TSTypeParameterDeclaration) => void; + TSTypeParameterInstantiation?: (node: TSTypeParameterInstantiation) => void; + "TSTypeParameterInstantiation:exit"?: (node: TSTypeParameterInstantiation) => void; + TSTypePredicate?: (node: TSTypePredicate) => void; + "TSTypePredicate:exit"?: (node: TSTypePredicate) => void; + TSTypeQuery?: (node: TSTypeQuery) => void; + "TSTypeQuery:exit"?: (node: TSTypeQuery) => void; + TSTypeReference?: (node: TSTypeReference) => void; + "TSTypeReference:exit"?: (node: TSTypeReference) => void; + TSUnionType?: (node: TSUnionType) => void; + "TSUnionType:exit"?: (node: TSUnionType) => void; +} +type VisitorObject = { [K in keyof StrictVisitorObject]?: BivarianceHackHandler> | undefined; } & Record void> | undefined>; +//#endregion +//#region src-js/plugins/types.d.ts +type BeforeHook = () => boolean | void; +type AfterHook = () => void; +type VisitorWithHooks = VisitorObject & { + before?: BeforeHook; + after?: AfterHook; +}; +interface Node extends Span {} +type NodeOrToken = Node | TokenType | CommentType; +//#endregion +//#region src-js/plugins/location.d.ts +/** + * Range of source offsets. + */ +type Range = [number, number]; +/** + * Interface for any type which has `range` field. + */ +interface Ranged { + range: Range; +} +/** + * Interface for any type which has location properties. + */ +interface Span extends Ranged { + start: number; + end: number; + loc: Location; +} +/** + * Source code location. + */ +interface Location { + start: LineColumn; + end: LineColumn; +} +/** + * Line number + column number pair. + * `line` is 1-indexed, `column` is 0-indexed. + */ +interface LineColumn { + line: number; + column: number; +} +/** + * Convert a source text index into a (line, column) pair. + * @param offset - The index of a character in a file. + * @returns `{line, column}` location object with 1-indexed line and 0-indexed column. + * @throws {TypeError|RangeError} If non-numeric `offset`, or `offset` out of range. + */ +declare function getLineColumnFromOffset(offset: number): LineColumn; +/** + * Convert a `{ line, column }` pair into a range index. + * @param loc - A line/column location. + * @returns The character index of the location in the file. + * @throws {TypeError|RangeError} If `loc` is not an object with a numeric `line` and `column`, + * or if the `line` is less than or equal to zero, or the line or column is out of the expected range. + */ +declare function getOffsetFromLineColumn(loc: LineColumn): number; +/** + * Get the range of the given node or token. + * @param nodeOrToken - Node or token to get the range of + * @returns Range of the node or token + */ +declare function getRange(nodeOrToken: NodeOrToken): Range; +/** + * Get the location of the given node or token. + * @param nodeOrToken - Node or token to get the location of + * @returns Location of the node or token + */ +declare function getLoc(nodeOrToken: NodeOrToken): Location; +/** + * Get the deepest node containing a range index. + * @param offset - Range index of the desired node + * @returns The node if found, or `null` if not found + */ +declare function getNodeByRangeIndex(offset: number): Node$1 | null; +//#endregion +//#region src-js/plugins/comments.d.ts +/** + * Comment. + */ +interface CommentType extends Span { + type: "Line" | "Block" | "Shebang"; + value: string; +} +declare namespace types_d_exports { + export { AccessorProperty, AccessorPropertyType, Argument, ArrayAssignmentTarget, ArrayExpression, ArrayExpressionElement, ArrayPattern, ArrowFunctionExpression, AssignmentExpression, AssignmentOperator, AssignmentPattern, AssignmentTarget, AssignmentTargetMaybeDefault, AssignmentTargetPattern, AssignmentTargetProperty, AssignmentTargetPropertyIdentifier, AssignmentTargetPropertyProperty, AssignmentTargetRest, AssignmentTargetWithDefault, AwaitExpression, BigIntLiteral, BinaryExpression, BinaryOperator, BindingIdentifier, BindingPattern, BindingProperty, BindingRestElement, BlockStatement, BooleanLiteral, BreakStatement, CallExpression, CatchClause, ChainElement, ChainExpression, Class, ClassBody, ClassElement, ClassType, CommentType as Comment, ComputedMemberExpression, ConditionalExpression, ContinueStatement, DebuggerStatement, Declaration, Decorator, Directive$1 as Directive, DoWhileStatement, EmptyStatement, ExportAllDeclaration, ExportDefaultDeclaration, ExportDefaultDeclarationKind, ExportNamedDeclaration, ExportSpecifier, Expression, ExpressionStatement, ForInStatement, ForOfStatement, ForStatement, ForStatementInit, ForStatementLeft, FormalParameter, FormalParameterRest, Function$1 as Function, FunctionBody, FunctionType, Hashbang, IdentifierName, IdentifierReference, IfStatement, ImportAttribute, ImportAttributeKey, ImportDeclaration, ImportDeclarationSpecifier, ImportDefaultSpecifier, ImportExpression, ImportNamespaceSpecifier, ImportOrExportKind, ImportPhase, ImportSpecifier, JSDocNonNullableType, JSDocNullableType, JSDocUnknownType, JSXAttribute, JSXAttributeItem, JSXAttributeName, JSXAttributeValue, JSXChild, JSXClosingElement, JSXClosingFragment, JSXElement, JSXElementName, JSXEmptyExpression, JSXExpression, JSXExpressionContainer, JSXFragment, JSXIdentifier, JSXMemberExpression, JSXMemberExpressionObject, JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, JSXSpreadAttribute, JSXSpreadChild, JSXText, LabelIdentifier, LabeledStatement, LogicalExpression, LogicalOperator, MemberExpression, MetaProperty, MethodDefinition, MethodDefinitionKind, MethodDefinitionType, ModuleDeclaration, ModuleExportName, ModuleKind, NewExpression, Node$1 as Node, NullLiteral, NumericLiteral, ObjectAssignmentTarget, ObjectExpression, ObjectPattern, ObjectProperty, ObjectPropertyKind, ParamPattern, ParenthesizedExpression, PrivateFieldExpression, PrivateIdentifier, PrivateInExpression, Program, PropertyDefinition, PropertyDefinitionType, PropertyKey$1 as PropertyKey, PropertyKind, RegExpLiteral, ReturnStatement, SequenceExpression, SimpleAssignmentTarget, Span, SpreadElement, Statement, StaticBlock, StaticMemberExpression, StringLiteral, Super, SwitchCase, SwitchStatement, TSAccessibility, TSAnyKeyword, TSArrayType, TSAsExpression, TSBigIntKeyword, TSBooleanKeyword, TSCallSignatureDeclaration, TSClassImplements, TSConditionalType, TSConstructSignatureDeclaration, TSConstructorType, TSEnumBody, TSEnumDeclaration, TSEnumMember, TSEnumMemberName, TSExportAssignment, TSExternalModuleReference, TSFunctionType, TSGlobalDeclaration, TSImportEqualsDeclaration, TSImportType, TSImportTypeQualifiedName, TSImportTypeQualifier, TSIndexSignature, TSIndexSignatureName, TSIndexedAccessType, TSInferType, TSInstantiationExpression, TSInterfaceBody, TSInterfaceDeclaration, TSInterfaceHeritage, TSIntersectionType, TSIntrinsicKeyword, TSLiteral, TSLiteralType, TSMappedType, TSMappedTypeModifierOperator, TSMethodSignature, TSMethodSignatureKind, TSModuleBlock, TSModuleDeclaration, TSModuleDeclarationKind, TSModuleReference, TSNamedTupleMember, TSNamespaceExportDeclaration, TSNeverKeyword, TSNonNullExpression, TSNullKeyword, TSNumberKeyword, TSObjectKeyword, TSOptionalType, TSParameterProperty, TSParenthesizedType, TSPropertySignature, TSQualifiedName, TSRestType, TSSatisfiesExpression, TSSignature, TSStringKeyword, TSSymbolKeyword, TSTemplateLiteralType, TSThisParameter, TSThisType, TSTupleElement, TSTupleType, TSType, TSTypeAliasDeclaration, TSTypeAnnotation, TSTypeAssertion, TSTypeLiteral, TSTypeName, TSTypeOperator, TSTypeOperatorOperator, TSTypeParameter, TSTypeParameterDeclaration, TSTypeParameterInstantiation, TSTypePredicate, TSTypePredicateName, TSTypeQuery, TSTypeQueryExprName, TSTypeReference, TSUndefinedKeyword, TSUnionType, TSUnknownKeyword, TSVoidKeyword, TaggedTemplateExpression, TemplateElement, TemplateElementValue, TemplateLiteral, ThisExpression, ThrowStatement, TokenType as Token, TryStatement, UnaryExpression, UnaryOperator, UpdateExpression, UpdateOperator, V8IntrinsicExpression, VariableDeclaration, VariableDeclarationKind, VariableDeclarator, WhileStatement, WithStatement, YieldExpression }; +} +interface Program extends Span { + type: "Program"; + body: Array; + sourceType: ModuleKind; + comments: CommentType[]; + tokens: TokenType[]; + parent: null; +} +type Expression = BooleanLiteral | NullLiteral | NumericLiteral | BigIntLiteral | RegExpLiteral | StringLiteral | TemplateLiteral | IdentifierReference | Super | ArrayExpression | ArrowFunctionExpression | AssignmentExpression | AwaitExpression | BinaryExpression | CallExpression | ChainExpression | Class | ConditionalExpression | Function$1 | ImportExpression | LogicalExpression | NewExpression | ObjectExpression | ParenthesizedExpression | SequenceExpression | TaggedTemplateExpression | ThisExpression | UnaryExpression | UpdateExpression | YieldExpression | PrivateInExpression | MetaProperty | JSXElement | JSXFragment | TSAsExpression | TSSatisfiesExpression | TSTypeAssertion | TSNonNullExpression | TSInstantiationExpression | V8IntrinsicExpression | MemberExpression; +interface IdentifierName extends Span { + type: "Identifier"; + decorators?: []; + name: string; + optional?: false; + typeAnnotation?: null; + parent: Node$1; +} +interface IdentifierReference extends Span { + type: "Identifier"; + decorators?: []; + name: string; + optional?: false; + typeAnnotation?: null; + parent: Node$1; +} +interface BindingIdentifier extends Span { + type: "Identifier"; + decorators?: []; + name: string; + optional?: false; + typeAnnotation?: TSTypeAnnotation | null; + parent: Node$1; +} +interface LabelIdentifier extends Span { + type: "Identifier"; + decorators?: []; + name: string; + optional?: false; + typeAnnotation?: null; + parent: Node$1; +} +interface ThisExpression extends Span { + type: "ThisExpression"; + parent: Node$1; +} +interface ArrayExpression extends Span { + type: "ArrayExpression"; + elements: Array; + parent: Node$1; +} +type ArrayExpressionElement = SpreadElement | null | Expression; +interface ObjectExpression extends Span { + type: "ObjectExpression"; + properties: Array; + parent: Node$1; +} +type ObjectPropertyKind = ObjectProperty | SpreadElement; +interface ObjectProperty extends Span { + type: "Property"; + kind: PropertyKind; + key: PropertyKey$1; + value: Expression; + method: boolean; + shorthand: boolean; + computed: boolean; + optional?: false; + parent: Node$1; +} +type PropertyKey$1 = IdentifierName | PrivateIdentifier | Expression; +type PropertyKind = "init" | "get" | "set"; +interface TemplateLiteral extends Span { + type: "TemplateLiteral"; + quasis: Array; + expressions: Array; + parent: Node$1; +} +interface TaggedTemplateExpression extends Span { + type: "TaggedTemplateExpression"; + tag: Expression; + typeArguments?: TSTypeParameterInstantiation | null; + quasi: TemplateLiteral; + parent: Node$1; +} +interface TemplateElement extends Span { + type: "TemplateElement"; + value: TemplateElementValue; + tail: boolean; + parent: Node$1; +} +interface TemplateElementValue { + raw: string; + cooked: string | null; +} +type MemberExpression = ComputedMemberExpression | StaticMemberExpression | PrivateFieldExpression; +interface ComputedMemberExpression extends Span { + type: "MemberExpression"; + object: Expression; + property: Expression; + optional: boolean; + computed: true; + parent: Node$1; +} +interface StaticMemberExpression extends Span { + type: "MemberExpression"; + object: Expression; + property: IdentifierName; + optional: boolean; + computed: false; + parent: Node$1; +} +interface PrivateFieldExpression extends Span { + type: "MemberExpression"; + object: Expression; + property: PrivateIdentifier; + optional: boolean; + computed: false; + parent: Node$1; +} +interface CallExpression extends Span { + type: "CallExpression"; + callee: Expression; + typeArguments?: TSTypeParameterInstantiation | null; + arguments: Array; + optional: boolean; + parent: Node$1; +} +interface NewExpression extends Span { + type: "NewExpression"; + callee: Expression; + typeArguments?: TSTypeParameterInstantiation | null; + arguments: Array; + parent: Node$1; +} +interface MetaProperty extends Span { + type: "MetaProperty"; + meta: IdentifierName; + property: IdentifierName; + parent: Node$1; +} +interface SpreadElement extends Span { + type: "SpreadElement"; + argument: Expression; + parent: Node$1; +} +type Argument = SpreadElement | Expression; +interface UpdateExpression extends Span { + type: "UpdateExpression"; + operator: UpdateOperator; + prefix: boolean; + argument: SimpleAssignmentTarget; + parent: Node$1; +} +interface UnaryExpression extends Span { + type: "UnaryExpression"; + operator: UnaryOperator; + argument: Expression; + prefix: true; + parent: Node$1; +} +interface BinaryExpression extends Span { + type: "BinaryExpression"; + left: Expression; + operator: BinaryOperator; + right: Expression; + parent: Node$1; +} +interface PrivateInExpression extends Span { + type: "BinaryExpression"; + left: PrivateIdentifier; + operator: "in"; + right: Expression; + parent: Node$1; +} +interface LogicalExpression extends Span { + type: "LogicalExpression"; + left: Expression; + operator: LogicalOperator; + right: Expression; + parent: Node$1; +} +interface ConditionalExpression extends Span { + type: "ConditionalExpression"; + test: Expression; + consequent: Expression; + alternate: Expression; + parent: Node$1; +} +interface AssignmentExpression extends Span { + type: "AssignmentExpression"; + operator: AssignmentOperator; + left: AssignmentTarget; + right: Expression; + parent: Node$1; +} +type AssignmentTarget = SimpleAssignmentTarget | AssignmentTargetPattern; +type SimpleAssignmentTarget = IdentifierReference | TSAsExpression | TSSatisfiesExpression | TSNonNullExpression | TSTypeAssertion | MemberExpression; +type AssignmentTargetPattern = ArrayAssignmentTarget | ObjectAssignmentTarget; +interface ArrayAssignmentTarget extends Span { + type: "ArrayPattern"; + decorators?: []; + elements: Array; + optional?: false; + typeAnnotation?: null; + parent: Node$1; +} +interface ObjectAssignmentTarget extends Span { + type: "ObjectPattern"; + decorators?: []; + properties: Array; + optional?: false; + typeAnnotation?: null; + parent: Node$1; +} +interface AssignmentTargetRest extends Span { + type: "RestElement"; + decorators?: []; + argument: AssignmentTarget; + optional?: false; + typeAnnotation?: null; + value?: null; + parent: Node$1; +} +type AssignmentTargetMaybeDefault = AssignmentTargetWithDefault | AssignmentTarget; +interface AssignmentTargetWithDefault extends Span { + type: "AssignmentPattern"; + decorators?: []; + left: AssignmentTarget; + right: Expression; + optional?: false; + typeAnnotation?: null; + parent: Node$1; +} +type AssignmentTargetProperty = AssignmentTargetPropertyIdentifier | AssignmentTargetPropertyProperty; +interface AssignmentTargetPropertyIdentifier extends Span { + type: "Property"; + kind: "init"; + key: IdentifierReference; + value: IdentifierReference | AssignmentTargetWithDefault; + method: false; + shorthand: true; + computed: false; + optional?: false; + parent: Node$1; +} +interface AssignmentTargetPropertyProperty extends Span { + type: "Property"; + kind: "init"; + key: PropertyKey$1; + value: AssignmentTargetMaybeDefault; + method: false; + shorthand: false; + computed: boolean; + optional?: false; + parent: Node$1; +} +interface SequenceExpression extends Span { + type: "SequenceExpression"; + expressions: Array; + parent: Node$1; +} +interface Super extends Span { + type: "Super"; + parent: Node$1; +} +interface AwaitExpression extends Span { + type: "AwaitExpression"; + argument: Expression; + parent: Node$1; +} +interface ChainExpression extends Span { + type: "ChainExpression"; + expression: ChainElement; + parent: Node$1; +} +type ChainElement = CallExpression | TSNonNullExpression | MemberExpression; +interface ParenthesizedExpression extends Span { + type: "ParenthesizedExpression"; + expression: Expression; + parent: Node$1; +} +type Statement = BlockStatement | BreakStatement | ContinueStatement | DebuggerStatement | DoWhileStatement | EmptyStatement | ExpressionStatement | ForInStatement | ForOfStatement | ForStatement | IfStatement | LabeledStatement | ReturnStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | WithStatement | Declaration | ModuleDeclaration; +interface Directive$1 extends Span { + type: "ExpressionStatement"; + expression: StringLiteral; + directive: string; + parent: Node$1; +} +interface Hashbang extends Span { + type: "Hashbang"; + value: string; + parent: Node$1; +} +interface BlockStatement extends Span { + type: "BlockStatement"; + body: Array; + parent: Node$1; +} +type Declaration = VariableDeclaration | Function$1 | Class | TSTypeAliasDeclaration | TSInterfaceDeclaration | TSEnumDeclaration | TSModuleDeclaration | TSGlobalDeclaration | TSImportEqualsDeclaration; +interface VariableDeclaration extends Span { + type: "VariableDeclaration"; + kind: VariableDeclarationKind; + declarations: Array; + declare?: boolean; + parent: Node$1; +} +type VariableDeclarationKind = "var" | "let" | "const" | "using" | "await using"; +interface VariableDeclarator extends Span { + type: "VariableDeclarator"; + id: BindingPattern; + init: Expression | null; + definite?: boolean; + parent: Node$1; +} +interface EmptyStatement extends Span { + type: "EmptyStatement"; + parent: Node$1; +} +interface ExpressionStatement extends Span { + type: "ExpressionStatement"; + expression: Expression; + directive?: string | null; + parent: Node$1; +} +interface IfStatement extends Span { + type: "IfStatement"; + test: Expression; + consequent: Statement; + alternate: Statement | null; + parent: Node$1; +} +interface DoWhileStatement extends Span { + type: "DoWhileStatement"; + body: Statement; + test: Expression; + parent: Node$1; +} +interface WhileStatement extends Span { + type: "WhileStatement"; + test: Expression; + body: Statement; + parent: Node$1; +} +interface ForStatement extends Span { + type: "ForStatement"; + init: ForStatementInit | null; + test: Expression | null; + update: Expression | null; + body: Statement; + parent: Node$1; +} +type ForStatementInit = VariableDeclaration | Expression; +interface ForInStatement extends Span { + type: "ForInStatement"; + left: ForStatementLeft; + right: Expression; + body: Statement; + parent: Node$1; +} +type ForStatementLeft = VariableDeclaration | AssignmentTarget; +interface ForOfStatement extends Span { + type: "ForOfStatement"; + await: boolean; + left: ForStatementLeft; + right: Expression; + body: Statement; + parent: Node$1; +} +interface ContinueStatement extends Span { + type: "ContinueStatement"; + label: LabelIdentifier | null; + parent: Node$1; +} +interface BreakStatement extends Span { + type: "BreakStatement"; + label: LabelIdentifier | null; + parent: Node$1; +} +interface ReturnStatement extends Span { + type: "ReturnStatement"; + argument: Expression | null; + parent: Node$1; +} +interface WithStatement extends Span { + type: "WithStatement"; + object: Expression; + body: Statement; + parent: Node$1; +} +interface SwitchStatement extends Span { + type: "SwitchStatement"; + discriminant: Expression; + cases: Array; + parent: Node$1; +} +interface SwitchCase extends Span { + type: "SwitchCase"; + test: Expression | null; + consequent: Array; + parent: Node$1; +} +interface LabeledStatement extends Span { + type: "LabeledStatement"; + label: LabelIdentifier; + body: Statement; + parent: Node$1; +} +interface ThrowStatement extends Span { + type: "ThrowStatement"; + argument: Expression; + parent: Node$1; +} +interface TryStatement extends Span { + type: "TryStatement"; + block: BlockStatement; + handler: CatchClause | null; + finalizer: BlockStatement | null; + parent: Node$1; +} +interface CatchClause extends Span { + type: "CatchClause"; + param: BindingPattern | null; + body: BlockStatement; + parent: Node$1; +} +interface DebuggerStatement extends Span { + type: "DebuggerStatement"; + parent: Node$1; +} +type BindingPattern = BindingIdentifier | ObjectPattern | ArrayPattern | AssignmentPattern; +interface AssignmentPattern extends Span { + type: "AssignmentPattern"; + decorators?: []; + left: BindingPattern; + right: Expression; + optional?: false; + typeAnnotation?: null; + parent: Node$1; +} +interface ObjectPattern extends Span { + type: "ObjectPattern"; + decorators?: []; + properties: Array; + optional?: false; + typeAnnotation?: TSTypeAnnotation | null; + parent: Node$1; +} +interface BindingProperty extends Span { + type: "Property"; + kind: "init"; + key: PropertyKey$1; + value: BindingPattern; + method: false; + shorthand: boolean; + computed: boolean; + optional?: false; + parent: Node$1; +} +interface ArrayPattern extends Span { + type: "ArrayPattern"; + decorators?: []; + elements: Array; + optional?: false; + typeAnnotation?: TSTypeAnnotation | null; + parent: Node$1; +} +interface BindingRestElement extends Span { + type: "RestElement"; + decorators?: []; + argument: BindingPattern; + optional?: false; + typeAnnotation?: TSTypeAnnotation | null; + value?: null; + parent: Node$1; +} +interface Function$1 extends Span { + type: FunctionType; + id: BindingIdentifier | null; + generator: boolean; + async: boolean; + declare?: boolean; + typeParameters?: TSTypeParameterDeclaration | null; + params: ParamPattern[]; + returnType?: TSTypeAnnotation | null; + body: FunctionBody | null; + expression: false; + parent: Node$1; +} +type ParamPattern = FormalParameter | TSParameterProperty | FormalParameterRest; +type FunctionType = "FunctionDeclaration" | "FunctionExpression" | "TSDeclareFunction" | "TSEmptyBodyFunctionExpression"; +interface FormalParameterRest extends Span { + type: "RestElement"; + argument: BindingPattern; + decorators?: []; + optional?: boolean; + typeAnnotation?: TSTypeAnnotation | null; + value?: null; + parent: Node$1; +} +type FormalParameter = { + decorators?: Array; +} & BindingPattern; +interface TSParameterProperty extends Span { + type: "TSParameterProperty"; + accessibility: TSAccessibility | null; + decorators: Array; + override: boolean; + parameter: FormalParameter; + readonly: boolean; + static: boolean; + parent: Node$1; +} +interface FunctionBody extends Span { + type: "BlockStatement"; + body: Array; + parent: Node$1; +} +interface ArrowFunctionExpression extends Span { + type: "ArrowFunctionExpression"; + expression: boolean; + async: boolean; + typeParameters?: TSTypeParameterDeclaration | null; + params: ParamPattern[]; + returnType?: TSTypeAnnotation | null; + body: FunctionBody | Expression; + id: null; + generator: false; + parent: Node$1; +} +interface YieldExpression extends Span { + type: "YieldExpression"; + delegate: boolean; + argument: Expression | null; + parent: Node$1; +} +interface Class extends Span { + type: ClassType; + decorators: Array; + id: BindingIdentifier | null; + typeParameters?: TSTypeParameterDeclaration | null; + superClass: Expression | null; + superTypeArguments?: TSTypeParameterInstantiation | null; + implements?: Array; + body: ClassBody; + abstract?: boolean; + declare?: boolean; + parent: Node$1; +} +type ClassType = "ClassDeclaration" | "ClassExpression"; +interface ClassBody extends Span { + type: "ClassBody"; + body: Array; + parent: Node$1; +} +type ClassElement = StaticBlock | MethodDefinition | PropertyDefinition | AccessorProperty | TSIndexSignature; +interface MethodDefinition extends Span { + type: MethodDefinitionType; + decorators: Array; + key: PropertyKey$1; + value: Function$1; + kind: MethodDefinitionKind; + computed: boolean; + static: boolean; + override?: boolean; + optional?: boolean; + accessibility?: TSAccessibility | null; + parent: Node$1; +} +type MethodDefinitionType = "MethodDefinition" | "TSAbstractMethodDefinition"; +interface PropertyDefinition extends Span { + type: PropertyDefinitionType; + decorators: Array; + key: PropertyKey$1; + typeAnnotation?: TSTypeAnnotation | null; + value: Expression | null; + computed: boolean; + static: boolean; + declare?: boolean; + override?: boolean; + optional?: boolean; + definite?: boolean; + readonly?: boolean; + accessibility?: TSAccessibility | null; + parent: Node$1; +} +type PropertyDefinitionType = "PropertyDefinition" | "TSAbstractPropertyDefinition"; +type MethodDefinitionKind = "constructor" | "method" | "get" | "set"; +interface PrivateIdentifier extends Span { + type: "PrivateIdentifier"; + name: string; + parent: Node$1; +} +interface StaticBlock extends Span { + type: "StaticBlock"; + body: Array; + parent: Node$1; +} +type ModuleDeclaration = ImportDeclaration | ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration | TSExportAssignment | TSNamespaceExportDeclaration; +type AccessorPropertyType = "AccessorProperty" | "TSAbstractAccessorProperty"; +interface AccessorProperty extends Span { + type: AccessorPropertyType; + decorators: Array; + key: PropertyKey$1; + typeAnnotation?: TSTypeAnnotation | null; + value: Expression | null; + computed: boolean; + static: boolean; + override?: boolean; + definite?: boolean; + accessibility?: TSAccessibility | null; + declare?: false; + optional?: false; + readonly?: false; + parent: Node$1; +} +interface ImportExpression extends Span { + type: "ImportExpression"; + source: Expression; + options: Expression | null; + phase: ImportPhase | null; + parent: Node$1; +} +interface ImportDeclaration extends Span { + type: "ImportDeclaration"; + specifiers: Array; + source: StringLiteral; + phase: ImportPhase | null; + attributes: Array; + importKind?: ImportOrExportKind; + parent: Node$1; +} +type ImportPhase = "source" | "defer"; +type ImportDeclarationSpecifier = ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier; +interface ImportSpecifier extends Span { + type: "ImportSpecifier"; + imported: ModuleExportName; + local: BindingIdentifier; + importKind?: ImportOrExportKind; + parent: Node$1; +} +interface ImportDefaultSpecifier extends Span { + type: "ImportDefaultSpecifier"; + local: BindingIdentifier; + parent: Node$1; +} +interface ImportNamespaceSpecifier extends Span { + type: "ImportNamespaceSpecifier"; + local: BindingIdentifier; + parent: Node$1; +} +interface ImportAttribute extends Span { + type: "ImportAttribute"; + key: ImportAttributeKey; + value: StringLiteral; + parent: Node$1; +} +type ImportAttributeKey = IdentifierName | StringLiteral; +interface ExportNamedDeclaration extends Span { + type: "ExportNamedDeclaration"; + declaration: Declaration | null; + specifiers: Array; + source: StringLiteral | null; + exportKind?: ImportOrExportKind; + attributes: Array; + parent: Node$1; +} +interface ExportDefaultDeclaration extends Span { + type: "ExportDefaultDeclaration"; + declaration: ExportDefaultDeclarationKind; + exportKind?: "value"; + parent: Node$1; +} +interface ExportAllDeclaration extends Span { + type: "ExportAllDeclaration"; + exported: ModuleExportName | null; + source: StringLiteral; + attributes: Array; + exportKind?: ImportOrExportKind; + parent: Node$1; +} +interface ExportSpecifier extends Span { + type: "ExportSpecifier"; + local: ModuleExportName; + exported: ModuleExportName; + exportKind?: ImportOrExportKind; + parent: Node$1; +} +type ExportDefaultDeclarationKind = Function$1 | Class | TSInterfaceDeclaration | Expression; +type ModuleExportName = IdentifierName | IdentifierReference | StringLiteral; +interface V8IntrinsicExpression extends Span { + type: "V8IntrinsicExpression"; + name: IdentifierName; + arguments: Array; + parent: Node$1; +} +interface BooleanLiteral extends Span { + type: "Literal"; + value: boolean; + raw: string | null; + parent: Node$1; +} +interface NullLiteral extends Span { + type: "Literal"; + value: null; + raw: "null" | null; + parent: Node$1; +} +interface NumericLiteral extends Span { + type: "Literal"; + value: number; + raw: string | null; + parent: Node$1; +} +interface StringLiteral extends Span { + type: "Literal"; + value: string; + raw: string | null; + parent: Node$1; +} +interface BigIntLiteral extends Span { + type: "Literal"; + value: bigint; + raw: string | null; + bigint: string; + parent: Node$1; +} +interface RegExpLiteral extends Span { + type: "Literal"; + value: RegExp | null; + raw: string | null; + regex: { + pattern: string; + flags: string; + }; + parent: Node$1; +} +interface JSXElement extends Span { + type: "JSXElement"; + openingElement: JSXOpeningElement; + children: Array; + closingElement: JSXClosingElement | null; + parent: Node$1; +} +interface JSXOpeningElement extends Span { + type: "JSXOpeningElement"; + name: JSXElementName; + typeArguments?: TSTypeParameterInstantiation | null; + attributes: Array; + selfClosing: boolean; + parent: Node$1; +} +interface JSXClosingElement extends Span { + type: "JSXClosingElement"; + name: JSXElementName; + parent: Node$1; +} +interface JSXFragment extends Span { + type: "JSXFragment"; + openingFragment: JSXOpeningFragment; + children: Array; + closingFragment: JSXClosingFragment; + parent: Node$1; +} +interface JSXOpeningFragment extends Span { + type: "JSXOpeningFragment"; + attributes?: []; + selfClosing?: false; + parent: Node$1; +} +interface JSXClosingFragment extends Span { + type: "JSXClosingFragment"; + parent: Node$1; +} +type JSXElementName = JSXIdentifier | JSXNamespacedName | JSXMemberExpression; +interface JSXNamespacedName extends Span { + type: "JSXNamespacedName"; + namespace: JSXIdentifier; + name: JSXIdentifier; + parent: Node$1; +} +interface JSXMemberExpression extends Span { + type: "JSXMemberExpression"; + object: JSXMemberExpressionObject; + property: JSXIdentifier; + parent: Node$1; +} +type JSXMemberExpressionObject = JSXIdentifier | JSXMemberExpression; +interface JSXExpressionContainer extends Span { + type: "JSXExpressionContainer"; + expression: JSXExpression; + parent: Node$1; +} +type JSXExpression = JSXEmptyExpression | Expression; +interface JSXEmptyExpression extends Span { + type: "JSXEmptyExpression"; + parent: Node$1; +} +type JSXAttributeItem = JSXAttribute | JSXSpreadAttribute; +interface JSXAttribute extends Span { + type: "JSXAttribute"; + name: JSXAttributeName; + value: JSXAttributeValue | null; + parent: Node$1; +} +interface JSXSpreadAttribute extends Span { + type: "JSXSpreadAttribute"; + argument: Expression; + parent: Node$1; +} +type JSXAttributeName = JSXIdentifier | JSXNamespacedName; +type JSXAttributeValue = StringLiteral | JSXExpressionContainer | JSXElement | JSXFragment; +interface JSXIdentifier extends Span { + type: "JSXIdentifier"; + name: string; + parent: Node$1; +} +type JSXChild = JSXText | JSXElement | JSXFragment | JSXExpressionContainer | JSXSpreadChild; +interface JSXSpreadChild extends Span { + type: "JSXSpreadChild"; + expression: Expression; + parent: Node$1; +} +interface JSXText extends Span { + type: "JSXText"; + value: string; + raw: string | null; + parent: Node$1; +} +interface TSThisParameter extends Span { + type: "Identifier"; + decorators: []; + name: "this"; + optional: false; + typeAnnotation: TSTypeAnnotation | null; + parent: Node$1; +} +interface TSEnumDeclaration extends Span { + type: "TSEnumDeclaration"; + id: BindingIdentifier; + body: TSEnumBody; + const: boolean; + declare: boolean; + parent: Node$1; +} +interface TSEnumBody extends Span { + type: "TSEnumBody"; + members: Array; + parent: Node$1; +} +interface TSEnumMember extends Span { + type: "TSEnumMember"; + id: TSEnumMemberName; + initializer: Expression | null; + computed: boolean; + parent: Node$1; +} +type TSEnumMemberName = IdentifierName | StringLiteral | TemplateLiteral; +interface TSTypeAnnotation extends Span { + type: "TSTypeAnnotation"; + typeAnnotation: TSType; + parent: Node$1; +} +interface TSLiteralType extends Span { + type: "TSLiteralType"; + literal: TSLiteral; + parent: Node$1; +} +type TSLiteral = BooleanLiteral | NumericLiteral | BigIntLiteral | StringLiteral | TemplateLiteral | UnaryExpression; +type TSType = TSAnyKeyword | TSBigIntKeyword | TSBooleanKeyword | TSIntrinsicKeyword | TSNeverKeyword | TSNullKeyword | TSNumberKeyword | TSObjectKeyword | TSStringKeyword | TSSymbolKeyword | TSUndefinedKeyword | TSUnknownKeyword | TSVoidKeyword | TSArrayType | TSConditionalType | TSConstructorType | TSFunctionType | TSImportType | TSIndexedAccessType | TSInferType | TSIntersectionType | TSLiteralType | TSMappedType | TSNamedTupleMember | TSTemplateLiteralType | TSThisType | TSTupleType | TSTypeLiteral | TSTypeOperator | TSTypePredicate | TSTypeQuery | TSTypeReference | TSUnionType | TSParenthesizedType | JSDocNullableType | JSDocNonNullableType | JSDocUnknownType; +interface TSConditionalType extends Span { + type: "TSConditionalType"; + checkType: TSType; + extendsType: TSType; + trueType: TSType; + falseType: TSType; + parent: Node$1; +} +interface TSUnionType extends Span { + type: "TSUnionType"; + types: Array; + parent: Node$1; +} +interface TSIntersectionType extends Span { + type: "TSIntersectionType"; + types: Array; + parent: Node$1; +} +interface TSParenthesizedType extends Span { + type: "TSParenthesizedType"; + typeAnnotation: TSType; + parent: Node$1; +} +interface TSTypeOperator extends Span { + type: "TSTypeOperator"; + operator: TSTypeOperatorOperator; + typeAnnotation: TSType; + parent: Node$1; +} +type TSTypeOperatorOperator = "keyof" | "unique" | "readonly"; +interface TSArrayType extends Span { + type: "TSArrayType"; + elementType: TSType; + parent: Node$1; +} +interface TSIndexedAccessType extends Span { + type: "TSIndexedAccessType"; + objectType: TSType; + indexType: TSType; + parent: Node$1; +} +interface TSTupleType extends Span { + type: "TSTupleType"; + elementTypes: Array; + parent: Node$1; +} +interface TSNamedTupleMember extends Span { + type: "TSNamedTupleMember"; + label: IdentifierName; + elementType: TSTupleElement; + optional: boolean; + parent: Node$1; +} +interface TSOptionalType extends Span { + type: "TSOptionalType"; + typeAnnotation: TSType; + parent: Node$1; +} +interface TSRestType extends Span { + type: "TSRestType"; + typeAnnotation: TSType; + parent: Node$1; +} +type TSTupleElement = TSOptionalType | TSRestType | TSType; +interface TSAnyKeyword extends Span { + type: "TSAnyKeyword"; + parent: Node$1; +} +interface TSStringKeyword extends Span { + type: "TSStringKeyword"; + parent: Node$1; +} +interface TSBooleanKeyword extends Span { + type: "TSBooleanKeyword"; + parent: Node$1; +} +interface TSNumberKeyword extends Span { + type: "TSNumberKeyword"; + parent: Node$1; +} +interface TSNeverKeyword extends Span { + type: "TSNeverKeyword"; + parent: Node$1; +} +interface TSIntrinsicKeyword extends Span { + type: "TSIntrinsicKeyword"; + parent: Node$1; +} +interface TSUnknownKeyword extends Span { + type: "TSUnknownKeyword"; + parent: Node$1; +} +interface TSNullKeyword extends Span { + type: "TSNullKeyword"; + parent: Node$1; +} +interface TSUndefinedKeyword extends Span { + type: "TSUndefinedKeyword"; + parent: Node$1; +} +interface TSVoidKeyword extends Span { + type: "TSVoidKeyword"; + parent: Node$1; +} +interface TSSymbolKeyword extends Span { + type: "TSSymbolKeyword"; + parent: Node$1; +} +interface TSThisType extends Span { + type: "TSThisType"; + parent: Node$1; +} +interface TSObjectKeyword extends Span { + type: "TSObjectKeyword"; + parent: Node$1; +} +interface TSBigIntKeyword extends Span { + type: "TSBigIntKeyword"; + parent: Node$1; +} +interface TSTypeReference extends Span { + type: "TSTypeReference"; + typeName: TSTypeName; + typeArguments: TSTypeParameterInstantiation | null; + parent: Node$1; +} +type TSTypeName = IdentifierReference | TSQualifiedName | ThisExpression; +interface TSQualifiedName extends Span { + type: "TSQualifiedName"; + left: TSTypeName; + right: IdentifierName; + parent: Node$1; +} +interface TSTypeParameterInstantiation extends Span { + type: "TSTypeParameterInstantiation"; + params: Array; + parent: Node$1; +} +interface TSTypeParameter extends Span { + type: "TSTypeParameter"; + name: BindingIdentifier; + constraint: TSType | null; + default: TSType | null; + in: boolean; + out: boolean; + const: boolean; + parent: Node$1; +} +interface TSTypeParameterDeclaration extends Span { + type: "TSTypeParameterDeclaration"; + params: Array; + parent: Node$1; +} +interface TSTypeAliasDeclaration extends Span { + type: "TSTypeAliasDeclaration"; + id: BindingIdentifier; + typeParameters: TSTypeParameterDeclaration | null; + typeAnnotation: TSType; + declare: boolean; + parent: Node$1; +} +type TSAccessibility = "private" | "protected" | "public"; +interface TSClassImplements extends Span { + type: "TSClassImplements"; + expression: IdentifierReference | ThisExpression | MemberExpression; + typeArguments: TSTypeParameterInstantiation | null; + parent: Node$1; +} +interface TSInterfaceDeclaration extends Span { + type: "TSInterfaceDeclaration"; + id: BindingIdentifier; + typeParameters: TSTypeParameterDeclaration | null; + extends: Array; + body: TSInterfaceBody; + declare: boolean; + parent: Node$1; +} +interface TSInterfaceBody extends Span { + type: "TSInterfaceBody"; + body: Array; + parent: Node$1; +} +interface TSPropertySignature extends Span { + type: "TSPropertySignature"; + computed: boolean; + optional: boolean; + readonly: boolean; + key: PropertyKey$1; + typeAnnotation: TSTypeAnnotation | null; + accessibility: null; + static: false; + parent: Node$1; +} +type TSSignature = TSIndexSignature | TSPropertySignature | TSCallSignatureDeclaration | TSConstructSignatureDeclaration | TSMethodSignature; +interface TSIndexSignature extends Span { + type: "TSIndexSignature"; + parameters: Array; + typeAnnotation: TSTypeAnnotation; + readonly: boolean; + static: boolean; + accessibility: null; + parent: Node$1; +} +interface TSCallSignatureDeclaration extends Span { + type: "TSCallSignatureDeclaration"; + typeParameters: TSTypeParameterDeclaration | null; + params: ParamPattern[]; + returnType: TSTypeAnnotation | null; + parent: Node$1; +} +type TSMethodSignatureKind = "method" | "get" | "set"; +interface TSMethodSignature extends Span { + type: "TSMethodSignature"; + key: PropertyKey$1; + computed: boolean; + optional: boolean; + kind: TSMethodSignatureKind; + typeParameters: TSTypeParameterDeclaration | null; + params: ParamPattern[]; + returnType: TSTypeAnnotation | null; + accessibility: null; + readonly: false; + static: false; + parent: Node$1; +} +interface TSConstructSignatureDeclaration extends Span { + type: "TSConstructSignatureDeclaration"; + typeParameters: TSTypeParameterDeclaration | null; + params: ParamPattern[]; + returnType: TSTypeAnnotation | null; + parent: Node$1; +} +interface TSIndexSignatureName extends Span { + type: "Identifier"; + decorators: []; + name: string; + optional: false; + typeAnnotation: TSTypeAnnotation; + parent: Node$1; +} +interface TSInterfaceHeritage extends Span { + type: "TSInterfaceHeritage"; + expression: Expression; + typeArguments: TSTypeParameterInstantiation | null; + parent: Node$1; +} +interface TSTypePredicate extends Span { + type: "TSTypePredicate"; + parameterName: TSTypePredicateName; + asserts: boolean; + typeAnnotation: TSTypeAnnotation | null; + parent: Node$1; +} +type TSTypePredicateName = IdentifierName | TSThisType; +type TSModuleDeclarationKind = "module" | "namespace"; +interface TSModuleDeclaration extends Span { + type: "TSModuleDeclaration"; + id: BindingIdentifier | StringLiteral | TSQualifiedName; + body: TSModuleBlock | null; + kind: TSModuleDeclarationKind; + declare: boolean; + global: false; + parent: Node$1; +} +interface TSGlobalDeclaration extends Span { + type: "TSModuleDeclaration"; + id: IdentifierName; + body: TSModuleBlock; + kind: "global"; + declare: boolean; + global: true; + parent: Node$1; +} +interface TSModuleBlock extends Span { + type: "TSModuleBlock"; + body: Array; + parent: Node$1; +} +interface TSTypeLiteral extends Span { + type: "TSTypeLiteral"; + members: Array; + parent: Node$1; +} +interface TSInferType extends Span { + type: "TSInferType"; + typeParameter: TSTypeParameter; + parent: Node$1; +} +interface TSTypeQuery extends Span { + type: "TSTypeQuery"; + exprName: TSTypeQueryExprName; + typeArguments: TSTypeParameterInstantiation | null; + parent: Node$1; +} +type TSTypeQueryExprName = TSImportType | TSTypeName; +interface TSImportType extends Span { + type: "TSImportType"; + source: StringLiteral; + options: ObjectExpression | null; + qualifier: TSImportTypeQualifier | null; + typeArguments: TSTypeParameterInstantiation | null; + parent: Node$1; +} +type TSImportTypeQualifier = IdentifierName | TSImportTypeQualifiedName; +interface TSImportTypeQualifiedName extends Span { + type: "TSQualifiedName"; + left: TSImportTypeQualifier; + right: IdentifierName; + parent: Node$1; +} +interface TSFunctionType extends Span { + type: "TSFunctionType"; + typeParameters: TSTypeParameterDeclaration | null; + params: ParamPattern[]; + returnType: TSTypeAnnotation; + parent: Node$1; +} +interface TSConstructorType extends Span { + type: "TSConstructorType"; + abstract: boolean; + typeParameters: TSTypeParameterDeclaration | null; + params: ParamPattern[]; + returnType: TSTypeAnnotation; + parent: Node$1; +} +interface TSMappedType extends Span { + type: "TSMappedType"; + key: BindingIdentifier; + constraint: TSType; + nameType: TSType | null; + typeAnnotation: TSType | null; + optional: TSMappedTypeModifierOperator | false; + readonly: TSMappedTypeModifierOperator | null; + parent: Node$1; +} +type TSMappedTypeModifierOperator = true | "+" | "-"; +interface TSTemplateLiteralType extends Span { + type: "TSTemplateLiteralType"; + quasis: Array; + types: Array; + parent: Node$1; +} +interface TSAsExpression extends Span { + type: "TSAsExpression"; + expression: Expression; + typeAnnotation: TSType; + parent: Node$1; +} +interface TSSatisfiesExpression extends Span { + type: "TSSatisfiesExpression"; + expression: Expression; + typeAnnotation: TSType; + parent: Node$1; +} +interface TSTypeAssertion extends Span { + type: "TSTypeAssertion"; + typeAnnotation: TSType; + expression: Expression; + parent: Node$1; +} +interface TSImportEqualsDeclaration extends Span { + type: "TSImportEqualsDeclaration"; + id: BindingIdentifier; + moduleReference: TSModuleReference; + importKind: ImportOrExportKind; + parent: Node$1; +} +type TSModuleReference = TSExternalModuleReference | IdentifierReference | TSQualifiedName; +interface TSExternalModuleReference extends Span { + type: "TSExternalModuleReference"; + expression: StringLiteral; + parent: Node$1; +} +interface TSNonNullExpression extends Span { + type: "TSNonNullExpression"; + expression: Expression; + parent: Node$1; +} +interface Decorator extends Span { + type: "Decorator"; + expression: Expression; + parent: Node$1; +} +interface TSExportAssignment extends Span { + type: "TSExportAssignment"; + expression: Expression; + parent: Node$1; +} +interface TSNamespaceExportDeclaration extends Span { + type: "TSNamespaceExportDeclaration"; + id: IdentifierName; + parent: Node$1; +} +interface TSInstantiationExpression extends Span { + type: "TSInstantiationExpression"; + expression: Expression; + typeArguments: TSTypeParameterInstantiation; + parent: Node$1; +} +type ImportOrExportKind = "value" | "type"; +interface JSDocNullableType extends Span { + type: "TSJSDocNullableType"; + typeAnnotation: TSType; + postfix: boolean; + parent: Node$1; +} +interface JSDocNonNullableType extends Span { + type: "TSJSDocNonNullableType"; + typeAnnotation: TSType; + postfix: boolean; + parent: Node$1; +} +interface JSDocUnknownType extends Span { + type: "TSJSDocUnknownType"; + parent: Node$1; +} +type ModuleKind = "script" | "module" | "commonjs"; +type AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "**=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=" | "||=" | "&&=" | "??="; +type BinaryOperator = "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "+" | "-" | "*" | "/" | "%" | "**" | "<<" | ">>" | ">>>" | "|" | "^" | "&" | "in" | "instanceof"; +type LogicalOperator = "||" | "&&" | "??"; +type UnaryOperator = "+" | "-" | "!" | "~" | "typeof" | "void" | "delete"; +type UpdateOperator = "++" | "--"; +type Node$1 = Program | IdentifierName | IdentifierReference | BindingIdentifier | LabelIdentifier | ThisExpression | ArrayExpression | ObjectExpression | ObjectProperty | TemplateLiteral | TaggedTemplateExpression | TemplateElement | ComputedMemberExpression | StaticMemberExpression | PrivateFieldExpression | CallExpression | NewExpression | MetaProperty | SpreadElement | UpdateExpression | UnaryExpression | BinaryExpression | PrivateInExpression | LogicalExpression | ConditionalExpression | AssignmentExpression | ArrayAssignmentTarget | ObjectAssignmentTarget | AssignmentTargetRest | AssignmentTargetWithDefault | AssignmentTargetPropertyIdentifier | AssignmentTargetPropertyProperty | SequenceExpression | Super | AwaitExpression | ChainExpression | ParenthesizedExpression | Directive$1 | Hashbang | BlockStatement | VariableDeclaration | VariableDeclarator | EmptyStatement | ExpressionStatement | IfStatement | DoWhileStatement | WhileStatement | ForStatement | ForInStatement | ForOfStatement | ContinueStatement | BreakStatement | ReturnStatement | WithStatement | SwitchStatement | SwitchCase | LabeledStatement | ThrowStatement | TryStatement | CatchClause | DebuggerStatement | AssignmentPattern | ObjectPattern | BindingProperty | ArrayPattern | BindingRestElement | Function$1 | FunctionBody | ArrowFunctionExpression | YieldExpression | Class | ClassBody | MethodDefinition | PropertyDefinition | PrivateIdentifier | StaticBlock | AccessorProperty | ImportExpression | ImportDeclaration | ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ImportAttribute | ExportNamedDeclaration | ExportDefaultDeclaration | ExportAllDeclaration | ExportSpecifier | V8IntrinsicExpression | BooleanLiteral | NullLiteral | NumericLiteral | StringLiteral | BigIntLiteral | RegExpLiteral | JSXElement | JSXOpeningElement | JSXClosingElement | JSXFragment | JSXOpeningFragment | JSXClosingFragment | JSXNamespacedName | JSXMemberExpression | JSXExpressionContainer | JSXEmptyExpression | JSXAttribute | JSXSpreadAttribute | JSXIdentifier | JSXSpreadChild | JSXText | TSThisParameter | TSEnumDeclaration | TSEnumBody | TSEnumMember | TSTypeAnnotation | TSLiteralType | TSConditionalType | TSUnionType | TSIntersectionType | TSParenthesizedType | TSTypeOperator | TSArrayType | TSIndexedAccessType | TSTupleType | TSNamedTupleMember | TSOptionalType | TSRestType | TSAnyKeyword | TSStringKeyword | TSBooleanKeyword | TSNumberKeyword | TSNeverKeyword | TSIntrinsicKeyword | TSUnknownKeyword | TSNullKeyword | TSUndefinedKeyword | TSVoidKeyword | TSSymbolKeyword | TSThisType | TSObjectKeyword | TSBigIntKeyword | TSTypeReference | TSQualifiedName | TSTypeParameterInstantiation | TSTypeParameter | TSTypeParameterDeclaration | TSTypeAliasDeclaration | TSClassImplements | TSInterfaceDeclaration | TSInterfaceBody | TSPropertySignature | TSIndexSignature | TSCallSignatureDeclaration | TSMethodSignature | TSConstructSignatureDeclaration | TSIndexSignatureName | TSInterfaceHeritage | TSTypePredicate | TSModuleDeclaration | TSGlobalDeclaration | TSModuleBlock | TSTypeLiteral | TSInferType | TSTypeQuery | TSImportType | TSImportTypeQualifiedName | TSFunctionType | TSConstructorType | TSMappedType | TSTemplateLiteralType | TSAsExpression | TSSatisfiesExpression | TSTypeAssertion | TSImportEqualsDeclaration | TSExternalModuleReference | TSNonNullExpression | Decorator | TSExportAssignment | TSNamespaceExportDeclaration | TSInstantiationExpression | JSDocNullableType | JSDocNonNullableType | JSDocUnknownType | ParamPattern; +//#endregion +//#region src-js/plugins/scope.d.ts +interface Scope { + type: ScopeType; + isStrict: boolean; + upper: Scope | null; + childScopes: Scope[]; + variableScope: Scope; + block: Node$1; + variables: Variable[]; + set: Map; + references: Reference[]; + through: Reference[]; + functionExpressionScope: boolean; + implicit?: { + variables: Variable[]; + set: Map; + }; +} +type ScopeType = "block" | "catch" | "class" | "class-field-initializer" | "class-static-block" | "for" | "function" | "function-expression-name" | "global" | "module" | "switch" | "with"; +interface Variable { + name: string; + scope: Scope; + identifiers: Identifier[]; + references: Reference[]; + defs: Definition[]; +} +interface Reference { + identifier: Identifier; + from: Scope; + resolved: Variable | null; + writeExpr: Expression | null; + init: boolean; + isWrite(): boolean; + isRead(): boolean; + isReadOnly(): boolean; + isWriteOnly(): boolean; + isReadWrite(): boolean; +} +interface Definition { + type: DefinitionType; + name: Identifier; + node: Node$1; + parent: Node$1 | null; +} +type DefinitionType = "CatchClause" | "ClassName" | "FunctionName" | "ImplicitGlobalVariable" | "ImportBinding" | "Parameter" | "Variable"; +type Identifier = IdentifierName | IdentifierReference | BindingIdentifier | LabelIdentifier | TSThisParameter | TSIndexSignatureName; +declare const SCOPE_MANAGER: Readonly<{ + /** + * All scopes. + */ + readonly scopes: Scope[]; + /** + * The root scope. + */ + readonly globalScope: Scope | null; + /** + * Get the variables that a given AST node defines. + * The returned variables' `def[].node` / `def[].parent` property is the node. + * If the node does not define any variable, this returns an empty array. + * @param node AST node to get variables of. + */ + getDeclaredVariables(node: Node$1): Variable[]; + /** + * Get the scope of a given AST node. The returned scope's `block` property is the node. + * This method never returns `function-expression-name` scope. + * If the node does not have a scope, returns `null`. + * + * @param node An AST node to get their scope. + * @param inner If the node has multiple scopes, this returns the outermost scope normally. + * If `inner` is `true` then this returns the innermost scope. + */ + acquire(node: Node$1, inner?: boolean): Scope | null; +}>; +type ScopeManager = typeof SCOPE_MANAGER; +/** + * Determine whether the given identifier node is a reference to a global variable. + * @param node - `Identifier` node to check. + * @returns `true` if the identifier is a reference to a global variable. + */ +declare function isGlobalReference(node: Node$1): boolean; +/** + * Get the variables that `node` defines. + * This is a convenience method that passes through to the same method on the `ScopeManager`. + * @param node - The node for which the variables are obtained. + * @returns An array of variable nodes representing the variables that `node` defines. + */ +declare function getDeclaredVariables(node: Node$1): Variable[]; +/** + * Get the scope for the given node. + * @param node - The node to get the scope of. + * @returns The scope information for this node. + */ +declare function getScope(node: Node$1): Scope; +/** + * Marks as used a variable with the given name in a scope indicated by the given reference node. + * + * IMPORTANT: At present marking variables as used only affects other JS plugins. + * It does *not* get communicated to Oxlint's rules which are implemented on Rust side e.g. `no-unused-vars`. + * This is a known shortcoming, and will be addressed in a future release. + * https://github.com/oxc-project/oxc/issues/20350 + * + * @param name - Variable name + * @param refNode - Reference node. Defaults to `Program` node if not provided. + * @returns `true` if a variable with the given name was found and marked as used, otherwise `false` + */ +declare function markVariableAsUsed(name: string, refNode?: Node$1): boolean; +//#endregion +//#region src-js/plugins/comments_methods.d.ts +/** + * Retrieve an array containing all comments in the source code. + * @returns Array of `Comment`s in order they appear in source. + */ +declare function getAllComments(): CommentType[]; +/** + * Get all comments directly before the given node or token. + * + * "Directly before" means only comments before this node, and after the preceding token. + * + * ```js + * // Define `x` + * const x = 1; + * // Define `y` + * const y = 2; + * ``` + * + * `sourceCode.getCommentsBefore(varDeclY)` will only return "Define `y`" comment, not also "Define `x`". + * + * @param nodeOrToken - The AST node or token to check for adjacent comment tokens. + * @returns Array of `Comment`s in occurrence order. + */ +declare function getCommentsBefore(nodeOrToken: NodeOrToken): CommentType[]; +/** + * Get all comment tokens directly after the given node or token. + * + * "Directly after" means only comments between end of this node, and the next token following it. + * + * ```js + * const x = 1; + * // Define `y` + * const y = 2; + * // Define `z` + * const z = 3; + * ``` + * + * `sourceCode.getCommentsAfter(varDeclX)` will only return "Define `y`" comment, not also "Define `z`". + * + * @param nodeOrToken - The AST node or token to check for adjacent comment tokens. + * @returns Array of `Comment`s in occurrence order. + */ +declare function getCommentsAfter(nodeOrToken: NodeOrToken): CommentType[]; +/** + * Get all comment tokens inside the given node. + * @param node - The AST node to get the comments for. + * @returns Array of `Comment`s in occurrence order. + */ +declare function getCommentsInside(node: Node): CommentType[]; +/** + * Check whether any comments exist or not between the given 2 nodes. + * @param nodeOrToken1 - Start node/token. + * @param nodeOrToken2 - End node/token. + * @returns `true` if one or more comments exist between the two. + */ +declare function commentsExistBetween(nodeOrToken1: NodeOrToken, nodeOrToken2: NodeOrToken): boolean; +/** + * Retrieve the JSDoc comment for a given node. + * + * @deprecated + * + * @param node - The AST node to get the comment for. + * @returns The JSDoc comment for the given node, or `null` if not found. + */ +declare function getJSDocComment(node: Node): CommentType | null; +//#endregion +//#region src-js/plugins/tokens_and_comments.d.ts +type TokenOrComment = TokenType | CommentType; +//#endregion +//#region src-js/plugins/tokens_methods.d.ts +/** + * Options for various `SourceCode` methods e.g. `getFirstToken`. + */ +interface SkipOptions { + /** Number of skipping tokens */ + skip?: number; + /** `true` to include comment tokens in the result */ + includeComments?: boolean; + /** Function to filter tokens */ + filter?: FilterFn | null; +} +/** + * Options for various `SourceCode` methods e.g. `getFirstTokens`. + */ +interface CountOptions { + /** Maximum number of tokens to return */ + count?: number; + /** `true` to include comment tokens in the result */ + includeComments?: boolean; + /** Function to filter tokens */ + filter?: FilterFn | null; +} +/** + * Options for `getTokenByRangeStart`. + */ +interface RangeOptions { + /** `true` to include comment tokens in the result */ + includeComments?: boolean; +} +/** + * Filter function, passed as `filter` property of `SkipOptions` and `CountOptions`. + */ +type FilterFn = (token: TokenOrComment) => boolean; +/** + * Whether `Options` may include comment tokens in the result. + * Resolves to `true` if `Options` has an `includeComments` property whose type includes `true` + * (i.e. it's `true`, `boolean`, or `boolean | undefined`), and `false` otherwise. + */ +type MayIncludeComments = Options extends { + includeComments: false; +} ? false : "includeComments" extends keyof Options ? true : false; +/** + * Resolves to `TokenOrComment` if `Options` may include comments, `Token` otherwise. + */ +type TokenResult = MayIncludeComments extends true ? TokenOrComment : TokenType; +/** + * Get all tokens that are related to the given node. + * @param node - The AST node. + * @param countOptions? - Options object. If is a function, equivalent to `{ filter: fn }`. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +/** + * Get all tokens that are related to the given node. + * @param node - The AST node. + * @param beforeCount? - The number of tokens before the node to retrieve. + * @param afterCount? - The number of tokens after the node to retrieve. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +declare function getTokens(node: Node, countOptions?: Options, afterCount?: number | null): TokenResult[]; +/** + * Get the first token of the given node. + * @param node - The AST node. + * @param skipOptions? - Options object. + * If is a number, equivalent to `{ skip: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns `Token` (or `Token | Comment` if `includeComments` is `true`), or `null` if none found. + */ +declare function getFirstToken(node: Node, skipOptions?: Options): TokenResult | null; +/** + * Get the first tokens of the given node. + * @param node - The AST node. + * @param countOptions? - Options object. + * If is a number, equivalent to `{ count: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +declare function getFirstTokens(node: Node, countOptions?: Options): TokenResult[]; +/** + * Get the last token of the given node. + * @param node - The AST node. + * @param skipOptions? - Options object. + * If is a number, equivalent to `{ skip: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns `Token` (or `Token | Comment` if `includeComments` is `true`), or `null` if none found. + */ +declare function getLastToken(node: Node, skipOptions?: Options): TokenResult | null; +/** + * Get the last tokens of the given node. + * @param node - The AST node. + * @param countOptions? - Options object. + * If is a number, equivalent to `{ count: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +declare function getLastTokens(node: Node, countOptions?: Options): TokenResult[]; +/** + * Get the token that precedes a given node or token. + * @param nodeOrToken - The AST node or token. + * @param skipOptions? - Options object. + * If is a number, equivalent to `{ skip: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns `Token` (or `Token | Comment` if `includeComments` is `true`), or `null` if none found. + */ +declare function getTokenBefore(nodeOrToken: NodeOrToken, skipOptions?: Options): TokenResult | null; +/** + * Get the token that precedes a given node or token. + * + * @deprecated Use `sourceCode.getTokenBefore` with `includeComments: true` instead. + * + * @param nodeOrToken The AST node or token. + * @param skip - Number of tokens to skip. + * @returns `TokenOrComment | null`. + */ +declare function getTokenOrCommentBefore(nodeOrToken: NodeOrToken, skip?: number): TokenOrComment | null; +/** + * Get the tokens that precede a given node or token. + * @param nodeOrToken - The AST node or token. + * @param countOptions? - Options object. + * If is a number, equivalent to `{ count: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +declare function getTokensBefore(nodeOrToken: NodeOrToken, countOptions?: Options): TokenResult[]; +/** + * Get the token that follows a given node or token. + * @param nodeOrToken - The AST node or token. + * @param skipOptions? - Options object. + * If is a number, equivalent to `{ skip: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns `Token` (or `Token | Comment` if `includeComments` is `true`), or `null` if none found. + */ +declare function getTokenAfter(nodeOrToken: NodeOrToken, skipOptions?: Options): TokenResult | null; +/** + * Get the token that follows a given node or token. + * + * @deprecated Use `sourceCode.getTokenAfter` with `includeComments: true` instead. + * + * @param nodeOrToken The AST node or token. + * @param skip - Number of tokens to skip. + * @returns `TokenOrComment | null`. + */ +declare function getTokenOrCommentAfter(nodeOrToken: NodeOrToken, skip?: number): TokenOrComment | null; +/** + * Get the tokens that follow a given node or token. + * @param nodeOrToken - The AST node or token. + * @param countOptions? - Options object. + * If is a number, equivalent to `{ count: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +declare function getTokensAfter(nodeOrToken: NodeOrToken, countOptions?: Options): TokenResult[]; +/** + * Get all of the tokens between two non-overlapping nodes. + * @param left - Node or token before the desired token range. + * @param right - Node or token after the desired token range. + * @param countOptions? - Options object. If is a function, equivalent to `{ filter: fn }`. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +/** + * Get all of the tokens between two non-overlapping nodes. + * @param left - Node or token before the desired token range. + * @param right - Node or token after the desired token range. + * @param padding - Number of extra tokens on either side of center. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +declare function getTokensBetween(left: NodeOrToken, right: NodeOrToken, countOptions?: Options): TokenResult[]; +/** + * Get the first token between two non-overlapping nodes. + * @param left - Node or token before the desired token range. + * @param right - Node or token after the desired token range. + * @param skipOptions? - Options object. + * If is a number, equivalent to `{ skip: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns `Token` (or `Token | Comment` if `includeComments` is `true`), or `null` if none found. + */ +declare function getFirstTokenBetween(left: NodeOrToken, right: NodeOrToken, skipOptions?: Options): TokenResult | null; +/** + * Get the first tokens between two non-overlapping nodes. + * @param left - Node or token before the desired token range. + * @param right - Node or token after the desired token range. + * @param countOptions? - Options object. + * If is a number, equivalent to `{ count: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +declare function getFirstTokensBetween(left: NodeOrToken, right: NodeOrToken, countOptions?: Options): TokenResult[]; +/** + * Get the last token between two non-overlapping nodes. + * @param left - Node or token before the desired token range. + * @param right - Node or token after the desired token range. + * @param skipOptions? - Options object. + * If is a number, equivalent to `{ skip: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns `Token` (or `Token | Comment` if `includeComments` is `true`), or `null` if none found. + */ +declare function getLastTokenBetween(left: NodeOrToken, right: NodeOrToken, skipOptions?: Options): TokenResult | null; +/** + * Get the last tokens between two non-overlapping nodes. + * @param left - Node or token before the desired token range. + * @param right - Node or token after the desired token range. + * @param countOptions? - Options object. + * If is a number, equivalent to `{ count: n }`. + * If is a function, equivalent to `{ filter: fn }`. + * @returns Array of `Token`s, or array of `Token | Comment`s if `includeComments` is `true`. + */ +declare function getLastTokensBetween(left: NodeOrToken, right: NodeOrToken, countOptions?: Options): TokenResult[]; +/** + * Get the token starting at the specified index. + * @param offset - Start offset of the token. + * @param rangeOptions - Options object. + * @returns `Token` (or `Token | Comment` if `includeComments` is `true`), or `null` if none found. + */ +declare function getTokenByRangeStart(offset: number, rangeOptions?: Options): TokenResult | null; +/** + * Determine if two nodes or tokens have at least one whitespace character between them. + * Order does not matter. + * + * Returns `false` if the given nodes or tokens overlap. + * + * Checks for whitespace *between tokens*, not including whitespace *inside tokens*. + * e.g. Returns `false` for `isSpaceBetween(x, y)` in `x+" "+y`. + * + * @param first - The first node or token to check between. + * @param second - The second node or token to check between. + * @returns `true` if there is a whitespace character between + * any of the tokens found between the two given nodes or tokens. + */ +declare function isSpaceBetween(first: NodeOrToken, second: NodeOrToken): boolean; +/** + * Determine if two nodes or tokens have at least one whitespace character between them. + * Order does not matter. + * + * Returns `false` if the given nodes or tokens overlap. + * + * Checks for whitespace *between tokens*, not including whitespace *inside tokens*. + * e.g. Returns `false` for `isSpaceBetween(x, y)` in `x+" "+y`. + * + * Unlike `SourceCode#isSpaceBetween`, this function does return `true` if there is a `JSText` token between the two + * input tokens, and it contains whitespace. + * e.g. Returns `true` for `isSpaceBetweenTokens(x, slash)` in `a b`. + * + * @deprecated Use `sourceCode.isSpaceBetween` instead. + * + * @param first - The first node or token to check between. + * @param second - The second node or token to check between. + * @returns `true` if there is a whitespace character between + * any of the tokens found between the two given nodes or tokens. + */ +declare function isSpaceBetweenTokens(first: NodeOrToken, second: NodeOrToken): boolean; +//#endregion +//#region src-js/plugins/directives.d.ts +interface Problem { + ruleId: string | null; + message: string; + loc: Location; +} +type DirectiveType = "disable" | "enable" | "disable-line" | "disable-next-line"; +interface Directive { + type: DirectiveType; + node: CommentType; + value: string; + justification: string; +} +declare function getDisableDirectives(): { + problems: Problem[]; + directives: Directive[]; +}; +//#endregion +//#region src-js/plugins/json.d.ts +/** + * A JSON value. + */ +type JsonValue = JsonObject | JsonValue[] | string | number | boolean | null; +/** + * A JSON object. + */ +type JsonObject = { + [key: string]: JsonValue; +}; +//#endregion +//#region src-js/plugins/globals.d.ts +/** + * Globals for the file being linted. + * + * Globals are deserialized from JSON, so can only contain JSON-compatible values. + * Each global variable maps to "readonly", "writable", or "off". + */ +type Globals = Record; +/** + * Environments for the file being linted. + * + * Only includes environments that are enabled, so all properties are `true`. + */ +type Envs = Record; +//#endregion +//#region ../../node_modules/.pnpm/@types+json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts +// ================================================================================================== +// JSON Schema Draft 04 +// ================================================================================================== +/** + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1 + */ +type JSONSchema4TypeName = "string" // + | "number" | "integer" | "boolean" | "object" | "array" | "null" | "any"; +/** + * @see https://tools.ietf.org/html/draft-zyp-json-schema-04#section-3.5 + */ +type JSONSchema4Type = string // + | number | boolean | JSONSchema4Object | JSONSchema4Array | null; +// Workaround for infinite type recursion +interface JSONSchema4Object { + [key: string]: JSONSchema4Type; +} +// Workaround for infinite type recursion +// https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540 +interface JSONSchema4Array extends Array {} +/** + * Meta schema + * + * Recommended values: + * - 'http://json-schema.org/schema#' + * - 'http://json-schema.org/hyper-schema#' + * - 'http://json-schema.org/draft-04/schema#' + * - 'http://json-schema.org/draft-04/hyper-schema#' + * - 'http://json-schema.org/draft-03/schema#' + * - 'http://json-schema.org/draft-03/hyper-schema#' + * + * @see https://tools.ietf.org/html/draft-handrews-json-schema-validation-01#section-5 + */ +type JSONSchema4Version = string; +/** + * JSON Schema V4 + * @see https://tools.ietf.org/html/draft-zyp-json-schema-04 + */ +interface JSONSchema4 { + id?: string | undefined; + $ref?: string | undefined; + $schema?: JSONSchema4Version | undefined; + /** + * This attribute is a string that provides a short description of the + * instance property. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.21 + */ + title?: string | undefined; + /** + * This attribute is a string that provides a full description of the of + * purpose the instance property. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.22 + */ + description?: string | undefined; + default?: JSONSchema4Type | undefined; + multipleOf?: number | undefined; + maximum?: number | undefined; + exclusiveMaximum?: boolean | undefined; + minimum?: number | undefined; + exclusiveMinimum?: boolean | undefined; + maxLength?: number | undefined; + minLength?: number | undefined; + pattern?: string | undefined; + /** + * May only be defined when "items" is defined, and is a tuple of JSONSchemas. + * + * This provides a definition for additional items in an array instance + * when tuple definitions of the items is provided. This can be false + * to indicate additional items in the array are not allowed, or it can + * be a schema that defines the schema of the additional items. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.6 + */ + additionalItems?: boolean | JSONSchema4 | undefined; + /** + * This attribute defines the allowed items in an instance array, and + * MUST be a schema or an array of schemas. The default value is an + * empty schema which allows any value for items in the instance array. + * + * When this attribute value is a schema and the instance value is an + * array, then all the items in the array MUST be valid according to the + * schema. + * + * When this attribute value is an array of schemas and the instance + * value is an array, each position in the instance array MUST conform + * to the schema in the corresponding position for this array. This + * called tuple typing. When tuple typing is used, additional items are + * allowed, disallowed, or constrained by the "additionalItems" + * (Section 5.6) attribute using the same rules as + * "additionalProperties" (Section 5.4) for objects. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.5 + */ + items?: JSONSchema4 | JSONSchema4[] | undefined; + maxItems?: number | undefined; + minItems?: number | undefined; + uniqueItems?: boolean | undefined; + maxProperties?: number | undefined; + minProperties?: number | undefined; + /** + * This attribute indicates if the instance must have a value, and not + * be undefined. This is false by default, making the instance + * optional. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.7 + */ + required?: boolean | string[] | undefined; + /** + * This attribute defines a schema for all properties that are not + * explicitly defined in an object type definition. If specified, the + * value MUST be a schema or a boolean. If false is provided, no + * additional properties are allowed beyond the properties defined in + * the schema. The default value is an empty schema which allows any + * value for additional properties. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.4 + */ + additionalProperties?: boolean | JSONSchema4 | undefined; + definitions?: { + [k: string]: JSONSchema4; + } | undefined; + /** + * This attribute is an object with property definitions that define the + * valid values of instance object property values. When the instance + * value is an object, the property values of the instance object MUST + * conform to the property definitions in this object. In this object, + * each property definition's value MUST be a schema, and the property's + * name MUST be the name of the instance property that it defines. The + * instance property value MUST be valid according to the schema from + * the property definition. Properties are considered unordered, the + * order of the instance properties MAY be in any order. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.2 + */ + properties?: { + [k: string]: JSONSchema4; + } | undefined; + /** + * This attribute is an object that defines the schema for a set of + * property names of an object instance. The name of each property of + * this attribute's object is a regular expression pattern in the ECMA + * 262/Perl 5 format, while the value is a schema. If the pattern + * matches the name of a property on the instance object, the value of + * the instance's property MUST be valid against the pattern name's + * schema value. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.3 + */ + patternProperties?: { + [k: string]: JSONSchema4; + } | undefined; + dependencies?: { + [k: string]: JSONSchema4 | string[]; + } | undefined; + /** + * This provides an enumeration of all possible values that are valid + * for the instance property. This MUST be an array, and each item in + * the array represents a possible value for the instance value. If + * this attribute is defined, the instance value MUST be one of the + * values in the array in order for the schema to be valid. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 + */ + enum?: JSONSchema4Type[] | undefined; + /** + * A single type, or a union of simple types + */ + type?: JSONSchema4TypeName | JSONSchema4TypeName[] | undefined; + allOf?: JSONSchema4[] | undefined; + anyOf?: JSONSchema4[] | undefined; + oneOf?: JSONSchema4[] | undefined; + not?: JSONSchema4 | undefined; + /** + * The value of this property MUST be another schema which will provide + * a base schema which the current schema will inherit from. The + * inheritance rules are such that any instance that is valid according + * to the current schema MUST be valid according to the referenced + * schema. This MAY also be an array, in which case, the instance MUST + * be valid for all the schemas in the array. A schema that extends + * another schema MAY define additional attributes, constrain existing + * attributes, or add other constraints. + * + * Conceptually, the behavior of extends can be seen as validating an + * instance against all constraints in the extending schema as well as + * the extended schema(s). + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.26 + */ + extends?: string | string[] | undefined; + /** + * @see https://tools.ietf.org/html/draft-zyp-json-schema-04#section-5.6 + */ + [k: string]: any; + format?: string | undefined; +} +//#endregion +//#region src-js/plugins/options.d.ts +/** + * Options for a rule on a file. + */ +type Options = JsonValue[]; +/** + * Schema describing valid options for a rule. + * `schema` property of `RuleMeta`. + * + * Can be one of: + * - `JSONSchema4` - Full JSON Schema object (must have `type: "array"` at root). + * - `JSONSchema4[]` - Array shorthand where each element describes corresponding options element. + * - `false` - Opts out of schema validation (not recommended). + */ +type RuleOptionsSchema = JSONSchema4 | JSONSchema4[] | false; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/is-any.d.ts +/** +Returns a boolean for whether the given type is `any`. + +@link https://stackoverflow.com/a/49928360/1490091 + +Useful in type utilities, such as disallowing `any`s to be passed to a function. + +@example +``` +import type {IsAny} from 'type-fest'; + +const typedObject = {a: 1, b: 2} as const; +const anyObject: any = {a: 1, b: 2}; + +function get extends true ? {} : Record), K extends keyof O = keyof O>(object: O, key: K) { + return object[key]; +} + +const typedA = get(typedObject, 'a'); +//=> 1 + +const anyA = get(anyObject, 'a'); +//=> any +``` + +@category Type Guard +@category Utilities +*/ +type IsAny = 0 extends 1 & NoInfer ? true : false; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/is-optional-key-of.d.ts +/** +Returns a boolean for whether the given key is an optional key of type. + +This is useful when writing utility types or schema validators that need to differentiate `optional` keys. + +@example +``` +import type {IsOptionalKeyOf} from 'type-fest'; + +type User = { + name: string; + surname: string; + + luckyNumber?: number; +}; + +type Admin = { + name: string; + surname?: string; +}; + +type T1 = IsOptionalKeyOf; +//=> true + +type T2 = IsOptionalKeyOf; +//=> false + +type T3 = IsOptionalKeyOf; +//=> boolean + +type T4 = IsOptionalKeyOf; +//=> false + +type T5 = IsOptionalKeyOf; +//=> boolean +``` + +@category Type Guard +@category Utilities +*/ +type IsOptionalKeyOf = IsAny extends true ? never : Key extends keyof Type ? Type extends Record ? false : true : false; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/optional-keys-of.d.ts +/** +Extract all optional keys from the given type. + +This is useful when you want to create a new type that contains different type values for the optional keys only. + +@example +``` +import type {OptionalKeysOf, Except} from 'type-fest'; + +type User = { + name: string; + surname: string; + + luckyNumber?: number; +}; + +const REMOVE_FIELD = Symbol('remove field symbol'); +type UpdateOperation = Except, OptionalKeysOf> & { + [Key in OptionalKeysOf]?: Entity[Key] | typeof REMOVE_FIELD; +}; + +const update1: UpdateOperation = { + name: 'Alice', +}; + +const update2: UpdateOperation = { + name: 'Bob', + luckyNumber: REMOVE_FIELD, +}; +``` + +@category Utilities +*/ +type OptionalKeysOf = Type extends unknown // For distributing `Type` + ? (keyof { [Key in keyof Type as IsOptionalKeyOf extends false ? never : Key]: never; }) & keyof Type // Intersect with `keyof Type` to ensure result of `OptionalKeysOf` is always assignable to `keyof Type` + : never; // Should never happen +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/required-keys-of.d.ts +/** +Extract all required keys from the given type. + +This is useful when you want to create a new type that contains different type values for the required keys only or use the list of keys for validation purposes, etc... + +@example +``` +import type {RequiredKeysOf} from 'type-fest'; + +declare function createValidation< + Entity extends object, + Key extends RequiredKeysOf = RequiredKeysOf, +>(field: Key, validator: (value: Entity[Key]) => boolean): (entity: Entity) => boolean; + +type User = { + name: string; + surname: string; + luckyNumber?: number; +}; + +const validator1 = createValidation('name', value => value.length < 25); +const validator2 = createValidation('surname', value => value.length < 25); + +// @ts-expect-error +const validator3 = createValidation('luckyNumber', value => value > 0); +// Error: Argument of type '"luckyNumber"' is not assignable to parameter of type '"name" | "surname"'. +``` + +@category Utilities +*/ +type RequiredKeysOf = Type extends unknown // For distributing `Type` + ? Exclude> : never; // Should never happen +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/is-never.d.ts +/** +Returns a boolean for whether the given type is `never`. + +@link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919 +@link https://stackoverflow.com/a/53984913/10292952 +@link https://www.zhenghao.io/posts/ts-never + +Useful in type utilities, such as checking if something does not occur. + +@example +``` +import type {IsNever, And} from 'type-fest'; + +type A = IsNever; +//=> true + +type B = IsNever; +//=> false + +type C = IsNever; +//=> false + +type D = IsNever; +//=> false + +type E = IsNever; +//=> false + +type F = IsNever; +//=> false +``` + +@example +``` +import type {IsNever} from 'type-fest'; + +type IsTrue = T extends true ? true : false; + +// When a distributive conditional is instantiated with `never`, the entire conditional results in `never`. +type A = IsTrue; +//=> never + +// If you don't want that behaviour, you can explicitly add an `IsNever` check before the distributive conditional. +type IsTrueFixed = + IsNever extends true ? false : T extends true ? true : false; + +type B = IsTrueFixed; +//=> false +``` + +@category Type Guard +@category Utilities +*/ +type IsNever = [T] extends [never] ? true : false; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/if.d.ts +/** +An if-else-like type that resolves depending on whether the given `boolean` type is `true` or `false`. + +Use-cases: +- You can use this in combination with `Is*` types to create an if-else-like experience. For example, `If, 'is any', 'not any'>`. + +Note: +- Returns a union of if branch and else branch if the given type is `boolean` or `any`. For example, `If` will return `'Y' | 'N'`. +- Returns the else branch if the given type is `never`. For example, `If` will return `'N'`. + +@example +``` +import type {If} from 'type-fest'; + +type A = If; +//=> 'yes' + +type B = If; +//=> 'no' + +type C = If; +//=> 'yes' | 'no' + +type D = If; +//=> 'yes' | 'no' + +type E = If; +//=> 'no' +``` + +@example +``` +import type {If, IsAny, IsNever} from 'type-fest'; + +type A = If, 'is any', 'not any'>; +//=> 'not any' + +type B = If, 'is never', 'not never'>; +//=> 'is never' +``` + +@example +``` +import type {If, IsEqual} from 'type-fest'; + +type IfEqual = If, IfBranch, ElseBranch>; + +type A = IfEqual; +//=> 'equal' + +type B = IfEqual; +//=> 'not equal' +``` + +Note: Sometimes using the `If` type can make an implementation non–tail-recursive, which can impact performance. In such cases, it’s better to use a conditional directly. Refer to the following example: + +@example +``` +import type {If, IsEqual, StringRepeat} from 'type-fest'; + +type HundredZeroes = StringRepeat<'0', 100>; + +// The following implementation is not tail recursive +type Includes = + S extends `${infer First}${infer Rest}` + ? If, + 'found', + Includes> + : 'not found'; + +// Hence, instantiations with long strings will fail +// @ts-expect-error +type Fails = Includes; +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Error: Type instantiation is excessively deep and possibly infinite. + +// However, if we use a simple conditional instead of `If`, the implementation becomes tail-recursive +type IncludesWithoutIf = + S extends `${infer First}${infer Rest}` + ? IsEqual extends true + ? 'found' + : IncludesWithoutIf + : 'not found'; + +// Now, instantiations with long strings will work +type Works = IncludesWithoutIf; +//=> 'not found' +``` + +@category Type Guard +@category Utilities +*/ +type If = IsNever extends true ? ElseBranch : Type extends true ? IfBranch : ElseBranch; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/internal/type.d.ts +/** +An if-else-like type that resolves depending on whether the given type is `any` or `never`. + +@example +``` +// When `T` is neither `any` nor `never` (like `string`) => Returns `IfNot` branch +type A = IfNotAnyOrNever; +//=> 'VALID' + +// When `T` is `any` => Returns `IfAny` branch +type B = IfNotAnyOrNever; +//=> 'IS_ANY' + +// When `T` is `never` => Returns `IfNever` branch +type C = IfNotAnyOrNever; +//=> 'IS_NEVER' +``` + +Note: Wrapping a tail-recursive type with `IfNotAnyOrNever` makes the implementation non-tail-recursive. To fix this, move the recursion into a helper type. Refer to the following example: + +@example +```ts +import type {StringRepeat} from 'type-fest'; + +type NineHundredNinetyNineSpaces = StringRepeat<' ', 999>; + +// The following implementation is not tail recursive +type TrimLeft = IfNotAnyOrNever : S}>; + +// Hence, instantiations with long strings will fail +// @ts-expect-error +type T1 = TrimLeft; +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Error: Type instantiation is excessively deep and possibly infinite. + +// To fix this, move the recursion into a helper type +type TrimLeftOptimised = IfNotAnyOrNever}>; + +type _TrimLeftOptimised = S extends ` ${infer R}` ? _TrimLeftOptimised : S; + +type T2 = TrimLeftOptimised; +//=> '' +``` +*/ +type IfNotAnyOrNever = IsAny extends true ? 'ifAny' extends keyof Cases ? Cases['ifAny'] : any : IsNever extends true ? 'ifNever' extends keyof Cases ? Cases['ifNever'] : never : Cases['ifNot']; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/simplify.d.ts +/** +Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability. + +@example +``` +import type {Simplify} from 'type-fest'; + +type PositionProps = { + top: number; + left: number; +}; + +type SizeProps = { + width: number; + height: number; +}; + +// In your editor, hovering over `Props` will show a flattened object with all the properties. +type Props = Simplify; +``` + +Sometimes it is desired to pass a value as a function argument that has a different type. At first inspection it may seem assignable, and then you discover it is not because the `value`'s type definition was defined as an interface. In the following example, `fn` requires an argument of type `Record`. If the value is defined as a literal, then it is assignable. And if the `value` is defined as type using the `Simplify` utility the value is assignable. But if the `value` is defined as an interface, it is not assignable because the interface is not sealed and elsewhere a non-string property could be added to the interface. + +If the type definition must be an interface (perhaps it was defined in a third-party npm package), then the `value` can be defined as `const value: Simplify = ...`. Then `value` will be assignable to the `fn` argument. Or the `value` can be cast as `Simplify` if you can't re-declare the `value`. + +@example +``` +import type {Simplify} from 'type-fest'; + +interface SomeInterface { + foo: number; + bar?: string; + baz: number | undefined; +} + +type SomeType = { + foo: number; + bar?: string; + baz: number | undefined; +}; + +const literal = {foo: 123, bar: 'hello', baz: 456}; +const someType: SomeType = literal; +const someInterface: SomeInterface = literal; + +declare function fn(object: Record): void; + +fn(literal); // Good: literal object type is sealed +fn(someType); // Good: type is sealed +// @ts-expect-error +fn(someInterface); // Error: Index signature for type 'string' is missing in type 'someInterface'. Because `interface` can be re-opened +fn(someInterface as Simplify); // Good: transform an `interface` into a `type` +``` + +@link https://github.com/microsoft/TypeScript/issues/15300 +@see {@link SimplifyDeep} +@category Object +*/ +type Simplify = { [KeyType in keyof T]: T[KeyType]; } & {}; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/is-equal.d.ts +/** +Returns a boolean for whether the two given types are equal. + +@link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650 +@link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796 + +Use-cases: +- If you want to make a conditional branch based on the result of a comparison of two types. + +@example +``` +import type {IsEqual} from 'type-fest'; + +// This type returns a boolean for whether the given array includes the given item. +// `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal. +type Includes = + Value extends readonly [Value[0], ...infer rest] + ? IsEqual extends true + ? true + : Includes + : false; +``` + +@category Type Guard +@category Utilities +*/ +type IsEqual = [A] extends [B] ? [B] extends [A] ? _IsEqual : false : false; +// This version fails the `equalWrappedTupleIntersectionToBeNeverAndNeverExpanded` test in `test-d/is-equal.ts`. +type _IsEqual = (() => G extends A & G | G ? 1 : 2) extends (() => G extends B & G | G ? 1 : 2) ? true : false; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/omit-index-signature.d.ts +/** +Omit any index signatures from the given object type, leaving only explicitly defined properties. + +This is the counterpart of `PickIndexSignature`. + +Use-cases: +- Remove overly permissive signatures from third-party types. + +This type was taken from this [StackOverflow answer](https://stackoverflow.com/a/68261113/420747). + +It relies on the fact that an empty object (`{}`) is assignable to an object with just an index signature, like `Record`, but not to an object with explicitly defined keys, like `Record<'foo' | 'bar', unknown>`. + +(The actual value type, `unknown`, is irrelevant and could be any type. Only the key type matters.) + +``` +const indexed: Record = {}; // Allowed + +// @ts-expect-error +const keyed: Record<'foo', unknown> = {}; // Error +// TS2739: Type '{}' is missing the following properties from type 'Record<"foo" | "bar", unknown>': foo, bar +``` + +Instead of causing a type error like the above, you can also use a [conditional type](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html) to test whether a type is assignable to another: + +``` +type Indexed = {} extends Record + ? '✅ `{}` is assignable to `Record`' + : '❌ `{}` is NOT assignable to `Record`'; + +type IndexedResult = Indexed; +//=> '✅ `{}` is assignable to `Record`' + +type Keyed = {} extends Record<'foo' | 'bar', unknown> + ? '✅ `{}` is assignable to `Record<\'foo\' | \'bar\', unknown>`' + : '❌ `{}` is NOT assignable to `Record<\'foo\' | \'bar\', unknown>`'; + +type KeyedResult = Keyed; +//=> '❌ `{}` is NOT assignable to `Record<\'foo\' | \'bar\', unknown>`' +``` + +Using a [mapped type](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#further-exploration), you can then check for each `KeyType` of `ObjectType`... + +``` +type OmitIndexSignature = { + [KeyType in keyof ObjectType // Map each key of `ObjectType`... + ]: ObjectType[KeyType]; // ...to its original value, i.e. `OmitIndexSignature == Foo`. +}; +``` + +...whether an empty object (`{}`) would be assignable to an object with that `KeyType` (`Record`)... + +``` +type OmitIndexSignature = { + [KeyType in keyof ObjectType + // Is `{}` assignable to `Record`? + as {} extends Record + ? never // ✅ `{}` is assignable to `Record` + : KeyType // ❌ `{}` is NOT assignable to `Record` + ]: ObjectType[KeyType]; +}; +``` + +If `{}` is assignable, it means that `KeyType` is an index signature and we want to remove it. If it is not assignable, `KeyType` is a "real" key and we want to keep it. + +@example +``` +import type {OmitIndexSignature} from 'type-fest'; + +type Example = { + // These index signatures will be removed. + [x: string]: any; + [x: number]: any; + [x: symbol]: any; + [x: `head-${string}`]: string; + [x: `${string}-tail`]: string; + [x: `head-${string}-tail`]: string; + [x: `${bigint}`]: string; + [x: `embedded-${number}`]: string; + + // These explicitly defined keys will remain. + foo: 'bar'; + qux?: 'baz'; +}; + +type ExampleWithoutIndexSignatures = OmitIndexSignature; +//=> {foo: 'bar'; qux?: 'baz'} +``` + +@see {@link PickIndexSignature} +@category Object +*/ +type OmitIndexSignature = { [KeyType in keyof ObjectType as {} extends Record ? never : KeyType]: ObjectType[KeyType]; }; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/pick-index-signature.d.ts +/** +Pick only index signatures from the given object type, leaving out all explicitly defined properties. + +This is the counterpart of `OmitIndexSignature`. + +@example +``` +import type {PickIndexSignature} from 'type-fest'; + +declare const symbolKey: unique symbol; + +type Example = { + // These index signatures will remain. + [x: string]: unknown; + [x: number]: unknown; + [x: symbol]: unknown; + [x: `head-${string}`]: string; + [x: `${string}-tail`]: string; + [x: `head-${string}-tail`]: string; + [x: `${bigint}`]: string; + [x: `embedded-${number}`]: string; + + // These explicitly defined keys will be removed. + ['kebab-case-key']: string; + [symbolKey]: string; + foo: 'bar'; + qux?: 'baz'; +}; + +type ExampleIndexSignature = PickIndexSignature; +// { +// [x: string]: unknown; +// [x: number]: unknown; +// [x: symbol]: unknown; +// [x: `head-${string}`]: string; +// [x: `${string}-tail`]: string; +// [x: `head-${string}-tail`]: string; +// [x: `${bigint}`]: string; +// [x: `embedded-${number}`]: string; +// } +``` + +@see {@link OmitIndexSignature} +@category Object +*/ +type PickIndexSignature = { [KeyType in keyof ObjectType as {} extends Record ? KeyType : never]: ObjectType[KeyType]; }; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/merge.d.ts +// Merges two objects without worrying about index signatures. +type SimpleMerge = Simplify<{ [Key in keyof Destination as Key extends keyof Source ? never : Key]: Destination[Key]; } & Source>; +/** +Merge two types into a new type. Keys of the second type overrides keys of the first type. + +This is different from the TypeScript `&` (intersection) operator. With `&`, conflicting property types are intersected, which often results in `never`. For example, `{a: string} & {a: number}` makes `a` become `string & number`, which resolves to `never`. With `Merge`, the second type's keys cleanly override the first, so `Merge<{a: string}, {a: number}>` gives `{a: number}` as expected. `Merge` also produces a flattened type (via `Simplify`), making it more readable in IDE tooltips compared to `A & B`. + +@example +``` +import type {Merge} from 'type-fest'; + +type Foo = { + a: string; + b: number; +}; + +type Bar = { + a: number; // Conflicts with Foo['a'] + c: boolean; +}; + +// With `&`, `a` becomes `string & number` which is `never`. Not what you want. +type WithIntersection = (Foo & Bar)['a']; +//=> never + +// With `Merge`, `a` is cleanly overridden to `number`. +type WithMerge = Merge['a']; +//=> number +``` + +@example +``` +import type {Merge} from 'type-fest'; + +type Foo = { + [x: string]: unknown; + [x: number]: unknown; + foo: string; + bar: symbol; +}; + +type Bar = { + [x: number]: number; + [x: symbol]: unknown; + bar: Date; + baz: boolean; +}; + +export type FooBar = Merge; +//=> { +// [x: string]: unknown; +// [x: number]: number; +// [x: symbol]: unknown; +// foo: string; +// bar: Date; +// baz: boolean; +// } +``` + +Note: If you want a merge type that more accurately reflects the runtime behavior of object spread or `Object.assign`, refer to the {@link ObjectMerge} type. + +@see {@link ObjectMerge} +@category Object +*/ +type Merge = Destination extends unknown // For distributing `Destination` + ? Source extends unknown // For distributing `Source` + ? If, Destination, _Merge> : never // Should never happen + : never; // Should never happen +type _Merge = Simplify, PickIndexSignature> & SimpleMerge, OmitIndexSignature>>; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/internal/object.d.ts +/** +Merges user specified options with default options. + +@example +``` +type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean}; +type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false}; +type SpecifiedOptions = {leavesOnly: true}; + +type Result = ApplyDefaultOptions; +//=> {maxRecursionDepth: 10; leavesOnly: true} +``` + +@example +``` +// Complains if default values are not provided for optional options + +type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean}; +type DefaultPathsOptions = {maxRecursionDepth: 10}; +type SpecifiedOptions = {}; + +type Result = ApplyDefaultOptions; +// ~~~~~~~~~~~~~~~~~~~ +// Property 'leavesOnly' is missing in type 'DefaultPathsOptions' but required in type '{ maxRecursionDepth: number; leavesOnly: boolean; }'. +``` + +@example +``` +// Complains if an option's default type does not conform to the expected type + +type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean}; +type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: 'no'}; +type SpecifiedOptions = {}; + +type Result = ApplyDefaultOptions; +// ~~~~~~~~~~~~~~~~~~~ +// Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'. +``` + +@example +``` +// Complains if an option's specified type does not conform to the expected type + +type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean}; +type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false}; +type SpecifiedOptions = {leavesOnly: 'yes'}; + +type Result = ApplyDefaultOptions; +// ~~~~~~~~~~~~~~~~ +// Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'. +``` +*/ +type ApplyDefaultOptions, RequiredKeysOf> & Partial, never>>>, SpecifiedOptions extends Options> = _ApplyDefaultOptions extends (infer Result extends Required // `extends Required` ensures that `ApplyDefaultOptions` is always assignable to `Required` +) ? Result : never; +type _ApplyDefaultOptions = If, Defaults, If, Defaults, Merge[Key & keyof Options] ? Key : undefined extends SpecifiedOptions[Key] ? never : Key]: SpecifiedOptions[Key]; }>>>; +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/except.d.ts +/** +Filter out keys from an object. + +Returns `never` if `Exclude` is strictly equal to `Key`. +Returns `never` if `Key` extends `Exclude`. +Returns `Key` otherwise. + +@example +``` +type Filtered = Filter<'foo', 'foo'>; +//=> never +``` + +@example +``` +type Filtered = Filter<'bar', string>; +//=> never +``` + +@example +``` +type Filtered = Filter<'bar', 'foo'>; +//=> 'bar' +``` + +@see {Except} +*/ +type Filter = IsEqual extends true ? never : (KeyType extends ExcludeType ? never : KeyType); +type ExceptOptions = { + /** + Disallow assigning non-specified properties. + + Note that any omitted properties in the resulting type will be present in autocomplete as `undefined`. + + @default false + */ + requireExactProps?: boolean; +}; +type DefaultExceptOptions = { + requireExactProps: false; +}; +/** +Create a type from an object type without certain keys. + +We recommend setting the `requireExactProps` option to `true`. + +This type is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). The `Omit` type does not restrict the omitted keys to be keys present on the given type, while `Except` does. The benefits of a stricter type are avoiding typos and allowing the compiler to pick up on rename refactors automatically. + +This type was proposed to the TypeScript team, which declined it, saying they prefer that libraries implement stricter versions of the built-in types ([microsoft/TypeScript#30825](https://github.com/microsoft/TypeScript/issues/30825#issuecomment-523668235)). + +@example +``` +import type {Except} from 'type-fest'; + +type Foo = { + a: number; + b: string; +}; + +type FooWithoutA = Except; +//=> {b: string} + +// @ts-expect-error +const fooWithoutA: FooWithoutA = {a: 1, b: '2'}; +// errors: 'a' does not exist in type '{ b: string; }' + +type FooWithoutB = Except; +//=> {a: number} & Partial> + +// @ts-expect-error +const fooWithoutB: FooWithoutB = {a: 1, b: '2'}; +// errors at 'b': Type 'string' is not assignable to type 'undefined'. + +// The `Omit` utility type doesn't work when omitting specific keys from objects containing index signatures. + +// Consider the following example: + +type UserData = { + [metadata: string]: string; + email: string; + name: string; + role: 'admin' | 'user'; +}; + +// `Omit` clearly doesn't behave as expected in this case: +type PostPayload = Omit; +//=> {[x: string]: string; [x: number]: string} + +// In situations like this, `Except` works better. +// It simply removes the `email` key while preserving all the other keys. +type PostPayloadFixed = Except; +//=> {[x: string]: string; name: string; role: 'admin' | 'user'} +``` + +@category Object +*/ +type Except = _Except>; +type _Except> = { [KeyType in keyof ObjectType as Filter]: ObjectType[KeyType]; } & (Options['requireExactProps'] extends true ? Partial> : {}); +//#endregion +//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/require-at-least-one.d.ts +/** +Create a type that requires at least one of the given keys, while keeping the remaining keys as is. + +@example +``` +import type {RequireAtLeastOne} from 'type-fest'; + +type Responder = { + text?: () => string; + json?: () => string; + secure?: boolean; +}; + +const responder: RequireAtLeastOne = { + json: () => '{"message": "ok"}', + secure: true, +}; +``` + +@category Object +*/ +type RequireAtLeastOne = IfNotAnyOrNever, never, _RequireAtLeastOne, keyof ObjectType, KeysType>>>; +}>; +type _RequireAtLeastOne = { [ +// For each `Key` in `KeysType` make a mapped type: +Key in KeysType]-?: Required> // 1. Make `Key`'s type required + & Partial>> // 2. Make all other keys in `KeysType` optional +; }[KeysType] & Except; // 3. Add the remaining keys not in `KeysType` +//#endregion +//#region src-js/plugins/fix.d.ts +type FixFn = (fixer: Fixer) => Fix | Array | IterableIterator | null | undefined; +/** + * Fix, as returned by `fix` function. + * + * `range` offsets are relative to start of the source text. + * When the file has a BOM, they are relative to the start of the source text *without* the BOM. + * + * To represent a position *before* a BOM, -1 is used to mean "before the BOM". + * ESLint's `unicode-bom` rule produces a fix `{ range: [-1, 0], text: "" }` to remove a BOM. + */ +interface Fix { + range: Range; + text: string; +} +declare const FIXER: Readonly<{ + insertTextBefore(nodeOrToken: Ranged, text: string): Fix; + insertTextBeforeRange(range: Range, text: string): Fix; + insertTextAfter(nodeOrToken: Ranged, text: string): Fix; + insertTextAfterRange(range: Range, text: string): Fix; + remove(nodeOrToken: Ranged): Fix; + removeRange(range: Range): Fix; + replaceText(nodeOrToken: Ranged, text: string): Fix; + replaceTextRange(range: Range, text: string): Fix; +}>; +type Fixer = typeof FIXER; +//#endregion +//#region src-js/plugins/report.d.ts +/** + * Diagnostic object. + * Passed to `Context#report()`. + * + * - Either `message` or `messageId` property must be provided. + * - Either `node` or `loc` property must be provided. + */ +type Diagnostic = RequireAtLeastOne, "message" | "messageId">; +interface DiagnosticBase { + message?: string | null | undefined; + messageId?: string | null | undefined; + node?: Ranged; + loc?: LocationWithOptionalEnd | LineColumn; + data?: DiagnosticData | null | undefined; + fix?: FixFn; + suggest?: Suggestion[] | null | undefined; +} +/** + * Location with `end` property optional. + */ +interface LocationWithOptionalEnd { + start: LineColumn; + end?: LineColumn | null | undefined; +} +/** + * Data to interpolate into a diagnostic message. + */ +type DiagnosticData = Record; +/** + * Suggested fix. + */ +type Suggestion = RequireAtLeastOne; +interface SuggestionBase { + desc?: string; + messageId?: string; + data?: DiagnosticData | null | undefined; + fix: FixFn; +} +//#endregion +//#region src-js/plugins/source_code.d.ts +declare const SOURCE_CODE: Readonly<{ + /** + * Source text. + */ + readonly text: string; + /** + * `true` if file has Unicode BOM. + */ + readonly hasBOM: boolean; + /** + * AST of the file. + */ + readonly ast: Program; + /** + * `true` if the AST is in ESTree format. + */ + isESTree: true; + /** + * `ScopeManager` for the file. + */ + readonly scopeManager: Readonly<{ + readonly scopes: Scope[]; + readonly globalScope: Scope | null; + getDeclaredVariables(node: Node$1): Variable[]; + acquire(node: Node$1, inner?: boolean): Scope | null; + }>; + /** + * Visitor keys to traverse this AST. + */ + readonly visitorKeys: Readonly>; + /** + * Parser services for the file. + * + * Oxlint does not offer any parser services. + */ + parserServices: Readonly>; + /** + * Source text as array of lines, split according to specification's definition of line breaks. + */ + readonly lines: string[]; + /** + * Character offset of the first character of each line in source text, + * split according to specification's definition of line breaks. + */ + readonly lineStartIndices: number[]; + /** + * Array of all tokens and comments in the file, in source order. + */ + readonly tokensAndComments: (TokenType | CommentType)[]; + /** + * Get the source code for the given node. + * @param node? - The AST node to get the text for. + * @param beforeCount? - The number of characters before the node to retrieve. + * @param afterCount? - The number of characters after the node to retrieve. + * @returns Source text representing the AST node. + */ + getText(node?: Ranged | null, beforeCount?: number | null, afterCount?: number | null): string; + /** + * Get all the ancestors of a given node. + * @param node - AST node + * @returns All the ancestor nodes in the AST, not including the provided node, + * starting from the root node at index 0 and going inwards to the parent node. + */ + getAncestors(node: Node): Node[]; + /** + * Get source text as array of lines, split according to specification's definition of line breaks. + */ + getLines(): string[]; + getRange: typeof getRange; + getLoc: typeof getLoc; + getNodeByRangeIndex: typeof getNodeByRangeIndex; + getLocFromIndex: typeof getLineColumnFromOffset; + getIndexFromLoc: typeof getOffsetFromLineColumn; + getAllComments: typeof getAllComments; + getCommentsBefore: typeof getCommentsBefore; + getCommentsAfter: typeof getCommentsAfter; + getCommentsInside: typeof getCommentsInside; + commentsExistBetween: typeof commentsExistBetween; + getJSDocComment: typeof getJSDocComment; + isGlobalReference: typeof isGlobalReference; + getDeclaredVariables: typeof getDeclaredVariables; + getScope: typeof getScope; + markVariableAsUsed: typeof markVariableAsUsed; + getTokens: typeof getTokens; + getFirstToken: typeof getFirstToken; + getFirstTokens: typeof getFirstTokens; + getLastToken: typeof getLastToken; + getLastTokens: typeof getLastTokens; + getTokenBefore: typeof getTokenBefore; + getTokenOrCommentBefore: typeof getTokenOrCommentBefore; + getTokensBefore: typeof getTokensBefore; + getTokenAfter: typeof getTokenAfter; + getTokenOrCommentAfter: typeof getTokenOrCommentAfter; + getTokensAfter: typeof getTokensAfter; + getTokensBetween: typeof getTokensBetween; + getFirstTokenBetween: typeof getFirstTokenBetween; + getFirstTokensBetween: typeof getFirstTokensBetween; + getLastTokenBetween: typeof getLastTokenBetween; + getLastTokensBetween: typeof getLastTokensBetween; + getTokenByRangeStart: typeof getTokenByRangeStart; + isSpaceBetween: typeof isSpaceBetween; + isSpaceBetweenTokens: typeof isSpaceBetweenTokens; + getDisableDirectives: typeof getDisableDirectives; +}>; +type SourceCode = typeof SOURCE_CODE; +//#endregion +//#region src-js/plugins/context.d.ts +declare const LANGUAGE_OPTIONS: { + /** + * Source type of the file being linted. + */ + readonly sourceType: ModuleKind; + /** + * ECMAScript version of the file being linted. + */ + ecmaVersion: number; + /** + * Parser used to parse the file being linted. + */ + parser: Readonly<{ + /** + * Parser name. + */ + name: "oxlint"; + /** + * Parser version. + */ + version: string; + /** + * Parse code into an AST. + * @param code - Code to parse + * @param options? - Parser options + * @returns AST + */ + parse(code: string, options?: Record): Program; + /** + * Visitor keys for AST nodes. + */ + VisitorKeys: Readonly<{ + DebuggerStatement: readonly never[]; + EmptyStatement: readonly never[]; + Literal: readonly never[]; + PrivateIdentifier: readonly never[]; + Super: readonly never[]; + TemplateElement: readonly never[]; + ThisExpression: readonly never[]; + JSXClosingFragment: readonly never[]; + JSXEmptyExpression: readonly never[]; + JSXIdentifier: readonly never[]; + JSXOpeningFragment: readonly never[]; + JSXText: readonly never[]; + TSAnyKeyword: readonly never[]; + TSBigIntKeyword: readonly never[]; + TSBooleanKeyword: readonly never[]; + TSIntrinsicKeyword: readonly never[]; + TSJSDocUnknownType: readonly never[]; + TSNeverKeyword: readonly never[]; + TSNullKeyword: readonly never[]; + TSNumberKeyword: readonly never[]; + TSObjectKeyword: readonly never[]; + TSStringKeyword: readonly never[]; + TSSymbolKeyword: readonly never[]; + TSThisType: readonly never[]; + TSUndefinedKeyword: readonly never[]; + TSUnknownKeyword: readonly never[]; + TSVoidKeyword: readonly never[]; + AccessorProperty: readonly string[]; + ArrayExpression: readonly string[]; + ArrayPattern: readonly string[]; + ArrowFunctionExpression: readonly string[]; + AssignmentExpression: readonly string[]; + AssignmentPattern: readonly string[]; + AwaitExpression: readonly string[]; + BinaryExpression: readonly string[]; + BlockStatement: readonly string[]; + BreakStatement: readonly string[]; + CallExpression: readonly string[]; + CatchClause: readonly string[]; + ChainExpression: readonly string[]; + ClassBody: readonly string[]; + ClassDeclaration: readonly string[]; + ClassExpression: readonly string[]; + ConditionalExpression: readonly string[]; + ContinueStatement: readonly string[]; + Decorator: readonly string[]; + DoWhileStatement: readonly string[]; + ExportAllDeclaration: readonly string[]; + ExportDefaultDeclaration: readonly string[]; + ExportNamedDeclaration: readonly string[]; + ExportSpecifier: readonly string[]; + ExpressionStatement: readonly string[]; + ForInStatement: readonly string[]; + ForOfStatement: readonly string[]; + ForStatement: readonly string[]; + FunctionDeclaration: readonly string[]; + FunctionExpression: readonly string[]; + Identifier: readonly string[]; + IfStatement: readonly string[]; + ImportAttribute: readonly string[]; + ImportDeclaration: readonly string[]; + ImportDefaultSpecifier: readonly string[]; + ImportExpression: readonly string[]; + ImportNamespaceSpecifier: readonly string[]; + ImportSpecifier: readonly string[]; + LabeledStatement: readonly string[]; + LogicalExpression: readonly string[]; + MemberExpression: readonly string[]; + MetaProperty: readonly string[]; + MethodDefinition: readonly string[]; + NewExpression: readonly string[]; + ObjectExpression: readonly string[]; + ObjectPattern: readonly string[]; + ParenthesizedExpression: readonly string[]; + Program: readonly string[]; + Property: readonly string[]; + PropertyDefinition: readonly string[]; + RestElement: readonly string[]; + ReturnStatement: readonly string[]; + SequenceExpression: readonly string[]; + SpreadElement: readonly string[]; + StaticBlock: readonly string[]; + SwitchCase: readonly string[]; + SwitchStatement: readonly string[]; + TaggedTemplateExpression: readonly string[]; + TemplateLiteral: readonly string[]; + ThrowStatement: readonly string[]; + TryStatement: readonly string[]; + UnaryExpression: readonly string[]; + UpdateExpression: readonly string[]; + V8IntrinsicExpression: readonly string[]; + VariableDeclaration: readonly string[]; + VariableDeclarator: readonly string[]; + WhileStatement: readonly string[]; + WithStatement: readonly string[]; + YieldExpression: readonly string[]; + JSXAttribute: readonly string[]; + JSXClosingElement: readonly string[]; + JSXElement: readonly string[]; + JSXExpressionContainer: readonly string[]; + JSXFragment: readonly string[]; + JSXMemberExpression: readonly string[]; + JSXNamespacedName: readonly string[]; + JSXOpeningElement: readonly string[]; + JSXSpreadAttribute: readonly string[]; + JSXSpreadChild: readonly string[]; + TSAbstractAccessorProperty: readonly string[]; + TSAbstractMethodDefinition: readonly string[]; + TSAbstractPropertyDefinition: readonly string[]; + TSArrayType: readonly string[]; + TSAsExpression: readonly string[]; + TSCallSignatureDeclaration: readonly string[]; + TSClassImplements: readonly string[]; + TSConditionalType: readonly string[]; + TSConstructSignatureDeclaration: readonly string[]; + TSConstructorType: readonly string[]; + TSDeclareFunction: readonly string[]; + TSEmptyBodyFunctionExpression: readonly string[]; + TSEnumBody: readonly string[]; + TSEnumDeclaration: readonly string[]; + TSEnumMember: readonly string[]; + TSExportAssignment: readonly string[]; + TSExternalModuleReference: readonly string[]; + TSFunctionType: readonly string[]; + TSImportEqualsDeclaration: readonly string[]; + TSImportType: readonly string[]; + TSIndexSignature: readonly string[]; + TSIndexedAccessType: readonly string[]; + TSInferType: readonly string[]; + TSInstantiationExpression: readonly string[]; + TSInterfaceBody: readonly string[]; + TSInterfaceDeclaration: readonly string[]; + TSInterfaceHeritage: readonly string[]; + TSIntersectionType: readonly string[]; + TSJSDocNonNullableType: readonly string[]; + TSJSDocNullableType: readonly string[]; + TSLiteralType: readonly string[]; + TSMappedType: readonly string[]; + TSMethodSignature: readonly string[]; + TSModuleBlock: readonly string[]; + TSModuleDeclaration: readonly string[]; + TSNamedTupleMember: readonly string[]; + TSNamespaceExportDeclaration: readonly string[]; + TSNonNullExpression: readonly string[]; + TSOptionalType: readonly string[]; + TSParameterProperty: readonly string[]; + TSParenthesizedType: readonly string[]; + TSPropertySignature: readonly string[]; + TSQualifiedName: readonly string[]; + TSRestType: readonly string[]; + TSSatisfiesExpression: readonly string[]; + TSTemplateLiteralType: readonly string[]; + TSTupleType: readonly string[]; + TSTypeAliasDeclaration: readonly string[]; + TSTypeAnnotation: readonly string[]; + TSTypeAssertion: readonly string[]; + TSTypeLiteral: readonly string[]; + TSTypeOperator: readonly string[]; + TSTypeParameter: readonly string[]; + TSTypeParameterDeclaration: readonly string[]; + TSTypeParameterInstantiation: readonly string[]; + TSTypePredicate: readonly string[]; + TSTypeQuery: readonly string[]; + TSTypeReference: readonly string[]; + TSUnionType: readonly string[]; + }>; + /** + * Ast node types. + */ + readonly Syntax: Readonly>; + /** + * Latest ECMAScript version supported by parser. + */ + latestEcmaVersion: 17; + /** + * ECMAScript versions supported by parser. + */ + supportedEcmaVersions: readonly number[]; + }>; + /** + * Parser options used to parse the file being linted. + */ + parserOptions: Readonly<{ + /** + * Source type of the file being linted. + */ + readonly sourceType: ModuleKind; + /** + * ECMA features. + */ + ecmaFeatures: Readonly<{ + /** + * `true` if file was parsed as JSX. + */ + readonly jsx: boolean; + /** + * `true` if file was parsed with top-level `return` statements allowed. + */ + readonly globalReturn: boolean; + /** + * `true` if file was parsed as strict mode code. + */ + readonly impliedStrict: boolean; + }>; + }>; + /** + * Globals defined for the file being linted. + */ + readonly globals: Readonly; + /** + * Environments defined for the file being linted. + */ + readonly env: Readonly; +}; +/** + * Language options used when parsing a file. + */ +type LanguageOptions = Readonly; +declare const FILE_CONTEXT: Readonly<{ + /** + * Absolute path of the file being linted. + */ + readonly filename: string; + /** + * Get absolute path of the file being linted. + * @returns Absolute path of the file being linted. + * @deprecated Use `context.filename` property instead. + */ + getFilename(): string; + /** + * Physical absolute path of the file being linted. + */ + readonly physicalFilename: string; + /** + * Get physical absolute path of the file being linted. + * @returns Physical absolute path of the file being linted. + * @deprecated Use `context.physicalFilename` property instead. + */ + getPhysicalFilename(): string; + /** + * Current working directory. + */ + readonly cwd: string; + /** + * Get current working directory. + * @returns The current working directory. + * @deprecated Use `context.cwd` property instead. + */ + getCwd(): string; + /** + * Source code of the file being linted. + */ + readonly sourceCode: Readonly<{ + readonly text: string; + readonly hasBOM: boolean; + readonly ast: Program; + isESTree: true; + readonly scopeManager: Readonly<{ + readonly scopes: Scope[]; + readonly globalScope: Scope | null; + getDeclaredVariables(node: Node$1): Variable[]; + acquire(node: Node$1, inner?: boolean): Scope | null; + }>; + readonly visitorKeys: Readonly>; + parserServices: Readonly>; + readonly lines: string[]; + readonly lineStartIndices: number[]; + readonly tokensAndComments: (TokenType | CommentType)[]; + getText(node?: Ranged | null, beforeCount?: number | null, afterCount?: number | null): string; + getAncestors(node: Node): Node[]; + getLines(): string[]; + getRange: typeof getRange; + getLoc: typeof getLoc; + getNodeByRangeIndex: typeof getNodeByRangeIndex; + getLocFromIndex: typeof getLineColumnFromOffset; + getIndexFromLoc: typeof getOffsetFromLineColumn; + getAllComments: typeof getAllComments; + getCommentsBefore: typeof getCommentsBefore; + getCommentsAfter: typeof getCommentsAfter; + getCommentsInside: typeof getCommentsInside; + commentsExistBetween: typeof commentsExistBetween; + getJSDocComment: typeof getJSDocComment; + isGlobalReference: typeof isGlobalReference; + getDeclaredVariables: typeof getDeclaredVariables; + getScope: typeof getScope; + markVariableAsUsed: typeof markVariableAsUsed; + getTokens: typeof getTokens; + getFirstToken: typeof getFirstToken; + getFirstTokens: typeof getFirstTokens; + getLastToken: typeof getLastToken; + getLastTokens: typeof getLastTokens; + getTokenBefore: typeof getTokenBefore; + getTokenOrCommentBefore: typeof getTokenOrCommentBefore; + getTokensBefore: typeof getTokensBefore; + getTokenAfter: typeof getTokenAfter; + getTokenOrCommentAfter: typeof getTokenOrCommentAfter; + getTokensAfter: typeof getTokensAfter; + getTokensBetween: typeof getTokensBetween; + getFirstTokenBetween: typeof getFirstTokenBetween; + getFirstTokensBetween: typeof getFirstTokensBetween; + getLastTokenBetween: typeof getLastTokenBetween; + getLastTokensBetween: typeof getLastTokensBetween; + getTokenByRangeStart: typeof getTokenByRangeStart; + isSpaceBetween: typeof isSpaceBetween; + isSpaceBetweenTokens: typeof isSpaceBetweenTokens; + getDisableDirectives: typeof getDisableDirectives; + }>; + /** + * Get source code of the file being linted. + * @returns Source code of the file being linted. + * @deprecated Use `context.sourceCode` property instead. + */ + getSourceCode(): SourceCode; + /** + * Language options used when parsing this file. + */ + readonly languageOptions: Readonly<{ + /** + * Source type of the file being linted. + */ + readonly sourceType: ModuleKind; + /** + * ECMAScript version of the file being linted. + */ + ecmaVersion: number; + /** + * Parser used to parse the file being linted. + */ + parser: Readonly<{ + /** + * Parser name. + */ + name: "oxlint"; + /** + * Parser version. + */ + version: string; + /** + * Parse code into an AST. + * @param code - Code to parse + * @param options? - Parser options + * @returns AST + */ + parse(code: string, options?: Record): Program; + /** + * Visitor keys for AST nodes. + */ + VisitorKeys: Readonly<{ + DebuggerStatement: readonly never[]; + EmptyStatement: readonly never[]; + Literal: readonly never[]; + PrivateIdentifier: readonly never[]; + Super: readonly never[]; + TemplateElement: readonly never[]; + ThisExpression: readonly never[]; + JSXClosingFragment: readonly never[]; + JSXEmptyExpression: readonly never[]; + JSXIdentifier: readonly never[]; + JSXOpeningFragment: readonly never[]; + JSXText: readonly never[]; + TSAnyKeyword: readonly never[]; + TSBigIntKeyword: readonly never[]; + TSBooleanKeyword: readonly never[]; + TSIntrinsicKeyword: readonly never[]; + TSJSDocUnknownType: readonly never[]; + TSNeverKeyword: readonly never[]; + TSNullKeyword: readonly never[]; + TSNumberKeyword: readonly never[]; + TSObjectKeyword: readonly never[]; + TSStringKeyword: readonly never[]; + TSSymbolKeyword: readonly never[]; + TSThisType: readonly never[]; + TSUndefinedKeyword: readonly never[]; + TSUnknownKeyword: readonly never[]; + TSVoidKeyword: readonly never[]; + AccessorProperty: readonly string[]; + ArrayExpression: readonly string[]; + ArrayPattern: readonly string[]; + ArrowFunctionExpression: readonly string[]; + AssignmentExpression: readonly string[]; + AssignmentPattern: readonly string[]; + AwaitExpression: readonly string[]; + BinaryExpression: readonly string[]; + BlockStatement: readonly string[]; + BreakStatement: readonly string[]; + CallExpression: readonly string[]; + CatchClause: readonly string[]; + ChainExpression: readonly string[]; + ClassBody: readonly string[]; + ClassDeclaration: readonly string[]; + ClassExpression: readonly string[]; + ConditionalExpression: readonly string[]; + ContinueStatement: readonly string[]; + Decorator: readonly string[]; + DoWhileStatement: readonly string[]; + ExportAllDeclaration: readonly string[]; + ExportDefaultDeclaration: readonly string[]; + ExportNamedDeclaration: readonly string[]; + ExportSpecifier: readonly string[]; + ExpressionStatement: readonly string[]; + ForInStatement: readonly string[]; + ForOfStatement: readonly string[]; + ForStatement: readonly string[]; + FunctionDeclaration: readonly string[]; + FunctionExpression: readonly string[]; + Identifier: readonly string[]; + IfStatement: readonly string[]; + ImportAttribute: readonly string[]; + ImportDeclaration: readonly string[]; + ImportDefaultSpecifier: readonly string[]; + ImportExpression: readonly string[]; + ImportNamespaceSpecifier: readonly string[]; + ImportSpecifier: readonly string[]; + LabeledStatement: readonly string[]; + LogicalExpression: readonly string[]; + MemberExpression: readonly string[]; + MetaProperty: readonly string[]; + MethodDefinition: readonly string[]; + NewExpression: readonly string[]; + ObjectExpression: readonly string[]; + ObjectPattern: readonly string[]; + ParenthesizedExpression: readonly string[]; + Program: readonly string[]; + Property: readonly string[]; + PropertyDefinition: readonly string[]; + RestElement: readonly string[]; + ReturnStatement: readonly string[]; + SequenceExpression: readonly string[]; + SpreadElement: readonly string[]; + StaticBlock: readonly string[]; + SwitchCase: readonly string[]; + SwitchStatement: readonly string[]; + TaggedTemplateExpression: readonly string[]; + TemplateLiteral: readonly string[]; + ThrowStatement: readonly string[]; + TryStatement: readonly string[]; + UnaryExpression: readonly string[]; + UpdateExpression: readonly string[]; + V8IntrinsicExpression: readonly string[]; + VariableDeclaration: readonly string[]; + VariableDeclarator: readonly string[]; + WhileStatement: readonly string[]; + WithStatement: readonly string[]; + YieldExpression: readonly string[]; + JSXAttribute: readonly string[]; + JSXClosingElement: readonly string[]; + JSXElement: readonly string[]; + JSXExpressionContainer: readonly string[]; + JSXFragment: readonly string[]; + JSXMemberExpression: readonly string[]; + JSXNamespacedName: readonly string[]; + JSXOpeningElement: readonly string[]; + JSXSpreadAttribute: readonly string[]; + JSXSpreadChild: readonly string[]; + TSAbstractAccessorProperty: readonly string[]; + TSAbstractMethodDefinition: readonly string[]; + TSAbstractPropertyDefinition: readonly string[]; + TSArrayType: readonly string[]; + TSAsExpression: readonly string[]; + TSCallSignatureDeclaration: readonly string[]; + TSClassImplements: readonly string[]; + TSConditionalType: readonly string[]; + TSConstructSignatureDeclaration: readonly string[]; + TSConstructorType: readonly string[]; + TSDeclareFunction: readonly string[]; + TSEmptyBodyFunctionExpression: readonly string[]; + TSEnumBody: readonly string[]; + TSEnumDeclaration: readonly string[]; + TSEnumMember: readonly string[]; + TSExportAssignment: readonly string[]; + TSExternalModuleReference: readonly string[]; + TSFunctionType: readonly string[]; + TSImportEqualsDeclaration: readonly string[]; + TSImportType: readonly string[]; + TSIndexSignature: readonly string[]; + TSIndexedAccessType: readonly string[]; + TSInferType: readonly string[]; + TSInstantiationExpression: readonly string[]; + TSInterfaceBody: readonly string[]; + TSInterfaceDeclaration: readonly string[]; + TSInterfaceHeritage: readonly string[]; + TSIntersectionType: readonly string[]; + TSJSDocNonNullableType: readonly string[]; + TSJSDocNullableType: readonly string[]; + TSLiteralType: readonly string[]; + TSMappedType: readonly string[]; + TSMethodSignature: readonly string[]; + TSModuleBlock: readonly string[]; + TSModuleDeclaration: readonly string[]; + TSNamedTupleMember: readonly string[]; + TSNamespaceExportDeclaration: readonly string[]; + TSNonNullExpression: readonly string[]; + TSOptionalType: readonly string[]; + TSParameterProperty: readonly string[]; + TSParenthesizedType: readonly string[]; + TSPropertySignature: readonly string[]; + TSQualifiedName: readonly string[]; + TSRestType: readonly string[]; + TSSatisfiesExpression: readonly string[]; + TSTemplateLiteralType: readonly string[]; + TSTupleType: readonly string[]; + TSTypeAliasDeclaration: readonly string[]; + TSTypeAnnotation: readonly string[]; + TSTypeAssertion: readonly string[]; + TSTypeLiteral: readonly string[]; + TSTypeOperator: readonly string[]; + TSTypeParameter: readonly string[]; + TSTypeParameterDeclaration: readonly string[]; + TSTypeParameterInstantiation: readonly string[]; + TSTypePredicate: readonly string[]; + TSTypeQuery: readonly string[]; + TSTypeReference: readonly string[]; + TSUnionType: readonly string[]; + }>; + /** + * Ast node types. + */ + readonly Syntax: Readonly>; + /** + * Latest ECMAScript version supported by parser. + */ + latestEcmaVersion: 17; + /** + * ECMAScript versions supported by parser. + */ + supportedEcmaVersions: readonly number[]; + }>; + /** + * Parser options used to parse the file being linted. + */ + parserOptions: Readonly<{ + /** + * Source type of the file being linted. + */ + readonly sourceType: ModuleKind; + /** + * ECMA features. + */ + ecmaFeatures: Readonly<{ + /** + * `true` if file was parsed as JSX. + */ + readonly jsx: boolean; + /** + * `true` if file was parsed with top-level `return` statements allowed. + */ + readonly globalReturn: boolean; + /** + * `true` if file was parsed as strict mode code. + */ + readonly impliedStrict: boolean; + }>; + }>; + /** + * Globals defined for the file being linted. + */ + readonly globals: Readonly; + /** + * Environments defined for the file being linted. + */ + readonly env: Readonly; + }>; + /** + * Settings for the file being linted. + */ + readonly settings: Readonly; + /** + * Create a new object with the current object as the prototype and + * the specified properties as its own properties. + * @param extension - The properties to add to the new object. + * @returns A new object with the current object as the prototype + * and the specified properties as its own properties. + */ + extend(this: FileContext, extension: Record): FileContext; + /** + * Parser options used to parse the file being linted. + * @deprecated Use `languageOptions.parserOptions` instead. + */ + readonly parserOptions: Record; + /** + * The path to the parser used to parse this file. + * @deprecated No longer supported. + */ + readonly parserPath: string | undefined; +}>; +/** + * Context object for a file. + * Is the prototype for `Context` objects for each rule. + */ +type FileContext = typeof FILE_CONTEXT; +/** + * Context object for a rule. + * Passed to `create` and `createOnce` functions. + */ +interface Context extends FileContext { + /** + * Rule ID, in form `/`. + */ + id: string; + /** + * Rule options for this rule on this file. + */ + options: Readonly; + /** + * Report an error/warning. + */ + report(this: void, diagnostic: Diagnostic): void; +} +//#endregion +//#region src-js/plugins/rule_meta.d.ts +/** + * Rule metadata. + * `meta` property of `Rule`. + */ +interface RuleMeta { + /** + * Type of rule. + * + * - `problem`: The rule is identifying code that either will cause an error or may cause a confusing behavior. + * Developers should consider this a high priority to resolve. + * - `suggestion`: The rule is identifying something that could be done in a better way but no errors will occur + * if the code isn’t changed. + * - `layout`: The rule cares primarily about whitespace, semicolons, commas, and parentheses, all the parts + * of the program that determine how the code looks rather than how it executes. + * These rules work on parts of the code that aren’t specified in the AST. + */ + type?: "problem" | "suggestion" | "layout"; + /** + * Rule documentation. + */ + docs?: RuleDocs; + /** + * Templates for error/warning messages. + */ + messages?: Record; + /** + * Type of fixes that the rule provides. + * Must be `'code'` or `'whitespace'` if the rule provides fixes. + */ + fixable?: "code" | "whitespace" | null | undefined; + /** + * Specifies whether rule can return suggestions. + * Must be `true` if the rule provides suggestions. + * @default false + */ + hasSuggestions?: boolean; + /** + * Shape of options for the rule. + * Mandatory if the rule has options. + */ + schema?: RuleOptionsSchema; + /** + * Default options for the rule. + * If present, any user-provided options in their config will be merged on top of them recursively. + */ + defaultOptions?: Options; + /** + * Indicates whether the rule has been deprecated, and info about the deprecation and possible replacements. + */ + deprecated?: boolean | RuleDeprecatedInfo; + /** + * Name of the rule(s) this rule was replaced by, if it was deprecated. + * @deprecated Use `deprecated.replacedBy` instead. + */ + replacedBy?: readonly string[]; +} +/** + * Rule documentation. + * `docs` property of `RuleMeta`. + * + * Often used for documentation generation and tooling. + */ +interface RuleDocs { + /** + * Short description of the rule. + */ + description?: string; + /** + * Typically a boolean, representing whether the rule is enabled by the recommended config. + */ + recommended?: unknown; + /** + * URL for rule documentation. + */ + url?: string; + /** + * Other arbitrary user-defined properties. + */ + [key: string]: unknown; +} +/** + * Info about deprecation of a rule, and possible replacements. + * `deprecated` property of `RuleMeta`. + */ +interface RuleDeprecatedInfo { + /** + * General message presentable to the user. May contain why this rule is deprecated or how to replace the rule. + */ + message?: string; + /** + * URL with more information about this rule deprecation. + */ + url?: string; + /** + * Information about available replacements for the rule. + * This may be an empty array to explicitly state there is no replacement. + */ + replacedBy?: RuleReplacedByInfo[]; + /** + * Version (as semver string) deprecating the rule. + */ + deprecatedSince?: string; + /** + * Version (as semver string) likely to remove the rule. + * e.g. the next major version. + * + * The special value `null` means the rule will no longer be changed, but will be kept available indefinitely. + */ + availableUntil?: string | null; +} +/** + * Info about a possible replacement for a rule. + */ +interface RuleReplacedByInfo { + /** + * A general message about this rule replacement. + */ + message?: string; + /** + * A URL with more information about this rule replacement. + */ + url?: string; + /** + * Which plugin has the replacement rule. + * + * The `name` property should be the package name, and should be: + * - `"oxlint"` if the replacement is an Oxlint core rule. + * - `"eslint"` if the replacement is an ESLint core rule. + * + * This property should be omitted if the replacement rule is in the same plugin. + */ + plugin?: RuleReplacedByExternalSpecifier; + /** + * Name of replacement rule. + * May be omitted if the plugin only contains a single rule, or has the same name as the rule. + */ + rule?: RuleReplacedByExternalSpecifier; +} +/** + * Details about a plugin or rule that replaces a deprecated rule. + */ +interface RuleReplacedByExternalSpecifier { + /** + * For a plugin, the package name. + * For a rule, the rule name. + */ + name?: string; + /** + * URL pointing to documentation for the plugin / rule. + */ + url?: string; +} +//#endregion +//#region src-js/plugins/load.d.ts +/** + * Linter plugin, comprising multiple rules + */ +interface Plugin { + meta?: { + name?: string; + }; + rules: Record; +} +/** + * Linter rule. + * + * `Rule` can have either `create` method, or `createOnce` method. + * If `createOnce` method is present, `create` is ignored. + * + * If defining the rule with `createOnce`, and you want the rule to work with ESLint too, + * you need to wrap the plugin containing the rule with `eslintCompatPlugin`. + */ +type Rule = CreateRule | CreateOnceRule; +interface CreateRule { + meta?: RuleMeta; + create: (context: Context) => VisitorObject; +} +interface CreateOnceRule { + meta?: RuleMeta; + create?: (context: Context) => VisitorObject; + createOnce: (context: Context) => VisitorWithHooks; +} +//#endregion +//#region src-js/package/define.d.ts +/** + * Define a plugin. + * + * No-op function, just to provide type safety. Input is passed through unchanged. + * + * @param plugin - Plugin to define + * @returns Same plugin as passed in + */ +declare function definePlugin(plugin: Plugin): Plugin; +/** + * Define a rule. + * + * No-op function, just to provide type safety. Input is passed through unchanged. + * + * @param rule - Rule to define + * @returns Same rule as passed in + */ +declare function defineRule(rule: Rule): Rule; +//#endregion +//#region src-js/package/compat.d.ts +/** + * Convert a plugin which used Oxlint's `createOnce` API to also work with ESLint. + * + * If any of the plugin's rules use the Oxlint alternative `createOnce` API, + * add ESLint-compatible `create` methods to those rules, which delegate to `createOnce`. + * This makes the plugin compatible with ESLint. + * + * The `plugin` object passed in is mutated in-place. + * + * @param plugin - Plugin to convert + * @returns Plugin with all rules having `create` method + * @throws {Error} If `plugin` is not an object, or `plugin.rules` is not an object + */ +declare function eslintCompatPlugin(plugin: Plugin): Plugin; +//#endregion +//#region src-js/plugins/settings.d.ts +/** + * Settings for the file being linted. + * + * Settings are deserialized from JSON, so can only contain JSON-compatible values. + */ +type Settings = JsonObject; +//#endregion +export { type AfterHook, type BeforeHook, type BooleanToken, type CommentType as Comment, type Context, type CountOptions, type CreateOnceRule, type CreateRule, type Definition, type DefinitionType, type Diagnostic, type DiagnosticData, type types_d_exports as ESTree, type Envs, type FilterFn, type Fix, type FixFn, type Fixer, type Globals, type IdentifierToken, type JSXIdentifierToken, type JSXTextToken, type KeywordToken, type LanguageOptions, type LineColumn, type Location, type Node, type NullToken, type NumericToken, type Options, type Plugin, type PrivateIdentifierToken, type PunctuatorToken, type Range, type RangeOptions, type Ranged, type Reference, type RegularExpressionToken, type Rule, type RuleDeprecatedInfo, type RuleDocs, type RuleMeta, type RuleOptionsSchema, type RuleReplacedByExternalSpecifier, type RuleReplacedByInfo, type Scope, type ScopeManager, type ScopeType, type Settings, type SkipOptions, type SourceCode, type Span, type StringToken, type Suggestion, type TemplateToken, type TokenType as Token, type Variable, type VisitorObject as Visitor, type VisitorWithHooks, definePlugin, defineRule, eslintCompatPlugin }; \ No newline at end of file diff --git a/.devkit/anti-slop/plugin/oxlint-plugins-api/index.js b/.devkit/anti-slop/plugin/oxlint-plugins-api/index.js new file mode 100644 index 0000000..040ce17 --- /dev/null +++ b/.devkit/anti-slop/plugin/oxlint-plugins-api/index.js @@ -0,0 +1,357 @@ +//#region src-js/package/define.ts +/** +* Define a plugin. +* +* No-op function, just to provide type safety. Input is passed through unchanged. +* +* @param plugin - Plugin to define +* @returns Same plugin as passed in +*/ +function definePlugin(plugin) { + return plugin; +} +/** +* Define a rule. +* +* No-op function, just to provide type safety. Input is passed through unchanged. +* +* @param rule - Rule to define +* @returns Same rule as passed in +*/ +function defineRule(rule) { + return rule; +} +//#endregion +//#region src-js/package/compat.ts +const EMPTY_VISITOR = {}; +/** +* Convert a plugin which used Oxlint's `createOnce` API to also work with ESLint. +* +* If any of the plugin's rules use the Oxlint alternative `createOnce` API, +* add ESLint-compatible `create` methods to those rules, which delegate to `createOnce`. +* This makes the plugin compatible with ESLint. +* +* The `plugin` object passed in is mutated in-place. +* +* @param plugin - Plugin to convert +* @returns Plugin with all rules having `create` method +* @throws {Error} If `plugin` is not an object, or `plugin.rules` is not an object +*/ +function eslintCompatPlugin(plugin) { + if (typeof plugin != "object" || !plugin) throw Error("Plugin must be an object"); + let { rules } = plugin; + if (typeof rules != "object" || !rules) throw Error("Plugin must have an object as `rules` property"); + let afterHooksState = new AfterHooksState(); + for (let ruleName in rules) Object.hasOwn(rules, ruleName) && convertRule(rules[ruleName], afterHooksState); + return plugin; +} +/** +* Class containing state for tracking if any `after` hooks for a plugin's rules need to be called. +* +* # Aims +* +* Aims are: +* 1. `after` hook of each rule runs after all other AST visit functions, and CFG event handlers. +* 2. `after` hooks for *all* a plugin's rules run after *all* that plugin's rules have completed visiting AST. +* 3. `after` hooks for *all* a plugin's rules run before *any* of plugin's rules begin linting another file. +* 4. In the case of an error during AST traversal, `after` hooks are always still run. +* +* The above exactly matches the behavior when running a `createOnce` rule in Oxlint. +* +* # Why this is important +* +* All the complication comes from ensuring `after` hooks run even after an error during AST traversal. +* +* In ESLint CLI, an error will crash the process, so it doesn't particularly matter if `after` hooks run or not, +* but language servers will typically swallow errors, and keep the process running. +* +* Rules using `before` and `after` hooks will often rely on both hooks running in a predictable order, +* to maintain some internal state. For example, they may use `before` and `after` hooks to maintain a per-file +* cache of data which is shared between rules. The cache use case is why rule (2) above is important. +* +* Below is an example of using `before` and `after` hooks to maintain a per-file cache, shared between rules. +* It relies on all `before` hooks running before any rule starts visiting the AST, +* and all `after` hooks running after all rules have finished visiting the AST. +* +* ```ts +* let cache: Data | null = null; +* +* let numRunningRules = 0; +* +* const setupCache = (context) => { +* if (cache === null) cache = new Data(context); +* numRunningRules++; +* }; +* +* const teardownCache = () => { +* numRunningRules--; +* if (numRunningRules === 0) cache = null; +* }; +* +* const rule1 = { +* createOnce(context) { +* return { +* before() { +* setupCache(context); +* }, +* Identifier(node) { +* // Use `cache` +* }, +* after: teardownCache, +* }; +* }, +* }; +* +* const rule2 = { +* // Same as above +* }; +* +* const rule3 = { +* // Same as above +* }; +* ``` +* +* If `after` hooks did not always run, the next lint run could get stale state, and malfunction. +* If `after` hooks ran in the wrong order (e.g. after some `before` hooks for next file), +* `numRunningRules` would never get to 0, and cache would never be cleared. +* +* Note that because all rules run together in a single AST traversal, if a rule from plugin X throws an error, +* it can disrupt rules from plugin Y. This would make it hard to debug. +* +* # Mechanism +* +* ## Initialization +* +* Rules with an `after` hook register themselves by: +* +* 1. Calling `registerResetFunction` to register a function to run `after` hook and clean up internal state. +* This call adds the reset fn to `resetFunctions`, and adds `AFTER_HOOK_INACTIVE` to `pendingStates`. +* 2. Adding an `onCodePathEnd` CFG event handler to the visitor which calls `ruleFinished` at end of AST traversal. +* +* ## Per-file setup +* +* Before linting a file, `create` will call `setupAfterHook` which is created by `createContextAndVisitor`. +* This registers that the `after` hook for the rule needs to run, by setting `pendingStates[ruleIndex]` +* to `AFTER_HOOK_PENDING`, and incrementing `pendingCount`. +* +* If a cleanup microtask has not been scheduled yet, one is scheduled now (see reason below). +* +* ## Normal operation +* +* AST traversal for each rule ends with `ruleFinished` hook being called from `onCodePathEnd` CFG event handler. +* It increments `lintFinishedCount`. If `lintFinishedCount` equals `pendingCount`, all rules have finished linting +* the file, and `reset` is called, which calls all the pending `after` hooks. +* +* ## Error handling +* +* If an error is thrown during AST traversal, we ensure that `after` hooks are still run by 2 mechanisms: +* +* ### 1. Next microtick +* +* Before any rules began linting files, a microtask was scheduled, which runs on next micro-tick. +* All language servers we're aware of run each lint task in a separate tick, so this microtask will run in next tick +* after a linting run, before the next lint task starts. +* +* If the linting run completed successfully, the microtask does nothing. +* +* But if an error was thrown during AST traversal, this will be visible from the state of `pendingCount`. +* The microtask will run any `after` hooks which need to be run, and reset state to reflect that there are +* no more pending `after` hooks. +* +* ### 2. Fallback: Next lint run +* +* Before linting any file, the state of `pendingCount` is checked. +* If any `after` hooks are still pending, they are run immediately. +* They're run before the `context` objects in `createOnce` closures are updated to the next file, +* so they run with access to the old `context` object from the last file. +* +* This fallback should not be required, but it's included as "belt and braces", to handle if any language server +* or other environment running ESLint programmatically, does not pause a tick between linting runs. +*/ +var AfterHooksState = class { + resetFunctions = []; + pendingStates = []; + pendingCount = 0; + lintFinishedCount = 0; + resetIsScheduled = !1; + sourceCode = null; + resetMicrotask = this.resetMicrotaskImpl.bind(this); + /** + * Register a function to run `after` hook for a rule, and reset state. + * @param reset - Function to run `after` hook and reset state + * @returns Index of rule + */ + registerResetFunction(reset) { + let { pendingStates } = this, index = pendingStates.length; + return pendingStates.push(0), this.resetFunctions.push(reset), index; + } + /** + * Register that a rule with `after` hook has completed linting a file. + * Called by `onCodePathEnd` CFG event handler which is added to visitor for rules with `after` hooks. + * + * If all rules with an `after` hook which needs to be run have completed linting the file, run all `after` hooks. + */ + ruleFinished() { + this.lintFinishedCount++, this.lintFinishedCount === this.pendingCount && this.reset(!1); + } + /** + * Call all reset functions where corresponding entry in `pendingStates` is `AFTER_HOOK_PENDING`. + * Should only be called when some `after` hooks are pending. + * + * @param ignoreErrors - `true` to catch and silently ignore any errors which occur in `after` hooks. + * `false` to throw them, + * @throws {unknown} If `ignoreErrors` is `false` and an error occurs in any `after` hooks. + */ + reset(ignoreErrors) { + this.pendingCount; + let { resetFunctions, pendingStates } = this, hooksLen = pendingStates.length, hasError = !1, error; + for (let i = 0; i < hooksLen; i++) if (pendingStates[i] !== 0) { + pendingStates[i] = 0; + try { + resetFunctions[i](); + } catch (e) { + hasError === !1 && (hasError = !0, error = e); + } + } + if (this.pendingCount = 0, this.lintFinishedCount = 0, this.sourceCode = null, hasError === !0 && ignoreErrors === !1) throw error; + } + /** + * Schedule a microtask to run `reset` functions. + */ + scheduleReset() { + queueMicrotask(this.resetMicrotask), this.resetIsScheduled = !0; + } + /** + * Function which is scheduled as the cleanup microtask. + * `scheduleReset` uses `resetMicrotask` which is this method bound to `this`. + */ + resetMicrotaskImpl() { + this.resetIsScheduled = !1, this.pendingCount !== 0 && this.reset(!0); + } +}; +/** +* Convert a rule. +* +* The `rule` object passed in is mutated in-place. +* +* @param rule - Rule to convert +* @param afterHooksState - State of `after` hooks +* @throws {Error} If `rule` is not an object +*/ +function convertRule(rule, afterHooksState) { + if (typeof rule != "object" || !rule) throw Error("Rule must be an object"); + if ("create" in rule) return; + let context = null, visitor, beforeHook, setupAfterHook; + rule.create = (eslintContext) => { + context === null && ({context, visitor, beforeHook, setupAfterHook} = createContextAndVisitor(rule, afterHooksState)); + let eslintFileContext = Object.getPrototypeOf(eslintContext); + if (setupAfterHook !== null) { + let { sourceCode } = eslintFileContext; + afterHooksState.sourceCode !== sourceCode && (afterHooksState.sourceCode = sourceCode, afterHooksState.pendingCount !== 0 && afterHooksState.reset(!0)); + } + return Object.defineProperties(context, { + id: { value: eslintContext.id }, + options: { value: eslintContext.options }, + report: { value: eslintContext.report } + }), Object.setPrototypeOf(context, eslintFileContext), beforeHook !== null && beforeHook() === !1 ? EMPTY_VISITOR : (setupAfterHook !== null && (setupAfterHook(eslintFileContext.sourceCode.ast), afterHooksState.resetIsScheduled === !1 && afterHooksState.scheduleReset()), visitor); + }; +} +const FILE_CONTEXT = Object.freeze({ + get filename() { + throw Error("Cannot access `context.filename` in `createOnce`"); + }, + getFilename() { + throw Error("Cannot call `context.getFilename` in `createOnce`"); + }, + get physicalFilename() { + throw Error("Cannot access `context.physicalFilename` in `createOnce`"); + }, + getPhysicalFilename() { + throw Error("Cannot call `context.getPhysicalFilename` in `createOnce`"); + }, + get cwd() { + throw Error("Cannot access `context.cwd` in `createOnce`"); + }, + getCwd() { + throw Error("Cannot call `context.getCwd` in `createOnce`"); + }, + get sourceCode() { + throw Error("Cannot access `context.sourceCode` in `createOnce`"); + }, + getSourceCode() { + throw Error("Cannot call `context.getSourceCode` in `createOnce`"); + }, + get languageOptions() { + throw Error("Cannot access `context.languageOptions` in `createOnce`"); + }, + get settings() { + throw Error("Cannot access `context.settings` in `createOnce`"); + }, + extend(extension) { + return Object.freeze(Object.assign(Object.create(this), extension)); + }, + get parserOptions() { + throw Error("Cannot access `context.parserOptions` in `createOnce`"); + }, + get parserPath() { + throw Error("Cannot access `context.parserPath` in `createOnce`"); + } +}); +/** +* Call `createOnce` method of rule, and return `Context`, `Visitor`, and `beforeHook` (if any). +* +* @param rule - Rule with `createOnce` method +* @param afterHooksState - State of `after` hooks +* @returns Object with `context`, `visitor`, and `beforeHook` properties, +* and `setupAfterHook` function if visitor has an `after` hook +*/ +function createContextAndVisitor(rule, afterHooksState) { + let { createOnce } = rule; + if (createOnce == null) throw Error("Rules must define either a `create` or `createOnce` method"); + if (typeof createOnce != "function") throw Error("Rule `createOnce` property must be a function"); + let context = Object.create(FILE_CONTEXT, { + id: { + value: null, + enumerable: !0, + configurable: !0 + }, + options: { + value: null, + enumerable: !0, + configurable: !0 + }, + report: { + value() { + throw Error("Cannot report errors in `createOnce`"); + }, + enumerable: !0, + configurable: !0 + } + }), { before: beforeHook, after: afterHook, ...visitor } = createOnce.call(rule, context); + if (beforeHook === void 0) beforeHook = null; + else if (beforeHook !== null && typeof beforeHook != "function") throw Error("`before` property of visitor must be a function if defined"); + let setupAfterHook = null; + if (afterHook != null) { + if (typeof afterHook != "function") throw Error("`after` property of visitor must be a function if defined"); + let program = null, ruleIndex = afterHooksState.registerResetFunction(() => { + program = null, afterHook(); + }); + setupAfterHook = (ast) => { + program = ast, afterHooksState.pendingStates[ruleIndex] = 1, afterHooksState.pendingCount++; + }; + let onCodePathEnd = visitor.onCodePathEnd; + visitor.onCodePathEnd = onCodePathEnd == null ? function(_codePath, node) { + node === program && afterHooksState.ruleFinished(); + } : function(codePath, node) { + onCodePathEnd.call(this, codePath, node), node === program && afterHooksState.ruleFinished(); + }; + } + return { + context, + visitor, + beforeHook, + setupAfterHook + }; +} +//#endregion +export { definePlugin, defineRule, eslintCompatPlugin }; diff --git a/.devkit/anti-slop/plugin/oxlint-plugins-api/package.json b/.devkit/anti-slop/plugin/oxlint-plugins-api/package.json new file mode 100644 index 0000000..bb5ccf1 --- /dev/null +++ b/.devkit/anti-slop/plugin/oxlint-plugins-api/package.json @@ -0,0 +1,43 @@ +{ + "name": "@oxlint/plugins", + "version": "1.78.0", + "description": "Plugin utilities for Oxlint", + "keywords": [ + "eslint", + "linter", + "oxlint", + "plugin" + ], + "homepage": "https://oxc.rs/docs/guide/usage/linter/js-plugins", + "bugs": "https://github.com/oxc-project/oxc/issues", + "license": "MIT", + "author": "Boshen and oxc contributors", + "repository": { + "type": "git", + "url": "git+https://github.com/oxc-project/oxc.git", + "directory": "npm/oxlint-plugins" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "files": [ + "index.js", + "index.cjs", + "index.d.ts", + "README.md" + ], + "type": "module", + "main": "index.js", + "types": "index.d.ts", + "exports": { + ".": { + "types": "./index.d.ts", + "import": "./index.js", + "require": "./index.cjs", + "default": "./index.js" + } + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } +} \ No newline at end of file diff --git a/.devkit/anti-slop/plugin/package.json b/.devkit/anti-slop/plugin/package.json new file mode 100644 index 0000000..0a90493 --- /dev/null +++ b/.devkit/anti-slop/plugin/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "type": "module", + "imports": { + "#oxlint-plugins": "./oxlint-plugins-api/index.js" + } +} diff --git a/.devkit/anti-slop/plugin/rules/no-chained-type-assertions.ts b/.devkit/anti-slop/plugin/rules/no-chained-type-assertions.ts new file mode 100644 index 0000000..bf984fa --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-chained-type-assertions.ts @@ -0,0 +1,77 @@ +import { defineRule } from "#oxlint-plugins"; +import type { ESTree } from "#oxlint-plugins"; + +type TypeAssertionExpression = ESTree.TSAsExpression | ESTree.TSTypeAssertion; + +function isTypeAssertionExpression(node: ESTree.Node): node is TypeAssertionExpression { + return node.type === "TSAsExpression" || node.type === "TSTypeAssertion"; +} + +function unwrapParenthesizedExpression(expression: ESTree.Expression): ESTree.Expression { + let current = expression; + while (current.type === "ParenthesizedExpression") { + current = current.expression; + } + return current; +} + +function isConstAssertion(node: TypeAssertionExpression): boolean { + const { typeAnnotation } = node; + return ( + typeAnnotation.type === "TSTypeReference" && + typeAnnotation.typeName.type === "Identifier" && + typeAnnotation.typeName.name === "const" + ); +} + +function isOutermostAssertionInChain(node: TypeAssertionExpression): boolean { + let current: ESTree.Expression = node; + let parent = node.parent; + + while (parent.type === "ParenthesizedExpression" && parent.expression === current) { + current = parent; + parent = parent.parent; + } + + return !isTypeAssertionExpression(parent) || parent.expression !== current; +} + +function isForbiddenAssertionChain(node: TypeAssertionExpression): boolean { + let assertionCount = 0; + let hasNonConstAssertion = false; + let current: ESTree.Expression = node; + + while (isTypeAssertionExpression(current)) { + assertionCount += 1; + hasNonConstAssertion ||= !isConstAssertion(current); + current = unwrapParenthesizedExpression(current.expression); + } + + return assertionCount > 1 && hasNonConstAssertion; +} + +/** Disallow nested TypeScript type assertions, while permitting chains made only of const assertions. */ +export const noChainedTypeAssertionsRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow chained TypeScript as and angle-bracket assertions, including parenthesized chains.", + }, + messages: { + chained: + "This assertion chain discards type evidence. Keep the original precise type, or parse untrusted input at its boundary before narrowing it.", + }, + }, + createOnce(context) { + const checkTypeAssertion = (node: TypeAssertionExpression) => { + if (!isOutermostAssertionInChain(node) || !isForbiddenAssertionChain(node)) return; + context.report({ node, messageId: "chained" }); + }; + + return { + TSAsExpression: checkTypeAssertion, + TSTypeAssertion: checkTypeAssertion, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-conditional-empty-object-spread.ts b/.devkit/anti-slop/plugin/rules/no-conditional-empty-object-spread.ts new file mode 100644 index 0000000..a6fd632 --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-conditional-empty-object-spread.ts @@ -0,0 +1,49 @@ +import { defineRule } from "#oxlint-plugins"; +import type { ESTree } from "#oxlint-plugins"; + +function unwrapParentheses(node: ESTree.Expression): ESTree.Expression { + let current = node; + while (current.type === "ParenthesizedExpression") { + current = current.expression; + } + return current; +} + +function isEmptyObjectExpression(node: ESTree.Expression): boolean { + return node.type === "ObjectExpression" && node.properties.length === 0; +} + +function isConditionalEmptyObjectSpread(node: ESTree.Expression): boolean { + const conditional = unwrapParentheses(node); + return ( + conditional.type === "ConditionalExpression" && + (isEmptyObjectExpression(conditional.consequent) || + isEmptyObjectExpression(conditional.alternate)) + ); +} + +/** Ban conditional empty-object spreads without changing their omission semantics. */ +export const noConditionalEmptyObjectSpreadRule = defineRule({ + meta: { + type: "suggestion", + docs: { + description: + "Disallow object spreads that conditionally spread an empty object to omit fields.", + }, + messages: { + avoid: + "This conditional spread hides property omission behind an empty object. Build the object in separate statements and add the property only when present.", + }, + }, + createOnce(context) { + return { + SpreadElement(node) { + if (node.parent.type !== "ObjectExpression") return; + + if (isConditionalEmptyObjectSpread(node.argument)) { + context.report({ node, messageId: "avoid" }); + } + }, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-known-value-widening.ts b/.devkit/anti-slop/plugin/rules/no-known-value-widening.ts new file mode 100644 index 0000000..5196421 --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-known-value-widening.ts @@ -0,0 +1,247 @@ +import { defineRule } from "#oxlint-plugins"; + +import { + classifyWideningTarget, + createTypeEnvironment, + isKnownEvidenceExpression, + type TypeEnvironment, + type WideningTarget, +} from "../shared/dictionary-types.ts"; + +import type { ESTree, Scope, SourceCode, Variable } from "#oxlint-plugins"; + +type FunctionExpression = ESTree.ArrowFunctionExpression | ESTree.Function; + +function unwrapExpression(expression: ESTree.Expression): ESTree.Expression { + let current = expression; + while ( + current.type === "ParenthesizedExpression" || + current.type === "TSAsExpression" || + current.type === "TSSatisfiesExpression" || + current.type === "TSTypeAssertion" || + current.type === "TSNonNullExpression" + ) { + current = current.expression; + } + return current; +} + +function resolveVariable( + sourceCode: SourceCode, + identifier: ESTree.IdentifierReference, +): Variable | null { + let scope: Scope | null = sourceCode.getScope(identifier); + while (scope !== null) { + const variable = scope.set.get(identifier.name); + if (variable !== undefined) return variable; + scope = scope.upper; + } + return null; +} + +function variableDeclarator(variable: Variable): ESTree.VariableDeclarator | null { + if (variable.defs.length !== 1) return null; + const [definition] = variable.defs; + return definition?.type === "Variable" && definition.node.type === "VariableDeclarator" + ? definition.node + : null; +} + +function isStableConstVariable(variable: Variable, declarator: ESTree.VariableDeclarator): boolean { + return ( + declarator.parent.type === "VariableDeclaration" && + declarator.parent.kind === "const" && + variable.references.every((reference) => reference.init || !reference.isWrite()) + ); +} + +function hasKnownEvidence( + sourceCode: SourceCode, + expression: ESTree.Expression, + visitedVariables = new Set(), +): boolean { + if (isKnownEvidenceExpression(expression)) return true; + const unwrapped = unwrapExpression(expression); + if (unwrapped.type !== "Identifier") return false; + const variable = resolveVariable(sourceCode, unwrapped); + if (variable === null || visitedVariables.has(variable)) return false; + const declarator = variableDeclarator(variable); + if ( + declarator === null || + declarator.init === null || + !isStableConstVariable(variable, declarator) + ) { + return false; + } + visitedVariables.add(variable); + return hasKnownEvidence(sourceCode, declarator.init, visitedVariables); +} + +function annotationTarget( + annotation: ESTree.TSTypeAnnotation | null | undefined, + environment: TypeEnvironment, +): WideningTarget | null { + return annotation === null || annotation === undefined + ? null + : classifyWideningTarget(annotation.typeAnnotation, environment); +} + +function enclosingFunction(node: ESTree.Node): FunctionExpression | null { + let current: ESTree.Node | null = node.parent; + while (current !== null && current.type !== "Program") { + if ( + current.type === "ArrowFunctionExpression" || + current.type === "FunctionDeclaration" || + current.type === "FunctionExpression" + ) { + return current; + } + current = current.parent; + } + return null; +} + +function sourceKeyName(sourceCode: SourceCode, key: ESTree.PropertyKey): string { + if (key.type === "Identifier" || key.type === "PrivateIdentifier") return key.name; + if (key.type === "Literal") return String(key.value); + return sourceCode.getText(key); +} + +function functionName(sourceCode: SourceCode, owner: FunctionExpression | null): string { + if (owner === null) return "anonymous function"; + if (owner.id !== null) return owner.id.name; + const parent = owner.parent; + if (parent.type === "VariableDeclarator" && parent.id.type === "Identifier") + return parent.id.name; + if (parent.type === "MethodDefinition") return sourceKeyName(sourceCode, parent.key); + return "anonymous function"; +} + +function isEmptyObjectExpression(expression: ESTree.Expression): boolean { + const unwrapped = unwrapExpression(expression); + return unwrapped.type === "ObjectExpression" && unwrapped.properties.length === 0; +} + +function isDictionaryAccumulatorTarget(destination: WideningTarget): boolean { + return destination.kind === "open dictionary" || destination.kind === "generic container"; +} + +function hasParentAssertion(node: ESTree.Node): boolean { + return node.parent?.type === "TSAsExpression" || node.parent?.type === "TSTypeAssertion"; +} + +/** Detect sound syntactic cases where a known value is explicitly widened and loses evidence. */ +export const noKnownValueWideningRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow syntactically established values from flowing into explicitly broad or anonymous target types that discard useful evidence.", + }, + messages: { + widening: + "The explicit {{target}} type on {{subject}} discards known type evidence. Keep inference, validate with `satisfies`, or use a named owner contract.", + }, + }, + createOnce(context) { + let environment: TypeEnvironment | null = null; + + const reportFlow = ( + expression: ESTree.Expression, + destination: WideningTarget | null, + subject: string, + ) => { + if (destination === null) return; + if ( + isDictionaryAccumulatorTarget(destination) && + isEmptyObjectExpression(expression) + ) { + return; + } + if (!hasKnownEvidence(context.sourceCode, expression)) return; + context.report({ + node: expression, + messageId: "widening", + data: { subject, target: destination.kind }, + }); + }; + + const targetFromAnnotation = (annotation: ESTree.TSTypeAnnotation | null | undefined) => + environment === null ? null : annotationTarget(annotation, environment); + + return { + Program(node) { + environment = createTypeEnvironment(node); + }, + VariableDeclarator(node) { + if (node.init === null || node.id.type !== "Identifier") return; + reportFlow( + node.init, + targetFromAnnotation(node.id.typeAnnotation), + `binding \`${node.id.name}\``, + ); + }, + PropertyDefinition(node) { + if (node.value === null) return; + reportFlow( + node.value, + targetFromAnnotation(node.typeAnnotation), + `property \`${sourceKeyName(context.sourceCode, node.key)}\``, + ); + }, + AccessorProperty(node) { + if (node.value === null) return; + reportFlow( + node.value, + targetFromAnnotation(node.typeAnnotation), + `property \`${sourceKeyName(context.sourceCode, node.key)}\``, + ); + }, + AssignmentExpression(node) { + if (node.operator !== "=" || node.left.type !== "Identifier") return; + const variable = resolveVariable(context.sourceCode, node.left); + if (variable === null) return; + const declarator = variableDeclarator(variable); + if (declarator === null || declarator.id.type !== "Identifier") return; + reportFlow( + node.right, + targetFromAnnotation(declarator.id.typeAnnotation), + `binding \`${declarator.id.name}\``, + ); + }, + ReturnStatement(node) { + if (node.argument === null) return; + const owner = enclosingFunction(node); + reportFlow( + node.argument, + targetFromAnnotation(owner?.returnType), + `return value of \`${functionName(context.sourceCode, owner)}\``, + ); + }, + ArrowFunctionExpression(node) { + if (node.body.type === "BlockStatement") return; + reportFlow( + node.body, + targetFromAnnotation(node.returnType), + `return value of \`${functionName(context.sourceCode, node)}\``, + ); + }, + TSAsExpression(node) { + if (environment === null || hasParentAssertion(node)) return; + reportFlow( + node.expression, + classifyWideningTarget(node.typeAnnotation, environment), + "assertion", + ); + }, + TSTypeAssertion(node) { + if (environment === null || hasParentAssertion(node)) return; + reportFlow( + node.expression, + classifyWideningTarget(node.typeAnnotation, environment), + "assertion", + ); + }, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-module-mocking.ts b/.devkit/anti-slop/plugin/rules/no-module-mocking.ts new file mode 100644 index 0000000..4cbf68d --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-module-mocking.ts @@ -0,0 +1,91 @@ +import { defineRule } from "#oxlint-plugins"; + +import type { ESTree, Scope, SourceCode, Variable } from "#oxlint-plugins"; + +const moduleMockMethods = new Set(["doMock", "mock", "unstable_mockModule"]); + +function resolveVariable( + sourceCode: SourceCode, + identifier: ESTree.IdentifierReference, +): Variable | null { + let scope: Scope | null = sourceCode.getScope(identifier); + while (scope !== null) { + const variable = scope.set.get(identifier.name); + if (variable !== undefined) return variable; + scope = scope.upper; + } + return null; +} + +function importedName(node: ESTree.Node): string | null { + if (node.type !== "ImportSpecifier") return null; + return node.imported.type === "Identifier" ? node.imported.name : node.imported.value; +} + +function isTestFrameworkObject( + sourceCode: SourceCode, + expression: ESTree.Expression, +): expression is ESTree.IdentifierReference { + if (expression.type !== "Identifier") return false; + if ( + (expression.name === "vi" || expression.name === "jest") && + sourceCode.isGlobalReference(expression) + ) { + return true; + } + + const variable = resolveVariable(sourceCode, expression); + if (variable === null || variable.defs.length === 0) { + return expression.name === "vi" || expression.name === "jest"; + } + return variable.defs.some((definition) => { + if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration") { + return false; + } + const source = definition.parent.source.value; + const name = importedName(definition.node); + return (source === "vitest" && name === "vi") || (source === "@jest/globals" && name === "jest"); + }); +} + +function moduleMockCall(sourceCode: SourceCode, callee: ESTree.Expression): boolean { + if (!("property" in callee) || !("object" in callee) || !("computed" in callee)) return false; + if (!isTestFrameworkObject(sourceCode, callee.object)) return false; + const property = callee.property; + const method = callee.computed + ? property.type === "Literal" && + (property.value === "doMock" || + property.value === "mock" || + property.value === "unstable_mockModule") + ? property.value + : null + : property.type === "Identifier" + ? property.name + : null; + return method !== null && moduleMockMethods.has(method); +} + +/** Ban test framework module mocking in favor of real dependency seams. */ +export const noModuleMockingRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow Vitest and Jest module mocking; tests must replace dependencies through real interfaces.", + }, + messages: { + moduleMock: + "Replace module mocking with dependency injection through a real interface, service layer, or faithful test implementation.", + }, + }, + createOnce(context) { + return { + CallExpression(node) { + if (node.callee.type === "Super" || node.callee.type === "V8IntrinsicExpression") return; + if (moduleMockCall(context.sourceCode, node.callee)) { + context.report({ node, messageId: "moduleMock" }); + } + }, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-object-parameters.ts b/.devkit/anti-slop/plugin/rules/no-object-parameters.ts new file mode 100644 index 0000000..bd2efe2 --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-object-parameters.ts @@ -0,0 +1,126 @@ +import { defineRule } from "#oxlint-plugins"; + +import type { ESTree, SourceCode } from "#oxlint-plugins"; + +import { lexicalTypeParameterNames } from "../shared/lexical-type-parameters.ts"; + +type Parameter = ESTree.ParamPattern; +type ParameterOwner = + | ESTree.ArrowFunctionExpression + | ESTree.Function + | ESTree.TSCallSignatureDeclaration + | ESTree.TSConstructSignatureDeclaration + | ESTree.TSConstructorType + | ESTree.TSFunctionType + | ESTree.TSMethodSignature; + +function parameterAnnotation(parameter: Parameter): ESTree.TSTypeAnnotation | null | undefined { + if (parameter.type === "TSParameterProperty") { + return parameterAnnotation(parameter.parameter); + } + if (parameter.type === "RestElement") { + return parameter.typeAnnotation ?? parameterAnnotation(parameter.argument); + } + if (parameter.type === "AssignmentPattern") { + return parameter.typeAnnotation ?? parameter.left.typeAnnotation; + } + return parameter.typeAnnotation; +} + +function parameterName(parameter: Parameter, sourceCode: SourceCode): string { + return parameter.type === "Identifier" + ? parameter.name + : sourceCode.getText(parameter).replace(/\s*:\s*object\s*$/u, ""); +} + +/** Ban the broad object type on function inputs, including local aliases to object. */ +export const noObjectParametersRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow object function parameters; inputs must use an owner-provided type and be parsed at their boundary.", + }, + messages: { + objectParameter: + "Parameter `{{parameter}}` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function.", + }, + }, + createOnce(context) { + const aliases = new Map(); + + const resolvesToObject = ( + type: ESTree.TSType, + shadowedAliases: ReadonlySet, + visited = new Set(), + ): boolean => { + if (type.type === "TSObjectKeyword") return true; + if (type.type === "TSParenthesizedType") + return resolvesToObject(type.typeAnnotation, shadowedAliases, visited); + if (type.type === "TSUnionType") { + return type.types.some((member) => + resolvesToObject(member, shadowedAliases, visited), + ); + } + if ( + type.type !== "TSTypeReference" || + type.typeName.type !== "Identifier" || + (type.typeArguments !== null && + type.typeArguments !== undefined && + type.typeArguments.params.length > 0) || + visited.has(type.typeName.name) || + shadowedAliases.has(type.typeName.name) + ) { + return false; + } + const alias = aliases.get(type.typeName.name); + if (alias === undefined) return false; + const nextVisited = new Set(visited); + nextVisited.add(type.typeName.name); + return resolvesToObject(alias, shadowedAliases, nextVisited); + }; + + const checkParameters = (node: ParameterOwner) => { + const shadowedAliases = lexicalTypeParameterNames( + node, + context.sourceCode.visitorKeys, + ); + for (const parameter of node.params) { + const annotation = parameterAnnotation(parameter); + if (annotation === null || annotation === undefined) continue; + if (!resolvesToObject(annotation.typeAnnotation, shadowedAliases)) continue; + context.report({ + node: annotation.typeAnnotation, + messageId: "objectParameter", + data: { parameter: parameterName(parameter, context.sourceCode) }, + }); + } + }; + + return { + Program(node) { + aliases.clear(); + for (const statement of node.body) { + const declaration = + statement.type === "ExportNamedDeclaration" ? statement.declaration : statement; + if ( + declaration?.type === "TSTypeAliasDeclaration" && + (declaration.typeParameters === null || declaration.typeParameters === undefined) + ) { + aliases.set(declaration.id.name, declaration.typeAnnotation); + } + } + }, + ArrowFunctionExpression: checkParameters, + FunctionDeclaration: checkParameters, + FunctionExpression: checkParameters, + TSCallSignatureDeclaration: checkParameters, + TSConstructSignatureDeclaration: checkParameters, + TSConstructorType: checkParameters, + TSDeclareFunction: checkParameters, + TSEmptyBodyFunctionExpression: checkParameters, + TSFunctionType: checkParameters, + TSMethodSignature: checkParameters, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-reflect-apply.ts b/.devkit/anti-slop/plugin/rules/no-reflect-apply.ts new file mode 100644 index 0000000..4e4e5fb --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-reflect-apply.ts @@ -0,0 +1,28 @@ +import { defineRule } from "#oxlint-plugins"; + +import { isGlobalReflectMethodCall } from "../shared/reflect-method.ts"; + +/** Ban Reflect.apply, which bypasses ordinary typed function calls. */ +export const noReflectApplyRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow Reflect.apply; call typed functions directly or model dynamic dispatch behind an interface.", + }, + messages: { + reflectApply: + "Replace `Reflect.apply` with a typed function call. Model dynamic dispatch behind a named interface.", + }, + }, + createOnce(context) { + return { + CallExpression(node) { + if (node.callee.type === "Super" || node.callee.type === "V8IntrinsicExpression") return; + if (isGlobalReflectMethodCall(context.sourceCode, node.callee, "apply")) { + context.report({ node, messageId: "reflectApply" }); + } + }, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-reflect-get.ts b/.devkit/anti-slop/plugin/rules/no-reflect-get.ts new file mode 100644 index 0000000..61949c9 --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-reflect-get.ts @@ -0,0 +1,28 @@ +import { defineRule } from "#oxlint-plugins"; + +import { isGlobalReflectMethodCall } from "../shared/reflect-method.ts"; + +/** Ban Reflect.get, which bypasses ordinary property access and useful type evidence. */ +export const noReflectGetRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow Reflect.get; use typed property access or parse dynamic input into a domain type.", + }, + messages: { + reflectGet: + "Replace `Reflect.get` with typed property access. Parse dynamic input into a named domain type before reading it.", + }, + }, + createOnce(context) { + return { + CallExpression(node) { + if (node.callee.type === "Super" || node.callee.type === "V8IntrinsicExpression") return; + if (isGlobalReflectMethodCall(context.sourceCode, node.callee, "get")) { + context.report({ node, messageId: "reflectGet" }); + } + }, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-runtime-typeof.ts b/.devkit/anti-slop/plugin/rules/no-runtime-typeof.ts new file mode 100644 index 0000000..66bbfc7 --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-runtime-typeof.ts @@ -0,0 +1,67 @@ +import { defineRule } from "#oxlint-plugins"; + +import type { ESTree } from "#oxlint-plugins"; + +type RuntimeFunction = ESTree.ArrowFunctionExpression | ESTree.Function; + +function isRuntimeFunction(node: ESTree.Node): node is RuntimeFunction { + return ( + node.type === "ArrowFunctionExpression" || + node.type === "FunctionDeclaration" || + node.type === "FunctionExpression" + ); +} + +function isInsideTypeGuard(node: ESTree.Node): boolean { + let current: ESTree.Node | null = node.parent; + while (current !== null && current.type !== "Program") { + if (isRuntimeFunction(current)) { + return current.returnType?.typeAnnotation.type === "TSTypePredicate"; + } + current = current.parent; + } + return false; +} + +/** Disallow runtime typeof checks that narrow unparsed values instead of decoding them. */ +export const noRuntimeTypeofRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow runtime typeof checks; external values must be decoded into meaningful types at their I/O boundary.", + }, + messages: { + runtimeTypeof: + "A `typeof` check narrows a representation without establishing its contract. Parse input at its I/O boundary, then branch on the domain value.", + }, + schema: [ + { + type: "object", + properties: { + allowInTypeGuards: { type: "boolean" }, + }, + additionalProperties: false, + }, + ], + defaultOptions: [{ allowInTypeGuards: false }], + }, + createOnce(context) { + return { + UnaryExpression(node) { + const option = context.options?.[0]; + const allowInTypeGuards = + typeof option === "object" && + option !== null && + !Array.isArray(option) && + option.allowInTypeGuards === true; + if ( + node.operator === "typeof" && + (!allowInTypeGuards || !isInsideTypeGuard(node)) + ) { + context.report({ node, messageId: "runtimeTypeof" }); + } + }, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-shape-in-symbol-names.ts b/.devkit/anti-slop/plugin/rules/no-shape-in-symbol-names.ts new file mode 100644 index 0000000..a6722aa --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-shape-in-symbol-names.ts @@ -0,0 +1,39 @@ +import { defineRule } from "#oxlint-plugins"; +import type { ESTree } from "#oxlint-plugins"; + +const FORBIDDEN_SYMBOL_NAME = "shape"; + +function containsForbiddenSymbolName(name: string): boolean { + return name.toLowerCase().includes(FORBIDDEN_SYMBOL_NAME); +} + +/** Ban the case-insensitive substring "shape" in every JavaScript and TypeScript symbol name. */ +export const noForbiddenTermInSymbolNamesRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + 'Disallow the case-insensitive substring "shape" in JavaScript, TypeScript, private, and JSX symbol names.', + }, + messages: { + forbiddenSymbolName: + 'Rename symbol "{{name}}" for its domain role; "shape" describes structure rather than ownership.', + }, + }, + createOnce(context) { + const reportForbiddenSymbolName = (node: ESTree.Node & { name: string }) => { + if (!containsForbiddenSymbolName(node.name)) return; + context.report({ + node, + messageId: "forbiddenSymbolName", + data: { name: node.name }, + }); + }; + + return { + Identifier: reportForbiddenSymbolName, + PrivateIdentifier: reportForbiddenSymbolName, + JSXIdentifier: reportForbiddenSymbolName, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-unknown-parameters.ts b/.devkit/anti-slop/plugin/rules/no-unknown-parameters.ts new file mode 100644 index 0000000..3199b29 --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-unknown-parameters.ts @@ -0,0 +1,83 @@ +import { defineRule } from "#oxlint-plugins"; +import type { ESTree } from "#oxlint-plugins"; + +type Parameter = ESTree.ParamPattern; +type ParameterOwner = + | ESTree.ArrowFunctionExpression + | ESTree.Function + | ESTree.TSCallSignatureDeclaration + | ESTree.TSConstructSignatureDeclaration + | ESTree.TSConstructorType + | ESTree.TSFunctionType + | ESTree.TSMethodSignature; + +function parameterAnnotation(parameter: Parameter): ESTree.TSTypeAnnotation | null | undefined { + if (parameter.type === "TSParameterProperty") { + return parameterAnnotation(parameter.parameter); + } + if (parameter.type === "RestElement") { + return parameter.typeAnnotation ?? parameterAnnotation(parameter.argument); + } + if (parameter.type === "AssignmentPattern") { + return parameter.typeAnnotation ?? parameter.left.typeAnnotation; + } + return parameter.typeAnnotation; +} + +function parameterName(parameter: Parameter, sourceText: string): string { + if (parameter.type === "TSParameterProperty") { + return parameterName(parameter.parameter, sourceText); + } + if (parameter.type === "AssignmentPattern") { + return parameterName(parameter.left, sourceText); + } + if (parameter.type === "RestElement") { + return parameterName(parameter.argument, sourceText); + } + return parameter.type === "Identifier" + ? parameter.name + : sourceText.replace(/\s*:\s*unknown\s*$/u, ""); +} + +/** Disallow unknown inputs except explicitly named error-cause enrichment. */ +export const noUnknownParametersRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow explicitly unknown function parameters except `cause`; decode unknown input at its I/O boundary instead.", + }, + messages: { + unknownParameter: + "Parameter `{{parameter}}` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function.", + }, + }, + createOnce(context) { + const checkParameters = (node: ParameterOwner) => { + for (const parameter of node.params) { + const annotation = parameterAnnotation(parameter); + if (annotation?.typeAnnotation.type !== "TSUnknownKeyword") continue; + const name = parameterName(parameter, context.sourceCode.getText(parameter)); + if (name === "cause") continue; + context.report({ + node: annotation.typeAnnotation, + messageId: "unknownParameter", + data: { parameter: name }, + }); + } + }; + + return { + ArrowFunctionExpression: checkParameters, + FunctionDeclaration: checkParameters, + FunctionExpression: checkParameters, + TSCallSignatureDeclaration: checkParameters, + TSConstructSignatureDeclaration: checkParameters, + TSConstructorType: checkParameters, + TSDeclareFunction: checkParameters, + TSEmptyBodyFunctionExpression: checkParameters, + TSFunctionType: checkParameters, + TSMethodSignature: checkParameters, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-unknown-returns.ts b/.devkit/anti-slop/plugin/rules/no-unknown-returns.ts new file mode 100644 index 0000000..137c465 --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-unknown-returns.ts @@ -0,0 +1,115 @@ +import { defineRule } from "#oxlint-plugins"; + +import type { ESTree } from "#oxlint-plugins"; + +import { lexicalTypeParameterNames } from "../shared/lexical-type-parameters.ts"; + +type FunctionWithReturnType = + | ESTree.ArrowFunctionExpression + | ESTree.Function + | ESTree.TSCallSignatureDeclaration + | ESTree.TSConstructSignatureDeclaration + | ESTree.TSConstructorType + | ESTree.TSFunctionType + | ESTree.TSMethodSignature; + +function referencedAliasName(type: ESTree.TSType): string | null { + if (type.type === "TSParenthesizedType") return referencedAliasName(type.typeAnnotation); + if (type.type !== "TSTypeReference" || type.typeName.type !== "Identifier") return null; + return type.typeArguments === null || + type.typeArguments === undefined || + type.typeArguments.params.length === 0 + ? type.typeName.name + : null; +} + +/** Ban function contracts that return unknown instead of a parsed domain type. */ +export const noUnknownReturnsRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow functions whose explicit return contract is unknown or Promise.", + }, + messages: { + unknownReturn: + "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type.", + }, + }, + createOnce(context) { + const aliases = new Map(); + + const resolvesToUnknown = ( + type: ESTree.TSType, + shadowedAliases: ReadonlySet, + visited = new Set(), + ): boolean => { + if (type.type === "TSUnknownKeyword") return true; + if (type.type === "TSParenthesizedType") { + return resolvesToUnknown(type.typeAnnotation, shadowedAliases, visited); + } + if (type.type === "TSUnionType") { + return type.types.some((member) => + resolvesToUnknown(member, shadowedAliases, visited), + ); + } + if ( + type.type === "TSTypeReference" && + type.typeName.type === "Identifier" && + (type.typeName.name === "Promise" || type.typeName.name === "PromiseLike") + ) { + const value = type.typeArguments?.params[0]; + return value !== undefined && resolvesToUnknown(value, shadowedAliases, visited); + } + const name = referencedAliasName(type); + if (name === null || visited.has(name) || shadowedAliases.has(name)) return false; + const alias = aliases.get(name); + if ( + alias === undefined || + (alias.typeParameters !== null && alias.typeParameters !== undefined) + ) { + return false; + } + const nextVisited = new Set(visited); + nextVisited.add(name); + return resolvesToUnknown(alias.typeAnnotation, shadowedAliases, nextVisited); + }; + + const checkReturnType = (node: FunctionWithReturnType) => { + const annotation = node.returnType; + if (annotation === null || annotation === undefined) return; + if ( + !resolvesToUnknown( + annotation.typeAnnotation, + lexicalTypeParameterNames(node, context.sourceCode.visitorKeys), + ) + ) { + return; + } + context.report({ node: annotation.typeAnnotation, messageId: "unknownReturn" }); + }; + + return { + Program(node) { + aliases.clear(); + for (const statement of node.body) { + const declaration = + statement.type === "ExportNamedDeclaration" ? statement.declaration : statement; + if (declaration?.type === "TSTypeAliasDeclaration") { + aliases.set(declaration.id.name, declaration); + } + } + }, + ArrowFunctionExpression: checkReturnType, + FunctionDeclaration: checkReturnType, + FunctionExpression: checkReturnType, + TSCallSignatureDeclaration: checkReturnType, + TSConstructSignatureDeclaration: checkReturnType, + TSConstructorType: checkReturnType, + TSDeclareFunction: checkReturnType, + TSEmptyBodyFunctionExpression: checkReturnType, + TSFunctionType: checkReturnType, + TSMethodSignature: checkReturnType, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-unknown-type-aliases.ts b/.devkit/anti-slop/plugin/rules/no-unknown-type-aliases.ts new file mode 100644 index 0000000..1cb3e87 --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-unknown-type-aliases.ts @@ -0,0 +1,70 @@ +import { defineRule } from "#oxlint-plugins"; + +import type { ESTree } from "#oxlint-plugins"; + +function referencedAliasName(type: ESTree.TSType): string | null { + if (type.type === "TSParenthesizedType") return referencedAliasName(type.typeAnnotation); + if (type.type !== "TSTypeReference" || type.typeName.type !== "Identifier") return null; + return type.typeArguments === null || + type.typeArguments === undefined || + type.typeArguments.params.length === 0 + ? type.typeName.name + : null; +} + +/** Ban named aliases that merely conceal TypeScript's unknown top type. */ +export const noUnknownTypeAliasesRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow type aliases whose resolved type is unknown; unknown must remain visible at an allowed boundary.", + }, + messages: { + unknownAlias: + "Type alias `{{alias}}` hides `unknown`. Keep `unknown` explicit at the parsing boundary or on an allowed `cause` field; otherwise use the parsed owner type.", + }, + }, + createOnce(context) { + const aliases = new Map(); + + const resolvesToUnknown = (type: ESTree.TSType, visited = new Set()): boolean => { + if (type.type === "TSUnknownKeyword") return true; + if (type.type === "TSParenthesizedType") + return resolvesToUnknown(type.typeAnnotation, visited); + const name = referencedAliasName(type); + if (name === null || visited.has(name)) return false; + const alias = aliases.get(name); + if ( + alias === undefined || + (alias.typeParameters !== null && alias.typeParameters !== undefined) + ) { + return false; + } + const nextVisited = new Set(visited); + nextVisited.add(name); + return resolvesToUnknown(alias.typeAnnotation, nextVisited); + }; + + return { + Program(node) { + aliases.clear(); + for (const statement of node.body) { + const declaration = + statement.type === "ExportNamedDeclaration" ? statement.declaration : statement; + if (declaration?.type === "TSTypeAliasDeclaration") { + aliases.set(declaration.id.name, declaration); + } + } + for (const alias of aliases.values()) { + if (!resolvesToUnknown(alias.typeAnnotation, new Set([alias.id.name]))) continue; + context.report({ + node: alias.id, + messageId: "unknownAlias", + data: { alias: alias.id.name }, + }); + } + }, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-unsafe-dictionary-type.ts b/.devkit/anti-slop/plugin/rules/no-unsafe-dictionary-type.ts new file mode 100644 index 0000000..76845ad --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-unsafe-dictionary-type.ts @@ -0,0 +1,134 @@ +import { defineRule } from "#oxlint-plugins"; + +import { + classifyUnsafeDictionary, + classifyUnsafeDictionaryValue, + createTypeEnvironment, + type TypeEnvironment, +} from "../shared/dictionary-types.ts"; + +import type { ESTree } from "#oxlint-plugins"; + +const typeNodeKinds: ReadonlySet = new Set([ + "JSDocNonNullableType", + "JSDocNullableType", + "JSDocUnknownType", + "TSAnyKeyword", + "TSArrayType", + "TSBigIntKeyword", + "TSBooleanKeyword", + "TSConditionalType", + "TSConstructorType", + "TSFunctionType", + "TSImportType", + "TSIndexedAccessType", + "TSInferType", + "TSIntersectionType", + "TSIntrinsicKeyword", + "TSLiteralType", + "TSMappedType", + "TSNamedTupleMember", + "TSNeverKeyword", + "TSNullKeyword", + "TSNumberKeyword", + "TSObjectKeyword", + "TSParenthesizedType", + "TSStringKeyword", + "TSSymbolKeyword", + "TSTemplateLiteralType", + "TSThisType", + "TSTupleType", + "TSTypeLiteral", + "TSTypeOperator", + "TSTypePredicate", + "TSTypeQuery", + "TSTypeReference", + "TSUndefinedKeyword", + "TSUnionType", + "TSUnknownKeyword", + "TSVoidKeyword", +]); + +function isTypeNode(node: ESTree.Node): node is ESTree.TSType { + return typeNodeKinds.has(node.type); +} + +function typeReferenceName(type: ESTree.TSTypeReference): string | null { + return type.typeName.type === "Identifier" ? type.typeName.name : null; +} + +function isInsideTypeAliasDeclaration(node: ESTree.Node): boolean { + let current: ESTree.Node | null = node.parent; + while (current !== null && current.type !== "Program") { + if (current.type === "TSTypeAliasDeclaration") return true; + current = current.parent; + } + return false; +} + +function isPlainAliasConsumerUse(node: ESTree.TSType, environment: TypeEnvironment): boolean { + if (node.type !== "TSTypeReference" || node.typeArguments?.params.length) return false; + const name = typeReferenceName(node); + return name !== null && environment.aliases.has(name) && !isInsideTypeAliasDeclaration(node); +} + +function shouldReportType(node: ESTree.TSType, environment: TypeEnvironment): boolean { + if (isPlainAliasConsumerUse(node, environment)) return false; + if (classifyUnsafeDictionary(node, environment) === null) return false; + let current: ESTree.Node | null = node.parent; + while (current !== null && current.type !== "Program") { + if (isTypeNode(current) && classifyUnsafeDictionary(current, environment) !== null) + return false; + current = current.parent; + } + return true; +} + +/** Disallow object-dictionary contracts whose direct value type is an unsafe escape hatch. */ +export const noUnsafeDictionaryTypeRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow object-dictionary contracts whose direct value type is unknown, any, object, {}, or a union/alias containing one of those escape hatches.", + }, + messages: { + unsafeDictionary: + "This dictionary's {{value}} value type gives callers no concrete value contract. Use an owner/schema-derived value type; parse external payloads before insertion.", + }, + }, + createOnce(context) { + let environment: TypeEnvironment | null = null; + const report = (node: ESTree.Node, value: string) => { + context.report({ node, messageId: "unsafeDictionary", data: { value } }); + }; + const reportIfUnsafe = (node: ESTree.TSType) => { + if (environment === null || !shouldReportType(node, environment)) return; + const unsafe = classifyUnsafeDictionary(node, environment); + if (unsafe === null) return; + report(node, unsafe.unsafeValue); + }; + + return { + Program(node) { + environment = createTypeEnvironment(node); + }, + TSTypeReference: reportIfUnsafe, + TSTypeLiteral: reportIfUnsafe, + TSMappedType: reportIfUnsafe, + TSIndexSignature(node) { + if ( + environment === null || + node.typeAnnotation === null || + node.parent.type === "TSTypeLiteral" + ) + return; + const unsafe = classifyUnsafeDictionaryValue( + node.typeAnnotation.typeAnnotation, + environment, + ); + if (unsafe !== null) report(node, unsafe.unsafeValue); + }, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/no-widen-then-assert.ts b/.devkit/anti-slop/plugin/rules/no-widen-then-assert.ts new file mode 100644 index 0000000..b140f7f --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/no-widen-then-assert.ts @@ -0,0 +1,366 @@ +import { defineRule } from "#oxlint-plugins"; +import type { ESTree, Variable } from "#oxlint-plugins"; + +type BroadTypeKind = "top" | "object" | "record"; + +type KnownValueEvidence = { + readonly type: ESTree.TSType | null; +}; + +const functionBoundaryTypes = new Set([ + "ArrowFunctionExpression", + "FunctionDeclaration", + "FunctionExpression", + "TSDeclareFunction", + "TSEmptyBodyFunctionExpression", +]); + +function unwrapExpressionParentheses(expression: ESTree.Expression): ESTree.Expression { + let current = expression; + while (current.type === "ParenthesizedExpression") current = current.expression; + return current; +} + +function unwrapTypeParentheses(type: ESTree.TSType): ESTree.TSType { + let current = type; + while (current.type === "TSParenthesizedType") current = current.typeAnnotation; + return current; +} + +function typeReferenceName(type: ESTree.TSTypeReference): string | null { + return type.typeName.type === "Identifier" ? type.typeName.name : null; +} + +function isUnknownOrAnyType(type: ESTree.TSType): boolean { + const unwrapped = unwrapTypeParentheses(type); + return unwrapped.type === "TSUnknownKeyword" || unwrapped.type === "TSAnyKeyword"; +} + +function isBroadRecordKeyType(type: ESTree.TSType): boolean { + const unwrapped = unwrapTypeParentheses(type); + if ( + unwrapped.type === "TSStringKeyword" || + unwrapped.type === "TSNumberKeyword" || + unwrapped.type === "TSSymbolKeyword" + ) { + return true; + } + if (unwrapped.type === "TSUnionType") return unwrapped.types.every(isBroadRecordKeyType); + return unwrapped.type === "TSTypeReference" && typeReferenceName(unwrapped) === "PropertyKey"; +} + +function isBroadRecordType(type: ESTree.TSType): boolean { + const unwrapped = unwrapTypeParentheses(type); + + if (unwrapped.type === "TSTypeReference") { + if (typeReferenceName(unwrapped) === "Readonly") { + const [inner] = unwrapped.typeArguments?.params ?? []; + return inner !== undefined && isBroadRecordType(inner); + } + + if (typeReferenceName(unwrapped) !== "Record") return false; + const parameters = unwrapped.typeArguments?.params ?? []; + return ( + parameters.length === 2 && + parameters[0] !== undefined && + parameters[1] !== undefined && + isBroadRecordKeyType(parameters[0]) && + isUnknownOrAnyType(parameters[1]) + ); + } + + if (unwrapped.type !== "TSTypeLiteral" || unwrapped.members.length !== 1) return false; + const [member] = unwrapped.members; + const [parameter] = member?.type === "TSIndexSignature" ? member.parameters : []; + return ( + member?.type === "TSIndexSignature" && + member.parameters.length === 1 && + parameter !== undefined && + isBroadRecordKeyType(parameter.typeAnnotation.typeAnnotation) && + isUnknownOrAnyType(member.typeAnnotation.typeAnnotation) + ); +} + +function broadTypeKind(type: ESTree.TSType): BroadTypeKind | null { + const unwrapped = unwrapTypeParentheses(type); + if (unwrapped.type === "TSUnknownKeyword" || unwrapped.type === "TSAnyKeyword") return "top"; + if (unwrapped.type === "TSObjectKeyword") return "object"; + return isBroadRecordType(unwrapped) ? "record" : null; +} + +function assertedExpression( + node: ESTree.TSAsExpression | ESTree.TSTypeAssertion, +): ESTree.Expression { + return unwrapExpressionParentheses(node.expression); +} + +function assertionFromExpression( + expression: ESTree.Expression, +): ESTree.TSAsExpression | ESTree.TSTypeAssertion | null { + const unwrapped = unwrapExpressionParentheses(expression); + return unwrapped.type === "TSAsExpression" || unwrapped.type === "TSTypeAssertion" + ? unwrapped + : null; +} + +function normalizedTypeText(sourceText: string, type: ESTree.TSType): string { + return sourceText.slice(type.start, type.end).replaceAll(/\s+/gu, ""); +} + +function typesHaveSameSyntax( + sourceText: string, + left: ESTree.TSType | null, + right: ESTree.TSType, +): boolean { + return ( + left !== null && + normalizedTypeText(sourceText, unwrapTypeParentheses(left)) === + normalizedTypeText(sourceText, unwrapTypeParentheses(right)) + ); +} + +function isDefinitelyObjectType(type: ESTree.TSType): boolean { + const unwrapped = unwrapTypeParentheses(type); + switch (unwrapped.type) { + case "TSArrayType": + case "TSConstructorType": + case "TSFunctionType": + case "TSMappedType": + case "TSObjectKeyword": + case "TSTupleType": + return true; + case "TSTypeLiteral": + return unwrapped.members.length > 0; + case "TSIntersectionType": + return unwrapped.types.every(isDefinitelyObjectType); + case "TSTypeOperator": + return unwrapped.operator === "readonly" && isDefinitelyObjectType(unwrapped.typeAnnotation); + default: + return false; + } +} + +function isDefinitelyNarrowerRecordType(type: ESTree.TSType): boolean { + const unwrapped = unwrapTypeParentheses(type); + if (unwrapped.type === "TSTypeLiteral") { + return unwrapped.members.some((member) => member.type !== "TSIndexSignature"); + } + + if (unwrapped.type !== "TSTypeReference") return false; + if (typeReferenceName(unwrapped) === "Readonly") { + const [inner] = unwrapped.typeArguments?.params ?? []; + return inner !== undefined && isDefinitelyNarrowerRecordType(inner); + } + if (typeReferenceName(unwrapped) !== "Record") return false; + + const parameters = unwrapped.typeArguments?.params ?? []; + return ( + parameters.length === 2 && parameters[1] !== undefined && !isUnknownOrAnyType(parameters[1]) + ); +} + +function functionBoundary(node: ESTree.Node): ESTree.Node | null { + let current = node.parent; + while (current !== null && current.type !== "Program") { + if (functionBoundaryTypes.has(current.type)) return current; + current = current.parent; + } + return null; +} + +function resolvedVariableForIdentifier( + scopes: readonly { + readonly references: readonly { + readonly identifier: ESTree.Node; + readonly resolved: Variable | null; + }[]; + }[], + identifier: ESTree.IdentifierReference, +): Variable | null { + for (const scope of scopes) { + const reference = scope.references.find( + (candidate) => + candidate.identifier.start === identifier.start && + candidate.identifier.end === identifier.end, + ); + if (reference !== undefined) return reference.resolved; + } + return null; +} + +function variableDeclarator(variable: Variable): ESTree.VariableDeclarator | null { + for (const definition of variable.defs) { + if (definition.type === "Variable" && definition.node.type === "VariableDeclarator") { + return definition.node; + } + } + return null; +} + +function knownValueEvidence( + expression: ESTree.Expression, + scopes: Parameters[0], + boundary: ESTree.Node | null, + visitedVariables: ReadonlySet, +): KnownValueEvidence | null { + const unwrapped = unwrapExpressionParentheses(expression); + + if (unwrapped.type === "TSAsExpression" || unwrapped.type === "TSTypeAssertion") { + if (broadTypeKind(unwrapped.typeAnnotation) !== null) return null; + return { type: unwrapped.typeAnnotation }; + } + + if (unwrapped.type === "Literal" || unwrapped.type === "TemplateLiteral") { + return { type: null }; + } + + if ( + unwrapped.type === "ArrayExpression" || + unwrapped.type === "ArrowFunctionExpression" || + unwrapped.type === "ClassExpression" || + unwrapped.type === "FunctionExpression" || + unwrapped.type === "NewExpression" || + unwrapped.type === "ObjectExpression" + ) { + return { type: null }; + } + + if (unwrapped.type !== "Identifier") return null; + const variable = resolvedVariableForIdentifier(scopes, unwrapped); + if (variable === null || visitedVariables.has(variable)) return null; + + const annotatedIdentifier = variable.identifiers.find( + (identifier) => identifier.typeAnnotation !== null && identifier.typeAnnotation !== undefined, + ); + const annotation = annotatedIdentifier?.typeAnnotation?.typeAnnotation; + if (annotation !== undefined && annotatedIdentifier !== undefined) { + if (functionBoundary(annotatedIdentifier) !== boundary || broadTypeKind(annotation) !== null) { + return null; + } + return { type: annotation }; + } + + const declarator = variableDeclarator(variable); + if ( + declarator === null || + declarator.parent.type !== "VariableDeclaration" || + declarator.parent.kind !== "const" || + declarator.init === null || + variable.references.some((reference) => reference.isWrite() && !reference.init) || + functionBoundary(declarator) !== boundary + ) { + return null; + } + + return knownValueEvidence( + declarator.init, + scopes, + boundary, + new Set([...visitedVariables, variable]), + ); +} + +function widenedBinding( + variable: Variable, + scopes: Parameters[0], +): { + readonly broadKind: BroadTypeKind; + readonly evidence: KnownValueEvidence; + readonly declaredAt: number; + readonly boundary: ESTree.Node | null; +} | null { + const declarator = variableDeclarator(variable); + if ( + declarator === null || + declarator.parent.type !== "VariableDeclaration" || + declarator.parent.kind !== "const" || + declarator.id.type !== "Identifier" || + declarator.init === null || + variable.references.some((reference) => reference.isWrite() && !reference.init) + ) { + return null; + } + + const boundary = functionBoundary(declarator); + const declaredType = declarator.id.typeAnnotation?.typeAnnotation; + const initializerAssertion = assertionFromExpression(declarator.init); + const initializerBroadKind = + initializerAssertion === null ? null : broadTypeKind(initializerAssertion.typeAnnotation); + const declaredBroadKind = declaredType === undefined ? null : broadTypeKind(declaredType); + const broadKind = declaredBroadKind ?? initializerBroadKind; + if (broadKind === null) return null; + + const originalExpression = + initializerAssertion !== null && initializerBroadKind !== null + ? assertedExpression(initializerAssertion) + : declarator.init; + const evidence = knownValueEvidence(originalExpression, scopes, boundary, new Set([variable])); + return evidence === null ? null : { broadKind, evidence, declaredAt: declarator.end, boundary }; +} + +function assertionIsNarrower( + sourceText: string, + broadKind: BroadTypeKind, + evidence: KnownValueEvidence, + assertedType: ESTree.TSType, +): boolean { + if (broadTypeKind(assertedType) !== null) return false; + if (broadKind === "top") return true; + if (typesHaveSameSyntax(sourceText, evidence.type, assertedType)) return true; + if (broadKind === "object") return isDefinitelyObjectType(assertedType); + return isDefinitelyNarrowerRecordType(assertedType); +} + +/** Detect immutable local bindings that erase a known type and are later asserted back to a narrower type. */ +export const noWidenThenAssertRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Disallow local const flows that explicitly widen a known value before asserting the widened binding to a narrower type.", + }, + messages: { + widenThenAssert: + 'Binding "{{name}}" discards type evidence and later recreates it with an assertion. Keep the precise type from initialization through use; parse boundary input once.', + }, + }, + createOnce(context) { + let scopes: Parameters[0] = []; + + const checkAssertion = (node: ESTree.TSAsExpression | ESTree.TSTypeAssertion) => { + const expression = assertedExpression(node); + if (expression.type !== "Identifier") return; + + const variable = resolvedVariableForIdentifier(scopes, expression); + if (variable === null) return; + const widened = widenedBinding(variable, scopes); + if ( + widened === null || + node.start <= widened.declaredAt || + functionBoundary(node) !== widened.boundary || + !assertionIsNarrower( + context.sourceCode.text, + widened.broadKind, + widened.evidence, + node.typeAnnotation, + ) + ) { + return; + } + + context.report({ + node, + messageId: "widenThenAssert", + data: { name: expression.name }, + }); + }; + + return { + Program() { + scopes = context.sourceCode.scopeManager.scopes; + }, + TSAsExpression: checkAssertion, + TSTypeAssertion: checkAssertion, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/rules/require-safety-comment-for-type-assertion.ts b/.devkit/anti-slop/plugin/rules/require-safety-comment-for-type-assertion.ts new file mode 100644 index 0000000..9229777 --- /dev/null +++ b/.devkit/anti-slop/plugin/rules/require-safety-comment-for-type-assertion.ts @@ -0,0 +1,62 @@ +import { defineRule } from "#oxlint-plugins"; + +import type { ESTree, SourceCode } from "#oxlint-plugins"; + +type TypeAssertion = ESTree.TSAsExpression | ESTree.TSTypeAssertion; + +const commentOwnerKinds = new Set([ + "ExpressionStatement", + "PropertyDefinition", + "ReturnStatement", + "ThrowStatement", + "VariableDeclaration", +]); + +function isConstAssertion(node: TypeAssertion): boolean { + return ( + node.typeAnnotation.type === "TSTypeReference" && + node.typeAnnotation.typeName.type === "Identifier" && + node.typeAnnotation.typeName.name === "const" + ); +} + +function hasSafetyComment(sourceCode: SourceCode, node: TypeAssertion): boolean { + let current: ESTree.Node = node; + while (true) { + if ( + sourceCode + .getCommentsBefore(current) + .some((comment) => comment.end <= node.start && /\bSAFETY\s*:/u.test(comment.value)) + ) { + return true; + } + if (commentOwnerKinds.has(current.type) || current.parent.type === "Program") return false; + current = current.parent; + } +} + +/** Require every non-const type assertion to state the invariant TypeScript cannot express. */ +export const requireSafetyCommentForTypeAssertionRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Require a nearby SAFETY comment for every TypeScript type assertion except const assertions.", + }, + messages: { + missingSafetyComment: + "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement.", + }, + }, + createOnce(context) { + const checkAssertion = (node: TypeAssertion) => { + if (isConstAssertion(node) || hasSafetyComment(context.sourceCode, node)) return; + context.report({ node, messageId: "missingSafetyComment" }); + }; + + return { + TSAsExpression: checkAssertion, + TSTypeAssertion: checkAssertion, + }; + }, +}); diff --git a/.devkit/anti-slop/plugin/shared/dictionary-types.ts b/.devkit/anti-slop/plugin/shared/dictionary-types.ts new file mode 100644 index 0000000..3e193ac --- /dev/null +++ b/.devkit/anti-slop/plugin/shared/dictionary-types.ts @@ -0,0 +1,502 @@ +import type { ESTree } from "#oxlint-plugins"; + +const BUILT_INS = new Set([ + "Record", + "Readonly", + "Partial", + "Required", + "Pick", + "Omit", + "PropertyKey", + "NonNullable", +]); +const TRANSPARENT_WRAPPERS = new Set(["Readonly", "Partial", "Required", "NonNullable"]); + +type TypeAliasEnvironment = ReadonlyMap; + +type ResolvedType = { + readonly type: ESTree.TSType; + readonly substitutions: TypeAliasEnvironment; +}; + +export type UnsafeDictionary = { + readonly kind: "unsafe-dictionary"; + readonly unsafeValue: "any" | "empty-object" | "object" | "union" | "unknown"; +}; + +export type WideningTargetKind = + | "anonymous object" + | "generic container" + | "object" + | "open dictionary" + | "unknown"; + +export type WideningTarget = { + readonly kind: WideningTargetKind; +}; + +export type TypeEnvironment = { + readonly aliases: ReadonlyMap; + readonly interfaces: ReadonlyMap; + readonly shadowedBuiltIns: ReadonlySet; +}; + +function declaredStatement(statement: ESTree.Statement): ESTree.Node | null { + return statement.type === "ExportNamedDeclaration" || + statement.type === "ExportDefaultDeclaration" + ? (statement.declaration ?? null) + : statement; +} + +export function createTypeEnvironment(program: ESTree.Program): TypeEnvironment { + const aliases = new Map(); + const interfaces = new Map(); + const shadowedBuiltIns = new Set(); + + for (const statement of program.body) { + const declaration = declaredStatement(statement); + if (declaration?.type === "ImportDeclaration") { + for (const specifier of declaration.specifiers) { + if (BUILT_INS.has(specifier.local.name)) shadowedBuiltIns.add(specifier.local.name); + } + continue; + } + + if (declaration?.type === "TSTypeAliasDeclaration") { + const existing = aliases.get(declaration.id.name); + if (existing === undefined) aliases.set(declaration.id.name, declaration); + else shadowedBuiltIns.add(declaration.id.name); + if (BUILT_INS.has(declaration.id.name)) shadowedBuiltIns.add(declaration.id.name); + continue; + } + + if (declaration?.type === "TSInterfaceDeclaration") { + const declarations = interfaces.get(declaration.id.name) ?? []; + declarations.push(declaration); + interfaces.set(declaration.id.name, declarations); + if (BUILT_INS.has(declaration.id.name)) shadowedBuiltIns.add(declaration.id.name); + continue; + } + + if (declaration?.type === "TSEnumDeclaration") { + if (BUILT_INS.has(declaration.id.name)) shadowedBuiltIns.add(declaration.id.name); + continue; + } + + if ( + (declaration?.type === "ClassDeclaration" || + declaration?.type === "FunctionDeclaration") && + declaration.id !== null + ) { + if (BUILT_INS.has(declaration.id.name)) shadowedBuiltIns.add(declaration.id.name); + } + } + + return { aliases, interfaces, shadowedBuiltIns }; +} + +function typeReferenceName(type: ESTree.TSTypeReference): string | null { + return type.typeName.type === "Identifier" ? type.typeName.name : null; +} + +function isBuiltIn(name: string, environment: TypeEnvironment): boolean { + return BUILT_INS.has(name) && !environment.shadowedBuiltIns.has(name); +} + +function isUnappliedReferenceTo(type: ESTree.TSType, name: string): boolean { + const unwrapped = unwrapTransparentType(type); + return ( + unwrapped.type === "TSTypeReference" && + typeReferenceName(unwrapped) === name && + (unwrapped.typeArguments === null || + unwrapped.typeArguments === undefined || + unwrapped.typeArguments.params.length === 0) + ); +} + +function unwrapTransparentType(type: ESTree.TSType): ESTree.TSType { + let current = type; + while ( + current.type === "TSParenthesizedType" || + (current.type === "TSTypeOperator" && current.operator === "readonly") + ) { + current = current.typeAnnotation; + } + return current; +} + +function isNeverType(type: ESTree.TSType): boolean { + return unwrapTransparentType(type).type === "TSNeverKeyword"; +} + +function isEffectivelyEmptyMember(member: ESTree.TSSignature): boolean { + return ( + member.type === "TSPropertySignature" && + member.optional === true && + member.typeAnnotation !== null && + member.typeAnnotation !== undefined && + isNeverType(member.typeAnnotation.typeAnnotation) + ); +} + +function isEffectivelyEmptyTypeLiteral(type: ESTree.TSTypeLiteral): boolean { + return type.members.length === 0 || type.members.every(isEffectivelyEmptyMember); +} + +function isEffectivelyEmptyInterface( + declarations: readonly ESTree.TSInterfaceDeclaration[], +): boolean { + if (declarations.length !== 1) return false; + const [type] = declarations; + return ( + type !== undefined && + type.extends.length === 0 && + (type.body.body.length === 0 || type.body.body.every(isEffectivelyEmptyMember)) + ); +} + +function resolvedSubstitutionArgument( + type: ESTree.TSType, + base: TypeAliasEnvironment, + resolving: ReadonlySet = new Set(), +): ESTree.TSType { + const unwrapped = unwrapTransparentType(type); + if (unwrapped.type !== "TSTypeReference") return type; + const name = typeReferenceName(unwrapped); + if (name === null || resolving.has(name)) return type; + const substitution = base.get(name); + if (substitution === undefined) return type; + const nextResolving = new Set(resolving); + nextResolving.add(name); + return resolvedSubstitutionArgument(substitution, base, nextResolving); +} + +function aliasSubstitution( + alias: ESTree.TSTypeAliasDeclaration, + type: ESTree.TSTypeReference, + base: TypeAliasEnvironment, +): TypeAliasEnvironment | null { + const parameters = alias.typeParameters?.params ?? []; + const arguments_ = type.typeArguments?.params ?? []; + const next = new Map(base); + for (const [index, parameter] of parameters.entries()) { + const argument = arguments_[index] ?? parameter.default; + if (argument === null || argument === undefined) return null; + next.set(parameter.name.name, resolvedSubstitutionArgument(argument, next)); + } + return next; +} + +function unsafeDirectValue( + type: ESTree.TSType, + environment: TypeEnvironment, + substitutions: TypeAliasEnvironment, + resolvingAliases: ReadonlySet, +): UnsafeDictionary["unsafeValue"] | null { + const unwrapped = unwrapTransparentType(type); + if (unwrapped.type === "TSUnknownKeyword") return "unknown"; + if (unwrapped.type === "TSAnyKeyword") return "any"; + if (unwrapped.type === "TSObjectKeyword") return "object"; + if (unwrapped.type === "TSTypeLiteral" && isEffectivelyEmptyTypeLiteral(unwrapped)) + return "empty-object"; + if (unwrapped.type === "TSUnionType") { + return unwrapped.types.some( + (member) => unsafeDirectValue(member, environment, substitutions, resolvingAliases) !== null, + ) + ? "union" + : null; + } + if (unwrapped.type === "TSIntersectionType") { + const unsafeMembers = unwrapped.types.map((member) => + unsafeDirectValue(member, environment, substitutions, resolvingAliases), + ); + if (unsafeMembers.includes("any")) return "any"; + return unsafeMembers.length > 0 && unsafeMembers.every((member) => member !== null) + ? unsafeMembers[0] + : null; + } + if (unwrapped.type !== "TSTypeReference") return null; + const name = typeReferenceName(unwrapped); + if (name === null) return null; + if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, environment)) { + const wrapped = unwrapped.typeArguments?.params[0]; + return wrapped === undefined + ? null + : unsafeDirectValue(wrapped, environment, substitutions, resolvingAliases); + } + const substitution = substitutions.get(name); + if (substitution !== undefined) { + return isUnappliedReferenceTo(substitution, name) + ? null + : unsafeDirectValue(substitution, environment, substitutions, resolvingAliases); + } + const interfaceDeclarations = environment.interfaces.get(name); + if (interfaceDeclarations !== undefined) { + return isEffectivelyEmptyInterface(interfaceDeclarations) ? "empty-object" : null; + } + const alias = environment.aliases.get(name); + if (alias === undefined || resolvingAliases.has(name)) return null; + const nextSubstitutions = aliasSubstitution(alias, unwrapped, substitutions); + if (nextSubstitutions === null) return null; + const nextResolving = new Set(resolvingAliases); + nextResolving.add(name); + return unsafeDirectValue(alias.typeAnnotation, environment, nextSubstitutions, nextResolving); +} + +function dictionaryValueTypes( + type: ESTree.TSType, + environment: TypeEnvironment, + substitutions: TypeAliasEnvironment, + resolvingAliases: ReadonlySet, +): readonly ResolvedType[] { + const unwrapped = unwrapTransparentType(type); + + if (unwrapped.type === "TSTypeLiteral") { + return unwrapped.members.flatMap((member): readonly ResolvedType[] => + member.type === "TSIndexSignature" && member.typeAnnotation !== null + ? [{ type: member.typeAnnotation.typeAnnotation, substitutions }] + : [], + ); + } + + if (unwrapped.type === "TSMappedType") { + return unwrapped.typeAnnotation === null + ? [] + : [{ type: unwrapped.typeAnnotation, substitutions }]; + } + + if (unwrapped.type !== "TSTypeReference") return []; + const name = typeReferenceName(unwrapped); + if (name === null) return []; + + const substitution = substitutions.get(name); + if (substitution !== undefined) { + return isUnappliedReferenceTo(substitution, name) + ? [] + : dictionaryValueTypes(substitution, environment, substitutions, resolvingAliases); + } + + if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, environment)) { + const wrapped = unwrapped.typeArguments?.params[0]; + return wrapped === undefined + ? [] + : dictionaryValueTypes(wrapped, environment, substitutions, resolvingAliases); + } + + if (name === "Record" && isBuiltIn(name, environment)) { + const value = unwrapped.typeArguments?.params[1] ?? null; + return value === null ? [] : [{ type: value, substitutions }]; + } + + if ((name === "Pick" || name === "Omit") && isBuiltIn(name, environment)) { + const source = unwrapped.typeArguments?.params[0]; + return source === undefined + ? [] + : dictionaryValueTypes(source, environment, substitutions, resolvingAliases); + } + + const alias = environment.aliases.get(name); + if (alias === undefined || resolvingAliases.has(name)) return []; + const nextSubstitutions = aliasSubstitution(alias, unwrapped, substitutions); + if (nextSubstitutions === null) return []; + const nextResolving = new Set(resolvingAliases); + nextResolving.add(name); + return dictionaryValueTypes(alias.typeAnnotation, environment, nextSubstitutions, nextResolving); +} + +export function classifyUnsafeDictionaryValue( + valueType: ESTree.TSType, + environment: TypeEnvironment, +): UnsafeDictionary | null { + const unsafeValue = unsafeDirectValue(valueType, environment, new Map(), new Set()); + return unsafeValue === null ? null : { kind: "unsafe-dictionary", unsafeValue }; +} + +export function classifyUnsafeDictionary( + type: ESTree.TSType, + environment: TypeEnvironment, +): UnsafeDictionary | null { + for (const valueType of dictionaryValueTypes(type, environment, new Map(), new Set())) { + const unsafeValue = unsafeDirectValue( + valueType.type, + environment, + valueType.substitutions, + new Set(), + ); + if (unsafeValue !== null) return { kind: "unsafe-dictionary", unsafeValue }; + } + return null; +} + +function resolvesToDictionary( + type: ESTree.TSType, + environment: TypeEnvironment, + substitutions: TypeAliasEnvironment, + resolvingAliases: ReadonlySet, +): boolean { + return dictionaryValueTypes(type, environment, substitutions, resolvingAliases).length > 0; +} + +export function classifyWideningTarget( + type: ESTree.TSType, + environment: TypeEnvironment, +): WideningTarget | null { + const unwrapped = unwrapTransparentType(type); + if (unwrapped.type === "TSUnknownKeyword") return { kind: "unknown" }; + if (unwrapped.type === "TSObjectKeyword") return { kind: "object" }; + if (unwrapped.type === "TSTypeLiteral") { + return unwrapped.members.some((member) => member.type === "TSIndexSignature") + ? { kind: "open dictionary" } + : unwrapped.members.length > 0 + ? { kind: "anonymous object" } + : null; + } + if (unwrapped.type === "TSMappedType") return { kind: "open dictionary" }; + if (unwrapped.type !== "TSTypeReference") return null; + const name = typeReferenceName(unwrapped); + if (name === null) return null; + if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, environment)) { + const wrapped = unwrapped.typeArguments?.params[0]; + return wrapped === undefined ? null : classifyWideningTarget(wrapped, environment); + } + if (name === "Record" && isBuiltIn(name, environment)) return { kind: "open dictionary" }; + const alias = environment.aliases.get(name); + if (alias === undefined) return null; + if ((alias.typeParameters?.params.length ?? 0) > 0) { + const substitutions = aliasSubstitution(alias, unwrapped, new Map()); + return substitutions !== null && + resolvesToDictionary(alias.typeAnnotation, environment, substitutions, new Set([name])) + ? { kind: "generic container" } + : null; + } + const substitutions = aliasSubstitution(alias, unwrapped, new Map()); + if (substitutions === null) return null; + const resolved = classifyAliasBroadTarget( + alias.typeAnnotation, + environment, + substitutions, + new Set([name]), + ); + return resolved; +} + +function isBroadMappedKey( + type: ESTree.TSType, + environment: TypeEnvironment, + substitutions: TypeAliasEnvironment, +): boolean { + const unwrapped = unwrapTransparentType(type); + if ( + unwrapped.type === "TSStringKeyword" || + unwrapped.type === "TSNumberKeyword" || + unwrapped.type === "TSSymbolKeyword" + ) { + return true; + } + if (unwrapped.type === "TSUnionType") { + return unwrapped.types.every((member) => + isBroadMappedKey(member, environment, substitutions), + ); + } + if (unwrapped.type !== "TSTypeReference") return false; + const name = typeReferenceName(unwrapped); + if (name === null) return false; + const substitution = substitutions.get(name); + if (substitution !== undefined && !isUnappliedReferenceTo(substitution, name)) { + return isBroadMappedKey(substitution, environment, substitutions); + } + return name === "PropertyKey" && isBuiltIn(name, environment); +} + +function classifyAliasBroadTarget( + type: ESTree.TSType, + environment: TypeEnvironment, + substitutions: TypeAliasEnvironment, + resolvingAliases: ReadonlySet, +): WideningTarget | null { + const unwrapped = unwrapTransparentType(type); + if (unwrapped.type === "TSUnknownKeyword") return { kind: "unknown" }; + if (unwrapped.type === "TSObjectKeyword") return { kind: "object" }; + if (unwrapped.type === "TSTypeLiteral") { + return unwrapped.members.some((member) => member.type === "TSIndexSignature") + ? { kind: "open dictionary" } + : null; + } + if (unwrapped.type === "TSMappedType") { + return isBroadMappedKey(unwrapped.constraint, environment, substitutions) + ? { kind: "open dictionary" } + : null; + } + if (unwrapped.type !== "TSTypeReference") return null; + const name = typeReferenceName(unwrapped); + if (name === null) return null; + const substitution = substitutions.get(name); + if (substitution !== undefined) { + return isUnappliedReferenceTo(substitution, name) + ? null + : classifyAliasBroadTarget( + substitution, + environment, + substitutions, + resolvingAliases, + ); + } + if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, environment)) { + const wrapped = unwrapped.typeArguments?.params[0]; + return wrapped === undefined + ? null + : classifyAliasBroadTarget(wrapped, environment, substitutions, resolvingAliases); + } + if (name === "Record" && isBuiltIn(name, environment)) { + return { kind: "open dictionary" }; + } + const alias = environment.aliases.get(name); + if (alias === undefined || resolvingAliases.has(name)) return null; + const nextSubstitutions = aliasSubstitution(alias, unwrapped, substitutions); + if (nextSubstitutions === null) return null; + const nextResolving = new Set(resolvingAliases); + nextResolving.add(name); + return classifyAliasBroadTarget( + alias.typeAnnotation, + environment, + nextSubstitutions, + nextResolving, + ); +} + +export function isPopulatedObjectExpression(expression: ESTree.Expression): boolean { + let current = expression; + while ( + current.type === "ParenthesizedExpression" || + current.type === "TSAsExpression" || + current.type === "TSTypeAssertion" || + current.type === "TSNonNullExpression" + ) { + current = current.expression; + } + return current.type === "ObjectExpression" && current.properties.length > 0; +} + +export function isKnownEvidenceExpression(expression: ESTree.Expression): boolean { + let current = expression; + while ( + current.type === "ParenthesizedExpression" || + current.type === "TSAsExpression" || + current.type === "TSTypeAssertion" || + current.type === "TSNonNullExpression" || + current.type === "TSSatisfiesExpression" + ) { + current = current.expression; + } + if (current.type === "ObjectExpression") return true; + return ( + current.type === "ArrayExpression" || + current.type === "ArrowFunctionExpression" || + current.type === "ClassExpression" || + current.type === "FunctionExpression" || + current.type === "NewExpression" || + current.type === "Literal" || + current.type === "TemplateLiteral" || + current.type === "UnaryExpression" + ); +} diff --git a/.devkit/anti-slop/plugin/shared/lexical-type-parameters.ts b/.devkit/anti-slop/plugin/shared/lexical-type-parameters.ts new file mode 100644 index 0000000..63e2adc --- /dev/null +++ b/.devkit/anti-slop/plugin/shared/lexical-type-parameters.ts @@ -0,0 +1,61 @@ +import type { ESTree } from "#oxlint-plugins"; + +type VisitorKeys = Readonly>; + +function isNode(value: unknown): value is ESTree.Node { + return ( + typeof value === "object" && + value !== null && + "type" in value && + typeof value.type === "string" + ); +} + +function collectInferTypeParameterNames( + node: ESTree.Node, + visitorKeys: VisitorKeys, + names: Set, +): void { + if (node.type === "TSInferType") names.add(node.typeParameter.name.name); + const record = node as unknown as Readonly>; + for (const key of visitorKeys[node.type] ?? []) { + const value = record[key]; + if (isNode(value)) { + collectInferTypeParameterNames(value, visitorKeys, names); + continue; + } + if (!Array.isArray(value)) continue; + for (const child of value) { + if (isNode(child)) collectInferTypeParameterNames(child, visitorKeys, names); + } + } +} + +/** Collect type binders that are in scope at a node and can shadow module aliases. */ +export function lexicalTypeParameterNames( + node: ESTree.Node, + visitorKeys: VisitorKeys, +): ReadonlySet { + const names = new Set(); + let descendant: ESTree.Node = node; + let current: ESTree.Node | null = node; + while (current !== null && current.type !== "Program") { + if ("typeParameters" in current) { + for (const parameter of current.typeParameters?.params ?? []) { + names.add(parameter.name.name); + } + } + if ( + current.type === "TSMappedType" && + (descendant === current.nameType || descendant === current.typeAnnotation) + ) { + names.add(current.key.name); + } + if (current.type === "TSConditionalType" && descendant === current.trueType) { + collectInferTypeParameterNames(current.extendsType, visitorKeys, names); + } + descendant = current; + current = current.parent; + } + return names; +} diff --git a/.devkit/anti-slop/plugin/shared/reflect-method.ts b/.devkit/anti-slop/plugin/shared/reflect-method.ts new file mode 100644 index 0000000..6c57d43 --- /dev/null +++ b/.devkit/anti-slop/plugin/shared/reflect-method.ts @@ -0,0 +1,35 @@ +import type { ESTree, Scope, SourceCode, Variable } from "#oxlint-plugins"; + +function resolveVariable( + sourceCode: SourceCode, + identifier: ESTree.IdentifierReference, +): Variable | null { + let scope: Scope | null = sourceCode.getScope(identifier); + while (scope !== null) { + const variable = scope.set.get(identifier.name); + if (variable !== undefined) return variable; + scope = scope.upper; + } + return null; +} + +function isGlobalReflect(sourceCode: SourceCode, expression: ESTree.Expression): boolean { + if (expression.type !== "Identifier" || expression.name !== "Reflect") return false; + if (sourceCode.isGlobalReference(expression)) return true; + const variable = resolveVariable(sourceCode, expression); + return variable === null || variable.defs.length === 0; +} + +/** Reports whether a call target names one method on the global Reflect object. */ +export function isGlobalReflectMethodCall( + sourceCode: SourceCode, + callee: ESTree.Expression, + methodName: string, +): boolean { + if (!("property" in callee) || !("object" in callee) || !("computed" in callee)) return false; + if (!isGlobalReflect(sourceCode, callee.object)) return false; + const property = callee.property; + return callee.computed + ? property.type === "Literal" && property.value === methodName + : property.type === "Identifier" && property.name === methodName; +} diff --git a/.devkit/anti-slop/probe.ts b/.devkit/anti-slop/probe.ts new file mode 100644 index 0000000..b66c33e --- /dev/null +++ b/.devkit/anti-slop/probe.ts @@ -0,0 +1 @@ +function devkitManagedProbe(value: object) { void __DEVKIT_OXC_BASE_1_78_0_MANAGED_PROBE__; return value; } diff --git a/.devkit/config.json b/.devkit/config.json index a4a51b1..48beed0 100644 --- a/.devkit/config.json +++ b/.devkit/config.json @@ -1,6 +1,6 @@ { "stack": "node-service", - "devkitRef": "v0.49.1", + "devkitRef": "v0.51.1", "initVersion": 2, "pkgRel": "", "standalone": false, @@ -15,9 +15,12 @@ "husky": true, "structure": false, "fallow": false, + "oxc": true, + "antiSlop": true, "searchCode": false, "lineGrowth": true, "adhd": true, + "priorArtGate": false, "agentTargets": [ "claude", "cursor" diff --git a/.devkit/oxc/manifest.json b/.devkit/oxc/manifest.json new file mode 100644 index 0000000..0e61195 --- /dev/null +++ b/.devkit/oxc/manifest.json @@ -0,0 +1,19 @@ +{ + "schemaVersion": 1, + "pins": { + "oxlint": "1.78.0", + "oxfmt": "0.63.0" + }, + "antiSlop": true, + "baseDigest": "54b3f55d5cc2b617c0f4de6609c18d763636a17e6cff65fe33432b256f9ef91d", + "configs": { + "oxlint": { + "path": ".oxlintrc.json", + "createdDigest": "fa25d82dc3c295514293ac58748dc18ecd30b246eecb58854eec0404dcef805c" + }, + "oxfmt": { + "path": ".oxfmtrc.json", + "createdDigest": null + } + } +} diff --git a/.devkit/oxc/oxlint.base.json b/.devkit/oxc/oxlint.base.json new file mode 100644 index 0000000..cdc3fd2 --- /dev/null +++ b/.devkit/oxc/oxlint.base.json @@ -0,0 +1,16 @@ +{ + "overrides": [ + { + "files": [ + ".devkit/anti-slop/probe.ts" + ], + "globals": { + "__DEVKIT_OXC_BASE_1_78_0_MANAGED_PROBE__": "readonly" + } + } + ], + "rules": {}, + "extends": [ + "../anti-slop/oxlint.json" + ] +} diff --git a/.devkit/skills-manifest.json b/.devkit/skills-manifest.json index 9b21213..c935ade 100644 --- a/.devkit/skills-manifest.json +++ b/.devkit/skills-manifest.json @@ -1,10 +1,8 @@ { - "devkitRef": "v0.51.0", - "generatedAt": "2026-08-12T13:33:41.449Z", - "targets": [ - "claude", - "cursor" - ], + "schemaVersion": 2, + "kind": "skills", + "devkitRef": "v0.51.1", + "generatedAt": "2026-08-16T02:26:52.070Z", "files": { "_devkit/checklist-store.mjs": "dfed06603d2ae528df28170c783c0a686b3d20effc3145a9bf88c3f0b6dc1b1a", "_devkit/review-roots.d.mts": "3c2cdf231cd93a60c1ff0e7ef0eaf17a01f873398917e32fe4e092f947b47bc4", @@ -38,5 +36,79 @@ "upstream-sync/scripts/sync.mjs": "218aa7ad7e96f280f281a38f99919f2ce55eace902ed95b1119a0099ddbb3c76", "upstream-sync/scripts/verify-merge.mjs": "afb2977ab8b7a96fac2e93e29a68ae432508ba7e63d03c580fcf03229fcd0676", "using-devkit/SKILL.md": "e78ccf732c44fce58b07001f414a2afaee13f8673cc0845749a74053382f1fda" + }, + "providers": { + "claude": { + "files": { + "_devkit/checklist-store.mjs": "dfed06603d2ae528df28170c783c0a686b3d20effc3145a9bf88c3f0b6dc1b1a", + "_devkit/review-roots.d.mts": "3c2cdf231cd93a60c1ff0e7ef0eaf17a01f873398917e32fe4e092f947b47bc4", + "_devkit/review-roots.mjs": "b3a98f8ef5a8c9fb000d81a277322e63970b06128e7673de4964b059511effdc", + "api-security/SKILL.md": "5916bc98f288a0b7269ec9df416692509c449274026afc93013388c40c13415e", + "api-security/scripts/checklist.mjs": "3c4cd9e29aa2ef20e9a99f265bf20800ceaeb0027a5d1f137b2b456eb5bd8b9d", + "backend-performance/SKILL.md": "5ff0858b34ffc91d677976dd279f27714d934aa5062f0a3f6b38088e7bd10ddb", + "backend-performance/scripts/checklist.mjs": "23b506a7f2d5d0f68723d75fe381b611574b727fd672f7cc5fe223127d86513c", + "brainstorming/SKILL.md": "1c25870729d5cb4ba17682a2ef251f6902a715d69aee0f20c4f548ea2715be5e", + "commit-guard/SKILL.md": "8c5e02bd1ed3c53cb47cdb11f444894f5880d6cb842822d1108bf6b7ab1bd8d8", + "commit-guard/references/co-occurrence.md": "0225034aeb87a8be80d59e4121aa67a99129f6ee8388a9605e0db484e7d767d4", + "commit-guard/scripts/checklist.mjs": "dc57c1f1407a0fe7503ebe72e30e9167b29bdf1154ab44e68de82b6d558770e1", + "correctness/SKILL.md": "4e8b656b3ee95934a7dc9f0fcd20d4eb5f1eb3be4112a182eea1f941f1b2fc82", + "correctness/scripts/checklist.mjs": "adb9777dc7b3fdeb5e4dc31bc5e231c2f947b0bca235b0d04b54f81c3180c427", + "decisions/SKILL.md": "9bdad17d600fed8c0bc5be1bb6f04822ed03327635629b266e2b5e07cb92b498", + "dup-detection/SKILL.md": "74a4964795bbb27ce2bda0e13b91da00f04a01a989bcbf6149d10ff9c3688a4c", + "feature-critique/SKILL.md": "0a595267e6dab2fad6e571b3861da4964ccff934d50ac9efaf137a23d3a8efef", + "frontend-accessibility/SKILL.md": "d950e1ddc87ec9a090936f05447d2298b25fb5e12e315345d2d9c02912c513a9", + "frontend-accessibility/scripts/checklist.mjs": "2e3bc576a8847a96e6f42472139d1ddfc8526d909b2b16d5d71b214c6c36e293", + "frontend-performance/SKILL.md": "6697c6583485c5eea8168437c2faee3f81f9051a0c9f85e739278d13c1c6b628", + "frontend-performance/scripts/checklist.mjs": "7ca245993dbc5d6d973947ebc9ad8c94e12f221e7afe151cc8ed24f7a0eab41f", + "frontend-security/SKILL.md": "b4f097efd4076ebf530d59b2042def53bb51d975c50e6dc12da698d882fe630f", + "frontend-security/scripts/checklist.mjs": "017cae47453060b336a91069bb7d2d588502cd133828b4ac70b7731e0c032a2b", + "parallel-neon-migration/SKILL.md": "b2c2d90ff77fe8bd4eb6e2dda074dd0c8b5adfc1b179ac136689445a4d2c981e", + "prior-art/SKILL.md": "633e10db0ced4abb96e9a575641db178763c5f5689126faa6fe27c8c7a46c34c", + "structure-governance/SKILL.md": "21fb605d1b6fadd81358da7dbe078c634b60115234b427dae4ae47ce8df30f04", + "structure-governance/references/fixing-lint-errors.md": "44ad9ba30d747bac4fac27d2d2a8f2ef788b5894db77df70d6c4f3359c7a1fc8", + "structure-governance/references/walls.md": "9986c487a0a2cdf06adad88ea1261657c0c6945179aa4c8b15d7cef086cd540d", + "testing/SKILL.md": "1816d2bbdb38b1269fd4355b0853bfdf951a84b7ec416c5c271825eb20cc2b64", + "upstream-sync/SKILL.md": "1007c8377ac15393dcc9db5384d80bd38487c85aa465921ae0b49ba5a91bad70", + "upstream-sync/scripts/sync.mjs": "218aa7ad7e96f280f281a38f99919f2ce55eace902ed95b1119a0099ddbb3c76", + "upstream-sync/scripts/verify-merge.mjs": "afb2977ab8b7a96fac2e93e29a68ae432508ba7e63d03c580fcf03229fcd0676", + "using-devkit/SKILL.md": "e78ccf732c44fce58b07001f414a2afaee13f8673cc0845749a74053382f1fda" + } + }, + "cursor": { + "files": { + "_devkit/checklist-store.mjs": "dfed06603d2ae528df28170c783c0a686b3d20effc3145a9bf88c3f0b6dc1b1a", + "_devkit/review-roots.d.mts": "3c2cdf231cd93a60c1ff0e7ef0eaf17a01f873398917e32fe4e092f947b47bc4", + "_devkit/review-roots.mjs": "b3a98f8ef5a8c9fb000d81a277322e63970b06128e7673de4964b059511effdc", + "api-security/SKILL.md": "5916bc98f288a0b7269ec9df416692509c449274026afc93013388c40c13415e", + "api-security/scripts/checklist.mjs": "3c4cd9e29aa2ef20e9a99f265bf20800ceaeb0027a5d1f137b2b456eb5bd8b9d", + "backend-performance/SKILL.md": "5ff0858b34ffc91d677976dd279f27714d934aa5062f0a3f6b38088e7bd10ddb", + "backend-performance/scripts/checklist.mjs": "23b506a7f2d5d0f68723d75fe381b611574b727fd672f7cc5fe223127d86513c", + "brainstorming/SKILL.md": "1c25870729d5cb4ba17682a2ef251f6902a715d69aee0f20c4f548ea2715be5e", + "commit-guard/SKILL.md": "8c5e02bd1ed3c53cb47cdb11f444894f5880d6cb842822d1108bf6b7ab1bd8d8", + "commit-guard/references/co-occurrence.md": "0225034aeb87a8be80d59e4121aa67a99129f6ee8388a9605e0db484e7d767d4", + "commit-guard/scripts/checklist.mjs": "dc57c1f1407a0fe7503ebe72e30e9167b29bdf1154ab44e68de82b6d558770e1", + "correctness/SKILL.md": "4e8b656b3ee95934a7dc9f0fcd20d4eb5f1eb3be4112a182eea1f941f1b2fc82", + "correctness/scripts/checklist.mjs": "adb9777dc7b3fdeb5e4dc31bc5e231c2f947b0bca235b0d04b54f81c3180c427", + "decisions/SKILL.md": "9bdad17d600fed8c0bc5be1bb6f04822ed03327635629b266e2b5e07cb92b498", + "dup-detection/SKILL.md": "74a4964795bbb27ce2bda0e13b91da00f04a01a989bcbf6149d10ff9c3688a4c", + "feature-critique/SKILL.md": "0a595267e6dab2fad6e571b3861da4964ccff934d50ac9efaf137a23d3a8efef", + "frontend-accessibility/SKILL.md": "d950e1ddc87ec9a090936f05447d2298b25fb5e12e315345d2d9c02912c513a9", + "frontend-accessibility/scripts/checklist.mjs": "2e3bc576a8847a96e6f42472139d1ddfc8526d909b2b16d5d71b214c6c36e293", + "frontend-performance/SKILL.md": "6697c6583485c5eea8168437c2faee3f81f9051a0c9f85e739278d13c1c6b628", + "frontend-performance/scripts/checklist.mjs": "7ca245993dbc5d6d973947ebc9ad8c94e12f221e7afe151cc8ed24f7a0eab41f", + "frontend-security/SKILL.md": "b4f097efd4076ebf530d59b2042def53bb51d975c50e6dc12da698d882fe630f", + "frontend-security/scripts/checklist.mjs": "017cae47453060b336a91069bb7d2d588502cd133828b4ac70b7731e0c032a2b", + "parallel-neon-migration/SKILL.md": "b2c2d90ff77fe8bd4eb6e2dda074dd0c8b5adfc1b179ac136689445a4d2c981e", + "prior-art/SKILL.md": "633e10db0ced4abb96e9a575641db178763c5f5689126faa6fe27c8c7a46c34c", + "structure-governance/SKILL.md": "21fb605d1b6fadd81358da7dbe078c634b60115234b427dae4ae47ce8df30f04", + "structure-governance/references/fixing-lint-errors.md": "44ad9ba30d747bac4fac27d2d2a8f2ef788b5894db77df70d6c4f3359c7a1fc8", + "structure-governance/references/walls.md": "9986c487a0a2cdf06adad88ea1261657c0c6945179aa4c8b15d7cef086cd540d", + "testing/SKILL.md": "1816d2bbdb38b1269fd4355b0853bfdf951a84b7ec416c5c271825eb20cc2b64", + "upstream-sync/SKILL.md": "1007c8377ac15393dcc9db5384d80bd38487c85aa465921ae0b49ba5a91bad70", + "upstream-sync/scripts/sync.mjs": "218aa7ad7e96f280f281a38f99919f2ce55eace902ed95b1119a0099ddbb3c76", + "upstream-sync/scripts/verify-merge.mjs": "afb2977ab8b7a96fac2e93e29a68ae432508ba7e63d03c580fcf03229fcd0676", + "using-devkit/SKILL.md": "e78ccf732c44fce58b07001f414a2afaee13f8673cc0845749a74053382f1fda" + } + } } } diff --git a/.github/workflows/gate.yml b/.github/workflows/gate.yml index d5f37ec..0f220f8 100644 --- a/.github/workflows/gate.yml +++ b/.github/workflows/gate.yml @@ -29,6 +29,18 @@ jobs: - name: Lint and assist (Biome) run: bun run lint + - name: Anti-slop (Oxlint, baseline-aware) + env: + ANTI_SLOP_BASE: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }} + ANTI_SLOP_HEAD: ${{ github.event.pull_request.head.sha || github.sha }} + run: | + if [[ -z "$ANTI_SLOP_BASE" || "$ANTI_SLOP_BASE" =~ ^0+$ ]]; then + ANTI_SLOP_BASE="$(git mktree ` for authorit devkit init --anti-slop devkit anti-slop create devkit anti-slop check +devkit anti-slop check --staged ``` `--anti-slop` implies the opt-in Oxc capability. Rules load beside the repository's other Oxlint rules; their severities and scoped overrides stay in the ordinary Oxlint config. Baseline creation is always explicit, normal checks are read-only, and pruning can only remove fixed debt. +The staged form reads the exact Git index, and CI can pass `--base ` to prevent a candidate +baseline from growing relative to its base commit. See the [anti-slop capability guide](docs/anti-slop.md) for provenance, the complete rule matrix, and the fingerprint contract. @@ -206,6 +209,7 @@ bun run test:run bun run typecheck bun run format:check bun run lint +bun run lint:anti-slop bun run lint:structure bun run benchmarks:check ``` @@ -215,6 +219,12 @@ commands use the current source instead of the last compiled package bin. Benchm development additionally uses `bun run benchmarks:typecheck`. Release builds compile `.mts` sources into `dist/`; day-to-day changes should not hand-edit generated `dist` files. +Devkit self-host mode always dogfoods its pinned Oxc and vendored anti-slop capabilities. The +managed `.devkit/oxc/` and `.devkit/anti-slop/` trees plus `.anti-slop-baseline.json` are committed; +the generated hook checks staged postimages while CI performs the full baseline-aware scan. See the +[assembled quality-stack benchmark](docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/README.md) +for the final ownership and performance rationale. + ## Documentation - [Benchmark methodology and immutable history](docs/benchmarks/README.md) diff --git a/cli/__tests__/apply-init.test.mts b/cli/__tests__/apply-init.test.mts index 4700135..33eb688 100644 --- a/cli/__tests__/apply-init.test.mts +++ b/cli/__tests__/apply-init.test.mts @@ -824,8 +824,14 @@ describe('self-host mode (devkit dogfooding itself)', () => { expect(hook).toContain('node gate-engine/deterministic/run.mts'); expect(hook).toContain('node gate-engine/review/cli.mts --gate'); expect(hook).toContain('--extra "lint=bun run lint"'); + expect(hook).toContain('--extra "anti-slop=node cli/index.mts anti-slop check --staged"'); expect(hook).not.toMatch(/bunx guard-/); - expect(config(root).selfHost).toBe(true); + expect(config(root)).toMatchObject({ + selfHost: true, + components: { oxc: true, antiSlop: true }, + }); + expect(existsSync(join(root, '.devkit', 'oxc', 'manifest.json'))).toBe(true); + expect(existsSync(join(root, '.devkit', 'anti-slop', 'manifest.json'))).toBe(true); }); }); diff --git a/cli/__tests__/self-host.test.mts b/cli/__tests__/self-host.test.mts index 464b241..445091a 100644 --- a/cli/__tests__/self-host.test.mts +++ b/cli/__tests__/self-host.test.mts @@ -77,6 +77,7 @@ describe('selfHostSelection', () => { for (const g of ['size', 'fanout', 'dup', 'clone', 'decisions', 'qavis-advisory', 'review']) expect(sel.guards).toContain(g); expect(sel.husky).toBe(true); + expect(sel).toMatchObject({ oxc: true, antiSlop: true }); }); // sc-1529. The fixed selection used to reset every opt-in on upgrade, so a dogfood repo running @@ -93,6 +94,10 @@ describe('selfHostSelection', () => { it('still lets a recorded OFF win over a default-on component', () => { expect(selfHostSelection({ lineGrowth: false }).lineGrowth).toBe(false); expect(selfHostSelection().lineGrowth).toBe(true); + expect(selfHostSelection({ oxc: false, antiSlop: false })).toMatchObject({ + oxc: true, + antiSlop: true, + }); }); // The guards half of the fixed selection is deliberate and must NOT follow the recorded value: @@ -118,6 +123,7 @@ describe('buildSelfHostHook', () => { expect(hook).toContain('node gate-engine/review/cli.mts --gate'); expect(hook).toContain('node gate-engine/decisions/cli.mts detect --gate'); expect(hook).toContain('--extra "lint=bun run lint"'); + expect(hook).toContain('--extra "anti-slop=node cli/index.mts anti-slop check --staged"'); expect(hook).toContain('--extra "benchmarks=bun run benchmarks:check -- --mode staged"'); expect(hook).toContain('--structure "bun run lint:structure"'); expect(hook).toContain('node_modules/.bin/oxfmt --threads 1 --write'); diff --git a/cli/commands/init.mts b/cli/commands/init.mts index 7f4b123..387addb 100644 --- a/cli/commands/init.mts +++ b/cli/commands/init.mts @@ -969,10 +969,9 @@ export async function applyInit(cwd: string, plan: InitPlan) { console.log('8b. search-code (opt-in semantic search)'); installSearchCode(cwd, dryRun); } - - if (selection.oxc && !selection.antiSlop && !selfHost) + if (selection.oxc && !selection.antiSlop) oxcLifecycle.syncOxcCapability(cwd, { dryRun, antiSlop: false }); - if (selection.antiSlop && !selfHost) antiSlopLifecycle.syncAntiSlopCapability(cwd, { dryRun }); + if (selection.antiSlop) antiSlopLifecycle.syncAntiSlopCapability(cwd, { dryRun }); // The vendored i-have-adhd skill, into devkit's own tree rather than the agent skills dirs — so it // no longer depends on the `skills` component. Called unconditionally: a false selection reclaims a @@ -996,8 +995,8 @@ export async function applyInit(cwd: string, plan: InitPlan) { husky: selection.husky, structure: isStructure, fallow: Boolean(selection.fallow), - oxc: Boolean(selection.oxc && !selfHost), - antiSlop: Boolean(selection.antiSlop && !selfHost), + oxc: Boolean(selection.oxc), + antiSlop: Boolean(selection.antiSlop), searchCode: Boolean(selection.searchCode), lineGrowth: Boolean(selection.lineGrowth), // Always written, including `false` — an ABSENT key is what marks a repo as never-offered, so @@ -1115,7 +1114,8 @@ export default async function run(args: string[], cwd: string) { const selfHost = isDevkitRepo(cwd); if (selfHost) { mode = 'self-host'; - selection = selfHostSelection(); + const recorded = readJson(join(cwd, '.devkit', 'config.json')) as DevkitConfig | null; + selection = selfHostSelection(recorded?.components); } else if (interactive) { const installed = detectInstalled(cwd); const result = await runWizard({ diff --git a/cli/commands/oxc/anti-slop.mts b/cli/commands/oxc/anti-slop.mts index f87e734..a5b5e56 100644 --- a/cli/commands/oxc/anti-slop.mts +++ b/cli/commands/oxc/anti-slop.mts @@ -6,6 +6,7 @@ import { withLock } from '../../lib/atomic-write.mts'; import { type AntiSlopBaseline, baselineFromGroups, + baselineIncreases, compareBaseline, pruneBaseline, readBaseline, @@ -16,6 +17,11 @@ import { ANTI_SLOP_BASELINE_REL, } from '../../lib/install/anti-slop/constants.mts'; import type { FindingGroup } from '../../lib/install/anti-slop/diagnostics.mts'; +import { + type GitBaselineEnvelope, + gitBaselineEnvelope, + withStagedAntiSlopSnapshot, +} from '../../lib/install/anti-slop/git-snapshot.mts'; import { collectAntiSlopGroups, resolveAntiSlopScope, @@ -28,7 +34,9 @@ export const meta = { Usage: devkit anti-slop create [--force] [paths...] Explicitly snapshot current findings - devkit anti-slop check [paths...] Fail on new error-severity findings (read-only) + devkit anti-slop check [paths...] Check working-tree findings (read-only) + devkit anti-slop check --staged Check the exact Git index against HEAD + devkit anti-slop check --base Full check + baseline monotonicity for CI devkit anti-slop inspect [--json] Inspect baseline debt without linting devkit anti-slop prune [paths...] Remove fixed debt; never add findings @@ -95,9 +103,44 @@ function create(cwd: string, args: string[], force: boolean): number { }); } -function check(cwd: string, args: string[]): number { +function checkBaselineEnvelope( + candidate: AntiSlopBaseline, + envelope: GitBaselineEnvelope | null, +): number { + if (!envelope?.base) return 0; // one-time bootstrap: the base commit has no baseline + const staleRenames = candidate.entries.flatMap((entry) => { + const nextFile = envelope.renames.get(entry.file); + return nextFile ? [{ ...entry, nextFile }] : []; + }); + if (staleRenames.length > 0) { + for (const entry of staleRenames) { + console.error( + `BASELINE-RENAME ${entry.ruleId} ${entry.file} -> ${entry.nextFile} (${entry.count} adopted finding(s))`, + ); + } + console.error( + 'anti-slop: FAIL — persist renamed debt with `devkit anti-slop create --force`, then stage the baseline', + ); + return 1; + } + const increases = baselineIncreases(envelope.base, candidate, envelope.renames); + if (increases.length === 0) return 0; + for (const entry of increases) { + console.error( + `BASELINE-GROWTH ${entry.ruleId} ${entry.file} (+${entry.additionalCount} adopted finding(s))`, + ); + } + console.error( + 'anti-slop: FAIL — the committed baseline may only shrink; fix the finding instead of adopting it', + ); + return 1; +} + +function check(cwd: string, args: string[], envelope: GitBaselineEnvelope | null = null): number { const baseline = baselineOrExplain(cwd); if (!baseline) return 2; + const envelopeStatus = checkBaselineEnvelope(baseline, envelope); + if (envelopeStatus !== 0) return envelopeStatus; const scope = resolveAntiSlopScope(cwd, args); const selected: AntiSlopBaseline = { ...baseline, @@ -178,8 +221,23 @@ export default function run(args: string[], cwd: string): number { const trailingPaths = separator >= 0 ? rest.slice(separator + 1) : []; const force = options.includes('--force'); const json = options.includes('--json'); + const staged = options.includes('--staged'); + const baseIndex = options.indexOf('--base'); + const baseRef = baseIndex >= 0 ? options[baseIndex + 1] : undefined; + if (baseIndex >= 0 && (!baseRef || baseRef.startsWith('-'))) { + console.error('anti-slop: --base requires a Git ref'); + return 2; + } + const consumed = new Set(); + if (baseIndex >= 0) { + consumed.add(baseIndex); + consumed.add(baseIndex + 1); + } const paths = [ - ...options.filter((arg) => arg !== '--force' && arg !== '--json'), + ...options.filter( + (arg, index) => + arg !== '--force' && arg !== '--json' && arg !== '--staged' && !consumed.has(index), + ), ...(separator >= 0 ? ['--', ...trailingPaths] : []), ]; if (force && operation !== 'create') { @@ -190,8 +248,32 @@ export default function run(args: string[], cwd: string): number { console.error('anti-slop: --json is accepted only by inspect'); return 2; } + if (staged && operation !== 'check') { + console.error('anti-slop: --staged is accepted only by check'); + return 2; + } + if (baseRef && operation !== 'check') { + console.error('anti-slop: --base is accepted only by check'); + return 2; + } + if (staged && (baseRef || paths.length > 0)) { + console.error('anti-slop: --staged uses the complete Git index and accepts no paths or --base'); + return 2; + } if (operation === 'create') return create(cwd, paths, force); - if (operation === 'check') return check(cwd, paths); + if (operation === 'check' && staged) { + return withStagedAntiSlopSnapshot(cwd, (snapshot) => { + if (snapshot.skipped) { + console.log('anti-slop: PASS — no relevant staged files or configuration changes'); + return 0; + } + return check(snapshot.cwd, snapshot.paths, snapshot); + }); + } + if (operation === 'check') { + const envelope = baseRef ? gitBaselineEnvelope(cwd, baseRef) : null; + return check(cwd, paths, envelope); + } if (operation === 'inspect') { if (paths.length > 0 || force) { console.error('anti-slop inspect accepts only --json'); diff --git a/cli/lib/doctor/self-host-doctor.mts b/cli/lib/doctor/self-host-doctor.mts index 76039bf..366206f 100644 --- a/cli/lib/doctor/self-host-doctor.mts +++ b/cli/lib/doctor/self-host-doctor.mts @@ -18,8 +18,14 @@ import { selfHostSelection, } from '../husky/self-host.mts'; import { checkAdhdSkill } from '../install/adhd-skill.mts'; +import { readBaseline } from '../install/anti-slop/baseline.mts'; +import { + checkAntiSlopCapability, + syncAntiSlopCapability, +} from '../install/anti-slop/lifecycle.mts'; +import { checkOxcCapability } from '../install/oxc/lifecycle.mts'; import { checkAgents, checkSkills } from './asset-checks.mts'; -import type { CheckResult } from './check-result.mts'; +import { type CheckResult, check } from './check-result.mts'; import { adviseSearchIndex } from './guard-config-checks.mts'; import { checkHookRunner } from './hook-checks.mts'; import { printStrayGateCalls } from './stray-gate-calls.mts'; @@ -38,6 +44,46 @@ export async function runSelfHostDoctor( const { gitRoot, pkgRel } = detectGitRoot(cwd); const hookPath = join(gitRoot, '.husky', 'pre-commit'); console.log('devkit doctor — self-host (source-mode dogfood)\n'); + const selection = selfHostSelection(cfg.components); + + let capabilityResults = [...checkOxcCapability(cwd), ...checkAntiSlopCapability(cwd)]; + if (fix && capabilityResults.some((result) => result.status !== 'OK')) { + syncAntiSlopCapability(cwd); + capabilityResults = [...checkOxcCapability(cwd), ...checkAntiSlopCapability(cwd)]; + } + for (const result of capabilityResults) { + const glyph = result.status === 'OK' ? '✓' : result.status === 'MISSING' ? '✗' : '⚠'; + console.log(` ${glyph} ${result.name}: ${result.detail}`); + if (result.status !== 'OK' && result.remediation) console.log(` → ${result.remediation}`); + } + let baselineResult: CheckResult; + try { + const baseline = readBaseline(cwd); + baselineResult = baseline + ? check( + 'anti-slop baseline', + 'OK', + `${baseline.entries.reduce((sum, entry) => sum + entry.count, 0)} adopted finding(s)`, + ) + : check( + 'anti-slop baseline', + 'MISSING', + '.anti-slop-baseline.json', + 'run `devkit anti-slop create` explicitly', + ); + } catch (error: unknown) { + baselineResult = check( + 'anti-slop baseline', + 'DRIFT', + error instanceof Error ? error.message : String(error), + 'inspect and explicitly recreate the baseline', + ); + } + console.log( + ` ${baselineResult.status === 'OK' ? '✓' : baselineResult.status === 'MISSING' ? '✗' : '⚠'} ${baselineResult.name}: ${baselineResult.detail}`, + ); + if (baselineResult.status !== 'OK' && baselineResult.remediation) + console.log(` → ${baselineResult.remediation}`); let hookOk = false; if (!existsSync(hookPath)) { @@ -45,7 +91,7 @@ export async function runSelfHostDoctor( } else { const currentBlock = extractGuardBlock(readFileSync(hookPath, 'utf8'), pkgRel); const expectedBlock = buildSelfHostBlock( - { ...selfHostSelection(), structureCmd: SELF_HOST_STRUCTURE_CMD, extras: SELF_HOST_EXTRAS }, + { ...selection, structureCmd: SELF_HOST_STRUCTURE_CMD, extras: SELF_HOST_EXTRAS }, pkgRel, cwd, ); @@ -53,7 +99,7 @@ export async function runSelfHostDoctor( hookOk = true; console.log(' ✓ .husky/pre-commit in sync with the generator'); } else if (fix) { - installSelfHostHook(gitRoot, pkgRel, selfHostSelection(), false, cwd); + installSelfHostHook(gitRoot, pkgRel, selection, false, cwd); hookOk = true; console.log( ' ✓ .husky/pre-commit regenerated (was stale — refreshed to the current generator)', @@ -100,5 +146,8 @@ export async function runSelfHostDoctor( console.log(` ${runner.status === 'OK' ? '✓' : '⚠'} ${runner.name}: ${runner.detail}`); if (runner.status !== 'OK') console.log(` → ${runner.remediation}`); - return hookOk && runner.status === 'OK' ? 0 : 1; + const capabilitiesOk = capabilityResults.every((result) => result.status === 'OK'); + return hookOk && runner.status === 'OK' && capabilitiesOk && baselineResult.status === 'OK' + ? 0 + : 1; } diff --git a/cli/lib/husky/self-host.mts b/cli/lib/husky/self-host.mts index 1d06afa..c6b0d1b 100644 --- a/cli/lib/husky/self-host.mts +++ b/cli/lib/husky/self-host.mts @@ -43,6 +43,7 @@ import { export const SELF_HOST_STRUCTURE_CMD = 'bun run lint:structure'; export const SELF_HOST_EXTRAS: Array<{ label: string; cmd: string }> = [ { label: 'lint', cmd: 'bun run lint' }, + { label: 'anti-slop', cmd: 'node cli/index.mts anti-slop check --staged' }, { label: 'benchmarks', cmd: 'bun run benchmarks:check -- --mode staged' }, ]; @@ -146,6 +147,10 @@ export function selfHostSelection(recorded?: Partial): Selection { // claimed was on. Undefined entries are dropped so an absent key falls through to the default // rather than overwriting it with undefined. ...definedOnly(recorded), + // Devkit is the soak environment for the exact-pinned Oxc + vendored anti-slop stack. These + // stay on even when an older recorded config predates them or explicitly recorded them off. + oxc: true, + antiSlop: true, // Guards stay FIXED even so: that is the deliberate part (see upgrade.mts) — a future // RECOMMENDED_GUARD_IDS addition must not open an interactive multiselect in the dogfood repo. guards: [...RECOMMENDED_GUARD_IDS, 'review'], diff --git a/cli/lib/install/anti-slop/baseline.mts b/cli/lib/install/anti-slop/baseline.mts index 108dd27..6ceac69 100644 --- a/cli/lib/install/anti-slop/baseline.mts +++ b/cli/lib/install/anti-slop/baseline.mts @@ -29,6 +29,10 @@ export interface BaselineComparison { resolvedCount: number; } +export interface BaselineIncrease extends BaselineEntry { + additionalCount: number; +} + function expectedFingerprint(entry: Omit): string { return createHash('sha256') .update(JSON.stringify([entry.ruleId, entry.file, entry.diagnostic, entry.context])) @@ -69,16 +73,12 @@ export function baselineFromGroups(groups: readonly FindingGroup[]): AntiSlopBas }; } -export function readBaseline(cwd: string): AntiSlopBaseline | null { - const path = join(cwd, ANTI_SLOP_BASELINE_REL); - if (!existsSync(path)) return null; +export function parseBaseline(json: string, source = ANTI_SLOP_BASELINE_REL): AntiSlopBaseline { let value: unknown; try { - value = JSON.parse(readFileSync(path, 'utf8')); + value = JSON.parse(json); } catch (error: unknown) { - throw new Error( - `invalid ${ANTI_SLOP_BASELINE_REL}: ${error instanceof Error ? error.message : String(error)}`, - ); + throw new Error(`invalid ${source}: ${error instanceof Error ? error.message : String(error)}`); } const baseline = value as Partial; if ( @@ -87,17 +87,20 @@ export function readBaseline(cwd: string): AntiSlopBaseline | null { !Array.isArray(baseline.entries) || !baseline.entries.every(validateEntry) ) { - throw new Error( - `invalid or stale ${ANTI_SLOP_BASELINE_REL}; inspect it, then explicitly recreate it`, - ); + throw new Error(`invalid or stale ${source}; inspect it, then explicitly recreate it`); } const sorted = [...baseline.entries].sort((a, b) => a.fingerprint.localeCompare(b.fingerprint)); if (new Set(sorted.map((entry) => entry.fingerprint)).size !== sorted.length) { - throw new Error(`invalid ${ANTI_SLOP_BASELINE_REL}: duplicate fingerprints`); + throw new Error(`invalid ${source}: duplicate fingerprints`); } return { schemaVersion: 1, upstreamCommit: baseline.upstreamCommit, entries: sorted }; } +export function readBaseline(cwd: string): AntiSlopBaseline | null { + const path = join(cwd, ANTI_SLOP_BASELINE_REL); + return existsSync(path) ? parseBaseline(readFileSync(path, 'utf8')) : null; +} + export function writeBaseline(cwd: string, baseline: AntiSlopBaseline): void { writeFileAtomic(join(cwd, ANTI_SLOP_BASELINE_REL), `${JSON.stringify(baseline, null, 2)}\n`); } @@ -122,6 +125,49 @@ export function compareBaseline( }; } +/** + * Move adopted debt across Git-detected file renames without allowing its rule/message/context or + * count to change. Multiple entries that converge on one fingerprint are deliberately combined. + */ +export function migrateBaselineRenames( + baseline: AntiSlopBaseline, + renames: ReadonlyMap, +): AntiSlopBaseline { + const migrated = new Map(); + for (const entry of baseline.entries) { + const file = renames.get(entry.file) ?? entry.file; + const stable = { + ruleId: entry.ruleId, + file, + diagnostic: entry.diagnostic, + context: entry.context, + }; + const fingerprint = expectedFingerprint(stable); + const current = migrated.get(fingerprint); + if (current) current.count += entry.count; + else migrated.set(fingerprint, { fingerprint, ...stable, count: entry.count }); + } + return { + ...baseline, + entries: [...migrated.values()].sort((a, b) => a.fingerprint.localeCompare(b.fingerprint)), + }; +} + +/** Return only candidate debt that exceeds the base commit's count envelope. */ +export function baselineIncreases( + base: AntiSlopBaseline, + candidate: AntiSlopBaseline, + renames: ReadonlyMap = new Map(), +): BaselineIncrease[] { + const allowed = new Map( + migrateBaselineRenames(base, renames).entries.map((entry) => [entry.fingerprint, entry.count]), + ); + return candidate.entries.flatMap((entry) => { + const additionalCount = Math.max(0, entry.count - (allowed.get(entry.fingerprint) ?? 0)); + return additionalCount > 0 ? [{ ...entry, additionalCount }] : []; + }); +} + /** Return only still-present baseline debt; never add an unbaselined current finding. */ export function pruneBaseline( baseline: AntiSlopBaseline, diff --git a/cli/lib/install/anti-slop/baseline.test.mts b/cli/lib/install/anti-slop/baseline.test.mts index 636badd..bb6f57d 100644 --- a/cli/lib/install/anti-slop/baseline.test.mts +++ b/cli/lib/install/anti-slop/baseline.test.mts @@ -1,5 +1,11 @@ import { describe, expect, it } from 'vitest'; -import { baselineFromGroups, compareBaseline, pruneBaseline } from './baseline.mts'; +import { + baselineFromGroups, + baselineIncreases, + compareBaseline, + migrateBaselineRenames, + pruneBaseline, +} from './baseline.mts'; import type { FindingGroup } from './diagnostics.mts'; const group = ( @@ -43,4 +49,36 @@ describe('anti-slop shrink-only baseline', () => { expect(baseline.entries[0]).not.toHaveProperty('severity'); expect(baseline.entries[0]).not.toHaveProperty('line'); }); + + it('forbids baseline growth while allowing shrinkage', () => { + const base = migrateBaselineRenames(baselineFromGroups([group('a', 2)]), new Map()); + const [entry] = base.entries; + if (!entry) throw new Error('expected one baseline entry'); + const smaller = { ...base, entries: [{ ...entry, count: 1 }] }; + const larger = { ...base, entries: [{ ...entry, count: 3 }] }; + + expect(baselineIncreases(base, smaller)).toEqual([]); + expect(baselineIncreases(base, larger)).toEqual([ + expect.objectContaining({ additionalCount: 1, count: 3 }), + ]); + }); + + it('migrates debt across a Git rename without increasing its count envelope', () => { + const base = baselineFromGroups([group('a', 2)]); + const renames = new Map([['src/file.ts', 'src/renamed.ts']]); + const renamed = migrateBaselineRenames(base, renames); + const [baseEntry] = base.entries; + const [renamedEntry] = renamed.entries; + if (!baseEntry || !renamedEntry) throw new Error('expected one renamed baseline entry'); + + expect(renamedEntry).toMatchObject({ file: 'src/renamed.ts', count: 2 }); + expect(renamedEntry.fingerprint).not.toBe(base.entries[0]?.fingerprint); + expect(baselineIncreases(base, base, renames)).toEqual([ + expect.objectContaining({ additionalCount: 2, file: 'src/file.ts' }), + ]); + expect(baselineIncreases(base, renamed, renames)).toEqual([]); + expect( + baselineIncreases(base, { ...renamed, entries: [{ ...renamedEntry, count: 3 }] }, renames), + ).toEqual([expect.objectContaining({ additionalCount: 1, file: 'src/renamed.ts' })]); + }); }); diff --git a/cli/lib/install/anti-slop/git-snapshot.mts b/cli/lib/install/anti-slop/git-snapshot.mts new file mode 100644 index 0000000..6074fd3 --- /dev/null +++ b/cli/lib/install/anti-slop/git-snapshot.mts @@ -0,0 +1,225 @@ +/** Exact Git-index materialization and base-commit baseline evidence for anti-slop gates. */ + +import { execFileSync, spawnSync } from 'node:child_process'; +import { mkdirSync, mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { type AntiSlopBaseline, parseBaseline } from './baseline.mts'; +import { ANTI_SLOP_BASELINE_REL } from './constants.mts'; + +const MAX_GIT_OUTPUT = 128 * 1024 * 1024; +const LINT_SOURCE = /\.(?:[cm]?[jt]sx?)$/u; +const FULL_SCAN_FILES = new Set([ + ANTI_SLOP_BASELINE_REL, + '.oxlintrc.json', + '.oxlintrc.jsonc', + 'oxlint.config.ts', + 'oxlint.config.mts', + 'package.json', + 'bun.lock', +]); + +interface GitLayout { + root: string; + prefix: string; +} + +interface GitChange { + status: string; + oldPath?: string; + path: string; +} + +export interface GitBaselineEnvelope { + base: AntiSlopBaseline | null; + renames: Map; +} + +export interface StagedAntiSlopSnapshot extends GitBaselineEnvelope { + cwd: string; + paths: string[]; + changedFiles: string[]; + fullScan: boolean; + skipped: boolean; +} + +function git(cwd: string, args: readonly string[]): string { + const output = execFileSync('git', [...args], { + cwd, + encoding: 'utf8', + maxBuffer: MAX_GIT_OUTPUT, + }); + return output.endsWith('\n') ? output.slice(0, -1) : output; +} + +function layout(cwd: string): GitLayout { + return { + root: git(cwd, ['rev-parse', '--show-toplevel']), + prefix: git(cwd, ['rev-parse', '--show-prefix']), + }; +} + +function treeForRef(root: string, ref: string): string { + const result = spawnSync('git', ['rev-parse', '--verify', `${ref}^{tree}`], { + cwd: root, + encoding: 'utf8', + }); + if (result.status === 0) return result.stdout.trim(); + if (ref !== 'HEAD') { + throw new Error(`anti-slop: Git base ${ref} does not resolve to a tree`); + } + const unborn = spawnSync('git', ['symbolic-ref', '-q', 'HEAD'], { + cwd: root, + encoding: 'utf8', + }); + if (unborn.status !== 0) throw new Error('anti-slop: HEAD could not be resolved safely'); + const empty = spawnSync('git', ['mktree'], { cwd: root, encoding: 'utf8', input: '' }); + if (empty.status !== 0) throw new Error('anti-slop: could not create the initial empty Git tree'); + return empty.stdout.trim(); +} + +function parseChanges(root: string, baseTree: string, candidateTree: string): GitChange[] { + const output = execFileSync( + 'git', + ['diff-tree', '--no-commit-id', '--name-status', '-r', '-z', '-M', baseTree, candidateTree], + { cwd: root, encoding: 'utf8', maxBuffer: MAX_GIT_OUTPUT }, + ); + const fields = output.split('\0'); + const changes: GitChange[] = []; + for (let index = 0; index < fields.length;) { + const status = fields[index++]; + if (!status) break; + if (status.startsWith('R') || status.startsWith('C')) { + const oldPath = fields[index++]; + const path = fields[index++]; + if (oldPath !== undefined && path !== undefined) changes.push({ status, oldPath, path }); + continue; + } + const path = fields[index++]; + if (path !== undefined) changes.push({ status, path }); + } + return changes; +} + +function packagePath(repoPath: string, prefix: string): string | null { + if (!prefix) return repoPath; + return repoPath.startsWith(prefix) ? repoPath.slice(prefix.length) : null; +} + +function baselineAtTree(layout: GitLayout, tree: string): AntiSlopBaseline | null { + const path = `${layout.prefix}${ANTI_SLOP_BASELINE_REL}`; + const listed = spawnSync('git', ['ls-tree', '-z', tree, '--', path], { + cwd: layout.root, + encoding: 'utf8', + }); + if (listed.status !== 0) { + throw new Error(`anti-slop: could not inspect the base baseline at ${tree.slice(0, 12)}`); + } + if (!listed.stdout) return null; + const json = execFileSync('git', ['show', `${tree}:${path}`], { + cwd: layout.root, + encoding: 'utf8', + maxBuffer: MAX_GIT_OUTPUT, + }); + return parseBaseline(json, `${tree.slice(0, 12)}:${path}`); +} + +function envelope( + cwd: string, + baseRef: string, + candidateTree: string, +): GitBaselineEnvelope & { layout: GitLayout; changes: GitChange[]; baseTree: string } { + const repo = layout(cwd); + const baseTree = treeForRef(repo.root, baseRef); + const changes = parseChanges(repo.root, baseTree, candidateTree); + const renames = new Map(); + for (const change of changes) { + if (!change.status.startsWith('R') || change.oldPath === undefined) continue; + const oldPath = packagePath(change.oldPath, repo.prefix); + const nextPath = packagePath(change.path, repo.prefix); + if (oldPath !== null && nextPath !== null) renames.set(oldPath, nextPath); + } + return { layout: repo, baseTree, changes, base: baselineAtTree(repo, baseTree), renames }; +} + +/** Read the base baseline and exact rename map used by a full-tree CI check. */ +export function gitBaselineEnvelope(cwd: string, baseRef: string): GitBaselineEnvelope { + const repo = layout(cwd); + const candidateTree = git(repo.root, ['write-tree']); + const { base, renames } = envelope(cwd, baseRef, candidateTree); + return { base, renames }; +} + +function requiresFullScan(path: string): boolean { + return ( + FULL_SCAN_FILES.has(path) || + path.startsWith('.devkit/oxc/') || + path.startsWith('.devkit/anti-slop/') + ); +} + +function extractTree(root: string, tree: string, destination: string): void { + mkdirSync(destination, { recursive: true }); + const archive = execFileSync('git', ['archive', '--format=tar', tree], { + cwd: root, + maxBuffer: MAX_GIT_OUTPUT, + }); + const extracted = spawnSync('tar', ['-x', '-C', destination], { input: archive }); + if (extracted.status !== 0) { + throw new Error( + `anti-slop: could not materialize staged Git tree: ${extracted.stderr?.toString().trim() || `tar exit ${extracted.status}`}`, + ); + } +} + +/** + * Run an action against the exact candidate index, never the mutable working tree. Unrelated + * package/repository changes are ignored; config or baseline changes force a complete package scan. + */ +export function withStagedAntiSlopSnapshot( + cwd: string, + action: (snapshot: StagedAntiSlopSnapshot) => T, +): T { + const repo = layout(cwd); + const candidateTree = git(repo.root, ['write-tree']); + const evidence = envelope(cwd, 'HEAD', candidateTree); + const packageChanges = evidence.changes.flatMap((change) => { + const path = packagePath(change.path, repo.prefix); + return path === null ? [] : [{ ...change, path }]; + }); + const changedFiles = packageChanges.map((change) => change.path); + const fullScan = changedFiles.some(requiresFullScan); + const paths = fullScan + ? [] + : packageChanges + .filter((change) => !change.status.startsWith('D') && LINT_SOURCE.test(change.path)) + .map((change) => change.path); + const skipped = !fullScan && paths.length === 0; + if (skipped) { + return action({ + cwd, + paths, + changedFiles, + fullScan, + skipped, + base: evidence.base, + renames: evidence.renames, + }); + } + + const temp = mkdtempSync(join(tmpdir(), 'devkit-anti-slop-index-')); + try { + extractTree(repo.root, candidateTree, temp); + return action({ + cwd: join(temp, repo.prefix), + paths, + changedFiles, + fullScan, + skipped, + base: evidence.base, + renames: evidence.renames, + }); + } finally { + rmSync(temp, { recursive: true, force: true }); + } +} diff --git a/cli/lib/install/anti-slop/git-snapshot.test.mts b/cli/lib/install/anti-slop/git-snapshot.test.mts new file mode 100644 index 0000000..c3c3125 --- /dev/null +++ b/cli/lib/install/anti-slop/git-snapshot.test.mts @@ -0,0 +1,129 @@ +import { execFileSync } from 'node:child_process'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { afterEach, describe, expect, it } from 'vitest'; +import { ANTI_SLOP_UPSTREAM } from './constants.mts'; +import { withStagedAntiSlopSnapshot } from './git-snapshot.mts'; + +const roots: string[] = []; +const EMPTY_BASELINE = `${JSON.stringify( + { schemaVersion: 1, upstreamCommit: ANTI_SLOP_UPSTREAM, entries: [] }, + null, + 2, +)}\n`; + +function git(cwd: string, args: string[]): string { + return execFileSync('git', args, { cwd, encoding: 'utf8' }).trim(); +} + +function repository(withCommit = true): string { + const root = mkdtempSync(join(tmpdir(), 'anti-slop-git-snapshot-')); + roots.push(root); + git(root, ['init', '-q']); + mkdirSync(join(root, 'src'), { recursive: true }); + writeFileSync(join(root, '.anti-slop-baseline.json'), EMPTY_BASELINE); + writeFileSync(join(root, 'src', 'file.ts'), 'export const value = "base";\n'); + git(root, ['add', '-A']); + if (withCommit) { + git(root, [ + '-c', + 'user.name=Devkit test', + '-c', + 'user.email=devkit@test.invalid', + 'commit', + '-qm', + 'base', + ]); + } + return root; +} + +afterEach(() => { + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); +}); + +describe('anti-slop staged Git snapshot', () => { + it('reads staged bytes even when the working tree contains different bytes', () => { + const root = repository(); + writeFileSync(join(root, 'src', 'file.ts'), 'export const value = "staged";\n'); + git(root, ['add', 'src/file.ts']); + writeFileSync(join(root, 'src', 'file.ts'), 'export const value = "working";\n'); + + withStagedAntiSlopSnapshot(root, (snapshot) => { + expect(snapshot.paths).toEqual(['src/file.ts']); + expect(readFileSync(join(snapshot.cwd, 'src', 'file.ts'), 'utf8')).toContain('"staged"'); + expect(snapshot.base?.entries).toEqual([]); + }); + }); + + it('forces a full scan for baseline, root config, or managed capability changes', () => { + const root = repository(); + writeFileSync(join(root, '.anti-slop-baseline.json'), `${EMPTY_BASELINE.trim()}\n\n`); + git(root, ['add', '.anti-slop-baseline.json']); + + withStagedAntiSlopSnapshot(root, (snapshot) => { + expect(snapshot.fullScan).toBe(true); + expect(snapshot.paths).toEqual([]); + expect(snapshot.skipped).toBe(false); + }); + }); + + it.each(['.oxlintrc.json', '.oxlintrc.jsonc', 'oxlint.config.ts', 'oxlint.config.mts'])( + 'forces a full scan when the recognized root config %s changes', + (config) => { + const root = repository(); + writeFileSync(join(root, config), '{}\n'); + git(root, ['add', config]); + + withStagedAntiSlopSnapshot(root, (snapshot) => { + expect(snapshot.changedFiles).toContain(config); + expect(snapshot.fullScan).toBe(true); + expect(snapshot.paths).toEqual([]); + expect(snapshot.skipped).toBe(false); + }); + }, + ); + + it('preserves spaces and newlines in staged source paths', () => { + const root = repository(); + const names = ['src/space file.ts', 'src/line\nbreak.ts']; + for (const name of names) writeFileSync(join(root, name), 'export const added = true;\n'); + git(root, ['add', ...names]); + + withStagedAntiSlopSnapshot(root, (snapshot) => { + expect(new Set(snapshot.paths)).toEqual(new Set(names)); + }); + }); + + it('scopes a monorepo package and ignores staged siblings', () => { + const root = repository(); + const app = join(root, 'packages', 'app'); + mkdirSync(join(app, 'src'), { recursive: true }); + writeFileSync(join(app, '.anti-slop-baseline.json'), EMPTY_BASELINE); + writeFileSync(join(app, 'src', 'inside.ts'), 'export const inside = 1;\n'); + writeFileSync(join(root, 'src', 'outside.ts'), 'export const outside = 1;\n'); + git(root, ['add', '-A']); + + withStagedAntiSlopSnapshot(app, (snapshot) => { + expect(snapshot.paths).toEqual([]); + expect(snapshot.changedFiles).toEqual(['.anti-slop-baseline.json', 'src/inside.ts']); + expect(snapshot.fullScan).toBe(true); + }); + }); + + it('supports an initial commit and records exact renames', () => { + const initial = repository(false); + withStagedAntiSlopSnapshot(initial, (snapshot) => { + expect(snapshot.base).toBeNull(); + expect(snapshot.fullScan).toBe(true); + }); + + const renamed = repository(); + git(renamed, ['mv', 'src/file.ts', 'src/renamed.ts']); + withStagedAntiSlopSnapshot(renamed, (snapshot) => { + expect(snapshot.renames.get('src/file.ts')).toBe('src/renamed.ts'); + expect(snapshot.paths).toEqual(['src/renamed.ts']); + }); + }); +}); diff --git a/cli/lib/install/anti-slop/lifecycle.mts b/cli/lib/install/anti-slop/lifecycle.mts index 86eb548..e94e758 100644 --- a/cli/lib/install/anti-slop/lifecycle.mts +++ b/cli/lib/install/anti-slop/lifecycle.mts @@ -165,7 +165,7 @@ function readManifest(cwd: string): AntiSlopManifest | null { /** Explain why an explicit request cannot activate in a non-repository mode. */ export function warnIfAntiSlopUnavailable(mode: string, requested: boolean): void { - if (!requested || (mode !== 'overlay' && mode !== 'self-host')) return; + if (!requested || mode !== 'overlay') return; console.warn( `devkit init --${mode}: --anti-slop is unavailable because it requires the tracked Oxc capability; skipping it.`, ); diff --git a/cli/lib/install/oxc/lifecycle.mts b/cli/lib/install/oxc/lifecycle.mts index e8c284d..9dbf284 100644 --- a/cli/lib/install/oxc/lifecycle.mts +++ b/cli/lib/install/oxc/lifecycle.mts @@ -45,7 +45,7 @@ interface SyncOptions { /** Explain why an explicitly requested capability cannot activate in a non-repository mode. */ export function warnIfOxcUnavailable(mode: string, requested: boolean): void { - if (!requested || (mode !== 'overlay' && mode !== 'self-host')) return; + if (!requested || mode !== 'overlay') return; console.warn( `devkit init --${mode}: --oxc is unavailable because Oxc activation writes tracked repository config; skipping it.`, ); diff --git a/dist/README.md b/dist/README.md index ad4b908..8c2541d 100644 --- a/dist/README.md +++ b/dist/README.md @@ -81,11 +81,14 @@ Run `devkit help` for the command index and `devkit help ` for authorit devkit init --anti-slop devkit anti-slop create devkit anti-slop check +devkit anti-slop check --staged ``` `--anti-slop` implies the opt-in Oxc capability. Rules load beside the repository's other Oxlint rules; their severities and scoped overrides stay in the ordinary Oxlint config. Baseline creation is always explicit, normal checks are read-only, and pruning can only remove fixed debt. +The staged form reads the exact Git index, and CI can pass `--base ` to prevent a candidate +baseline from growing relative to its base commit. See the [anti-slop capability guide](docs/anti-slop.md) for provenance, the complete rule matrix, and the fingerprint contract. @@ -206,6 +209,7 @@ bun run test:run bun run typecheck bun run format:check bun run lint +bun run lint:anti-slop bun run lint:structure bun run benchmarks:check ``` @@ -215,6 +219,12 @@ commands use the current source instead of the last compiled package bin. Benchm development additionally uses `bun run benchmarks:typecheck`. Release builds compile `.mts` sources into `dist/`; day-to-day changes should not hand-edit generated `dist` files. +Devkit self-host mode always dogfoods its pinned Oxc and vendored anti-slop capabilities. The +managed `.devkit/oxc/` and `.devkit/anti-slop/` trees plus `.anti-slop-baseline.json` are committed; +the generated hook checks staged postimages while CI performs the full baseline-aware scan. See the +[assembled quality-stack benchmark](docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/README.md) +for the final ownership and performance rationale. + ## Documentation - [Benchmark methodology and immutable history](docs/benchmarks/README.md) diff --git a/dist/cli/commands/init.mjs b/dist/cli/commands/init.mjs index 77498f7..a400a94 100644 --- a/dist/cli/commands/init.mjs +++ b/dist/cli/commands/init.mjs @@ -789,9 +789,9 @@ export async function applyInit(cwd, plan) { console.log('8b. search-code (opt-in semantic search)'); installSearchCode(cwd, dryRun); } - if (selection.oxc && !selection.antiSlop && !selfHost) + if (selection.oxc && !selection.antiSlop) oxcLifecycle.syncOxcCapability(cwd, { dryRun, antiSlop: false }); - if (selection.antiSlop && !selfHost) + if (selection.antiSlop) antiSlopLifecycle.syncAntiSlopCapability(cwd, { dryRun }); // The vendored i-have-adhd skill, into devkit's own tree rather than the agent skills dirs — so it // no longer depends on the `skills` component. Called unconditionally: a false selection reclaims a @@ -814,8 +814,8 @@ export async function applyInit(cwd, plan) { husky: selection.husky, structure: isStructure, fallow: Boolean(selection.fallow), - oxc: Boolean(selection.oxc && !selfHost), - antiSlop: Boolean(selection.antiSlop && !selfHost), + oxc: Boolean(selection.oxc), + antiSlop: Boolean(selection.antiSlop), searchCode: Boolean(selection.searchCode), lineGrowth: Boolean(selection.lineGrowth), // Always written, including `false` — an ABSENT key is what marks a repo as never-offered, so @@ -917,7 +917,8 @@ export default async function run(args, cwd) { const selfHost = isDevkitRepo(cwd); if (selfHost) { mode = 'self-host'; - selection = selfHostSelection(); + const recorded = readJson(join(cwd, '.devkit', 'config.json')); + selection = selfHostSelection(recorded?.components); } else if (interactive) { const installed = detectInstalled(cwd); diff --git a/dist/cli/commands/oxc/anti-slop.mjs b/dist/cli/commands/oxc/anti-slop.mjs index 57ef175..483c696 100644 --- a/dist/cli/commands/oxc/anti-slop.mjs +++ b/dist/cli/commands/oxc/anti-slop.mjs @@ -2,8 +2,9 @@ import { existsSync } from 'node:fs'; import { join } from 'node:path'; import { withLock } from "../../lib/atomic-write.mjs"; -import { baselineFromGroups, compareBaseline, pruneBaseline, readBaseline, writeBaseline, } from "../../lib/install/anti-slop/baseline.mjs"; +import { baselineFromGroups, baselineIncreases, compareBaseline, pruneBaseline, readBaseline, writeBaseline, } from "../../lib/install/anti-slop/baseline.mjs"; import { ANTI_SLOP_BASELINE_LOCK_REL, ANTI_SLOP_BASELINE_REL, } from "../../lib/install/anti-slop/constants.mjs"; +import { gitBaselineEnvelope, withStagedAntiSlopSnapshot, } from "../../lib/install/anti-slop/git-snapshot.mjs"; import { collectAntiSlopGroups, resolveAntiSlopScope, } from "../../lib/install/anti-slop/runner.mjs"; export const meta = { name: 'anti-slop', @@ -12,7 +13,9 @@ export const meta = { Usage: devkit anti-slop create [--force] [paths...] Explicitly snapshot current findings - devkit anti-slop check [paths...] Fail on new error-severity findings (read-only) + devkit anti-slop check [paths...] Check working-tree findings (read-only) + devkit anti-slop check --staged Check the exact Git index against HEAD + devkit anti-slop check --base Full check + baseline monotonicity for CI devkit anti-slop inspect [--json] Inspect baseline debt without linting devkit anti-slop prune [paths...] Remove fixed debt; never add findings @@ -67,10 +70,36 @@ function create(cwd, args, force) { return 0; }); } -function check(cwd, args) { +function checkBaselineEnvelope(candidate, envelope) { + if (!envelope?.base) + return 0; // one-time bootstrap: the base commit has no baseline + const staleRenames = candidate.entries.flatMap((entry) => { + const nextFile = envelope.renames.get(entry.file); + return nextFile ? [{ ...entry, nextFile }] : []; + }); + if (staleRenames.length > 0) { + for (const entry of staleRenames) { + console.error(`BASELINE-RENAME ${entry.ruleId} ${entry.file} -> ${entry.nextFile} (${entry.count} adopted finding(s))`); + } + console.error('anti-slop: FAIL — persist renamed debt with `devkit anti-slop create --force`, then stage the baseline'); + return 1; + } + const increases = baselineIncreases(envelope.base, candidate, envelope.renames); + if (increases.length === 0) + return 0; + for (const entry of increases) { + console.error(`BASELINE-GROWTH ${entry.ruleId} ${entry.file} (+${entry.additionalCount} adopted finding(s))`); + } + console.error('anti-slop: FAIL — the committed baseline may only shrink; fix the finding instead of adopting it'); + return 1; +} +function check(cwd, args, envelope = null) { const baseline = baselineOrExplain(cwd); if (!baseline) return 2; + const envelopeStatus = checkBaselineEnvelope(baseline, envelope); + if (envelopeStatus !== 0) + return envelopeStatus; const scope = resolveAntiSlopScope(cwd, args); const selected = { ...baseline, @@ -143,8 +172,20 @@ export default function run(args, cwd) { const trailingPaths = separator >= 0 ? rest.slice(separator + 1) : []; const force = options.includes('--force'); const json = options.includes('--json'); + const staged = options.includes('--staged'); + const baseIndex = options.indexOf('--base'); + const baseRef = baseIndex >= 0 ? options[baseIndex + 1] : undefined; + if (baseIndex >= 0 && (!baseRef || baseRef.startsWith('-'))) { + console.error('anti-slop: --base requires a Git ref'); + return 2; + } + const consumed = new Set(); + if (baseIndex >= 0) { + consumed.add(baseIndex); + consumed.add(baseIndex + 1); + } const paths = [ - ...options.filter((arg) => arg !== '--force' && arg !== '--json'), + ...options.filter((arg, index) => arg !== '--force' && arg !== '--json' && arg !== '--staged' && !consumed.has(index)), ...(separator >= 0 ? ['--', ...trailingPaths] : []), ]; if (force && operation !== 'create') { @@ -155,10 +196,33 @@ export default function run(args, cwd) { console.error('anti-slop: --json is accepted only by inspect'); return 2; } + if (staged && operation !== 'check') { + console.error('anti-slop: --staged is accepted only by check'); + return 2; + } + if (baseRef && operation !== 'check') { + console.error('anti-slop: --base is accepted only by check'); + return 2; + } + if (staged && (baseRef || paths.length > 0)) { + console.error('anti-slop: --staged uses the complete Git index and accepts no paths or --base'); + return 2; + } if (operation === 'create') return create(cwd, paths, force); - if (operation === 'check') - return check(cwd, paths); + if (operation === 'check' && staged) { + return withStagedAntiSlopSnapshot(cwd, (snapshot) => { + if (snapshot.skipped) { + console.log('anti-slop: PASS — no relevant staged files or configuration changes'); + return 0; + } + return check(snapshot.cwd, snapshot.paths, snapshot); + }); + } + if (operation === 'check') { + const envelope = baseRef ? gitBaselineEnvelope(cwd, baseRef) : null; + return check(cwd, paths, envelope); + } if (operation === 'inspect') { if (paths.length > 0 || force) { console.error('anti-slop inspect accepts only --json'); diff --git a/dist/cli/lib/doctor/self-host-doctor.mjs b/dist/cli/lib/doctor/self-host-doctor.mjs index 3acfb1a..88d9a47 100644 --- a/dist/cli/lib/doctor/self-host-doctor.mjs +++ b/dist/cli/lib/doctor/self-host-doctor.mjs @@ -10,7 +10,11 @@ import { detectGitRoot } from "../detect-git-root.mjs"; import { extractGuardBlock } from "../husky/husky-block.mjs"; import { buildSelfHostBlock, installSelfHostHook, SELF_HOST_EXTRAS, SELF_HOST_STRUCTURE_CMD, selfHostSelection, } from "../husky/self-host.mjs"; import { checkAdhdSkill } from "../install/adhd-skill.mjs"; +import { readBaseline } from "../install/anti-slop/baseline.mjs"; +import { checkAntiSlopCapability, syncAntiSlopCapability, } from "../install/anti-slop/lifecycle.mjs"; +import { checkOxcCapability } from "../install/oxc/lifecycle.mjs"; import { checkAgents, checkSkills } from "./asset-checks.mjs"; +import { check } from "./check-result.mjs"; import { adviseSearchIndex } from "./guard-config-checks.mjs"; import { checkHookRunner } from "./hook-checks.mjs"; import { printStrayGateCalls } from "./stray-gate-calls.mjs"; @@ -19,19 +23,44 @@ export async function runSelfHostDoctor(cwd, cfg, fix) { const { gitRoot, pkgRel } = detectGitRoot(cwd); const hookPath = join(gitRoot, '.husky', 'pre-commit'); console.log('devkit doctor — self-host (source-mode dogfood)\n'); + const selection = selfHostSelection(cfg.components); + let capabilityResults = [...checkOxcCapability(cwd), ...checkAntiSlopCapability(cwd)]; + if (fix && capabilityResults.some((result) => result.status !== 'OK')) { + syncAntiSlopCapability(cwd); + capabilityResults = [...checkOxcCapability(cwd), ...checkAntiSlopCapability(cwd)]; + } + for (const result of capabilityResults) { + const glyph = result.status === 'OK' ? '✓' : result.status === 'MISSING' ? '✗' : '⚠'; + console.log(` ${glyph} ${result.name}: ${result.detail}`); + if (result.status !== 'OK' && result.remediation) + console.log(` → ${result.remediation}`); + } + let baselineResult; + try { + const baseline = readBaseline(cwd); + baselineResult = baseline + ? check('anti-slop baseline', 'OK', `${baseline.entries.reduce((sum, entry) => sum + entry.count, 0)} adopted finding(s)`) + : check('anti-slop baseline', 'MISSING', '.anti-slop-baseline.json', 'run `devkit anti-slop create` explicitly'); + } + catch (error) { + baselineResult = check('anti-slop baseline', 'DRIFT', error instanceof Error ? error.message : String(error), 'inspect and explicitly recreate the baseline'); + } + console.log(` ${baselineResult.status === 'OK' ? '✓' : baselineResult.status === 'MISSING' ? '✗' : '⚠'} ${baselineResult.name}: ${baselineResult.detail}`); + if (baselineResult.status !== 'OK' && baselineResult.remediation) + console.log(` → ${baselineResult.remediation}`); let hookOk = false; if (!existsSync(hookPath)) { console.log(' ✗ .husky/pre-commit MISSING — run `devkit init` (self-host)'); } else { const currentBlock = extractGuardBlock(readFileSync(hookPath, 'utf8'), pkgRel); - const expectedBlock = buildSelfHostBlock({ ...selfHostSelection(), structureCmd: SELF_HOST_STRUCTURE_CMD, extras: SELF_HOST_EXTRAS }, pkgRel, cwd); + const expectedBlock = buildSelfHostBlock({ ...selection, structureCmd: SELF_HOST_STRUCTURE_CMD, extras: SELF_HOST_EXTRAS }, pkgRel, cwd); if (currentBlock !== null && currentBlock.trim() === expectedBlock.trim()) { hookOk = true; console.log(' ✓ .husky/pre-commit in sync with the generator'); } else if (fix) { - installSelfHostHook(gitRoot, pkgRel, selfHostSelection(), false, cwd); + installSelfHostHook(gitRoot, pkgRel, selection, false, cwd); hookOk = true; console.log(' ✓ .husky/pre-commit regenerated (was stale — refreshed to the current generator)'); } @@ -75,5 +104,8 @@ export async function runSelfHostDoctor(cwd, cfg, fix) { console.log(` ${runner.status === 'OK' ? '✓' : '⚠'} ${runner.name}: ${runner.detail}`); if (runner.status !== 'OK') console.log(` → ${runner.remediation}`); - return hookOk && runner.status === 'OK' ? 0 : 1; + const capabilitiesOk = capabilityResults.every((result) => result.status === 'OK'); + return hookOk && runner.status === 'OK' && capabilitiesOk && baselineResult.status === 'OK' + ? 0 + : 1; } diff --git a/dist/cli/lib/husky/self-host.mjs b/dist/cli/lib/husky/self-host.mjs index 0de1a92..18923fd 100644 --- a/dist/cli/lib/husky/self-host.mjs +++ b/dist/cli/lib/husky/self-host.mjs @@ -36,6 +36,7 @@ import { buildFullHook, buildGuardBlock, extractGuardBlock, replaceGuardBlock, } export const SELF_HOST_STRUCTURE_CMD = 'bun run lint:structure'; export const SELF_HOST_EXTRAS = [ { label: 'lint', cmd: 'bun run lint' }, + { label: 'anti-slop', cmd: 'node cli/index.mts anti-slop check --staged' }, { label: 'benchmarks', cmd: 'bun run benchmarks:check -- --mode staged' }, ]; // The hand hook ended with an ADVISORY fallow audit (dead-code / duplication / complexity on the @@ -123,6 +124,10 @@ export function selfHostSelection(recorded) { // claimed was on. Undefined entries are dropped so an absent key falls through to the default // rather than overwriting it with undefined. ...definedOnly(recorded), + // Devkit is the soak environment for the exact-pinned Oxc + vendored anti-slop stack. These + // stay on even when an older recorded config predates them or explicitly recorded them off. + oxc: true, + antiSlop: true, // Guards stay FIXED even so: that is the deliberate part (see upgrade.mts) — a future // RECOMMENDED_GUARD_IDS addition must not open an interactive multiselect in the dogfood repo. guards: [...RECOMMENDED_GUARD_IDS, 'review'], diff --git a/dist/cli/lib/install/anti-slop/baseline.mjs b/dist/cli/lib/install/anti-slop/baseline.mjs index 3db54d7..5f40518 100644 --- a/dist/cli/lib/install/anti-slop/baseline.mjs +++ b/dist/cli/lib/install/anti-slop/baseline.mjs @@ -38,30 +38,31 @@ export function baselineFromGroups(groups) { .map(({ severity: _severity, line: _line, column: _column, ...entry }) => entry), }; } -export function readBaseline(cwd) { - const path = join(cwd, ANTI_SLOP_BASELINE_REL); - if (!existsSync(path)) - return null; +export function parseBaseline(json, source = ANTI_SLOP_BASELINE_REL) { let value; try { - value = JSON.parse(readFileSync(path, 'utf8')); + value = JSON.parse(json); } catch (error) { - throw new Error(`invalid ${ANTI_SLOP_BASELINE_REL}: ${error instanceof Error ? error.message : String(error)}`); + throw new Error(`invalid ${source}: ${error instanceof Error ? error.message : String(error)}`); } const baseline = value; if (baseline.schemaVersion !== 1 || baseline.upstreamCommit !== ANTI_SLOP_UPSTREAM || !Array.isArray(baseline.entries) || !baseline.entries.every(validateEntry)) { - throw new Error(`invalid or stale ${ANTI_SLOP_BASELINE_REL}; inspect it, then explicitly recreate it`); + throw new Error(`invalid or stale ${source}; inspect it, then explicitly recreate it`); } const sorted = [...baseline.entries].sort((a, b) => a.fingerprint.localeCompare(b.fingerprint)); if (new Set(sorted.map((entry) => entry.fingerprint)).size !== sorted.length) { - throw new Error(`invalid ${ANTI_SLOP_BASELINE_REL}: duplicate fingerprints`); + throw new Error(`invalid ${source}: duplicate fingerprints`); } return { schemaVersion: 1, upstreamCommit: baseline.upstreamCommit, entries: sorted }; } +export function readBaseline(cwd) { + const path = join(cwd, ANTI_SLOP_BASELINE_REL); + return existsSync(path) ? parseBaseline(readFileSync(path, 'utf8')) : null; +} export function writeBaseline(cwd, baseline) { writeFileAtomic(join(cwd, ANTI_SLOP_BASELINE_REL), `${JSON.stringify(baseline, null, 2)}\n`); } @@ -78,6 +79,40 @@ export function compareBaseline(baseline, groups) { resolvedCount: baseline.entries.reduce((sum, entry) => sum + Math.max(0, entry.count - (current.get(entry.fingerprint) ?? 0)), 0), }; } +/** + * Move adopted debt across Git-detected file renames without allowing its rule/message/context or + * count to change. Multiple entries that converge on one fingerprint are deliberately combined. + */ +export function migrateBaselineRenames(baseline, renames) { + const migrated = new Map(); + for (const entry of baseline.entries) { + const file = renames.get(entry.file) ?? entry.file; + const stable = { + ruleId: entry.ruleId, + file, + diagnostic: entry.diagnostic, + context: entry.context, + }; + const fingerprint = expectedFingerprint(stable); + const current = migrated.get(fingerprint); + if (current) + current.count += entry.count; + else + migrated.set(fingerprint, { fingerprint, ...stable, count: entry.count }); + } + return { + ...baseline, + entries: [...migrated.values()].sort((a, b) => a.fingerprint.localeCompare(b.fingerprint)), + }; +} +/** Return only candidate debt that exceeds the base commit's count envelope. */ +export function baselineIncreases(base, candidate, renames = new Map()) { + const allowed = new Map(migrateBaselineRenames(base, renames).entries.map((entry) => [entry.fingerprint, entry.count])); + return candidate.entries.flatMap((entry) => { + const additionalCount = Math.max(0, entry.count - (allowed.get(entry.fingerprint) ?? 0)); + return additionalCount > 0 ? [{ ...entry, additionalCount }] : []; + }); +} /** Return only still-present baseline debt; never add an unbaselined current finding. */ export function pruneBaseline(baseline, groups) { const current = new Map(groups.map((group) => [group.fingerprint, group.count])); diff --git a/dist/cli/lib/install/anti-slop/git-snapshot.mjs b/dist/cli/lib/install/anti-slop/git-snapshot.mjs new file mode 100644 index 0000000..037a41d --- /dev/null +++ b/dist/cli/lib/install/anti-slop/git-snapshot.mjs @@ -0,0 +1,183 @@ +/** Exact Git-index materialization and base-commit baseline evidence for anti-slop gates. */ +import { execFileSync, spawnSync } from 'node:child_process'; +import { mkdirSync, mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { parseBaseline } from "./baseline.mjs"; +import { ANTI_SLOP_BASELINE_REL } from "./constants.mjs"; +const MAX_GIT_OUTPUT = 128 * 1024 * 1024; +const LINT_SOURCE = /\.(?:[cm]?[jt]sx?)$/u; +const FULL_SCAN_FILES = new Set([ + ANTI_SLOP_BASELINE_REL, + '.oxlintrc.json', + '.oxlintrc.jsonc', + 'oxlint.config.ts', + 'oxlint.config.mts', + 'package.json', + 'bun.lock', +]); +function git(cwd, args) { + const output = execFileSync('git', [...args], { + cwd, + encoding: 'utf8', + maxBuffer: MAX_GIT_OUTPUT, + }); + return output.endsWith('\n') ? output.slice(0, -1) : output; +} +function layout(cwd) { + return { + root: git(cwd, ['rev-parse', '--show-toplevel']), + prefix: git(cwd, ['rev-parse', '--show-prefix']), + }; +} +function treeForRef(root, ref) { + const result = spawnSync('git', ['rev-parse', '--verify', `${ref}^{tree}`], { + cwd: root, + encoding: 'utf8', + }); + if (result.status === 0) + return result.stdout.trim(); + if (ref !== 'HEAD') { + throw new Error(`anti-slop: Git base ${ref} does not resolve to a tree`); + } + const unborn = spawnSync('git', ['symbolic-ref', '-q', 'HEAD'], { + cwd: root, + encoding: 'utf8', + }); + if (unborn.status !== 0) + throw new Error('anti-slop: HEAD could not be resolved safely'); + const empty = spawnSync('git', ['mktree'], { cwd: root, encoding: 'utf8', input: '' }); + if (empty.status !== 0) + throw new Error('anti-slop: could not create the initial empty Git tree'); + return empty.stdout.trim(); +} +function parseChanges(root, baseTree, candidateTree) { + const output = execFileSync('git', ['diff-tree', '--no-commit-id', '--name-status', '-r', '-z', '-M', baseTree, candidateTree], { cwd: root, encoding: 'utf8', maxBuffer: MAX_GIT_OUTPUT }); + const fields = output.split('\0'); + const changes = []; + for (let index = 0; index < fields.length;) { + const status = fields[index++]; + if (!status) + break; + if (status.startsWith('R') || status.startsWith('C')) { + const oldPath = fields[index++]; + const path = fields[index++]; + if (oldPath !== undefined && path !== undefined) + changes.push({ status, oldPath, path }); + continue; + } + const path = fields[index++]; + if (path !== undefined) + changes.push({ status, path }); + } + return changes; +} +function packagePath(repoPath, prefix) { + if (!prefix) + return repoPath; + return repoPath.startsWith(prefix) ? repoPath.slice(prefix.length) : null; +} +function baselineAtTree(layout, tree) { + const path = `${layout.prefix}${ANTI_SLOP_BASELINE_REL}`; + const listed = spawnSync('git', ['ls-tree', '-z', tree, '--', path], { + cwd: layout.root, + encoding: 'utf8', + }); + if (listed.status !== 0) { + throw new Error(`anti-slop: could not inspect the base baseline at ${tree.slice(0, 12)}`); + } + if (!listed.stdout) + return null; + const json = execFileSync('git', ['show', `${tree}:${path}`], { + cwd: layout.root, + encoding: 'utf8', + maxBuffer: MAX_GIT_OUTPUT, + }); + return parseBaseline(json, `${tree.slice(0, 12)}:${path}`); +} +function envelope(cwd, baseRef, candidateTree) { + const repo = layout(cwd); + const baseTree = treeForRef(repo.root, baseRef); + const changes = parseChanges(repo.root, baseTree, candidateTree); + const renames = new Map(); + for (const change of changes) { + if (!change.status.startsWith('R') || change.oldPath === undefined) + continue; + const oldPath = packagePath(change.oldPath, repo.prefix); + const nextPath = packagePath(change.path, repo.prefix); + if (oldPath !== null && nextPath !== null) + renames.set(oldPath, nextPath); + } + return { layout: repo, baseTree, changes, base: baselineAtTree(repo, baseTree), renames }; +} +/** Read the base baseline and exact rename map used by a full-tree CI check. */ +export function gitBaselineEnvelope(cwd, baseRef) { + const repo = layout(cwd); + const candidateTree = git(repo.root, ['write-tree']); + const { base, renames } = envelope(cwd, baseRef, candidateTree); + return { base, renames }; +} +function requiresFullScan(path) { + return (FULL_SCAN_FILES.has(path) || + path.startsWith('.devkit/oxc/') || + path.startsWith('.devkit/anti-slop/')); +} +function extractTree(root, tree, destination) { + mkdirSync(destination, { recursive: true }); + const archive = execFileSync('git', ['archive', '--format=tar', tree], { + cwd: root, + maxBuffer: MAX_GIT_OUTPUT, + }); + const extracted = spawnSync('tar', ['-x', '-C', destination], { input: archive }); + if (extracted.status !== 0) { + throw new Error(`anti-slop: could not materialize staged Git tree: ${extracted.stderr?.toString().trim() || `tar exit ${extracted.status}`}`); + } +} +/** + * Run an action against the exact candidate index, never the mutable working tree. Unrelated + * package/repository changes are ignored; config or baseline changes force a complete package scan. + */ +export function withStagedAntiSlopSnapshot(cwd, action) { + const repo = layout(cwd); + const candidateTree = git(repo.root, ['write-tree']); + const evidence = envelope(cwd, 'HEAD', candidateTree); + const packageChanges = evidence.changes.flatMap((change) => { + const path = packagePath(change.path, repo.prefix); + return path === null ? [] : [{ ...change, path }]; + }); + const changedFiles = packageChanges.map((change) => change.path); + const fullScan = changedFiles.some(requiresFullScan); + const paths = fullScan + ? [] + : packageChanges + .filter((change) => !change.status.startsWith('D') && LINT_SOURCE.test(change.path)) + .map((change) => change.path); + const skipped = !fullScan && paths.length === 0; + if (skipped) { + return action({ + cwd, + paths, + changedFiles, + fullScan, + skipped, + base: evidence.base, + renames: evidence.renames, + }); + } + const temp = mkdtempSync(join(tmpdir(), 'devkit-anti-slop-index-')); + try { + extractTree(repo.root, candidateTree, temp); + return action({ + cwd: join(temp, repo.prefix), + paths, + changedFiles, + fullScan, + skipped, + base: evidence.base, + renames: evidence.renames, + }); + } + finally { + rmSync(temp, { recursive: true, force: true }); + } +} diff --git a/dist/cli/lib/install/anti-slop/lifecycle.mjs b/dist/cli/lib/install/anti-slop/lifecycle.mjs index f883f1e..d858dc7 100644 --- a/dist/cli/lib/install/anti-slop/lifecycle.mjs +++ b/dist/cli/lib/install/anti-slop/lifecycle.mjs @@ -92,7 +92,7 @@ function readManifest(cwd) { } /** Explain why an explicit request cannot activate in a non-repository mode. */ export function warnIfAntiSlopUnavailable(mode, requested) { - if (!requested || (mode !== 'overlay' && mode !== 'self-host')) + if (!requested || mode !== 'overlay') return; console.warn(`devkit init --${mode}: --anti-slop is unavailable because it requires the tracked Oxc capability; skipping it.`); } diff --git a/dist/cli/lib/install/oxc/lifecycle.mjs b/dist/cli/lib/install/oxc/lifecycle.mjs index 1d05ce8..ec80f67 100644 --- a/dist/cli/lib/install/oxc/lifecycle.mjs +++ b/dist/cli/lib/install/oxc/lifecycle.mjs @@ -20,7 +20,7 @@ const BASE_REL = '.devkit/oxc/oxlint.base.json'; const LOCK_REL = '.devkit/oxc.lock'; /** Explain why an explicitly requested capability cannot activate in a non-repository mode. */ export function warnIfOxcUnavailable(mode, requested) { - if (!requested || (mode !== 'overlay' && mode !== 'self-host')) + if (!requested || mode !== 'overlay') return; console.warn(`devkit init --${mode}: --oxc is unavailable because Oxc activation writes tracked repository config; skipping it.`); } diff --git a/dist/package.json b/dist/package.json index 0bb1108..2341572 100644 --- a/dist/package.json +++ b/dist/package.json @@ -59,6 +59,7 @@ "test:e2e": "vitest run -c vitest.e2e.config.mjs", "playground": "bun scripts/playground.mts", "lint": "biome check --formatter-enabled=false --error-on-warnings .", + "lint:anti-slop": "node cli/index.mts anti-slop check", "lint:structure": "eslint cli gate-engine", "benchmarks:check": "bun gate-engine/eval/cli.mts check", "benchmarks:render": "bun gate-engine/eval/cli.mts render", diff --git a/docs/anti-slop.md b/docs/anti-slop.md index a8ee4f3..09d34bb 100644 --- a/docs/anti-slop.md +++ b/docs/anti-slop.md @@ -26,6 +26,8 @@ Baseline creation is deliberately never implicit: devkit anti-slop create [paths...] # refuses an existing baseline devkit anti-slop create --force [paths...] # explicit replacement devkit anti-slop check [paths...] # read-only; CI/agent-loop gate +devkit anti-slop check --staged # exact Git-index snapshot against HEAD +devkit anti-slop check --base # full CI scan + baseline monotonicity devkit anti-slop inspect [--json] # read-only debt inventory devkit anti-slop prune [paths...] # shrink existing debt only ~~~ @@ -40,6 +42,19 @@ count when one of several identical occurrences is fixed. It cannot add a curren Devkit clean deliberately keeps the baseline because it is the repository's debt record, not replaceable Devkit state. +The staged gate materializes `git write-tree` into a disposable directory. Source files, the root +Oxlint config, managed plugin/config bytes, and the candidate baseline are therefore all read from +the index rather than a partially staged working tree. A root config, managed capability, or +baseline change forces a full scan; otherwise only staged JavaScript/TypeScript postimages are +linted. Deleted and unrelated files no-op. + +`--staged` compares the candidate baseline with `HEAD`; `--base` compares it with the named CI base. +Once a base baseline exists, candidate fingerprints and counts may only stay equal or shrink. A base +with no baseline is the sole bootstrap exception. A Git-detected rename of a file with adopted debt +must persist that debt under the new path in the same commit: run `devkit anti-slop create --force`, +stage the resulting baseline, and check again. The base debt is migrated in memory only to verify +that the persisted count did not grow. This keeps the baseline valid after merge; checks never write. + Occurrences with the same rule, repository-relative file, normalized diagnostic, and normalized source line are intentionally fungible and share one counted fingerprint. The ratchet prevents that debt class from growing; it does not assign provenance to otherwise indistinguishable occurrences. @@ -112,7 +127,9 @@ repository root to managed Oxc base link and the managed base to anti-slop plugi The packed E2E fixture asserts that all 15 namespaced diagnostics load from the emitted package, that off, warn, error, and scoped overrides work, and that create to new violation to fix to prune -preserves the shrink-only contract. +preserves the shrink-only contract. It also proves both partial-staging directions, baseline-growth +rejection, same-commit baseline persistence for Git renames, and a post-merge check against the +packed consumer binary. ## Intentional differences and limits diff --git a/docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/README.md b/docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/README.md new file mode 100644 index 0000000..c169575 --- /dev/null +++ b/docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/README.md @@ -0,0 +1,158 @@ +# Devkit Oxc dogfood: assembled quality-stack benchmark + +- Date: 2026-08-16 +- Shortcut: SC-1681 +- Host: Apple M4, 10 logical CPUs, 24 GiB RAM, macOS 26.5 +- Runtime: Node 24.19.0, Bun 1.3.1 + +## Decision + +Ship the mixed stack, not an all-Oxc replacement: + +- Oxfmt owns Devkit formatting and the self-host staged formatter. +- Biome still owns JavaScript/TypeScript/JSON/CSS lint and assist diagnostics. +- Oxlint owns the 15 vendored anti-slop rules through the explicit shrink-only baseline. +- ESLint still owns filesystem/cross-file topology and import walls. +- `tsc` still owns TypeScript 6 compiler diagnostics and JavaScript build emission. + +The assembled local agent lane is effectively CPU-neutral while adding the 15 anti-slop rules: +median CPU is **-3.0%**, p95 CPU is **+3.8%**, median process-tree RSS is **-2.7%**, and median +wall time is **+1.7%**. Paired per-sample CPU deltas have a -3.5% median, but the decision table +uses the more conservative independently summarized medians. This is not the large end-to-end CPU +win the epic ultimately targets; it is the costed Devkit compatibility boundary. + +The full CI lane is intentionally heavier: median CPU is **+39.4%**, median wall is **+67.1%**, and +median process-tree RSS is **+6.5%**. The lane adds a second full-repository policy family (15 +anti-slop rules), checks formatting separately with Oxfmt, and typechecks the newly vendored +anti-slop source. It does not justify removing Biome, ESLint, or `tsc`; their parity studies already +found unmatched responsibilities. Frink must run its own assembled benchmark before enabling the +same gates. + +## Results + +Three warmups were discarded. Ten measured samples alternated control-first and candidate-first. +CPU is aggregate user + system time from `/usr/bin/time -lp`; RSS is the maximum 10 ms sampled sum +of the wrapper and all descendants. Raw samples and machine-readable protocol are in +[`results.json`](results.json). + +### Local deterministic quality segment + +This is the hot agent loop. Both sides run the real staged formatter fragment extracted from their +generated hook, full lint, retained topology, and the unchanged staged benchmark-evidence gate. The +candidate additionally runs the real exact-index anti-slop command. The staged fixture is one extra +blank line in `skills/_devkit/checklist-store.mjs`, an extension selected by both the old Biome hook +and new Oxfmt hook. + +| Metric | Control median | Candidate median | Delta | Control p95 | Candidate p95 | Delta | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | +| CPU | 10.500 s | 10.190 s | -3.0% | 11.460 s | 11.890 s | +3.8% | +| Wall | 5.344 s | 5.436 s | +1.7% | 6.143 s | 6.598 s | +7.4% | +| Process-tree RSS | 218.4 MiB | 212.5 MiB | -2.7% | 218.8 MiB | 212.9 MiB | -2.7% | + +Control command: + +```sh +sh "$DEVKIT_FORMAT_FRAGMENT" \ + && bun run lint \ + && bun run lint:structure \ + && bun run benchmarks:check -- --mode staged +``` + +Candidate command: + +```sh +sh "$DEVKIT_FORMAT_FRAGMENT" \ + && bun run lint \ + && node cli/index.mts anti-slop check --staged \ + && bun run lint:structure \ + && bun run benchmarks:check -- --mode staged +``` + +### Full repository static-quality segment + +| Metric | Control median | Candidate median | Delta | Control p95 | Candidate p95 | Delta | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | +| CPU | 8.335 s | 11.620 s | +39.4% | 9.750 s | 13.390 s | +37.3% | +| Wall | 2.236 s | 3.737 s | +67.1% | 2.860 s | 4.336 s | +51.6% | +| Process-tree RSS | 469.4 MiB | 500.1 MiB | +6.5% | 482.0 MiB | 510.6 MiB | +5.9% | + +Control command: + +```sh +bun run lint && bun run lint:structure && bun run typecheck +``` + +Candidate command: + +```sh +bun run format:check \ + && bun run lint \ + && bun run lint:anti-slop \ + && bun run lint:structure \ + && bun run typecheck +``` + +## Reproduction and controls + +- Control: clean `origin/main` archive at `4d624d059c8974aa58e0f3a27277cd6fd90383a4`. +- Candidate: exact staged index tree `44b64383172500584abd31392c0d43a43ef52186`. +- The candidate hash is captured before the harness writes its output. The only subsequent changes + are this evidence file and its human-readable summary; neither is in the measured command scope. +- Dependencies: the same installed `node_modules` tree is symlinked into both disposable mirrors and + excluded from timing. +- Each mirror is initialized and committed independently. The local fixture is reset and staged + before every sample. +- Reviewer, completeness, test, ratchet, and release lanes are excluded from both sides because this + experiment isolates the changed static-quality segment. They remain in the real hook/CI. +- The harness fails on any nonzero command and deletes its disposable mirrors in `finally`. + +Run from a clean/staged candidate tree: + +```sh +node docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/benchmark.mjs \ + --output docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/results.json +``` + +## Diagnostic ownership and duplicate-work audit + +| Responsibility | Owner | Local path | CI path | Why it remains | +| --- | --- | --- | --- | --- | +| Formatting | Oxfmt 0.63.0 | Exact proven staged scope, direct pinned binary | `format:check` over the same authored scope | A5 proved byte parity and substantially lower formatter-only CPU. | +| JS/TS/JSON/CSS lint + assists | Biome 2.5.6 | `bun run lint` | `bun run lint` | A3 found unmatched lint/assist scope; Oxfmt is formatting only. | +| Anti-slop syntax/scope rules | Oxlint 1.78.0 + vendored plugin | Exact Git-index snapshot with shrink-only baseline | Full tree plus base-vs-candidate baseline monotonicity | New responsibility; no incumbent duplicate exists. | +| Filesystem topology + import walls | ESLint 10.5.0 + project-structure plugin | `lint:structure` | `lint:structure` | A4 found missing empty-directory, Electron topology, and import-wall parity. | +| Type diagnostics | TypeScript 6.0.3 | Deliberately not in pre-commit | `typecheck` | A6 found semantic/diagnostic mismatch in Oxc's TypeScript-7-oriented path. | +| Ratchets, benchmark evidence, reviewers | Devkit gate-engine | Generated hook | Dedicated CI steps where applicable | Governance, not lint/format/type work. | + +No responsibility is run by both Biome and Oxlint: the managed Oxlint base enables only anti-slop, +while Biome's formatter is disabled and Oxfmt owns formatting. ESLint is invoked only for topology. + +## Baseline, Git-index, doctor, and editor evidence + +- Devkit explicitly adopted 1,677 findings / 1,543 stable fingerprints in + `.anti-slop-baseline.json`; the file has no timestamp and is deterministic. +- `check --staged` exports `git write-tree` into a temporary mirror and reads source, root config, + managed config/plugin bytes, and baseline from that exact tree. Partial staging is covered in both + directions. Config/baseline changes force a full scan; unrelated staged files no-op. +- A candidate baseline may only shrink relative to the base commit. The only bootstrap exception is + a base with no baseline. A debt-bearing Git rename must persist the regenerated baseline in the + same commit; the gate verifies the new-path count did not grow and remains valid after merge. +- Self-host init always selects Oxc + anti-slop after applying recorded options. Managed trees and + their manifests are committed; init/upgrade can reproduce them. Doctor checks runtime pins, + managed bytes, root composition, all 15 rules, baseline validity, hook parity, and never rewrites + the baseline—even under `--fix`. +- `.vscode/extensions.json` recommends the official `oxc.oxc-vscode` extension. Oxc's official + editor documentation says it launches the repository-local `oxlint --lsp`, and its JS-plugin + documentation includes language-server diagnostics/suggestions in the supported API. CLI/CI + remain authoritative because the editor extension is optional and the JS-plugin API is alpha. + +## Revisit conditions + +- Do not migrate Biome lint, ESLint topology, or `tsc` merely to reduce process count. Reopen only + when their own parity gaps are closed and an assembled benchmark—not a tool-only microbenchmark— + lowers agent-loop CPU. +- Before Frink adoption, repeat this exact control/candidate protocol on Frink's staged and full + scopes. Its current ~13k anti-slop debt makes deterministic bootstrap and monotonicity evidence + mandatory. +- Reconsider the full-CI composition if Oxc can own Biome's remaining diagnostics or TypeScript 6 + compiler semantics; that is where the current extra full-tree passes can actually be removed. diff --git a/docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/benchmark.mjs b/docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/benchmark.mjs new file mode 100644 index 0000000..27227c8 --- /dev/null +++ b/docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/benchmark.mjs @@ -0,0 +1,295 @@ +#!/usr/bin/env node + +import { execFileSync, spawn, spawnSync } from 'node:child_process'; +import { + mkdtempSync, + mkdirSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { performance } from 'node:perf_hooks'; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = join(HERE, '..', '..', '..', '..'); +const CONTROL_REF = 'origin/main'; +const WARMUPS = 3; +const SAMPLES = 10; +const TIME_BIN = '/usr/bin/time'; +const PS_BIN = '/bin/ps'; +const LOCAL_FIXTURE = 'skills/_devkit/checklist-store.mjs'; + +const FULL_COMMANDS = { + control: 'bun run lint && bun run lint:structure && bun run typecheck', + candidate: + 'bun run format:check && bun run lint && bun run lint:anti-slop && bun run lint:structure && bun run typecheck', +}; + +const LOCAL_COMMANDS = { + control: + 'sh "$DEVKIT_FORMAT_FRAGMENT" && bun run lint && bun run lint:structure && bun run benchmarks:check -- --mode staged', + candidate: + 'sh "$DEVKIT_FORMAT_FRAGMENT" && bun run lint && node cli/index.mts anti-slop check --staged && bun run lint:structure && bun run benchmarks:check -- --mode staged', +}; + +function processTreeRss(rootPid) { + try { + const rows = execFileSync(PS_BIN, ['-axo', 'pid=,ppid=,rss='], { encoding: 'utf8' }) + .trim() + .split('\n') + .map((line) => line.trim().split(/\s+/).map(Number)) + .filter(([pid, parent, rss]) => pid > 0 && parent >= 0 && rss >= 0); + const children = new Map(); + const rssByPid = new Map(); + for (const [pid, parent, rss] of rows) { + rssByPid.set(pid, rss); + const siblings = children.get(parent) ?? []; + siblings.push(pid); + children.set(parent, siblings); + } + const pending = [rootPid]; + const seen = new Set(); + let kib = 0; + while (pending.length > 0) { + const pid = pending.pop(); + if (seen.has(pid)) continue; + seen.add(pid); + kib += rssByPid.get(pid) ?? 0; + pending.push(...(children.get(pid) ?? [])); + } + return kib * 1024; + } catch { + return 0; + } +} + +function parseTime(stderr) { + const value = (pattern, label) => { + const match = stderr.match(pattern); + if (!match) throw new Error(`/usr/bin/time output omitted ${label}`); + return Number(match[1]); + }; + return { + userMs: value(/([0-9.]+)\s+user/, 'user CPU') * 1000, + systemMs: value(/([0-9.]+)\s+sys/, 'system CPU') * 1000, + directPeakRssBytes: value( + /([0-9]+)\s+maximum resident set size/, + 'maximum resident set size', + ), + }; +} + +async function measure(command, cwd, env = {}) { + const started = performance.now(); + const child = spawn(TIME_BIN, ['-lp', 'sh', '-c', command], { + cwd, + env: { ...process.env, NO_COLOR: '1', ...env }, + stdio: ['ignore', 'pipe', 'pipe'], + }); + let stdout = ''; + let stderr = ''; + let treePeakRssBytes = 0; + child.stdout.setEncoding('utf8'); + child.stderr.setEncoding('utf8'); + child.stdout.on('data', (chunk) => { + stdout += chunk; + }); + child.stderr.on('data', (chunk) => { + stderr += chunk; + }); + const sampler = setInterval(() => { + treePeakRssBytes = Math.max(treePeakRssBytes, processTreeRss(child.pid)); + }, 10); + const status = await new Promise((resolve, reject) => { + child.on('error', reject); + child.on('close', resolve); + }); + clearInterval(sampler); + if (status !== 0) throw new Error(`timed command failed (${status}): ${stdout}\n${stderr}`); + const timing = parseTime(stderr); + return { + wallMs: performance.now() - started, + cpuMs: timing.userMs + timing.systemMs, + userMs: timing.userMs, + systemMs: timing.systemMs, + treePeakRssBytes: Math.max(treePeakRssBytes, timing.directPeakRssBytes), + directPeakRssBytes: timing.directPeakRssBytes, + }; +} + +function median(values) { + const sorted = [...values].sort((a, b) => a - b); + const middle = Math.floor(sorted.length / 2); + return sorted.length % 2 === 0 ? (sorted[middle - 1] + sorted[middle]) / 2 : sorted[middle]; +} + +function p95(values) { + return [...values].sort((a, b) => a - b)[Math.ceil(values.length * 0.95) - 1]; +} + +function summarize(samples) { + return Object.fromEntries( + ['wallMs', 'cpuMs', 'userMs', 'systemMs', 'treePeakRssBytes', 'directPeakRssBytes'].map( + (field) => [ + field, + { + median: median(samples.map((sample) => sample[field])), + p95: p95(samples.map((sample) => sample[field])), + }, + ], + ), + ); +} + +function git(cwd, args, options = {}) { + return execFileSync('git', args, { cwd, encoding: 'utf8', ...options }).trim(); +} + +function commitFixture(root) { + git(root, ['init', '-q']); + git(root, ['add', '-A']); + git(root, [ + '-c', + 'user.name=Devkit benchmark', + '-c', + 'user.email=benchmark@invalid', + 'commit', + '-qm', + 'benchmark fixture', + ]); +} + +function extractFormatFragment(root, outputPath) { + const hook = readFileSync(join(root, '.husky', 'pre-commit'), 'utf8'); + const fragment = hook.match(/# devkit:biome-format[\s\S]*?# \/devkit:biome-format/)?.[0]; + if (!fragment) throw new Error(`formatter fragment missing from ${root}/.husky/pre-commit`); + writeFileSync(outputPath, `${fragment}\n`); +} + +function prepareMirrors(tempRoot) { + const control = join(tempRoot, 'control'); + const candidate = join(tempRoot, 'candidate'); + mkdirSync(control, { recursive: true }); + mkdirSync(candidate, { recursive: true }); + + const archive = execFileSync('git', ['archive', CONTROL_REF], { + cwd: REPO_ROOT, + maxBuffer: 128 * 1024 * 1024, + }); + const extracted = spawnSync('tar', ['-x', '-C', control], { input: archive }); + if (extracted.status !== 0) throw new Error(`control archive extraction failed: ${extracted.stderr}`); + execFileSync('git', ['checkout-index', '--all', `--prefix=${candidate}/`], { cwd: REPO_ROOT }); + + for (const root of [control, candidate]) { + symlinkSync(join(REPO_ROOT, 'node_modules'), join(root, 'node_modules'), 'dir'); + commitFixture(root); + } + + const fragments = { + control: join(tempRoot, 'control-format.sh'), + candidate: join(tempRoot, 'candidate-format.sh'), + }; + extractFormatFragment(control, fragments.control); + extractFormatFragment(candidate, fragments.candidate); + return { control, candidate, fragments }; +} + +function stageLocalFixture(root) { + git(root, ['checkout', '--', LOCAL_FIXTURE]); + const path = join(root, LOCAL_FIXTURE); + writeFileSync(path, `${readFileSync(path, 'utf8').trimEnd()}\n\n`); + git(root, ['add', LOCAL_FIXTURE]); +} + +async function runLane(name, roots, fragments, commands, reset) { + const samples = { control: [], candidate: [] }; + for (let index = 0; index < WARMUPS; index += 1) { + for (const side of ['control', 'candidate']) { + reset?.(roots[side]); + await measure(commands[side], roots[side], { + DEVKIT_FORMAT_FRAGMENT: fragments[side], + }); + } + } + for (let index = 0; index < SAMPLES; index += 1) { + const order = index % 2 === 0 ? ['control', 'candidate'] : ['candidate', 'control']; + for (const side of order) { + reset?.(roots[side]); + samples[side].push( + await measure(commands[side], roots[side], { + DEVKIT_FORMAT_FRAGMENT: fragments[side], + }), + ); + } + } + return { + name, + commands, + samples, + summary: { + control: summarize(samples.control), + candidate: summarize(samples.candidate), + }, + }; +} + +async function main() { + const tempRoot = mkdtempSync(join(tmpdir(), 'devkit-dogfood-benchmark-')); + try { + const { control, candidate, fragments } = prepareMirrors(tempRoot); + const roots = { control, candidate }; + const local = await runLane( + 'local deterministic quality segment', + roots, + fragments, + LOCAL_COMMANDS, + stageLocalFixture, + ); + const full = await runLane('full repository static-quality segment', roots, fragments, FULL_COMMANDS); + const results = { + schemaVersion: 1, + recordedAt: new Date().toISOString(), + source: { + controlRef: CONTROL_REF, + controlCommit: git(REPO_ROOT, ['rev-parse', CONTROL_REF]), + candidateTree: git(REPO_ROOT, ['write-tree']), + }, + host: { + uname: execFileSync('uname', ['-a'], { encoding: 'utf8' }).trim(), + node: process.version, + bun: execFileSync('bun', ['--version'], { encoding: 'utf8' }).trim(), + logicalCpuCount: Number( + execFileSync('sysctl', ['-n', 'hw.logicalcpu'], { encoding: 'utf8' }).trim(), + ), + }, + protocol: { + warmups: WARMUPS, + samples: SAMPLES, + order: 'alternating control-first/candidate-first', + control: 'clean origin/main archive', + candidate: 'exact staged index exported with git checkout-index', + dependencies: 'shared installed node_modules, excluded from timing', + localFixture: `one extra trailing blank line staged in ${LOCAL_FIXTURE} before every sample`, + scope: + 'unchanged ratchet, benchmark-evidence, test, reviewer, and completeness lanes excluded from both sides', + rss: '10ms sampling; sum RSS of /usr/bin/time wrapper and all descendants', + cpu: '/usr/bin/time -lp aggregate user + sys', + }, + lanes: { local, full }, + }; + const outputIndex = process.argv.indexOf('--output'); + if (outputIndex >= 0) { + writeFileSync(join(process.cwd(), process.argv[outputIndex + 1]), `${JSON.stringify(results, null, 2)}\n`); + } else { + console.log(JSON.stringify(results, null, 2)); + } + } finally { + rmSync(tempRoot, { recursive: true, force: true }); + } +} + +await main(); diff --git a/docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/results.json b/docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/results.json new file mode 100644 index 0000000..c23ab19 --- /dev/null +++ b/docs/benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/results.json @@ -0,0 +1,483 @@ +{ + "schemaVersion": 1, + "recordedAt": "2026-08-16T03:58:48.568Z", + "source": { + "controlRef": "origin/main", + "controlCommit": "4d624d059c8974aa58e0f3a27277cd6fd90383a4", + "candidateTree": "44b64383172500584abd31392c0d43a43ef52186" + }, + "host": { + "uname": "Darwin Benji-mac 25.5.0 Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:26 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T8132 arm64", + "node": "v24.19.0", + "bun": "1.3.1", + "logicalCpuCount": 10 + }, + "protocol": { + "warmups": 3, + "samples": 10, + "order": "alternating control-first/candidate-first", + "control": "clean origin/main archive", + "candidate": "exact staged index exported with git checkout-index", + "dependencies": "shared installed node_modules, excluded from timing", + "localFixture": "one extra trailing blank line staged in skills/_devkit/checklist-store.mjs before every sample", + "scope": "unchanged ratchet, benchmark-evidence, test, reviewer, and completeness lanes excluded from both sides", + "rss": "10ms sampling; sum RSS of /usr/bin/time wrapper and all descendants", + "cpu": "/usr/bin/time -lp aggregate user + sys" + }, + "lanes": { + "local": { + "name": "local deterministic quality segment", + "commands": { + "control": "sh \"$DEVKIT_FORMAT_FRAGMENT\" && bun run lint && bun run lint:structure && bun run benchmarks:check -- --mode staged", + "candidate": "sh \"$DEVKIT_FORMAT_FRAGMENT\" && bun run lint && node cli/index.mts anti-slop check --staged && bun run lint:structure && bun run benchmarks:check -- --mode staged" + }, + "samples": { + "control": [ + { + "wallMs": 5241.345416000004, + "cpuMs": 10410, + "userMs": 5220, + "systemMs": 5190, + "treePeakRssBytes": 228786176, + "directPeakRssBytes": 193347584 + }, + { + "wallMs": 6143.276458, + "cpuMs": 11460, + "userMs": 6100, + "systemMs": 5360, + "treePeakRssBytes": 228966400, + "directPeakRssBytes": 197476352 + }, + { + "wallMs": 4824.627832999999, + "cpuMs": 9910, + "userMs": 4790, + "systemMs": 5120, + "treePeakRssBytes": 229097472, + "directPeakRssBytes": 196902912 + }, + { + "wallMs": 5890.852415999994, + "cpuMs": 11210, + "userMs": 5870, + "systemMs": 5340, + "treePeakRssBytes": 228950016, + "directPeakRssBytes": 194838528 + }, + { + "wallMs": 5639.5947920000035, + "cpuMs": 10880, + "userMs": 5600, + "systemMs": 5280, + "treePeakRssBytes": 229195776, + "directPeakRssBytes": 197705728 + }, + { + "wallMs": 5689.496499999994, + "cpuMs": 10910, + "userMs": 5660, + "systemMs": 5250, + "treePeakRssBytes": 229376000, + "directPeakRssBytes": 198426624 + }, + { + "wallMs": 4697.918833000003, + "cpuMs": 9590, + "userMs": 4670, + "systemMs": 4920, + "treePeakRssBytes": 228556800, + "directPeakRssBytes": 195526656 + }, + { + "wallMs": 5447.233334000004, + "cpuMs": 10590, + "userMs": 5420, + "systemMs": 5170, + "treePeakRssBytes": 228573184, + "directPeakRssBytes": 197607424 + }, + { + "wallMs": 5212.365124999982, + "cpuMs": 10330, + "userMs": 5180, + "systemMs": 5150, + "treePeakRssBytes": 228425728, + "directPeakRssBytes": 195379200 + }, + { + "wallMs": 5215.986791000003, + "cpuMs": 10340, + "userMs": 5190, + "systemMs": 5150, + "treePeakRssBytes": 229195776, + "directPeakRssBytes": 195117056 + } + ], + "candidate": [ + { + "wallMs": 4616.986791000003, + "cpuMs": 9140, + "userMs": 4600, + "systemMs": 4540, + "treePeakRssBytes": 222642176, + "directPeakRssBytes": 196116480 + }, + { + "wallMs": 5746.278042000005, + "cpuMs": 10640, + "userMs": 5720, + "systemMs": 4920, + "treePeakRssBytes": 222478336, + "directPeakRssBytes": 188579840 + }, + { + "wallMs": 5974.577917000002, + "cpuMs": 11000, + "userMs": 5940, + "systemMs": 5060, + "treePeakRssBytes": 222445568, + "directPeakRssBytes": 202424320 + }, + { + "wallMs": 6597.797040999998, + "cpuMs": 11890, + "userMs": 6560, + "systemMs": 5330, + "treePeakRssBytes": 222838784, + "directPeakRssBytes": 201801728 + }, + { + "wallMs": 6235.094375000001, + "cpuMs": 11150, + "userMs": 6210, + "systemMs": 4940, + "treePeakRssBytes": 223215616, + "directPeakRssBytes": 197394432 + }, + { + "wallMs": 5832.557667000001, + "cpuMs": 10850, + "userMs": 5810, + "systemMs": 5040, + "treePeakRssBytes": 223035392, + "directPeakRssBytes": 199852032 + }, + { + "wallMs": 4968.190166, + "cpuMs": 9460, + "userMs": 4940, + "systemMs": 4520, + "treePeakRssBytes": 222478336, + "directPeakRssBytes": 196280320 + }, + { + "wallMs": 4778.127916999991, + "cpuMs": 9260, + "userMs": 4750, + "systemMs": 4510, + "treePeakRssBytes": 223133696, + "directPeakRssBytes": 196886528 + }, + { + "wallMs": 5125.3540840000205, + "cpuMs": 9740, + "userMs": 5090, + "systemMs": 4650, + "treePeakRssBytes": 222740480, + "directPeakRssBytes": 196198400 + }, + { + "wallMs": 4783.438125000015, + "cpuMs": 9460, + "userMs": 4750, + "systemMs": 4710, + "treePeakRssBytes": 223215616, + "directPeakRssBytes": 196198400 + } + ] + }, + "summary": { + "control": { + "wallMs": { + "median": 5344.289375000004, + "p95": 6143.276458 + }, + "cpuMs": { + "median": 10500, + "p95": 11460 + }, + "userMs": { + "median": 5320, + "p95": 6100 + }, + "systemMs": { + "median": 5180, + "p95": 5360 + }, + "treePeakRssBytes": { + "median": 228958208, + "p95": 229376000 + }, + "directPeakRssBytes": { + "median": 196214784, + "p95": 198426624 + } + }, + "candidate": { + "wallMs": { + "median": 5435.816063000013, + "p95": 6597.797040999998 + }, + "cpuMs": { + "median": 10190, + "p95": 11890 + }, + "userMs": { + "median": 5405, + "p95": 6560 + }, + "systemMs": { + "median": 4815, + "p95": 5330 + }, + "treePeakRssBytes": { + "median": 222789632, + "p95": 223215616 + }, + "directPeakRssBytes": { + "median": 196583424, + "p95": 202424320 + } + } + } + }, + "full": { + "name": "full repository static-quality segment", + "commands": { + "control": "bun run lint && bun run lint:structure && bun run typecheck", + "candidate": "bun run format:check && bun run lint && bun run lint:anti-slop && bun run lint:structure && bun run typecheck" + }, + "samples": { + "control": [ + { + "wallMs": 2176.905708999984, + "cpuMs": 8170, + "userMs": 2150, + "systemMs": 6020, + "treePeakRssBytes": 497598464, + "directPeakRssBytes": 487440384 + }, + { + "wallMs": 2859.8013329999812, + "cpuMs": 9750, + "userMs": 2830, + "systemMs": 6920, + "treePeakRssBytes": 505430016, + "directPeakRssBytes": 495075328 + }, + { + "wallMs": 2275.4988329999906, + "cpuMs": 8390, + "userMs": 2250, + "systemMs": 6140, + "treePeakRssBytes": 485949440, + "directPeakRssBytes": 475758592 + }, + { + "wallMs": 2223.189458000008, + "cpuMs": 8370, + "userMs": 2200, + "systemMs": 6170, + "treePeakRssBytes": 494141440, + "directPeakRssBytes": 483917824 + }, + { + "wallMs": 2595.494207999989, + "cpuMs": 9210, + "userMs": 2570, + "systemMs": 6640, + "treePeakRssBytes": 487276544, + "directPeakRssBytes": 477052928 + }, + { + "wallMs": 2249.1377090000024, + "cpuMs": 8300, + "userMs": 2230, + "systemMs": 6070, + "treePeakRssBytes": 490668032, + "directPeakRssBytes": 480428032 + }, + { + "wallMs": 2804.832374999998, + "cpuMs": 9690, + "userMs": 2780, + "systemMs": 6910, + "treePeakRssBytes": 488488960, + "directPeakRssBytes": 478101504 + }, + { + "wallMs": 2160.6835409999767, + "cpuMs": 8190, + "userMs": 2130, + "systemMs": 6060, + "treePeakRssBytes": 489553920, + "directPeakRssBytes": 479264768 + }, + { + "wallMs": 2140.4600840000203, + "cpuMs": 8130, + "userMs": 2110, + "systemMs": 6020, + "treePeakRssBytes": 493780992, + "directPeakRssBytes": 483491840 + }, + { + "wallMs": 2213.76449999999, + "cpuMs": 8230, + "userMs": 2190, + "systemMs": 6040, + "treePeakRssBytes": 501235712, + "directPeakRssBytes": 490864640 + } + ], + "candidate": [ + { + "wallMs": 4202.810083999997, + "cpuMs": 12890, + "userMs": 4180, + "systemMs": 8710, + "treePeakRssBytes": 518504448, + "directPeakRssBytes": 508329984 + }, + { + "wallMs": 3526.3294590000005, + "cpuMs": 11380, + "userMs": 3500, + "systemMs": 7880, + "treePeakRssBytes": 524632064, + "directPeakRssBytes": 514473984 + }, + { + "wallMs": 3909.8047500000102, + "cpuMs": 12140, + "userMs": 3880, + "systemMs": 8260, + "treePeakRssBytes": 522731520, + "directPeakRssBytes": 512458752 + }, + { + "wallMs": 3312.964041999978, + "cpuMs": 10850, + "userMs": 3290, + "systemMs": 7560, + "treePeakRssBytes": 531152896, + "directPeakRssBytes": 521027584 + }, + { + "wallMs": 4335.600791000004, + "cpuMs": 13390, + "userMs": 4310, + "systemMs": 9080, + "treePeakRssBytes": 535379968, + "directPeakRssBytes": 529301504 + }, + { + "wallMs": 4122.333416999987, + "cpuMs": 12790, + "userMs": 4090, + "systemMs": 8700, + "treePeakRssBytes": 516423680, + "directPeakRssBytes": 506052608 + }, + { + "wallMs": 3924.252625000023, + "cpuMs": 11820, + "userMs": 3900, + "systemMs": 7920, + "treePeakRssBytes": 534413312, + "directPeakRssBytes": 524189696 + }, + { + "wallMs": 3564.033666000003, + "cpuMs": 11420, + "userMs": 3540, + "systemMs": 7880, + "treePeakRssBytes": 524206080, + "directPeakRssBytes": 518029312 + }, + { + "wallMs": 3372.5224160000216, + "cpuMs": 11020, + "userMs": 3350, + "systemMs": 7670, + "treePeakRssBytes": 516702208, + "directPeakRssBytes": 510443520 + }, + { + "wallMs": 3356.1503750000265, + "cpuMs": 11030, + "userMs": 3330, + "systemMs": 7700, + "treePeakRssBytes": 526221312, + "directPeakRssBytes": 515751936 + } + ] + }, + "summary": { + "control": { + "wallMs": { + "median": 2236.163583500005, + "p95": 2859.8013329999812 + }, + "cpuMs": { + "median": 8335, + "p95": 9750 + }, + "userMs": { + "median": 2215, + "p95": 2830 + }, + "systemMs": { + "median": 6105, + "p95": 6920 + }, + "treePeakRssBytes": { + "median": 492224512, + "p95": 505430016 + }, + "directPeakRssBytes": { + "median": 481959936, + "p95": 495075328 + } + }, + "candidate": { + "wallMs": { + "median": 3736.9192080000066, + "p95": 4335.600791000004 + }, + "cpuMs": { + "median": 11620, + "p95": 13390 + }, + "userMs": { + "median": 3710, + "p95": 4310 + }, + "systemMs": { + "median": 7900, + "p95": 9080 + }, + "treePeakRssBytes": { + "median": 524419072, + "p95": 535379968 + }, + "directPeakRssBytes": { + "median": 515112960, + "p95": 529301504 + } + } + } + } + } +} diff --git a/docs/decisions/oxc-toolchain-migration.md b/docs/decisions/oxc-toolchain-migration.md index 1b2ebb2..c3ebf3a 100644 --- a/docs/decisions/oxc-toolchain-migration.md +++ b/docs/decisions/oxc-toolchain-migration.md @@ -22,3 +22,4 @@ created: 2026-08-15 - 2026-08-15 — sc-1675 packages exact oxlint@1.78.0 and oxfmt@0.63.0 pins behind an opt-in package/standalone capability. devkit oxc resolves those binaries through Devkit's own module graph; init/upgrade/doctor/clean manage a replaceable Oxlint base plus collision-safe consumer-owned root configs. Existing Biome, ESLint topology, tsc, scripts, and hooks remain unchanged until their separate parity tickets satisfy this Target's evidence gates; overlay and self-host activation remain unsupported. - 2026-08-16 — sc-1679 proves Oxfmt 0.63.0 over Devkit's exact 558-file Biome formatting scope. The corrected migration changes seven TypeScript files with formatter-only hunks, is byte-idempotent on pass two, and keeps JSON/JSONC/package ordering stable through explicit overrides. Ten paired samples show the direct pinned binary cuts full-scope median CPU 72.6% (0.8709s to 0.2382s), wall 37.8% (0.1997s to 0.1242s), and process-tree RSS 24.1% (143.7 to 109.1 MiB); a one-file single-thread check-mode proxy cuts CPU 8.1% but increases wall/RSS. Devkit adopts direct Oxfmt for its own formatting, CI, and staged self-host path, retains Biome for lint and consumer configs/hooks, and keeps devkit oxc fmt out of the hot staged path because Node-wrapper startup measured 0.1113s CPU and 137.0 MiB there. - 2026-08-16 — sc-1676 vendors anti-slop commit 446268e5d15baa968eaec669ff65358d36ae6259 with @oxlint/plugins@1.78.0 into the managed Oxc configuration and adds an explicit, deterministic create/check/inspect/prune baseline lifecycle. Normal checks stay read-only and reject only unbaselined error-severity findings; prune can only delete absent debt or reduce duplicate counts. Rule severity and scoped overrides remain native Oxlint config so anti-slop composes with other Oxc rules. +- 2026-08-16 — sc-1681 closes Devkit dogfooding with the mixed ownership boundary recorded in the [assembled benchmark](../benchmarks/experiments/2026-08-16-oxc-devkit-dogfood/README.md). Oxfmt and anti-slop/Oxlint are adopted; Biome lint, ESLint topology, and TypeScript remain because sc-1677, sc-1678, and sc-1680 found concrete diagnostic or semantic gaps despite faster candidates. Devkit now commits its managed Oxc/plugin bytes and 1,677-finding baseline, gates the exact Git index locally, rejects base-to-candidate baseline growth in CI, and checks all managed state through self-host doctor. The measured local agent segment is slightly faster while adding the policy (-3.0% median CPU, -2.7% median process-tree RSS), while full CI is +39.4% median CPU because it deliberately adds anti-slop and typechecks its vendored source. Frink adoption therefore requires its own assembled benchmark; individual microbenchmark speed is not enough to remove an incumbent owner. diff --git a/e2e/anti-slop.e2e.test.mts b/e2e/anti-slop.e2e.test.mts index 2b3ef3a..e3ea9b9 100644 --- a/e2e/anti-slop.e2e.test.mts +++ b/e2e/anti-slop.e2e.test.mts @@ -169,6 +169,68 @@ describe('e2e: packed anti-slop capability', () => { expect(checked.status, out(checked)).toBe(0); }); + it('checks exact staged bytes, rejects growth, and persists Git renames durably', async () => { + const fx = await fixture(); + const packageArgs = INIT_ARGS.filter((argument) => argument !== '--standalone'); + expect(fx.run('devkit', packageArgs).status).toBe(0); + expect(fx.run('devkit', ['anti-slop', 'create']).status).toBe(0); + expect(fx.git('add', '-A').status).toBe(0); + expect(fx.git('commit', '-qm', 'bootstrap').status).toBe(0); + + const staged = join(fx.repoDir, 'staged.ts'); + writeFileSync(staged, 'function staged(value: object) { return value; }\n'); + expect(fx.git('add', 'staged.ts').status).toBe(0); + writeFileSync(staged, 'export const workingTreeIsClean = true;\n'); + const stagedBad = fx.run('devkit', ['anti-slop', 'check', '--staged']); + expect(stagedBad.status, out(stagedBad)).toBe(1); + expect(out(stagedBad)).toContain('anti-slop/no-object-parameters'); + + expect(fx.git('reset', '-q', 'HEAD', '--', 'staged.ts').status).toBe(0); + writeFileSync(staged, 'export const stagedIsClean = true;\n'); + expect(fx.git('add', 'staged.ts').status).toBe(0); + writeFileSync(staged, 'function working(value: object) { return value; }\n'); + const stagedClean = fx.run('devkit', ['anti-slop', 'check', '--staged']); + expect(stagedClean.status, out(stagedClean)).toBe(0); + + expect(fx.git('reset', '-q', 'HEAD', '--', 'staged.ts').status).toBe(0); + rmSync(staged, { force: true }); + writeFileSync(join(fx.repoDir, 'adopted.ts'), 'function adopted(value: object) { return value; }\n'); + expect(fx.run('devkit', ['anti-slop', 'create', '--force']).status).toBe(0); + expect(fx.git('add', 'adopted.ts', '.anti-slop-baseline.json').status).toBe(0); + const laundered = fx.run('devkit', ['anti-slop', 'check', '--staged']); + expect(laundered.status, out(laundered)).toBe(1); + expect(out(laundered)).toContain('BASELINE-GROWTH'); + const ciLaundered = fx.run('devkit', ['anti-slop', 'check', '--base', 'HEAD']); + expect(ciLaundered.status, out(ciLaundered)).toBe(1); + expect(out(ciLaundered)).toContain('BASELINE-GROWTH'); + + const renamed = await fixture(); + expect(renamed.run('devkit', packageArgs).status).toBe(0); + writeFileSync( + join(renamed.repoDir, 'legacy.ts'), + 'function legacy(value: object) { return value; }\n', + ); + expect(renamed.run('devkit', ['anti-slop', 'create']).status).toBe(0); + expect(renamed.git('add', '-A').status).toBe(0); + expect(renamed.git('commit', '-qm', 'adopt legacy debt').status).toBe(0); + expect(renamed.git('mv', 'legacy.ts', 'renamed.ts').status).toBe(0); + const staleRenameCheck = renamed.run('devkit', ['anti-slop', 'check', '--staged']); + expect(staleRenameCheck.status, out(staleRenameCheck)).toBe(1); + expect(out(staleRenameCheck)).toContain('BASELINE-RENAME'); + expect(renamed.run('devkit', ['anti-slop', 'create', '--force']).status).toBe(0); + expect(renamed.git('add', '.anti-slop-baseline.json').status).toBe(0); + const renameCheck = renamed.run('devkit', ['anti-slop', 'check', '--staged']); + expect(renameCheck.status, out(renameCheck)).toBe(0); + const ciRenameCheck = renamed.run('devkit', ['anti-slop', 'check', '--base', 'HEAD']); + expect(ciRenameCheck.status, out(ciRenameCheck)).toBe(0); + expect(renamed.git('commit', '-qm', 'persist renamed debt').status).toBe(0); + expect(renamed.run('devkit', ['anti-slop', 'check']).status).toBe(0); + writeFileSync(join(renamed.repoDir, 'unrelated.ts'), 'export const unrelated = true;\n'); + expect(renamed.git('add', 'unrelated.ts').status).toBe(0); + expect(renamed.run('devkit', ['anti-slop', 'check', '--staged']).status).toBe(0); + expect(renamed.run('devkit', ['anti-slop', 'check', '--base', 'HEAD']).status).toBe(0); + }); + it('vendors all rules and enforces an explicit deterministic shrink-only adoption flow', async () => { const fx = await fixture(); const init = fx.run('devkit', INIT_ARGS); diff --git a/package.json b/package.json index 0bb1108..2341572 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "test:e2e": "vitest run -c vitest.e2e.config.mjs", "playground": "bun scripts/playground.mts", "lint": "biome check --formatter-enabled=false --error-on-warnings .", + "lint:anti-slop": "node cli/index.mts anti-slop check", "lint:structure": "eslint cli gate-engine", "benchmarks:check": "bun gate-engine/eval/cli.mts check", "benchmarks:render": "bun gate-engine/eval/cli.mts render",