diff --git a/src/backend/services/ai_chat_session_ingestion_service.py b/src/backend/services/ai_chat_session_ingestion_service.py index 3d50c4a3..44b574d7 100644 --- a/src/backend/services/ai_chat_session_ingestion_service.py +++ b/src/backend/services/ai_chat_session_ingestion_service.py @@ -119,6 +119,7 @@ class SessionDecision: record: SessionRecord document_concept_id: str repair_file_copy_concept_id: str | None = None + existing_file_copy_concept_id: str | None = None @dataclass @@ -781,6 +782,7 @@ def run( "source_session_id": decision.record.source_session_id, "document_concept_id": decision.document_concept_id, "action": "unchanged", + "file_copy_concept_id": decision.existing_file_copy_concept_id, "reason": decision.reason, "success": True, "storage_object_written": False, @@ -1073,6 +1075,9 @@ def _classify_record(self, record: SessionRecord) -> SessionDecision: reason="content_hash_match", record=record, document_concept_id=document_concept_id, + existing_file_copy_concept_id=self._read_attribute( + existing, "current_file_copy_concept_id" + ), ) return SessionDecision( diff --git a/src/backend/services/external_conversation_import_service.py b/src/backend/services/external_conversation_import_service.py index 5fe5ec08..4f7dfcb5 100644 --- a/src/backend/services/external_conversation_import_service.py +++ b/src/backend/services/external_conversation_import_service.py @@ -30,7 +30,7 @@ EXTERNAL_CONVERSATION_PACKAGE_SCHEMA_VERSION = "external_conversation_package.v1" -EXTERNAL_CONVERSATION_PARSER_VERSION = "2026-09-16.1" +EXTERNAL_CONVERSATION_PARSER_VERSION = "2026-09-16.2" EXTERNAL_CONVERSATION_ORIGIN_KIND = "external_conversation_import" EXTERNAL_CONVERSATION_LINEAGE_SCHEMA_VERSION = "conversation_lineage.v1" MAX_EXTERNAL_CONVERSATION_SOURCE_BYTES = 32 * 1024 * 1024 diff --git a/tests/backend/test_ai_chat_session_ingestion_service.py b/tests/backend/test_ai_chat_session_ingestion_service.py index 4e0a2a64..e32e889a 100644 --- a/tests/backend/test_ai_chat_session_ingestion_service.py +++ b/tests/backend/test_ai_chat_session_ingestion_service.py @@ -203,7 +203,6 @@ def discover(self): def test_run_unchanged_record_skips_mutation(monkeypatch, tmp_path): from src.backend.services.ai_chat_session_ingestion_service import ( AIChatSessionIngestionService, - SessionDecision, ) record = _record(tmp_path=tmp_path) @@ -220,15 +219,20 @@ def discover(self): ) monkeypatch.setattr(service, "ensure_ontology_types", lambda: []) + _install_source_profile_authority(service) monkeypatch.setattr( service, - "_classify_record", - lambda _rec: SessionDecision( - action="unchanged", - reason="content_hash_match", - record=_rec, - document_concept_id=_rec.document_concept_id, - ), + "_get_concept", + lambda _concept_id: { + "concept_id": record.document_concept_id, + "attributes": { + "source_content_sha256": record.content_sha256, + "current_file_copy_concept_id": "#V#retained_file_copy", + }, + "relationships": { + service._document_has_file_predicate_id(): ["#V#retained_file_copy"] + }, + }, ) result = service.run(dry_run=False) @@ -239,6 +243,7 @@ def discover(self): assert result.counters.skipped == 1 assert result.counters.intended_mutations == 0 assert result.counters.executed_mutations == 0 + assert result.records[0]["file_copy_concept_id"] == "#V#retained_file_copy" def test_dry_run_uses_ontology_validation_not_bootstrap(monkeypatch, tmp_path): @@ -272,6 +277,7 @@ def _validate(): monkeypatch.setattr(service, "ensure_ontology_types", _bootstrap) monkeypatch.setattr(service, "validate_ontology_types", _validate) + monkeypatch.setattr(service, "_get_concept", lambda _concept_id: None) result = service.run(dry_run=True)