Skip to content

chore(eslint): enforce kebab-case filenames, purge convention prose#1747

Open
hercemer42 wants to merge 4 commits into
mainfrom
feature/prd-759-lint-rules-agent-nodejs-encode-mechanical-conventions-in
Open

chore(eslint): enforce kebab-case filenames, purge convention prose#1747
hercemer42 wants to merge 4 commits into
mainfrom
feature/prd-759-lint-rules-agent-nodejs-encode-mechanical-conventions-in

Conversation

@hercemer42

@hercemer42 hercemer42 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What

Encodes the one enforceable agent-nodejs convention as an ESLint rule (from the PRD-711 conventions analysis) and drops the unmeasurable clean-code prose from CLAUDE.md.

  • unicorn/filename-caseerror, kebab-case. Prevents a real bug class: macOS (case-insensitive) vs Linux CI (case-sensitive) import-path mismatches. Relaxed via ignore-globs for the generated ANTLR parser (can't rename), snake_case datasource-demo-fintech fixtures, and _-grouped test files — every existing violation is covered, so CI stays green while new violations are blocked.
  • One new devDep, pinned for ESLint 8: eslint-plugin-unicorn@^48.0.1 (later majors require ESLint ≥8.56).
  • CLAUDE.md: purged DRY/KISS/YAGNI, single-responsibility, AAA, pure-functions, comments-why-not-what, descriptive-names — generic prose that carried no repo-specific information.

Why cutting the prose costs the models nothing: CLAUDE.md is injected into every agent session, so each line spends context budget. DRY/KISS/YAGNI/AAA-style advice is the most over-represented guidance in any model's training data — models (and experienced devs) already default to it unprompted, so restating it changes zero behavior. The repo's own measurements confirm the habits hold without the prose (median 8 lines/function, 99.9% of ~46k functions ≤4 params, kebab-case at 846/849). Meanwhile every generic line dilutes the doc's real job: carrying the Forest-specific signal a model can't guess — architecture, workflows, and the conventions the linter actually enforces.

What was considered and dropped

Three advisory rules (max-params: 4, max-lines-per-function: 50, promise/prefer-await-to-then) were measured (46 / 131 / 16 existing src violations) and initially added as warn — then removed: CI has no --max-warnings gate, so a warning nobody fails on is dormant documentation, not enforcement. They can return as error + bulk suppressions after the ESLint 9 upgrade (blocked today by airbnb-config deprecation, separate ticket). max-lines-per-function is the least likely to return as-is: the length distribution is bimodal (median 8, but a legitimate tail of long-declarative route handlers and decorator wiring), so a blunt line count can't separate justified outliers from real smells — that's per-function judgment, which belongs in the conventions corpus, not lint.

Notes for reviewer

  • Config + docs only — no production code touched.
  • Local lint on an unbuilt worktree shows 4 pre-existing @typescript-eslint/no-throw-literal errors in agent/src/routes/.../action-authorization.ts; this is a type-resolution artifact of the unbuilt tree (CI builds before linting and is clean). Unrelated to this change.

Refs PRD-759

Note

Enforce kebab-case filenames via eslint-plugin-unicorn and trim CLAUDE.md conventions

  • Adds eslint-plugin-unicorn and enables the unicorn/filename-case rule (kebab-case) in .eslintrc.js, with overrides disabling it for generated ANTLR parser files, demo fixture packages, and test directories.
  • Removes prescriptive prose from CLAUDE.md (DRY/KISS/YAGNI, naming, size, parameter, and AAA test bullets), replacing it with a note that ESLint owns mechanical rules and the remaining points are judgment calls.

Macroscope summarized 99443ce.

Add unicorn/filename-case (error, kebab-case) to catch macOS/Linux import
casing mismatches, plus max-params, max-lines-per-function and
promise/prefer-await-to-then as warnings. Relax filename-case for the
generated ANTLR parser, snake_case demo fixtures and _-grouped tests, and
scope max-lines-per-function to src. Drop the now-linted and unmeasurable
clean-code prose from CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Jul 9, 2026

Copy link
Copy Markdown

PRD-759

@qltysh

qltysh Bot commented Jul 9, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

This PR will not change total coverage.

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

Count only code lines so the length smell reflects logic, not comments or
spacing. Non-blocking (warn); resolves the validator's preferential note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hercemer42

hercemer42 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Claude Fable 5 (claude-fable-5) — review + scope history

  1. A /validator pending review found one Preferential issue (max-lines-per-function counted comment/blank lines); fixed in 29e9691d.
  2. Scope was then cut in 84fa5312: all three advisory warn rules (max-params, max-lines-per-function, promise/prefer-await-to-then) removed — CI has no --max-warnings gate, so ungated warnings are dormant documentation, not enforcement. The pending review was discarded as moot (its finding anchored to a removed rule).

Final scope: unicorn/filename-case (error, kebab-case, ignore-globs for generated parser / demo fixtures / tests) + the CLAUDE.md prose purge. See the PR description.

CI note: the workflow-executor test failure (AI payload bounding (HasMany)) is pre-existing on main — the run for b4e7fcd2 (this branch's fork point) fails the same job. The three "failed" datasource jobs are fail-fast cancellations; every lint step that ran on this PR passed.

Warnings CI never gates on are dormant documentation, not enforcement.
Keep the one rule with teeth (kebab-case filenames, blocks macOS/Linux
import-casing bugs) and drop max-params, max-lines-per-function and
promise/prefer-await-to-then along with the now-unused promise plugin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hercemer42 hercemer42 changed the title chore(eslint): encode mechanical conventions as lint rules chore(eslint): enforce kebab-case filenames, purge convention prose Jul 10, 2026
Comment thread CLAUDE.md Outdated
Comment thread CLAUDE.md
Comment thread CLAUDE.md
Comment thread CLAUDE.md
Only file naming, formatting and unused-variable checks live in ESLint;
the deleted principles were removed as generic prose, not migrated. Also
drop the unused-variables checklist item — the linter already errors on it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hercemer42
hercemer42 marked this pull request as ready for review July 10, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant