REPO_POLICIES.md binds this repo to a JS styleguide ("Use const for everything... Never use var"), but nothing checks it. script/fmt-check is gofmt -s -l . only, and script/lint is golangci-lint — both Go-only. static/js/app.js is covered by no tooling at all.
This is not hypothetical: the review of #116 failed on five var declarations in static/js/app.js that a fully green make check and a cache-defeated script/cibuild both passed. The gate cannot see the file.
The JS surface here is small, which is the argument for fixing it now while it is cheap rather than after it grows.
Definition of done
A linter covers static/js/ and runs as part of script/lint, so make check and CI both fail on a styleguide violation.
It runs in Docker, consistent with #109's direction for lint tooling, and is pinned by digest per repo policy — not installed ad hoc on the host.
Acceptance check: reintroducing a var in static/js/app.js makes the gate go red. Without that demonstration the fix is unverified.
Implementation notes
Whatever tool is chosen should be configured to the styleguide REPO_POLICIES.md names, not to its own defaults.
Consider whether the existing lint container can host it rather than adding a second image.
Branch from next, PR based on next, single commit, title ending (closes #N).
`REPO_POLICIES.md` binds this repo to a JS styleguide ("Use `const` for everything... Never use `var`"), but nothing checks it. `script/fmt-check` is `gofmt -s -l .` only, and `script/lint` is golangci-lint — both Go-only. `static/js/app.js` is covered by no tooling at all.
This is not hypothetical: the review of https://git.eeqj.de/sneak/webhooker/pulls/116 failed on five `var` declarations in `static/js/app.js` that a fully green `make check` and a cache-defeated `script/cibuild` both passed. The gate cannot see the file.
The JS surface here is small, which is the argument for fixing it now while it is cheap rather than after it grows.
## Definition of done
- A linter covers `static/js/` and runs as part of `script/lint`, so `make check` and CI both fail on a styleguide violation.
- It runs in Docker, consistent with https://git.eeqj.de/sneak/webhooker/issues/109's direction for lint tooling, and is pinned by digest per repo policy — not installed ad hoc on the host.
- Acceptance check: reintroducing a `var` in `static/js/app.js` makes the gate go red. Without that demonstration the fix is unverified.
## Implementation notes
- Whatever tool is chosen should be configured to the styleguide `REPO_POLICIES.md` names, not to its own defaults.
- Consider whether the existing lint container can host it rather than adding a second image.
- Branch from `next`, PR based on `next`, single commit, title ending ` (closes #N)`.
ESLint, at a pinned version from a committed package.json and lockfile, lints static/js/ (not the vendored Alpine.js). It runs only in Docker like the Go linter: a stage on a node image pinned by digest, reusing one the repo already pins if it has one. script/lint runs it, so make lint and make check fail on a violation, and a run counts as a pass only when the linter's own output shows it ran, as script/lint already requires of the Go linter.
The config states the rules of the JavaScript styleguide REPO_POLICIES.md links to, each one it can check (for example no-var, prefer-const), not ESLint's defaults alone.
Any violation already in static/js/app.js is fixed in the same change.
Acceptance: a var put back into static/js/app.js turns make check red; the PR says in one line that this was tried.
Model: opus-5-5
Plan.
- ESLint, at a pinned version from a committed `package.json` and lockfile, lints `static/js/` (not the vendored Alpine.js). It runs only in Docker like the Go linter: a stage on a node image pinned by digest, reusing one the repo already pins if it has one. `script/lint` runs it, so `make lint` and `make check` fail on a violation, and a run counts as a pass only when the linter's own output shows it ran, as `script/lint` already requires of the Go linter.
- The config states the rules of the JavaScript styleguide `REPO_POLICIES.md` links to, each one it can check (for example `no-var`, `prefer-const`), not ESLint's defaults alone.
- Any violation already in `static/js/app.js` is fixed in the same change.
- Acceptance: a `var` put back into `static/js/app.js` turns `make check` red; the PR says in one line that this was tried.
Model: opus-5-5
Done in #486. ESLint, pinned by package.json and yarn.lock, now lints static/js/ in a js-lint stage of the Dockerfile on the digest-pinned node 24 LTS image. script/lint builds that stage, and the image build depends on it. eslint.config.mjs turns on the styleguide's two checkable rules, no-var and prefer-const. static/js/app.js already complied.
Deviation from the plan: script/lint does not look for ESLint's output, because ESLint prints nothing on a pass. It names the stage once for both --target and --no-cache-filter, so a renamed stage fails the build rather than replaying a cached pass.
Judgement call: one stage, so every make lint downloads ESLint again (hash-checked).
Not covered: the styleguide's prettier rule, a formatter's job (#215).
Tried: a var in static/js/app.js turns make check red.
Model: opus-5-5
Done in https://git.eeqj.de/sneak/webhooker/pulls/486. ESLint, pinned by `package.json` and `yarn.lock`, now lints `static/js/` in a `js-lint` stage of the `Dockerfile` on the digest-pinned node 24 LTS image. `script/lint` builds that stage, and the image build depends on it. `eslint.config.mjs` turns on the styleguide's two checkable rules, `no-var` and `prefer-const`. `static/js/app.js` already complied.
- Deviation from the plan: `script/lint` does not look for ESLint's output, because ESLint prints nothing on a pass. It names the stage once for both `--target` and `--no-cache-filter`, so a renamed stage fails the build rather than replaying a cached pass.
- Judgement call: one stage, so every `make lint` downloads ESLint again (hash-checked).
- Not covered: the styleguide's prettier rule, a formatter's job (https://git.eeqj.de/sneak/webhooker/issues/215).
- Tried: a `var` in `static/js/app.js` turns `make check` red.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
REPO_POLICIES.mdbinds this repo to a JS styleguide ("Useconstfor everything... Never usevar"), but nothing checks it.script/fmt-checkisgofmt -s -l .only, andscript/lintis golangci-lint — both Go-only.static/js/app.jsis covered by no tooling at all.This is not hypothetical: the review of #116 failed on five
vardeclarations instatic/js/app.jsthat a fully greenmake checkand a cache-defeatedscript/cibuildboth passed. The gate cannot see the file.The JS surface here is small, which is the argument for fixing it now while it is cheap rather than after it grows.
Definition of done
static/js/and runs as part ofscript/lint, somake checkand CI both fail on a styleguide violation.varinstatic/js/app.jsmakes the gate go red. Without that demonstration the fix is unverified.Implementation notes
REPO_POLICIES.mdnames, not to its own defaults.next, PR based onnext, single commit, title ending(closes #N).Plan.
package.jsonand lockfile, lintsstatic/js/(not the vendored Alpine.js). It runs only in Docker like the Go linter: a stage on a node image pinned by digest, reusing one the repo already pins if it has one.script/lintruns it, somake lintandmake checkfail on a violation, and a run counts as a pass only when the linter's own output shows it ran, asscript/lintalready requires of the Go linter.REPO_POLICIES.mdlinks to, each one it can check (for exampleno-var,prefer-const), not ESLint's defaults alone.static/js/app.jsis fixed in the same change.varput back intostatic/js/app.jsturnsmake checkred; the PR says in one line that this was tried.Model: opus-5-5
Done in #486. ESLint, pinned by
package.jsonandyarn.lock, now lintsstatic/js/in ajs-lintstage of theDockerfileon the digest-pinned node 24 LTS image.script/lintbuilds that stage, and the image build depends on it.eslint.config.mjsturns on the styleguide's two checkable rules,no-varandprefer-const.static/js/app.jsalready complied.script/lintdoes not look for ESLint's output, because ESLint prints nothing on a pass. It names the stage once for both--targetand--no-cache-filter, so a renamed stage fails the build rather than replaying a cached pass.make lintdownloads ESLint again (hash-checked).varinstatic/js/app.jsturnsmake checkred.Model: opus-5-5