ADR-0006: Removing the lint step rather than faking it

Edit this page

Status: Superseded by ADR-0008 Date: 2026-08-14

Context

The first time CI ran against a fully populated repository, the TypeScript job failed at pnpm lint. The cause was not a lint violation.

The workspace has no ESLint configuration of any kind — no eslint.config.js, no .eslintrc.*, and neither eslint nor eslint-config-next in any package.json. Both applications declared "lint": "next lint", and two packages declared "lint": "eslint src".

With no configuration present, next lint does not fail — it opens its interactive setup prompt, "How would you like to configure ESLint?". CI has no terminal to answer, so the process cancelled and exited non-zero. The bare eslint src invocations aborted with the ESLint 9 flat-config migration notice.

The important part: this had been true since the workflow was written. The lint step had never linted a single file. make lint advertised "eslint + golangci-lint + squawk" and delivered none of the first.

The obvious fix — add eslint, eslint-config-next and a flat config — was not available in the session that found this. Adding a dependency requires regenerating pnpm-lock.yaml, and CI installs with --frozen-lockfile; a manifest edit without a matching lockfile update breaks every job. The environment that discovered the problem could not run pnpm install.

Decision

Remove the lint step from CI and delete the phantom lint scripts, rather than leave a step that appears to enforce something it does not.

Concretely: pnpm lint is gone from the TypeScript job, with a comment explaining why; "lint": "eslint src" is removed from packages/contracts and packages/shared, since turbo skips packages that do not define a task. CONTRIBUTING and the changelog both state that no JavaScript or TypeScript linter currently runs.

Restoring it is tracked as a Next item on the roadmap. The work is: add eslint and eslint-config-next, write a flat eslint.config.mjs, fix whatever it finds on first run, and restore the CI step.

Alternatives considered

Mark the step continue-on-error: true. Rejected, firmly. This is the same pattern as the "Skip if Dockerfile missing" step that let the release pipeline report success while publishing nothing for two of three images. A green check that means nothing is worse than a missing check, because it actively misleads.

Replace the script with prettier --check. Considered. Prettier is already a root dependency, so this would have been a real check with no new dependency. Rejected because it could not be verified in the environment that made the change — if the repository is not already prettier-clean, the job turns red for a formatting reason unrelated to the problem being fixed, and we would be trading one broken job for another.

Add ESLint anyway and hope the lockfile resolves in CI. Rejected. It would have broken pnpm install --frozen-lockfile for every job in the workflow, turning one failing step into a completely red pipeline.

Leave it failing until someone fixes it properly. Rejected. The repository was about to be published. A permanently red badge on a security tool's front page is a worse first impression than an honestly narrower set of checks.

Consequences

Accepted costs.

  • No JavaScript or TypeScript linting runs. Unused imports, shadowed variables, accessibility problems in JSX and React hook mistakes will not be caught mechanically until this is reversed.
  • make lint now overstates what it does for the TypeScript half, until the restoration lands.

Mitigations already in place.

  • TypeScript runs in strict mode and tsc --noEmit covers all four packages in CI, catching the largest class of errors a linter would.
  • The codebase contains zero any, zero @ts-ignore and zero eslint-disable — so there is no accumulated suppression debt for a future linter to fight through.
  • gofmt, go vet and golangci-lint still cover the Go services, and squawk covers migrations.

Gains.

  • CI is honest. Every remaining check does what its name says.
  • The state is documented in three places a contributor will look — CONTRIBUTING, the changelog and the roadmap — rather than being a surprise.

Reversal criteria met. eslint.config.mjs exists, the dependencies are in the lockfile, and the CI step is restored and passing. See ADR-0008.