linting and formatting
why
- reviewer attention is the scarce resource a review spends.
- unowned formatting puts mechanical noise in every diff — reviewers fight it line-by-line or learn to ignore it; ignoring eventually hides real defects.
- package-owned mechanical gates keep style out of human review, so remaining human signal is behavior.
- separate owned format/lint commands make each failure tell the repair loop exactly which loop to run.
rule
- formatting and linting are compulsory quality gates: code works only when it behaves correctly and follows one consistent project style, so reviewers focus on changed behavior, not formatting noise.
- formatting = mechanical presentation; linting = correctness, stable boundaries, durable source conventions.
- keep their ownership and failure messages separate so each signal tells the repair loop what to do.
formatting
- each package owns a
formatcheck and an explicitformat:fixcommand. - one formatter configuration for authored files in that package.
- format only files the formatter owns; never format generated output, applied migrations, or protected files.
- inspect the focused diff after a formatter writes, especially in a concurrent working tree.
linting
- each package owns a
lintcheck for the language and framework it runs. - enforce structural facts statically when objective: forbidden import direction, generated-output edits, generic filenames, aliasing, component placement.
- judgement calls that are not mechanically provable go to a design review rule; no opaque lint heuristics for taste.
- suppression is narrow, documented, temporary; removed with the underlying cause.
workspace execution
- root Turbo tasks coordinate package-local
format,lint,typecheck. - run the narrow package check while iterating; run the relevant workspace pipeline before claiming shared readiness.
- a lint or formatting failure blocks handoff until the responsible source or configuration is corrected.
choose enforcement by proof strength
| rule kind | enforcement | reason |
|---|---|---|
| syntax, formatting, import direction, generated-file ownership | formatter/linter/static check | objective source fact with deterministic detection. |
| type compatibility or public contract | typecheck/generation | compiler/generator owns the proof. |
| runtime/user-visible behavior | focused test, smoke path, or UAT | static analysis cannot observe the outcome. |
| ownership judgement or visual coherence | documented review question | a heuristic would produce false authority and encourage bypasses. |
repair loop
- read the exact tool output; identify the owning file/configuration.
- make the narrowest source correction; rerun the same narrow command.
- no global disables, exclusions, or formatter overrides to make unrelated violations disappear.
- broaden from package check to workspace graph only after the local failure is understood and repaired.
verification
- the command runs from the package that owns the files.
- the failure points at a real source/configuration boundary.
- a suppression — if truly unavoidable — names its reason, scope, owner, and removal condition.
- inspect the formatter diff separately from behavior changes.
good and bad
bad
eslint . --rule "no-restricted-imports: off" # global disable
- a global disable makes unrelated violations disappear; the failure message can no longer tell the repair loop what to fix.
- the enforced rule — import direction, generated-file ownership, naming — stops being checked anywhere in that run; violations accumulate silently behind the disable.
- the next reader inherits both the defects and the habit of switching rules off to make output green.
good
pnpm --filter @app/web lint # package-owned check failspnpm --filter @app/web lint # rerun the same command after the narrow fix
- each package owns its lint gate; the narrowest source correction repairs the failure and the same command proves it.
- reviews stay free of mechanical noise — human attention spends only on behavior.
- structural conventions are enforced deterministically on every run, not by a reviewer remembering them.
- the gate stays cheap enough to run continuously, which keeps drift from compounding between checks.
do not
- treat a formatter pass as proof of correctness.
- hide lint violations with broad disable directives or configuration excludes.
- use a root script to reach into package files without that package owning the command.