What happened

On July 17, 2026, the release build for Simple CVE Tracker v1.2.0 failed. The code had passed a local lint check minutes earlier. The step that failed was the linter, and it stopped the build before it could package or publish anything.

The artifact

The release workflow ran ruff check . --select E4,E7,E9,F,B and printed:

B905 `zip()` without an explicit `strict=` parameter
   |
90 |     for seg_a, seg_b in zip(key_a, key_b):
   |
help: Add explicit value for parameter `strict=`
Found 1 error.

The line was in the version comparison in matcher.py. The build stopped at the release / build job, and the release / publish job never ran. The failed run is public at Simple-CVE-Tracker actions run 29617190618.

Root cause

ruff check . with no rule selection uses ruff’s default set, which is a subset of the pycodestyle E rules plus the Pyflakes F rules. It does not include flake8-bugbear, the B rules. B905 is a bugbear rule. So a bare local ruff check . never sees it.

The release workflow does not use the defaults. It selects E4,E7,E9,F,B, which turns bugbear on. The B in that list is the whole difference. Code that a plain local run calls clean fails the moment bugbear is switched on, and the first place that happens is the release build.

The fix

The immediate fix was one word: zip(key_a, key_b, strict=False). That is the honest fix here, not a way to silence the rule, because the two version-part lists can legitimately be different lengths and the intent is to stop at the shorter one. B905 exists to force that choice to be written down instead of left implicit. Where equal length is actually required, strict=True is the right answer and will raise if the lengths differ.

The durable fix is to make the local check run the same rules as the build. Build-Tools ships a templates/dev/requirements.txt that tool repos copy as requirements-dev.txt, and the same --select string, so a check run on the developer’s machine matches the one in the release build. A lint that only runs one way finds problems at the worst time.

Evidence boundary

This is a gap between two rule sets, not a claim that bugbear catches every bug or that a passing lint means correct code. B905 flags an unstated strict=. It does not judge whether stopping at the shorter list is right for the logic, and that judgment stayed with the author.

Source ledger

Source owner Primary URL Review class Last reviewed Exact claim or evidence mapped
JDE-Projects Simple CVE Tracker https://github.com/JDE-Projects/Simple-CVE-Tracker/actions/runs/29617190618 Production evidence August 18, 2026 The v1.2.0 release build failed on B905 with the quoted output.
JDE-Projects Simple CVE Tracker https://github.com/JDE-Projects/Simple-CVE-Tracker/commit/fc56f039dc586e5573617b641129999a3f6ecb2b Production evidence August 18, 2026 The fix added strict=False to the version-compare zip.
JDE-Projects Build-Tools https://github.com/JDE-Projects/Build-Tools/blob/01090b68a33074fda7fcd97d088cb29aa9718f61/README.md Production evidence August 18, 2026 CI selects E4,E7,E9,F,B, not ruff’s defaults, and dev requirements match CI.
Astral https://docs.astral.sh/ruff/rules/zip-without-explicit-strict/ Framework-critical August 18, 2026 B905 is the flake8-bugbear zip-without-explicit-strict rule.