Skip to content

ci(repo): detect throwing-stub-with-live-callers anti-pattern #2410

@alexey-pelykh

Description

@alexey-pelykh

Summary

Add a CI-enforced check that fails when any symbol defined as a "stub" (unconditional-throw or silent-neuter return) has live non-test callers. Prevents recurrence of the class documented in #2408 and #2337.

Rationale

Both #2408 (unconditional-throw regression) and #2337 (silent-neuter regressions — Telegram vision, node-host skills, TUI listModels) shipped because:

  • TypeScript accepts never-return functions and empty-return stubs anywhere a compatible signature is expected.
  • Unit tests mock the stub, so the integration-level error is invisible.
  • No lint rule forbids the pattern.

A CI gate closes this hole without relying on reviewer vigilance or memory of the anti-pattern.

Detection scope

Minimum target: (..._args: unknown[]): never { throw ... } with live non-test callers.

Stretch target: silent-neuter forms (=> false, => [], => {}, => undefined) explicitly marked as upstream-compat stubs (e.g., via a // Gutted in RemoteClaw fork comment convention, a @upstream-stub JSDoc tag, or similar).

Implementation options (choose during design phase)

  1. oxlint custom rule — AST-based detection. Check whether the repo's oxlint setup supports custom rules.
  2. Script in scripts/ — invoked from pnpm check or a dedicated pnpm lint:stubs step in CI. Grep for pattern + caller graph, fail on live non-test callers.
  3. Brand-type phantom parameter — give stubs a never-typed phantom parameter callers cannot satisfy. Most invasive; fallback only.

Acceptance criteria

Related

Dependencies

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions