Repository navigation
ever-better@0.4.1
Highlights
Four bug fixes, every one of them found by using the tool rather than reading it — three while writing the article about it, and one by running the whole loop on a fresh clone of debug-js/debug.
The security tier is no longer dropped on browser bundles (#43)
security.configs.recommended was removed entirely for runtime: "browser", on the ground that everything it looks for is Node-side. Two of its rules are not:
detect-object-injectionis the only rule in the whole generated config that sees a lookup answering out of the prototype chain. A key of"constructor"returns an inherited function, theif (!found)guard never fires, and no type objects —Record<string, T>claims that key holds aT. Six of those were found in a browser TypeScript UI, and two more in a 13-year-old JavaScript CLI.- A super-linear regex freezes the tab, not the server.
The plugin now loads everywhere, with the seven genuinely Node-side rules turned off on browser bundles instead. A rule that cannot fire costs nothing; a rule that is missing cost six bugs.
mocha is recognised as a test runner (#43)
detectTestRunner knew only vitest, jest and node:test, so a repository testing with mocha came back "none" — and "none" is what bootstrap installs vitest on. The cost was not a wrong label in a report; it was a second test runner added to a repository that already had one. mocha, ava, tap and jasmine are now detected from dependencies. A bare test script is still not evidence: "test": "echo nope" names no runner.
ever-better strictness no longer appears in the migrate skill (#43)
The skill told the agent to run a command that does not exist, mid-migration. Strictness pricing is something bootstrap already does — it enables each flag in a temporary config extending yours, counts the errors, and reports which it turned on for free and what the rest would cost.
freeze says where the unsuppressable errors are (#43)
Before: WARNING: N errors could not be suppressed and will fail CI. Fix the config before committing. — no rule, no file. These errors have no rule id by definition, so the message sent the reader to the config they had just generated rather than to the file that was failing. Now:
WARNING: 5 error(s) could not be suppressed and will fail CI:
5 (parse error)
Where they are:
src/browser.js:1 /* eslint-env */ comments are no longer supported.
src/browser.js:134 Unused eslint-disable directive (no problems were reported from 'no-return-assign').
src/common.js:205 Unused eslint-disable directive (no problems were reported from 'no-negated-condition').
The sample is capped at three in the formatter, which keeps its output constant-size the way the counts already are.
Also in this release
ever-better next --fan-in (#42)
next ranks the backlog by how much work a rule is; it said nothing about how far that work travels. A no-explicit-any in a module twenty files import changes an exported shape and lands errors in files the diff never opened. The same finding in a leaf is one edit. --fan-in counts importers per row. It is a flag rather than a default because it reads every source file, and it changes no ordering — a widely imported file is only expensive for the rules that move types, and that judgement stays with you.
Skill guidance: what a real drain actually looks like (#43, #44)
ever-better-drain gained the operational half that only shows up on a repository measured in thousands:
- Two bug families worth hunting by hand. The prototype lookup, with a note that the type system endorses it —
Record<string, Thing>saystable[key]is aThing, so the not-found branch is dead code that typechecks. And super-linear regexes, where the rule was measured wrong in both directions. - Leaving
no-explicit-anyoff at the start is sequencing, not surrender. Finding the ten violations that matter inside 1,413 is not a thing anyone does, and every other rule's findings sit underneath it. Clear the mechanical tiers first; taken last it is the largest single reduction available, taken first it is where the effort stops on day one. Whatoffmust not become is the end state. - The largest
anygroup is annotations written over types the library already publishes — delete, do not write. - Directory-level promotion
off → warn → error, because a file list goes stale the moment someone adds a sibling. - Slicing an identical group is for review accuracy, not reviewer capacity. The reviewer is an agent and will read all 167 hunks without complaint; what falls as the diff grows is recall, and in an identical group every hunk looks plausible.
- For a refactor too big to characterise with a handful of tests, keep the old body and diff against it. The old implementation already knows every answer, so make it the oracle. Two things make or break it: the inputs must not be ones you invented, and the old body must be copied rather than delegated to.
docs/RESULTS.md and a report-a-run template (#43)
The bug-yield claim rests on two repositories and both are mine. This says so plainly and asks for rows — numbers only, no source. A run that found zero real bugs is the most useful row that table could get, and the least likely to be volunteered.
Verified
yarn install/typecheck/lint/build/test— green, 270 tests, on Linux, macOS and Windowsclaude plugin validate .passes on both the working tree and a fresh clone ofmain- End-to-end on a fresh clone of debug-js/debug: diagnose → bootstrap → freeze → check, with a new violation producing
exit 1while the existing 72 stayed silent
📦 npm: ever-better@0.4.1
What's Changed
- feat: Vue, React, Next and Nuxt support by @isamu in #1
- fix: ship the ESLint formatter in the npm package by @isamu in #2
- docs: badges, verified publish/install, and the Python assessment by @isamu in #3
- chore: dependabot, duplication and dead-code scans by @isamu in #4
- chore: remove the dead exports knip found by @isamu in #8
- feat: the drain and dry skills — the phases that actually clean up by @isamu in #10
- feat: ever-better-run — the unattended mode, and lead with it by @isamu in #11
- feat: worklist, work log, and a stale-diagnosis warning by @isamu in #12
- fix: keep Prettier off what ever-better generates by @isamu in #13
- feat: measure what is actually enforced, not what the config says by @isamu in #14
- chore(deps): Bump actions/setup-node from 5 to 7 by @dependabot[bot] in #5
- chore(deps): Bump github/codeql-action from 3 to 4 by @dependabot[bot] in #9
- chore(deps): Bump actions/checkout from 5 to 7 by @dependabot[bot] in #6
- chore(deps-dev): Bump @types/node from 24.13.3 to 26.1.2 in the dev group by @dependabot[bot] in #7
- feat: generate the whole four-layer setup, and stop the pinned versions rotting by @isamu in #15
- docs: 0.2.0 — the four layers, the log, and staleness by @isamu in #16
- fix: wire the gate into repos that already have CI by @isamu in #17
- feat: turn on the strictness flags that cost nothing, price the rest by @isamu in #18
- feat: strengthen an ESLint config the repository already wrote by @isamu in #19
- feat: the security and readability tiers, and why no import plugin by @isamu in #20
- feat: ever-better-prepare, and a Codex review workflow in CI by @isamu in #21
- feat: emit-diff — prove a type-only refactor changed nothing by @isamu in #22
- docs: show what you actually end up with, rendered not transcribed by @isamu in #23
- test: the lifecycle end to end, against real ESLint by @isamu in #24
- feat: catalog — the helpers that already exist by @isamu in #25
- docs: 0.3.0 — refresh the handoff and state the target by @isamu in #26
- fix: Prettier was never enforced, and casts had four doors left open by @isamu in #27
- feat: migrate — JavaScript to TypeScript, one file at a time by @isamu in #28
- docs: 0.4.0 — everything from the original scope has shipped by @isamu in #29
- docs: size the two remaining directions and link their issues by @isamu in #32
- docs: move the session's record into the repo by @isamu in #33
- feat: 160-column Prettier template, one-pass JS migration, and the owner's working rules in the skills by @isamu in #34
- feat: var → let → const as a lint rule, and a work log the owner can actually read by @isamu in #35
- docs: make the work log a step in every skill, not only the unattended one by @isamu in #36
- docs: lead with the Claude Code path, not the CLI by @isamu in #37
- feat: rank the drain backlog by leverage, with
ever-better nextby @isamu in #40 - feat:
ever-better next --fan-in— how far a fix in this file reaches by @isamu in #42 - fix: four things writing the article surfaced by @isamu in #43
- docs: for a big refactor, keep the old body and diff against it by @isamu in #44
- ever-better@0.4.1 by @isamu in #45
New Contributors
- @isamu made their first contribution in #1
- @dependabot[bot] made their first contribution in #5
Full Changelog: https://github.com/isamu/ever-better/commits/0.4.1