def test_pending_review_is_not_bypassed_by_new_safe_message(self): self.bot.send_mode = 'auto' self.assistant.has_pending.return_value = True self.bot._reply_needs_review = mock.Mock(return_value=(False, '')) blanket, required, reason = self.bot._reply_review_decision({}, 'new question', 'safe answer') self.assertFalse(blanket) self.assertTrue(required) self.assertIn('待审核', reason) self.bot._reply_needs_review.assert_called_once() def test_late_mobile_sync_does_not_hide_new_customer_message(self): human = dict(self.context['last_message']) human.update(send_time=3, rowid=5) newer = {'is_self': False, 'dedup_key': 'next-question', 'content': 'new question', 'send_time': 4, 'rowid': 4, 'account': 'account-one', 'conv_id': 'S:1_2'} self.context['messages'] = [newer, human] self.context['last_message'] = human self.assistant.reconcile.return_value.update(send_time=3, rowid=5) self.poll() self.assertEqual(self.bot.enqueue_detected.call_args.kwargs['database_event']['message_id'], 'next-question') def test_send_attempt_failure_prevents_dispatch_and_local_completion_keeps_approval(self): self.assistant.record_automated_attempt.side_effect = OSError('synthetic disk failure') self.assertFalse(self.bot._record_assistant_automated_attempt(self.state, 'new draft')) self.state['review_approved'] = True self.bot._record_assistant_automated_send(self.state) self.assistant.complete_local_review.assert_called_once_with(self.state) self.assistant.record_automated_send.assert_not_called() # No real server receipt. class SharedVisualAssistantTests(VisualAssistantTests): """Use the real durable coordinator, keeping all transports mocked.""" def use_real_coordinator(self): from review_assistant import ReviewAssistantCoordinator self.bot._review_assistant_identity = ('123', 42) self.state['account'] = '123' self.context['account'] = '123' incoming = {'account': '123', 'conv_id': 'S:1_2', 'is_self': False, 'sender_id': '2', 'dedup_key': 'incoming-one', 'server_id': '10', 'rowid': 1, 'send_time': time.time()-1, 'content': 'original question'} self.context['messages'] = [incoming] self.context['last_message'] = incoming coordinator = ReviewAssistantCoordinator(root=self.root, account='123', pid=42, settings_loader=lambda: {'review_assistant_accounts': {'123': { 'enabled': True, 'recipient_conv_id': 'M:9'}}}) coordinator.enqueue_notifications = mock.Mock() self.addCleanup(coordinator.close) self.bot._get_review_assistant.return_value = coordinator self.bot._register_assistant_review(self.fp) self.assertTrue(self.state.get('assistant_review_id')) return coordinator def add_human(self, *, content='human phone reply'): outgoing = {'account': '123', 'conv_id': 'S:1_2', 'is_self': True, 'sender_id': '123', 'dedup_key': 'human-two', 'server_id': '11', 'rowid': 2, 'send_time': time.time()+.1, 'content': content} self.context['messages'].append(outgoing) self.context['last_message'] = outgoing def test_real_shared_human_completion_then_new_risk(self): coordinator = self.use_real_coordinator() self.add_human() self.poll() self.assertNotIn(self.key, self.bot._pending_reply_sessions) self.assertTrue(coordinator.resumed('S:1_2')) self.bot.send_mode = 'review' self.bot._reply_needs_review = mock.Mock(return_value=(True, 'new risk')) self.assertEqual(self.bot._reply_review_decision({'account':'123', 'conv_id':'S:1_2'}, 'q', 'a'), (False, True, 'new risk')) def test_real_shared_automated_attempt_is_not_human_reply(self): coordinator = self.use_real_coordinator() coordinator.record_automated_attempt(self.state) self.add_human(content='old AI draft') self.poll() self.assertIn(self.key, self.bot._pending_reply_sessions) self.assertFalse(coordinator.resumed('S:1_2')) def test_real_shared_local_approval_closes_reminder_without_resuming(self): coordinator = self.use_real_coordinator() self.state['review_approved'] = True self.bot._record_assistant_automated_send(self.state) self.assertFalse(coordinator.has_pending('S:1_2')) self.assertFalse(coordinator.resumed('S:1_2')) def test_real_shared_completion_retries_original_episode_after_disk_failure(self): coordinator = self.use_real_coordinator() review_id = self.state['assistant_review_id'] self.add_human() with mock.patch.object(self.bot, '_persist_pending_replies', side_effect=[True, False]): self.poll() self.assertIn(self.key, self.bot._pending_reply_sessions) self.assertTrue(coordinator.resumed('S:1_2')) self.poll() self.assertNotIn(self.key, self.bot._pending_reply_sessions) self.assertEqual(self.state['assistant_review_id'], review_id)