From c2239a0fa128111d42b21cd72ab9fb081c4507da Mon Sep 17 00:00:00 2001 From: witbrock Date: Thu, 10 Sep 2026 21:45:07 -0400 Subject: [PATCH] Avoid full task hydration for Jira relation identity lookup (JVNAUTOSCI-2737) --- .../services/jira_task_import_service.py | 1 + .../services/task_management_service.py | 15 +++++-- tests/backend/test_task_management_service.py | 44 +++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/backend/services/jira_task_import_service.py b/src/backend/services/jira_task_import_service.py index 35245a123..044385c69 100644 --- a/src/backend/services/jira_task_import_service.py +++ b/src/backend/services/jira_task_import_service.py @@ -1672,6 +1672,7 @@ def _resolve_existing_task_id( source_system=_JIRA_SOURCE_SYSTEM, external_id=jira_issue_key, organisation_concept_id=organisation_concept_id, + include_details=False, ) task_id = None if isinstance(existing_task, Mapping): diff --git a/src/backend/services/task_management_service.py b/src/backend/services/task_management_service.py index f45746843..94650b9ef 100644 --- a/src/backend/services/task_management_service.py +++ b/src/backend/services/task_management_service.py @@ -5435,7 +5435,9 @@ def find_task_by_external_reference( source_system: str, external_id: str, organisation_concept_id: str | None = None, + include_details: bool = True, ) -> Dict[str, Any] | None: + """Resolve the same visible task with optional response construction.""" source_key = _normalise_external_reference_source_system(source_system) external_value = _normalise_external_reference_id(external_id) @@ -5451,6 +5453,11 @@ def find_task_by_external_reference( ], } doc: Dict[str, Any] | None = None + lookup_options = ( + {} + if include_details + else {"projection": {"concept_id": 1, "relationships.is_an_instance_of": 1}} + ) if organisation_concept_id: org_id = _normalise_optional_concept_id(organisation_concept_id) if not org_id: @@ -5459,18 +5466,20 @@ def find_task_by_external_reference( ) scoped_query = dict(query_base) scoped_query[f"metadata.{TASK_METADATA_KEY_ORGANISATION}"] = org_id - doc = ConceptsRepository.find_one(scoped_query) + doc = ConceptsRepository.find_one(scoped_query, **lookup_options) if not isinstance(doc, dict) or not _is_task_doc(doc): # Legacy imports were often unscoped; allow a constrained fallback # to null/absent organisation scope for idempotent repair runs. legacy_query = dict(query_base) legacy_query[f"metadata.{TASK_METADATA_KEY_ORGANISATION}"] = None - doc = ConceptsRepository.find_one(legacy_query) + doc = ConceptsRepository.find_one(legacy_query, **lookup_options) else: - doc = ConceptsRepository.find_one(query_base) + doc = ConceptsRepository.find_one(query_base, **lookup_options) if not isinstance(doc, dict) or not _is_task_doc(doc): return None + if not include_details: + return {"task_concept_id": doc.get("concept_id")} return _build_task_response(doc) diff --git a/tests/backend/test_task_management_service.py b/tests/backend/test_task_management_service.py index d0396248a..a4890bbf3 100644 --- a/tests/backend/test_task_management_service.py +++ b/tests/backend/test_task_management_service.py @@ -2100,6 +2100,50 @@ def _fake_get_texts( class TestTaskExternalReferences: + @patch("src.backend.services.task_management_service._build_task_response") + @patch("src.backend.services.task_management_service.ConceptsRepository") + def test_identity_lookup_preserves_alias_and_legacy_scope_without_hydration( + self, mock_repo: MagicMock, build_response: MagicMock + ) -> None: + mock_repo.find_one.side_effect = [ + None, + { + "concept_id": "#V#legacy_task", + "relationships": {"is_an_instance_of": [TASK_SPECIFICATION_TYPE_ID]}, + }, + ] + result = find_task_by_external_reference( + source_system="jira", + external_id="OLD-1", + organisation_concept_id="#V#org", + include_details=False, + ) + assert result == {"task_concept_id": "#V#legacy_task"} + build_response.assert_not_called() + calls = mock_repo.find_one.call_args_list + assert [call.args[0]["metadata.organisation_concept_id"] for call in calls] == [ + "#V#org", None + ] + for call in calls: + assert {"metadata.external_references.jira.previous_issue_keys": "OLD-1"} in ( + call.args[0]["$or"] + ) + assert call.kwargs["projection"] == { + "concept_id": 1, "relationships.is_an_instance_of": 1 + } + + @pytest.mark.parametrize("doc", [None, {"concept_id": "#V#not_a_task"}]) + @patch("src.backend.services.task_management_service._build_task_response") + @patch("src.backend.services.task_management_service.ConceptsRepository") + def test_identity_lookup_does_not_return_missing_or_non_task_records( + self, mock_repo: MagicMock, build_response: MagicMock, doc + ) -> None: + mock_repo.find_one.return_value = doc + assert find_task_by_external_reference( + source_system="jira", external_id="PROJ-1", include_details=False + ) is None + build_response.assert_not_called() + @patch("src.backend.services.task_management_service.ConceptsRepository") @patch("src.backend.services.task_management_service.get_texts_for_concept") def test_find_task_by_external_reference_returns_task(