diff --git a/scripts/v8std_mcp_index.py b/scripts/v8std_mcp_index.py index a668834..18c9d24 100644 --- a/scripts/v8std_mcp_index.py +++ b/scripts/v8std_mcp_index.py @@ -109,6 +109,17 @@ def require_text(value: Any, field_name: str, max_chars: int) -> str: return value +def truncate_for_query(text: str, max_chars: int = MAX_QUERY_CHARS) -> str: + """Обрезает построенный поисковый текст до лимита query, не разрывая слово.""" + if len(text) <= max_chars: + return text + cut = text[:max_chars] + boundary = cut.rfind(" ") + if boundary > max_chars // 2: + cut = cut[:boundary] + return cut.strip() + + def require_string_list(values: Any, field_name: str, item_max_chars: int) -> list[str] | None: if values is None: return None @@ -592,7 +603,8 @@ def explain_snippet( *signal_targets, ] ) - search_result = self.search(signal_text or snippet, types=None, mode="hybrid", limit=limit) + search_text = truncate_for_query(signal_text or snippet) + search_result = self.search(search_text, types=None, mode="hybrid", limit=limit) diagnostics = [] standards = [] diff --git a/tests/test_v8std_mcp_index.py b/tests/test_v8std_mcp_index.py index 06820d5..9bbc5b5 100644 --- a/tests/test_v8std_mcp_index.py +++ b/tests/test_v8std_mcp_index.py @@ -241,6 +241,25 @@ def test_related_and_batch_preserve_multiple_clauses_of_one_standard(self): expected, ) + def test_explain_snippet_accepts_long_snippet(self): + # Регресс: длинный сниппет падал с "query is too long: max 500 characters", + # хотя explain_snippet заявляет лимит MAX_SNIPPET_CHARS (4000). + snippet = ( + 'Процедура ПриЗаписи(Источник, Отказ) Экспорт\n' + '\tПопытка\n' + '\t\tОбработатьИсточник(Источник);\n' + '\tИсключение\n' + '\t\tЗаписьЖурналаРегистрации("Пример", УровеньЖурналаРегистрации.Ошибка, , ' + 'Источник.Ссылка, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));\n' + '\tКонецПопытки;\n' + 'КонецПроцедуры\n' + ) * 3 + self.assertGreater(len(snippet), 500) + self.assertLess(len(snippet), 4000) + result = self.index.explain_snippet(snippet) + self.assertIn("diagnostics", result) + self.assertIn("signals", result) + def test_explain_snippet_and_batch_diagnostics(self): snippet = self.index.explain_snippet( 'Запрос = Новый Запрос("ВЫБРАТЬ РАЗРЕШЕННЫЕ ...")'