8000 Four issues reported against 1.4.0rc2 by devill · Pull Request #144 · habit-hooks/habit-hooks · GitHub
[go: up one dir, main page]

Skip to content

Four issues reported against 1.4.0rc2 - #144

Merged
devill merged 9 commits into
mainfrom
windows-hardening
Aug 21, 2026
Merged

devill merged 9 commits into
mainfrom
windows-hardening

Conversation

@devill
@devill devill commented Aug 21, 2026
Copy link
Copy Markdown
Collaborator

Draft, opened to run CI on the Windows leg before tagging v1.4.0rc3.

Fixes #142, #140, #143, plus a [runners] traceback and two false cleans found on the way.

Local: 956 passed, 2 skipped, ruff clean, uv run habit-hooks --all exit 0.

Opened by Claude on Ivett's behalf, while she is away.

devill added 9 commits August 21, 2026 17:50
The quoted diagnosis was capped at twenty lines and no bytes at all, and
`eslint -f json` is one line however many megabytes it holds — so a sensor
that died mid-report put the whole report into a notice habit-hooks writes
into a coding agent's context. Measured at two million characters.

Both ends of a long line survive, by the same economy the line budget already
used: cut only when the cut is shorter, which is also what keeps the elision
from ever reading `1 characters omitted`. The lines that survive are chosen
before any of them is cut, so bounding megabytes no longer costs a second
copy of them.
Routing a smell to an executable guide and naming a command that is not there
printed a Python stack trace: `cli.run_console` catches `ToolError` and this
spawn raised `FileNotFoundError`. It is the same first-contact mistake #114
answered for a missing sensor tool, a mistyped config and a bare `--help`, in
the one place that sweep did not reach.

The guide is named beside the command, because a project routes a smell to a
runner by the guide's extension — so which file asked for this is the
reader's next question.
…aller's

Node caps a captured stream at 1 MB unless told otherwise. `project_tool.run`
never told it otherwise, so a bigger report came back with no exit status, a
truncated stdout and an empty stderr — and `eslint.cjs` forwarded the empty
stderr. The whole notice was a command line with nothing under it (#142).
Around a hundred files with findings is enough, on any platform.

knip carried both guards at its own call site and eslint carried neither,
which is the actual defect: two callers, one question, no shared answer. The
seam now owns all of it — no output ceiling, one predicate for "this run
produced nothing worth reading", and a complaint that cannot be empty. What a
tool half-wrote to stdout is never the complaint: it is a report cut off
mid-write, not a diagnosis.
It asks a project to install eslint, knip, ts-morph, jscpd and the two
@typescript-eslint packages, and then reported every one of them as declared
and imported nowhere (#143). It was complaining about its own footprint.

The shipped knip config overlooks them; a project with its own knip config is
untouched, as it is for every other setting. The list is derived from each
plugin's declared detectors and from what the shipped eslint config resolves,
so a plugin that grows a Node tool cannot quietly bring the bug back.

knip spells a column `col`; the sensor contract spells it `column`, and a
field name is vocabulary like any other.
Two sensors can mean one smell — eslint's `max-lines` and the line counter
both mean `oversized-file` — and one sensor can report a smell many times
over, as jscpd does per clone. The mapper printed a block per finding, so
each of those was another copy of the same two hundred words (#140).

Findings that resolve to the same guide are one finding. The guide, not the
smell name: a repo holding Python and TypeScript has two `high-complexity`
guides, and collapsing them would coach a .ts file in Python. Severity is per
smell, so the smell stays in the key too — keyed on the guide alone a
suggested finding could absorb an enforced one and lower the exit code.

A sensor's own issue list is never thinned. Two variables declared on one
line are two things to fix, and pmd, phpmd and the comment sensor all name a
line without a column, so only the sensor can tell them apart.
Every git-derived mode asked git and so had never seen a build artifact;
`--all` walked the tree and measured whatever it found. One project, two
universes: the monorepo in #142 held 321 tracked .ts/.tsx and 843 on disk,
and its owner had to write `!**/dist/**` into `[files]` before a run was
usable. A default somebody has to patch is the wrong default.

A project git cannot answer for still measures the disk — outside a
repository, with no git installed, on any failure, and when the project is
itself ignored by the repository around it. Git saying nothing is never read
as nothing to scan.

A submodule leaves the scope, as it always did from every git mode, and now
says so rather than shrinking the scan in silence.
Both found the hard way today. Two suites keep working state inside the
checkout rather than in a temp directory, so a second concurrent pytest walks
into the middle of the first one's run and both go red for no reason.

And `GIT_CEILING_DIRECTORIES` is not the guard a scratch fixture needs: it
stops git walking up to find a repository, which a script already standing in
this one never needs it to. A multi-line command whose first line is `&&`-
guarded and whose third is not put 45 files of four agents' work into a commit
titled `init`.
Four issues reported against rc2, none of them a Windows bug: a sensor that
died without a word when its tool printed more than a megabyte (#142), a smell
coached once per sensor that saw it (#140), habit-hooks reporting its own tools
as unused dependencies (#143), and a whole-project scan that measured build
artifacts every git-derived mode had never seen (#142 again).

A release candidate does not move the minor, so only the six version lines
move; the plugin floors are minor-grained and already satisfied.
Windows has no signals: `process.kill(pid, "SIGKILL")` there is
`TerminateProcess(handle, 1)`, so a tool killed halfway through writing its
report exits 1 — which is exactly what eslint and knip exit when they found
something to report. Nothing upstream can tell the two apart, so the half-
written array reached `JSON.parse` and both sensors answered a reader with a
`SyntaxError` and four frames of Node.

Reading a tool's report is the seam's question for the same reason running it
and describing its failure already were: both callers need the same answer, and
the last time one of them was left to decide for itself was #142. A run that
printed plenty and left nothing usable says so, rather than borrowing the words
for one that said nothing at all.

The test that found this now asserts both platforms rather than the one the
author's machine could produce.
@devill
devill merged commit 3d7080a into main Aug 21, 2026
3 checks passed
@devill
devill deleted the windows-hardening branch August 21, 2026 17:16
@devill
devill deployed to pypi-java August 21, 2026 17:16 — with GitHub Actions Active
@devill
devill deployed to pypi-php August 21, 2026 17:16 — with GitHub Actions Active
@devill
devill deployed to pypi-typescript August 21, 2026 17:16 — with GitHub Actions Active
@devill
devill deployed to pypi-generic August 21, 2026 17:16 — with GitHub Actions Active
@devill
devill deployed to pypi-python August 21, 2026 17:16 — with GitHub Actions Active

This branch was successfully deployed

6 active deployments
pypi-java — 3d7080ad Deployed Aug 21, 2026 by devill via publish (habit_hooks_java, pypi-java) #15
pypi-php — 3d7080ad Deployed Aug 21, 2026 by devill via publish (habit_hooks_php, pypi-php) #15
pypi-typescript — 3d7080ad Deployed Aug 21, 2026 by devill via publish (habit_hooks_typescript, pypi-typescript) #15
pypi — 3d7080ad Deployed Aug 21, 2026 by devill via publish (habit_hooks, pypi) #15
pypi-generic — 3d7080ad Deployed Aug 21, 2026 by devill via publish (habit_hooks_generic, pypi-generic) #15
pypi-python — 3d7080ad Deployed Aug 21, 2026 by devill via publish (habit_hooks_python, pypi-python) #15
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.

eslint sensor fails on --all: file list exceeds the Windows argv limit

1 participant

0