feat(ci): make ruff check and mypy hard CI gates#48
Conversation
Phase 3 PRs 1-7 (plus the PR-7.5 follow-up fix) cleaned the codebase to where `ruff check` and `mypy --strict src` both exit 0. This PR flips the corresponding CI steps to hard gates. - `.github/workflows/tests.yml`: drop `continue-on-error: true` on both `ruff check` and `mypy` steps; remove the now-stale comment blocks above them. - `pyproject.toml [tool.mypy]`: set `strict = true`; remove `strict_optional` (implied). - `src/cancelchain/wallet.py`: restore proper `type: ignore[no-any-return]` comments for Crypto library calls that strict mode catches; these are legitimate (library has incomplete stubs). - `CLAUDE.md`: update Style section prose. Phase 3 / PR 8 of 9. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR flips CI enforcement so ruff check and mypy failures now fail the build, aligning CI with the now-clean lint/type baseline for the cancelchain codebase.
Changes:
- Removes
continue-on-error: truesouv run ruff check …anduv run mypy …are hard CI gates. - Updates
[tool.mypy]configuration to enablestrict = true. - Refreshes
CLAUDE.mdStyle section to reflect the new CI gating posture.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
pyproject.toml |
Enables strict mypy mode and adjusts mypy target configuration. |
CLAUDE.md |
Updates contributor guidance about ruff/mypy gating (but still contains a few now-incorrect statements; see comments). |
.github/workflows/tests.yml |
Makes ruff check and mypy blocking steps by removing continue-on-error. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ## Style | ||
|
|
||
| - `ruff` config in `pyproject.toml`: `[tool.ruff]` holds top-level settings (target Python 3.12, `line-length = 80`), `[tool.ruff.lint]` holds the rule selection — large rule set enabled (`A,B,C,DTZ,E,EM,F,FBT,I,ICN,ISC,N,PLC,PLE,PLR,PLW,Q,RUF,S,SIM,T,TID,UP,W,YTT`). Several rules are ignored project-wide — notably `Q000` (single-quote convention enforced via `[tool.ruff.format] quote-style = "single"`) and `S101` (assert allowed in tests). In Phase 1 CI, `ruff check` is `continue-on-error: true` to allow incremental cleanup of pre-existing debt; only `ruff format --check` is a hard gate. Phase 3 removes the `continue-on-error` once the existing lint is cleaned up. | ||
| - `ruff` config in `pyproject.toml`: `[tool.ruff]` holds top-level settings (target Python 3.12, `line-length = 80`), `[tool.ruff.lint]` holds the rule selection — large rule set enabled (`A,B,C,DTZ,E,EM,F,FBT,I,ICN,ISC,N,PLC,PLE,PLR,PLW,Q,RUF,S,SIM,T,TID,UP,W,YTT`). Several rules are ignored project-wide — notably `Q000` (single-quote convention enforced via `[tool.ruff.format] quote-style = "single"`) and `S101` (assert allowed in tests). Both `ruff check` and `ruff format --check` are hard CI gates as of Phase 3 / PR 8. |
There was a problem hiding this comment.
Fixed in 16f21ed. The Q000 ignore was dropped back in PR-1 of Phase 3 when we added the [tool.ruff.lint.flake8-quotes] inline-quotes = "single" config to match the formatter. Updated the Style section to describe the current enforcement mechanism rather than the stale ignore claim.
|
|
||
| - `ruff` config in `pyproject.toml`: `[tool.ruff]` holds top-level settings (target Python 3.12, `line-length = 80`), `[tool.ruff.lint]` holds the rule selection — large rule set enabled (`A,B,C,DTZ,E,EM,F,FBT,I,ICN,ISC,N,PLC,PLE,PLR,PLW,Q,RUF,S,SIM,T,TID,UP,W,YTT`). Several rules are ignored project-wide — notably `Q000` (single-quote convention enforced via `[tool.ruff.format] quote-style = "single"`) and `S101` (assert allowed in tests). In Phase 1 CI, `ruff check` is `continue-on-error: true` to allow incremental cleanup of pre-existing debt; only `ruff format --check` is a hard gate. Phase 3 removes the `continue-on-error` once the existing lint is cleaned up. | ||
| - `ruff` config in `pyproject.toml`: `[tool.ruff]` holds top-level settings (target Python 3.12, `line-length = 80`), `[tool.ruff.lint]` holds the rule selection — large rule set enabled (`A,B,C,DTZ,E,EM,F,FBT,I,ICN,ISC,N,PLC,PLE,PLR,PLW,Q,RUF,S,SIM,T,TID,UP,W,YTT`). Several rules are ignored project-wide — notably `Q000` (single-quote convention enforced via `[tool.ruff.format] quote-style = "single"`) and `S101` (assert allowed in tests). Both `ruff check` and `ruff format --check` are hard CI gates as of Phase 3 / PR 8. | ||
| - `mypy` runs under `[tool.mypy] strict = true` against `src/cancelchain/` and is a hard CI gate as of Phase 3. |
There was a problem hiding this comment.
Fixed in 16f21ed alongside the pyproject.toml drift. Aligned by changing the CI step from uv run mypy src to uv run mypy (no positional args) so the files = ["src/cancelchain"] config controls. Updated the CLAUDE.md line to call out the contract: "invoke with uv run mypy (no positional args) so config and CI agree."
| # MYPY | ||
| [tool.mypy] | ||
| python_version = "3.12" | ||
| files = ["src/cancelchain"] |
There was a problem hiding this comment.
Same fix in 16f21ed — went with option (a): CI step changed to uv run mypy with no positional args, so the files = ["src/cancelchain"] setting drives the target set everywhere (local + CI). files stays in the config; the explicit-target drift is gone.
| - SQLAlchemy is pinned `<2.0`; don't import from 2.0-only namespaces. Flask-SQLAlchemy is 3.x (uses `db.Model`, `db.session`, classic `Model.query` style). | ||
| - pymerkle is pinned `>=4,<5` (block Merkle tree). v5 has breaking changes. |
There was a problem hiding this comment.
Good catch — fixed in 16f21ed. Both lines were leftover from before Phase 2's library upgrades. Updated:
- SQLAlchemy line now says
>=2.0withMapped[]annotations on every DAO in models.py, notes Flask-SQLAlchemy 3.1 still preserves the legacyModel.queryAPI, and flags query-style modernization todb.session.execute(db.select(...))as Phase 6. - pymerkle line now says
>=5(currently 6.1.0) with the v5/v6InmemoryTreeAPI in block.py.
Both reconcile with the actual pyproject.toml constraints.
Addresses Copilot review on PR #48. 1. **\`Q000\` ignore claim was stale.** PR-1 of Phase 3 dropped \`Q000\` from the ignore list once the \`[tool.ruff.lint.flake8-quotes] inline-quotes = "single"\` config was added. Updated the Style section to describe the current quote-style enforcement mechanism rather than a no-longer-present ignore. 2. **\`mypy src\` CI invocation drifts from \`files=\` config.** When mypy is given an explicit positional target, the \`[tool.mypy] files\` setting is ignored. Aligned by: - Changing CI step from \`uv run mypy src\` to \`uv run mypy\` (no args, so \`files = ["src/cancelchain"]\` controls). - Updating the CLAUDE.md mypy line to call this out: "invoke with \`uv run mypy\` (no positional args) so config and CI agree." 3. **SQLAlchemy/pymerkle pin claims were stale** from Phase 2 — they said \`<2.0\` and \`>=4,<5\` but Phase 2 upgraded to \`>=2.0\` and \`>=5\` (with \`Mapped[]\` in models.py and InmemoryTree in block.py). Updated both lines to reflect current state and point at the right next-phase modernization milestones. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
continue-on-error: truefromruff checkandmypyin.github/workflows/tests.yml.[tool.mypy] strict = trueinpyproject.toml.CLAUDE.mdStyle section prose.PRs 1-7 (+ PR-7.5 fix) cleared the underlying debt; this is the gate flip.
Phase 3 / PR 8 of 9.
Test plan
uv run ruff check src testsexits 0.uv run ruff format --check src testsexits 0.uv run mypy srcexits 0 understrict = true(24 files).uv run pytestpasses (177 passed, 1 skipped).🤖 Generated with Claude Code