From fc6f1e1da2e504c45556a20cd9d65a189cce29a1 Mon Sep 17 00:00:00 2001 From: Jonathan Roemer Date: Sat, 29 Aug 2026 05:50:04 -0500 Subject: [PATCH 1/9] Add super-linter Same configuration as the other repos: super-linter v8 pinned to a commit SHA, least-privilege permissions, and a checkout that does not persist the job token. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ozRgn6mdQHtjoWbGfDWw2 --- .github/workflows/linter.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/linter.yml diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..7780d53 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,35 @@ +--- +name: Lint + +on: # yamllint disable-line rule:truthy + push: + pull_request: + +permissions: {} + +jobs: + build: + name: Lint + runs-on: ubuntu-latest + + permissions: + contents: read + packages: read + statuses: write + + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # zizmor/artipacked: keep the token out of .git/config; this job + # only reads the tree, it never pushes. + persist-credentials: false + # super-linter diffs against the base, so it needs full history. + fetch-depth: 0 + + - name: Super-linter + uses: super-linter/super-linter@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 + env: + VALIDATE_ALL_CODEBASE: true + DEFAULT_BRANCH: main + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From cfd45f0e31f6a819d74368c877fe3b77872ed88d Mon Sep 17 00:00:00 2001 From: Jonathan Roemer Date: Sat, 29 Aug 2026 06:03:30 -0500 Subject: [PATCH 2/9] Apply the mechanical lint fixes persist-credentials: false on checkout steps that only read the tree, which is zizmor's artipacked finding. Workflows that push keep the credential. prettier --write over the file types super-linter's *_PRETTIER linters cover. Formatting only, no content changes. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ozRgn6mdQHtjoWbGfDWw2 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 42e7d43..6ac089c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # strangerduino + Stranger Things Christmas Lights Communicator ## Description + Built for a family member's Halloween display, this allows for displaying arbitrary "words" as highlighted by an appropriately numbered LED light, as well as a randomized "Christmas" mode. This assumes a LED light string supported by the [FastLED](https://fastled.io/) library. From ca425bc148205f8ebfe81ee90cda3aea2d7363ac Mon Sep 17 00:00:00 2001 From: Jonathan Roemer Date: Sat, 29 Aug 2026 07:30:35 -0500 Subject: [PATCH 3/9] Disable NATURAL_LANGUAGE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Its terminology rules fight the prose in these repos more than they help — the false positives outnumber the real findings. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ozRgn6mdQHtjoWbGfDWw2 --- .github/workflows/linter.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 7780d53..547516e 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -32,4 +32,6 @@ jobs: env: VALIDATE_ALL_CODEBASE: true DEFAULT_BRANCH: main + # Terminology rules fight the prose in these repos more than they help. + VALIDATE_NATURAL_LANGUAGE: false GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 90701fd7840aad4fccbf2c748c3660a78a70d7ea Mon Sep 17 00:00:00 2001 From: Jonathan Roemer Date: Sat, 29 Aug 2026 09:40:18 -0500 Subject: [PATCH 4/9] Disable JSCPD and configure codespell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JSCPD flags intentional repetition — generated files and repeated markup — far more often than real duplication, so it is off. codespell stays on for real typos, but skips binaries and lockfiles (it was reading PDFs as text) and ignores four words it gets wrong: coo, pres, unparseable, and lifes ('still lifes' is the Game of Life term of art). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ozRgn6mdQHtjoWbGfDWw2 --- .github/linters/.codespellrc | 9 +++++++++ .github/workflows/linter.yml | 3 +++ 2 files changed, 12 insertions(+) create mode 100644 .github/linters/.codespellrc diff --git a/.github/linters/.codespellrc b/.github/linters/.codespellrc new file mode 100644 index 0000000..71bf6b5 --- /dev/null +++ b/.github/linters/.codespellrc @@ -0,0 +1,9 @@ +[codespell] +# Binary and generated files produce nothing but noise: codespell reads PDFs +# as text and lockfiles are full of package names that look like typos. +skip = *.pdf,*.lock,*.min.js,*.min.css,*.svg,*.png,*.jpg,*.ico,./node_modules,./.git,./dist,./build,pnpm-lock.yaml,package-lock.json,uv.lock,go.sum +# coo — Chief Operating Officer +# pres — slide/presentation identifier, not "press" +# unparseable— an accepted spelling +# lifes — "still lifes" is the Conway's Game of Life term of art +ignore-words-list = coo,pres,unparseable,lifes diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 547516e..44f1ecc 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -34,4 +34,7 @@ jobs: DEFAULT_BRANCH: main # Terminology rules fight the prose in these repos more than they help. VALIDATE_NATURAL_LANGUAGE: false + # Flags intentional repetition (generated files, repeated markup) far more + # often than real duplication. + VALIDATE_JSCPD: false GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 8a9496c8b96a76b063c7a4eaeb439aafb581a1d6 Mon Sep 17 00:00:00 2001 From: Jonathan Roemer Date: Sat, 29 Aug 2026 09:54:09 -0500 Subject: [PATCH 5/9] Disable BIOME_FORMAT; prettier is the formatter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit super-linter runs BIOME_FORMAT and the *_PRETTIER linters over the same files, but biome indents with tabs and prettier with spaces, so no formatting can satisfy both. prettier wins because it covers markdown, html, css, yaml and json as well. BIOME_LINT is unaffected — it is a linter, not a formatter. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ozRgn6mdQHtjoWbGfDWw2 --- .github/workflows/linter.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 44f1ecc..c937ea6 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -37,4 +37,8 @@ jobs: # Flags intentional repetition (generated files, repeated markup) far more # often than real duplication. VALIDATE_JSCPD: false + # biome and prettier disagree on indentation (tabs vs spaces) and both + # run on the same files, so no formatting satisfies both. prettier wins + # here because it covers more file types; BIOME_LINT stays on. + VALIDATE_BIOME_FORMAT: false GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 051682cf4c3f7310b877e3eff5c02f31b18af8e7 Mon Sep 17 00:00:00 2001 From: Jonathan Roemer Date: Sat, 29 Aug 2026 19:12:10 -0500 Subject: [PATCH 6/9] Disable stylelint; format with super-linter's tool versions biome and stylelint both lint CSS with different opinions. biome is the more widely used and also covers js/ts, so stylelint is the one dropped. The formatters are re-run pinned to the versions super-linter actually ships (ruff 0.15.17, black 26.5.1, isort 8.0.1, prettier 3.8.4). Running newer local versions produced formatting CI then rejected. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ozRgn6mdQHtjoWbGfDWw2 --- .github/workflows/linter.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index c937ea6..9d6cdc4 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -41,4 +41,7 @@ jobs: # run on the same files, so no formatting satisfies both. prettier wins # here because it covers more file types; BIOME_LINT stays on. VALIDATE_BIOME_FORMAT: false + # stylelint and biome both lint CSS with different opinions. biome is the + # more widely used of the two and also covers js/ts, so it is the one kept. + VALIDATE_CSS: false GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From b95bd2f0926a506110323a4a37449675b646378d Mon Sep 17 00:00:00 2001 From: Jonathan Roemer Date: Sat, 29 Aug 2026 19:23:05 -0500 Subject: [PATCH 7/9] Let ruff format be the Python formatter black and ruff format both run in CI and disagree on assert-message wrapping, which no config setting reconciles. ruff is far more widely used, its formatter is >99.9% black-compatible, and it also covers what isort and flake8 do, so black is the one dropped. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ozRgn6mdQHtjoWbGfDWw2 --- .github/workflows/linter.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 9d6cdc4..a699516 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -44,4 +44,8 @@ jobs: # stylelint and biome both lint CSS with different opinions. biome is the # more widely used of the two and also covers js/ts, so it is the one kept. VALIDATE_CSS: false + # black and ruff format disagree on assert-message wrapping, and both + # run here. ruff is the more widely used of the two and its formatter + # is >99.9% black-compatible, so ruff format is the authority. + VALIDATE_PYTHON_BLACK: false GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 0a51de8273747f4cd36fdec305c3a433c65546f6 Mon Sep 17 00:00:00 2001 From: Jonathan Roemer Date: Mon, 31 Aug 2026 06:15:37 -0500 Subject: [PATCH 8/9] Configure markdownlint, pylint and golangci Turns off the rules that fire on correct patterns in this codebase rather than on defects, each annotated with why. Rules that find real problems - MD025, MD040, the biome correctness set, mypy - stay on. pylint's max-line-length is aligned to the ruff config so the two tools cannot drift apart. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ozRgn6mdQHtjoWbGfDWw2 --- .github/linters/.markdown-lint.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/linters/.markdown-lint.yml diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml new file mode 100644 index 0000000..9df650b --- /dev/null +++ b/.github/linters/.markdown-lint.yml @@ -0,0 +1,6 @@ +--- +# Hard-wrapping prose at a fixed column is a style most markdown tooling has +# moved on from. +MD013: false +# A README that opens with a sentence rather than a title is fine. +MD041: false From c2c0e520965ee1681a7d48394289cc425310a1c7 Mon Sep 17 00:00:00 2001 From: Jonathan Roemer Date: Mon, 31 Aug 2026 19:45:39 -0500 Subject: [PATCH 9/9] Configure htmlhint and JSON linting; ignore E722 on the MagTag htmlhint keeps its standard checks but drops doctype-first (Jinja partials are fragments) and id-class-value (camelCase ids are standard in JS-driven pages, and these are queried by name from script). super-linter warns that biome and eslint both lint JSON and may conflict; biome is kept, matching the call already made for CSS. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ozRgn6mdQHtjoWbGfDWw2 --- .github/linters/.htmlhintrc | 14 ++++++++++++++ .github/workflows/linter.yml | 4 ++++ 2 files changed, 18 insertions(+) create mode 100644 .github/linters/.htmlhintrc diff --git a/.github/linters/.htmlhintrc b/.github/linters/.htmlhintrc new file mode 100644 index 0000000..5b656e9 --- /dev/null +++ b/.github/linters/.htmlhintrc @@ -0,0 +1,14 @@ +{ + "tagname-lowercase": true, + "attr-lowercase": true, + "attr-value-double-quotes": true, + "tag-pair": true, + "spec-char-escape": true, + "id-unique": true, + "src-not-empty": true, + "attr-no-duplication": true, + "title-require": true, + "_comment": "doctype-first is off because Jinja partials are fragments, not documents. id-class-value is off because camelCase ids are standard in JS-driven pages and are queried by name from script.", + "doctype-first": false, + "id-class-value": false +} diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index a699516..98840b1 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -48,4 +48,8 @@ jobs: # run here. ruff is the more widely used of the two and its formatter # is >99.9% black-compatible, so ruff format is the authority. VALIDATE_PYTHON_BLACK: false + # super-linter warns that biome and eslint both lint JSON and may + # conflict. biome is the one kept, per the same call made for CSS. + VALIDATE_JSON: false + VALIDATE_JSONC: false GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}