fix(mypy): clear Annotation-debt bucket for in-scope codes (closes #117) #119

Merged
Mark merged 1 commit from fix/117-annotation-tidy-rebased into main 2026-09-10 14:24:51 +00:00
Owner

Rebase of PR #118 (fix/annotation-tidy-t_5df1a1a4 @ 7e9a485) onto current main, opened as a new branch because the original head required a history rewrite to land.

Why a new PR

PR #118 was mergeable=false: its head was 15 commits behind main and conflicted in two files. Both conflicts were cases where main had already landed an equivalent-or-better version of the same change:

  • backend/app/modules/base.py — #118 proposed requires_config: ClassVar[list[str]] = []; main already has ClassVar[tuple[str, ...]] = () (immutable, prevents config leaking across module classes). Resolved in favour of main.
  • backend/app/services/investigations/orchestrator_enhanced.py — both sides fix the same order_by typing; main's desc(cast(ColumnElement, ...)) form is equivalent. Resolved in favour of main.

Residual value after rebase

Five files still carry non-redundant fixes not present on main:

  • modules/registry.py — list_module_details return type used the builtin any instead of typing.Any.
  • routers/investigations.py — two order_by(...) sites cast to ColumnElement[Any].
  • services/investigations/async_executor.py — order_by cast.
  • services/investigations/orchestrator_v3_llm.py — order_by cast.
  • services/investigations/state_machine.py — order_by cast.

Verification (Python 3.12 — repo requires >=3.12)

Gate origin/main this branch
mypy backend/app/ 312 errors / 82 files 305 errors / 80 files
ruff check . pass pass
pytest (full suite) 83 failed, 1700 passed, 9 skipped 83 failed, 1700 passed, 9 skipped

The two failure sets are identical (comm on the sorted FAILED lists yields empty in both directions) — this branch introduces no regressions and fixes 7 mypy errors.

Also fixed one defect carried by the original commit: it left sqlalchemy imports out of order in async_executor.py and orchestrator_v3_llm.py, which failed ruff I001. Corrected via ruff check --fix.

Note on the 83 pre-existing failures

Unrelated to this PR and present on main. ~19 are test_module_metadata cases still asserting the old list form, e.g.:

assert self.module.requires_config == ["dehashed_api_key"]
E   AssertionError: assert ('dehashed_api_key',) == ['dehashed_api_key']

These are fallout from the ClassVar[tuple[...]] change already on main; the tests were never updated. Tracked separately — not in scope for #117.

Supersedes #118.

Rebase of PR #118 (`fix/annotation-tidy-t_5df1a1a4` @ 7e9a485) onto current `main`, opened as a new branch because the original head required a history rewrite to land. ## Why a new PR PR #118 was `mergeable=false`: its head was 15 commits behind `main` and conflicted in two files. Both conflicts were cases where `main` had already landed an equivalent-or-better version of the same change: - `backend/app/modules/base.py` — #118 proposed `requires_config: ClassVar[list[str]] = []`; `main` already has `ClassVar[tuple[str, ...]] = ()` (immutable, prevents config leaking across module classes). Resolved in favour of `main`. - `backend/app/services/investigations/orchestrator_enhanced.py` — both sides fix the same `order_by` typing; `main`'s `desc(cast(ColumnElement, ...))` form is equivalent. Resolved in favour of `main`. ## Residual value after rebase Five files still carry non-redundant fixes not present on `main`: - `modules/registry.py` — `list_module_details` return type used the builtin `any` instead of `typing.Any`. - `routers/investigations.py` — two `order_by(...)` sites cast to `ColumnElement[Any]`. - `services/investigations/async_executor.py` — `order_by` cast. - `services/investigations/orchestrator_v3_llm.py` — `order_by` cast. - `services/investigations/state_machine.py` — `order_by` cast. ## Verification (Python 3.12 — repo requires >=3.12) | Gate | `origin/main` | this branch | |---|---|---| | `mypy backend/app/` | 312 errors / 82 files | **305 errors / 80 files** | | `ruff check .` | pass | **pass** | | `pytest` (full suite) | 83 failed, 1700 passed, 9 skipped | **83 failed, 1700 passed, 9 skipped** | The two failure sets are **identical** (`comm` on the sorted `FAILED` lists yields empty in both directions) — this branch introduces no regressions and fixes 7 mypy errors. Also fixed one defect carried by the original commit: it left `sqlalchemy` imports out of order in `async_executor.py` and `orchestrator_v3_llm.py`, which failed `ruff` I001. Corrected via `ruff check --fix`. ## Note on the 83 pre-existing failures Unrelated to this PR and present on `main`. ~19 are `test_module_metadata` cases still asserting the old list form, e.g.: ``` assert self.module.requires_config == ["dehashed_api_key"] E AssertionError: assert ('dehashed_api_key',) == ['dehashed_api_key'] ``` These are fallout from the `ClassVar[tuple[...]]` change already on `main`; the tests were never updated. Tracked separately — not in scope for #117. Supersedes #118.
fix(mypy): clear Annotation-debt bucket for in-scope codes (closes #117)
Some checks failed
CI / Backend Lint & Format (pull_request) Failing after 5s
CI / Golden Fixture Validation (pull_request) Has been skipped
CI / Backend Tests (pull_request) Has been skipped
CI / Backend Security Tests (pull_request) Has been skipped
CI / Frontend Lint (pull_request) Failing after 24s
CI / Frontend Tests (pull_request) Has been skipped
CI / Dependency Security Scan (pull_request) Has been skipped
Performance Regression Tests / Performance Regression Detection (pull_request) Failing after 7s
Stress Tests / Stress & Pipeline Tests (pull_request) Failing after 6s
Stress Tests / Full Data Pipeline Validation (pull_request) Has been skipped
CI / Frontend E2E Tests (pull_request) Has been skipped
Performance Regression Tests / Compare with Baseline (pull_request) Has been skipped
CI / All Checks Passed (pull_request) Failing after 1s
3dc33547e1
Sub-issue of #109 (umbrella mypy debt). Tries to close out 165 mypy errors
classified as Annotation-debt for in-scope error codes [misc], [arg-type],
[valid-type] per the per-error artifact produced by t_32c522a2.

Fixes
------
1. app/modules/base.py: declare EvidenceModule.name / description /
   requires_config as ClassVar (single 3-line edit). Cascades to clear
   158 [misc] 'Cannot override instance variable with class variable'
   errors across every EvidenceModule subclass.

2. Six [arg-type] SQLAlchemy order_by typing gaps. Fix by
   cast(ColumnElement[Any], <model column>) at the use site:
   - app/services/investigations/state_machine.py:149
     InvestigationCheckpoint.step_number
   - app/services/investigations/async_executor.py:98
     InvestigationTask.created_at
   - app/services/investigations/orchestrator_enhanced.py:327
     EntityActionQueue.created_at
   - app/services/investigations/orchestrator_v3_llm.py:767
     InvestigationStep.step_number (legacy Query overload)
   - app/routers/investigations.py:861 InvestigationTask.created_at
   - app/routers/investigations.py:889 EntityActionQueue.created_at

3. app/modules/registry.py:237 [valid-type] 'Function builtins.any is
   not valid as a type' — replace builtin 'any' with typing 'Any' and
   import it.

Out of scope (per parent card body)
-----------------------------------
[assignment], [return-value], [attr-defined], [call-arg] — these codes
are entirely Real-bug bucket; sibling card t_43df672f and issue #116
own those fixes. Annotation-debt rows whose code is [var-annotated],
[no-any-return], [index], [call-overload], or [override] are
explicitly excluded by the card body's 'stay within scope' clause and
require separate decomposition.

Verification
------------
- cd backend && mypy app/ --config-file ../pyproject.toml: 666 -> 498
  errors (net -168; +41 sibling R-bucket errors unmasked by mypy's
  per-statement short-circuit when the A-bucket error was removed; no
  new errors introduced — see commit-message notes / artifact diff).
- All 165 A-bucket in-scope rows in mypy_classification.json (t_32c522a2
  workspace artifact) are no longer reported at their original file:line.
- All 165 artifact rows verified against post-fix log via the
  fuzzy-match script in /tmp/verify_a_remaining.py.
- 77 unit tests pass for app/modules/base.py + app/modules/registry.py.
- 48 unit tests pass across state_machine / async_executor /
  orchestrator / investigations modules.
- ruff check on touched files: 88 -> 88 (no new ruff errors;
  pre-existing ruff debt on origin/main is owned by #100).

Refs #109, #117
Mark merged commit abdf87df0c into main 2026-09-10 14:24:51 +00:00
Mark deleted branch fix/117-annotation-tidy-rebased 2026-09-10 14:24:51 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/osint-hub!119
No description provided.