You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+17Lines changed: 17 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -53,6 +53,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
53
53
54
54
### Added
55
55
56
+
-**Mypy graduation: typed GraphQL resolvers, mutations, and filters** (Issue #1332): Raised return-annotation coverage in `config/graphql/` from ~4.8% at the start of #1331 to **91.5%** (421/460 function defs) and removed 22 modules from the `mypy.ini` baseline allow-list.
57
+
- **Root-cause annotation fixes in `opencontractserver/utils/permissioning.py`**: `set_permissions_for_obj_to_user`, `user_has_permission_for_obj`, `get_users_permissions_for_obj`, and `get_permission_id_to_name_map_for_model` were previously annotated with `instance: type[django.db.models.Model]` (a class) despite every call site passing an instance — and with `user: type[User]` instead of the `User` runtime instance. These were annotation bugs (the code was correct, the annotations were inverted), which compounded: every mutation calling `set_permissions_for_obj_to_user(user, obj, ...)` was a single `[arg-type]` error each. Corrected to `instance: django.db.models.Model` / `user: UserModel` (forward-referenced via `TYPE_CHECKING` import of `opencontractserver.users.models.User`). Also added the missing `dict[int, str]` annotation on `this_model_permission_id_map` and removed the `user_instance=User` (class) default on `get_users_group_ids`, which would have exploded at runtime if any caller ever omitted the argument. Module graduated out of the baseline.
58
+
-**Graduated from `mypy.ini` baseline** (22 modules): `config.graphql.{action_queries, agent_mutations, badge_mutations, base_types, conversation_mutations, conversation_types, corpus_types, document_queries, filters, ingestion_source_mutations, moderation_mutations, og_metadata_queries, pipeline_queries, security, serializers, slug_queries, smart_label_mutations, social_types, user_queries, user_types, voting_mutations}` and `opencontractserver.utils.permissioning`. Each had the underlying mypy errors fixed first (root-cause in `permissioning.py` cleared the `set_permissions_for_obj_to_user` cluster across every mutation file above).
59
+
-**Per-file type fixes**:
60
+
-`config/graphql/slug_queries.py` & `config/graphql/user_types.py` & `config/graphql/social_types.py` & `config/graphql/corpus_types.py`: Reversed `.filter(...).visible_to_user(user)` → `.visible_to_user(user).filter(...)` so the custom manager method (typed on the manager) resolves before `.filter()` flattens to the base `QuerySet[Model]` that django-stubs doesn't know carries `visible_to_user`. Semantics are preserved — both orderings AND the conditions. The CLAUDE.md permissioning docs already recommend the manager-first pattern.
61
+
-`config/graphql/og_metadata_queries.py`: Guarded against `Extract.corpus` being `None` (the FK uses `on_delete=SET_NULL`, so `corpus` is nullable in the DB but the OG metadata resolver was treating it as non-null).
62
+
-`config/graphql/pipeline_queries.py`: Narrowed the `mimetype` optional before passing to `get_components_by_mimetype_cached` (which required `str`), and typed `components_data` as `dict[str, Sequence[PipelineComponentDefinition]]` so both branches (which return `list[...]` vs `tuple[...]`) type-check against the unified annotation.
63
+
-`config/graphql/ingestion_source_mutations.py`: Replaced `if error:` with `if pk is None:` in two call sites — the error-then-continue pattern left mypy unable to narrow `pk: str | None` through the conditional. Functionally equivalent (`error is None ⟺ pk is not None` by construction of `_parse_ingestion_source_global_id`).
64
+
-`config/graphql/conversation_types.py`: Fixed `base64.binascii.Error` → `binascii.Error` with an explicit `import binascii` — `base64` doesn't re-export `binascii` as an attribute, so the reference was broken under `warn_unused_ignores`.
65
+
-`config/graphql/filters.py`: Coerced `from_global_id(value)[1]` (returns `str`) to `int` before passing to `folder_id` lookup.
66
+
-`config/graphql/security.py`: Replaced `CsrfViewMiddleware(lambda req: None)` with a typed `_csrf_noop_get_response(request) -> HttpResponse` so the middleware's `get_response` contract is satisfied in-types; switched `wrapped_view.csrf_exempt = True` and `request._dont_enforce_csrf_checks = True` to `setattr(...)` to avoid typing-only attribute errors against Django stubs that don't carry these internal flags. Behaviour identical.
67
+
-`config/graphql/moderation_mutations.py`: Added an explicit `Union[ChatMessage, Conversation, None]` annotation on `target` where the surrounding `if/else` mixes the two types (mypy can't unify across branches without the hint).
68
+
-`config/graphql/action_queries.py`: Coerced `from_global_id(...)[1]` to `int` at the three call sites where it feeds `for_corpus` / `for_document` custom queryset methods (which expect `int` PKs).
69
+
-**Docs & baseline maintenance**: `mypy.ini` baseline section for `config.graphql` trimmed from 35 modules to 14; 63 matching error lines pruned from `docs/typing/mypy_baseline.txt` so the reference file matches the live baseline.
70
+
-**Known remaining bugs surfaced by mypy** (filed as separate issues per the scope rules of #1332):
71
+
-#1359 — `RemoveLabelsFromLabelsetMutation` calls non-existent `labelset.documents`. Silent runtime failure (swallowed by a broad `except Exception`). Blocks `config.graphql.label_mutations` graduation; one-line fix + test needed.
72
+
-#1360 — `DRFMutation.IOSettings` declares `model: django.db.models.Model = None` and `serializer = None`. Non-trivial refactor of the base mutation class; blocks `config.graphql.base` graduation.
56
73
-**Coverage: raise Corpus Chat & Agent Management component tests** (Issue #1276): added 36 new Playwright CT tests across the four lowest-ROI corpus components to drive coverage toward the ≥60% target. Breakdown:
57
74
-`frontend/tests/CorpusChat.ct.tsx` (+13 tests): `initialQuery` auto-send, tool-call timeline entries (ASYNC_THOUGHT), ASYNC_SOURCES merge, SYNC_CONTENT rendering, ASYNC_RESUME, ask_document sub-tool approval remapping, unknown-type default branch, back-to-list navigation, server-message-with-sources rendering, title-filter debounce, and additional navigation-header coverage. Extended the shared `StubSocket` in `beforeEach` with new query-triggered frame sequences.
0 commit comments