One tool instead of three, one config instead of four duplicated
blocks. black/isort/flake8 dropped from every package's dev deps,
ruff added once; .flake8 deleted, [tool.black]/[tool.isort] blocks
deleted from all 4 sub-package pyproject.toml files.
Config lives once, at the workspace root: ruff walks up from any file
it's checking until it finds a pyproject.toml with a [tool.ruff]
table (verified empirically — a package's own pyproject.toml lacking
that table doesn't stop the search), so the root-level [tool.ruff]
applies to all four packages without duplication. That's the one real
win over the old per-package black/isort blocks, which had to be
copy-pasted four times and kept in sync by hand.
Same rule surface as before, not more: select = E/F/W/I (pycodestyle
+ pyflakes + isort-equivalent), matching exactly what flake8 checked.
ruff has other rule groups (UP/pyupgrade, B/bugbear) that would
surface real things — deliberately left off. Turning those on finds
new debt and is a separate decision with its own diff to review, not
a side effect of swapping the tool underneath an unchanged rule set.
Same E501 exclusion carried over too, same reasoning: the formatter
is the sole authority on line length.
known-first-party carries over unchanged (same isort concern this
repo already fixed once — see "app" vs "flowsint_api" in the ratchet
history) and the wildcard-import per-file-ignore for
flowsint_core/__init__.py still applies, verified directly.
Six files reformatted by `ruff format` where it disagreed with black
on edge cases (import grouping, ternary line-breaking, blank lines
after a class statement) — all cosmetic, no behavior change, reviewed
diff by diff. One real ruff-check finding (an import block ruff's
isort-equivalent wanted sorted differently) — took ruff check --fix.
Verified: `make lint` clean, `make test` green (all 4 packages),
lint-staged tested with a real staged-file run (not just config
inspection) to confirm `uv run ruff format` / `uv run ruff check --fix`
actually execute, mypy ratchet target unaffected (still fires on its
own pre-existing backlog, unrelated to this change).
flake8/mypy/eslint were configured (or, for eslint, declared) but no CI
job and no pre-commit hook ever executed them — black/isort/flake8 had
no line-length agreement either (flake8 defaulted to 79, black to 88).
- .flake8: align max-line-length with black, ignore black-conflicting
codes, carve out the one file with an intentional wildcard-export API
- Makefile: `make lint` (black/isort/flake8, blocking — repo is clean),
`make typecheck` (mypy, ratcheted to files the branch touched — ~2200
pre-existing errors workspace-wide, not fixed blindly in one pass)
- .github/workflows/lint.yml: runs the above in CI, plus the frontend
equivalents (prettier/eslint blocking where clean, eslint/tsc
ratcheted where not)
- .github/workflows/tests.yml: add the vitest job that never existed
- flowsint-app/.eslintrc.cjs: parser was declared but never installed
(yarn lint threw immediately) — install @typescript-eslint/*, add
react-hooks/recommended; no-explicit-any set to warn (real backlog,
not fixed blindly)
- lint-staged + husky pre-commit: mirrors the CI checks that are
actually clean today (black/isort/flake8, prettier). eslint is left
out of pre-commit on purpose — its backlog would block unrelated
commits; it stays a CI-only ratchet until paid down.
workflow_dispatch button to bump version (patch/minor/major/custom),
update CHANGELOG.md, commit, tag and push to main via standard-version
— reusing the existing yarn release / sync-versions.js / .versionrc
setup instead of duplicating bump logic in YAML. The tag push then
triggers images.yml as-is.
Requires a GH_PAT secret: pushes made with the default GITHUB_TOKEN
don't trigger other workflows (GitHub anti-loop policy), so a plain
checkout token would silently skip the images.yml build.
sync-versions.js now also bumps the 4 workspace pyproject.toml files
(flowsint-api/core/enrichers/types) — previously only root
pyproject.toml and flowsint-app/package.json were kept in sync.
standard-version added as an explicit devDependency (was only
resolved transitively via yarn.lock before).