Summary
ruff check and the ruff / ruff-format pre-commit hooks have been unrunnable since v0.5.4 (Feb 2026). scripts/bump_version.py rewrites [tool.ruff] target-version in src/pyproject.toml to the application version on every release, producing a value ruff cannot parse.
Reproduce
cd src && hatch -e dev run lint
ruff failed
Cause: Failed to parse src/pyproject.toml
Cause: TOML parse error at line 128, column 18
|
128 | target-version = "1.0.1"
| ^^^^^^^
unknown variant `1.0.1`, expected one of `py37`, `py38`, `py39`, `py310`, `py311`, `py312`, `py313`, `py314`, `py315`
Because the config fails to parse, ruff exits before linting anything — so lint, lint-fix, format, format-check and pre-commit-run are all dead, and the ruff / ruff-format hooks in .pre-commit-config.yaml (both scoped to ^src/backend/) never run either.
Cause
scripts/bump_version.py matches the version with an unanchored pattern:
(
"pyproject.toml",
False,
r'(version\s*=\s*")[^"]+(")',
r'\g<1>{version}\g<2>',
),
re.sub replaces every match, and target-version = "py310" contains the substring version = ". So each bump rewrites it alongside the real [project] version key.
History confirms it — target-version was py310 when the tooling landed and has tracked the app version ever since:
53fce85b 2026-02-04 feat: add code quality tooling +target-version = "py310"
48167bd2 2026-02-13 chore: bump version to 0.5.4 -py310 → +"0.5.4"
8c21f90c 2026-03-18 chore: bump version to 0.6.0 -"0.5.4" → +"0.6.0"
8564fda9 2026-03-26 chore: set version to v0.6.1 -"0.6.0" → +"0.6.1"
bc0e502b 2026-07-17 back-merge main (#615) -"0.6.1" → +"1.0.1"
CI does not run ruff (test-coverage.yml has no lint job), so nothing surfaced it.
Suggested fix
Anchor the pattern to the start of a line. ^version\s*= matches the [project] key but not target-version, and not the version-bump / version-show script entries either:
(
"pyproject.toml",
False,
r'(?m)^(version\s*=\s*")[^"]+(")',
r'\g<1>{version}\g<2>',
),
plus restoring target-version in src/pyproject.toml. [tool.hatch.envs.dev] python = "3.11" and requires-python = ">=3.11,<3.13" suggest py311 is the honest value today, though py310 is what it was before the drift — your call which.
Note get_current_version() (line ~149) uses the same unanchored pattern for reading. It happens to be correct today because re.search returns the first match and [project] version comes first in the file, but it is the same latent bug.
Impact of fixing
Once ruff parses again it reports ~750 pre-existing violations across backend/src (mostly W293 blank-line-with-whitespace, plus UP045/UP006 annotation modernisation and F541), ~677 auto-fixable. That is a deliberate sweep to sequence rather than a drive-by, which is why I have not bundled the fix into a PR.
Worth noting one of the things that stayed hidden: ruff flags F811 redefined-while-unused 5 times in src/backend/src/tools/data_products.py and data_contracts.py — duplicate tool class definitions that silently shadowed the maintained implementations and broke MCP tool scopes and the whole data-contract tool surface. See #677.
Happy to open a PR for the two-line fix if you want it separated from the reformat.
Summary
ruff checkand theruff/ruff-formatpre-commit hooks have been unrunnable since v0.5.4 (Feb 2026).scripts/bump_version.pyrewrites[tool.ruff] target-versioninsrc/pyproject.tomlto the application version on every release, producing a value ruff cannot parse.Reproduce
Because the config fails to parse, ruff exits before linting anything — so
lint,lint-fix,format,format-checkandpre-commit-runare all dead, and theruff/ruff-formathooks in.pre-commit-config.yaml(both scoped to^src/backend/) never run either.Cause
scripts/bump_version.pymatches the version with an unanchored pattern:( "pyproject.toml", False, r'(version\s*=\s*")[^"]+(")', r'\g<1>{version}\g<2>', ),re.subreplaces every match, andtarget-version = "py310"contains the substringversion = ". So each bump rewrites it alongside the real[project] versionkey.History confirms it —
target-versionwaspy310when the tooling landed and has tracked the app version ever since:CI does not run ruff (
test-coverage.ymlhas no lint job), so nothing surfaced it.Suggested fix
Anchor the pattern to the start of a line.
^version\s*=matches the[project]key but nottarget-version, and not theversion-bump/version-showscript entries either:( "pyproject.toml", False, r'(?m)^(version\s*=\s*")[^"]+(")', r'\g<1>{version}\g<2>', ),plus restoring
target-versioninsrc/pyproject.toml.[tool.hatch.envs.dev] python = "3.11"andrequires-python = ">=3.11,<3.13"suggestpy311is the honest value today, thoughpy310is what it was before the drift — your call which.Note
get_current_version()(line ~149) uses the same unanchored pattern for reading. It happens to be correct today becausere.searchreturns the first match and[project] versioncomes first in the file, but it is the same latent bug.Impact of fixing
Once ruff parses again it reports ~750 pre-existing violations across
backend/src(mostlyW293blank-line-with-whitespace, plusUP045/UP006annotation modernisation andF541), ~677 auto-fixable. That is a deliberate sweep to sequence rather than a drive-by, which is why I have not bundled the fix into a PR.Worth noting one of the things that stayed hidden: ruff flags
F811 redefined-while-unused5 times insrc/backend/src/tools/data_products.pyanddata_contracts.py— duplicate tool class definitions that silently shadowed the maintained implementations and broke MCP tool scopes and the whole data-contract tool surface. See #677.Happy to open a PR for the two-line fix if you want it separated from the reformat.