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
-**`PermissionedQueryManagerProtocol.visible_to_user` signature mismatch** (`opencontractserver/types/protocols.py:147`): the protocol declared `visible_to_user(self, user: Any = None)` but `PermissionManager.visible_to_user` and `UserFeedbackManager.visible_to_user` have no default. A caller holding a protocol-typed reference could call `.visible_to_user()` with no args and trigger a runtime `TypeError`, and mypy would also reject the concrete classes as structural matches. Dropped the `= None` default so the protocol pins the strictest contract; the docstring now explains that callers must pass an `AnonymousUser` when no authenticated principal is available. Lenient managers (e.g. `BaseVisibilityManager` with `user=None`) still satisfy the protocol — verified with both `isinstance` and `issubclass` checks.
14
+
-**`ToolProtocol``@property` descriptors against a `@dataclass`** (`opencontractserver/types/protocols.py:97`): `CoreTool` is a `@dataclass` exposing `name` / `description` / `parameters` / `requires_approval` as plain instance attributes. Mypy accepted dataclass fields against the property-shaped protocol, but the asymmetry was a footgun for future implementors who would reach for `@property` based on the protocol surface. Converted to plain attribute declarations matching the concrete class.
15
+
-**`StreamObserverProtocol` drift hazard** (`opencontractserver/types/protocols.py:152`): the protocol duplicated `opencontractserver.llms.types.StreamObserver` with no automated enforcement. A naive re-export creates a real circular-import risk because `protocols.py` is imported by `opencontractserver.shared.Managers` during Django app loading and `opencontractserver.llms.__init__` eagerly pulls in the heavy LLM stack (`api` → conversation models, agent factories). Kept duplicated definitions but added explicit "Must be kept in sync with…" notices on both sides (`opencontractserver/llms/types.py:18` and `opencontractserver/types/protocols.py:152`) explaining the rationale, and aligned the `__call__` return type on `llms.types.StreamObserver` (`-> None`, dropping the redundant `Awaitable[None]` wrapper that was already implicit in `async def`).
16
+
-**`VectorStoreProtocol` test missed renames** (`opencontractserver/tests/test_protocols.py:24`): the canonical-implementation test used `hasattr` against hard-coded method names instead of the `@runtime_checkable` machinery used by the other three tests in the file. Renaming `search` / `async_search` would have left the test passing as long as the attribute names happened to exist via some other code path. Switched to `issubclass(CoreAnnotationVectorStore, VectorStoreProtocol)`, which executes the protocol's structural check without instantiating the class. The negative test for plain `object` was tightened from a manual `hasattr` to `issubclass(object, VectorStoreProtocol)` for symmetry.
17
+
10
18
### Added
11
19
12
20
-**VCR.py wrapper for LLM calls in `doc_extract_query_task`** — `opencontractserver/utils/vcr_replay.py` exposes a `maybe_vcr_cassette()` context manager that, when `OC_LLM_VCR_MODE` and `OC_LLM_VCR_CASSETTE` are set on the celery worker, records or replays every HTTP call to LLM provider hosts (currently `api.openai.com` / `api.anthropic.com`). A custom request-body matcher strips volatile values (millisecond timestamps, Django document PKs, OpenAI tool-call IDs, UUIDs) so a cassette recorded against one DB replays cleanly against another. With the env vars unset the wrapper is a no-op — production behavior is unchanged. Pre-recorded cassette for the E2E extract spec lives at `opencontractserver/tests/fixtures/cassettes/e2e_extract_pdf_workflow/extract.yaml`. Replay was verified end-to-end against a deliberately-fake `OPENAI_API_KEY` to confirm no real network call is made. See `docs/development/e2e_vcr.md` for record / replay / debug instructions.
0 commit comments