Phase 1 Step 4 follow-up addressing the debt flagged in the worked-example
commit (4a91814).
## mypy --strict policy
Adds backend-compliance/mypy.ini declaring the strict-mode scope:
Fully strict (enforced today):
- compliance/domain/
- compliance/schemas/
- compliance/api/_http_errors.py
- compliance/api/audit_routes.py (refactored in Step 4)
- compliance/services/audit_session_service.py
- compliance/services/audit_signoff_service.py
Loose (ignore_errors=True) with a migration path:
- compliance/db/* — SQLAlchemy 1.x Column[] vs
runtime T; unblocks Phase 1
until a Mapped[T] migration.
- compliance/api/<route>.py — each route file flips to
strict as its own Step 4
refactor lands.
- compliance/services/<legacy util> — 14 utility services
(llm_provider, pdf_extractor,
seeder, ...) that predate the
clean-arch refactor.
- compliance/tests/ — excluded (legacy placeholder
style). The new TestClient-
based integration suite is
type-annotated.
The two new service files carry a scoped `# mypy: disable-error-code="arg-type,assignment"`
header for the ORM Column[T] issue — same underlying SQLAlchemy limitation,
narrowly scoped rather than wholesale ignore_errors.
Flow: `cd backend-compliance && mypy compliance/` -> clean on 119 files.
CI yaml updated to use the config instead of ad-hoc package lists.
## Bugs fixed while enabling strict
mypy --strict surfaced two latent bugs in the pre-refactor code. Both
were invisible because the old `compliance/tests/test_audit_routes.py`
is a placeholder suite that asserts on request-data shape and never
calls the handlers:
- AuditSessionResponse.updated_at is a required field in the schema,
but the original handler didn't pass it. Fixed in
AuditSessionService._to_response.
- PaginationMeta requires has_next + has_prev. The original audit
checklist handler didn't compute them. Fixed in
AuditSignOffService.get_checklist.
Both are behavior-preserving at the HTTP level because the old code
would have raised Pydantic ValidationError at response serialization
had the endpoint actually been exercised.
## Integration test suite
Adds backend-compliance/tests/test_audit_routes_integration.py — 26
real TestClient tests against an in-memory sqlite backend (StaticPool).
Replaces the coverage gap left by the placeholder suite.
Covers:
- Session CRUD + lifecycle transitions (draft -> in_progress -> completed
-> archived), including the 409 paths for illegal transitions
- Checklist pagination, filtering, search
- Sign-off create / update / auto-start-session / count-flipping
- Sign-off 400 (invalid result), 404 (missing requirement), 409 (completed session)
- Get-signoff 404 / 200 round-trip
Uses a module-scoped schema fixture + per-test DELETE-sweep so the
suite runs in ~2.3s despite the ~50-table ORM surface.
Verified:
- 199/199 pytest (173 original + 26 new audit integration) pass
- tests/contracts/test_openapi_baseline.py green, OpenAPI 360/484 unchanged
- mypy compliance/ -> Success: no issues found in 119 source files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
78 lines
2.9 KiB
INI
78 lines
2.9 KiB
INI
[mypy]
|
|
python_version = 3.12
|
|
strict = True
|
|
implicit_reexport = True
|
|
ignore_missing_imports = True
|
|
warn_unused_configs = True
|
|
exclude = (?x)(
|
|
^compliance/tests/
|
|
| ^compliance/data/
|
|
| ^compliance/scripts/
|
|
)
|
|
|
|
# Tests are not type-checked (legacy; will be tightened when TestClient-based
|
|
# integration tests land in Phase 1 Step 4 follow-up).
|
|
[mypy-compliance.tests.*]
|
|
ignore_errors = True
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Phase 1 refactor policy:
|
|
# - compliance.domain / compliance.schemas : fully strict
|
|
# - compliance.api._http_errors : fully strict
|
|
# - compliance.services.<new_clean_arch_service> : strict (list explicitly)
|
|
# - compliance.repositories.* : strict with ORM arg-type
|
|
# ignore (see per-file)
|
|
# - compliance.db.* : loose (ORM models)
|
|
# - compliance.services.<legacy utility modules> : loose (pre-refactor)
|
|
# - compliance.api.<route files> : loose until Step 4
|
|
# ----------------------------------------------------------------------
|
|
|
|
# Legacy utility services that predate the Phase 1 refactor. Not touched
|
|
# by the clean-arch extraction. Left loose until their own refactor pass.
|
|
[mypy-compliance.services.ai_compliance_assistant]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.audit_pdf_generator]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.auto_risk_updater]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.control_generator]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.export_generator]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.llm_provider]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.pdf_extractor]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.regulation_scraper]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.report_generator]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.seeder]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.similarity_detector]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.license_gate]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.anchor_finder]
|
|
ignore_errors = True
|
|
[mypy-compliance.services.rag_client]
|
|
ignore_errors = True
|
|
|
|
# SQLAlchemy ORM layer: models use Column() rather than Mapped[T], so
|
|
# static analysis sees descriptors as Column[T] while runtime returns T.
|
|
# Loose for the whole db package until a future Mapped[T] migration.
|
|
[mypy-compliance.db.*]
|
|
ignore_errors = True
|
|
|
|
# Route files (Phase 1 Step 4 in progress): only the refactored ones are
|
|
# checked strictly via explicit extension of the strict scope in CI.
|
|
# Until each file is refactored, it stays loose.
|
|
[mypy-compliance.api.*]
|
|
ignore_errors = True
|
|
|
|
# Refactored route module under Step 4 — override the blanket rule above.
|
|
[mypy-compliance.api.audit_routes]
|
|
ignore_errors = False
|
|
[mypy-compliance.api._http_errors]
|
|
ignore_errors = False
|