9.3 KiB
9.3 KiB
Context
Пакет C сверки follow-ups 25.10.2026 (sdlc-hub#129). Все правки — в Python-коде хаба, без смены схемы базы и контракта с агентами. Владелец пропустил вопросы brainstorming («не сталкивался и не хочу»): решения ниже приняты агентом и продублированы в «Decisions made without discussion».
Decisions
- Нормализация параметров — один шаг в
validate. После всех проверокvalidateкладёт в пакет параметры, приведённые функциейnormalize(ctype, params) -> dict(modules/jira/commands.py). Проверки на пустоту (.strip()) остаются как есть. Обрезаются строковые параметры всех типов, кроме текстовыхsummary,description,body,goal. Это ключи,temp_key,sprint,rename_to,move_open_to,link_type,assignee,priority, даты,marker,attachment_id,file,filename,issue_type,target(строка или элементы списка). Элементы списковlabels,labels_add,labels_remove,keysтоже обрезаются. Числа, логические значения иnullне меняются. Нормализация возвращает новый словарь и не меняет вход. filename— NFC.normalizeприводитfilenameуensure_attachmentкunicodedata.normalize("NFC", …). MCP подставляет имя по умолчанию изPath(path).nameи тоже приводит его к NFC; на macOS имена из пути приходят в NFD. Поиск вложения по имени в MCP-инструментеattachmentсравнивает имена в NFC с обеих сторон.- Проверки
hooks.check_batchидут по нормализованным параметрам.validateвызывается раньше, поэтомуfilenameс пробелами по краям проверяется уже обрезанным. - ASCII-цифры. В
core/http.py(рядом сint_group) появляется функцияis_digits(s) -> bool:s— непустая строка только из0-9(s.isascii() and s.isdigit()). Модуль jira использует её вместоstr.isdigit()везде, где за проверкой идётint()или где строка — идентификатор:hooks.py(attachment_id),mirror.py(check_attachments),attachments.py(сортировка),fetch.py(версия агента),mcp.py(ссылка#<id>). В разборе датhistory.pyиmcp.pyзначение уже прошло форматную проверку, но для единообразия там тожеis_digits. - Форма элементов состояния.
mirror.check_issues(issues)вызывается доcheck_commentsиcheck_attachments. Она требует:issues— список (иначе сейчас 500 на итерации), каждый элемент — объект с непустым строковымkey. ИначеValueErrorс номером элемента. ОбработчикPOST /agent/stateуже превращаетValueErrorв 422bad_state, как для комментариев. POST /wiki/sync. Еслиprojectв теле задан и это не строка, ответ 422bad_request«project — строка» до обращения к проектам.- Файлы хранилища.
files.sizeиfiles.readловятOSError.FileNotFoundErrorпо-прежнему тихо даётNone. Остальные ошибки тоже даютNone, но пишут в лог предупреждение с путём и ошибкой. Дальше всё идёт по существующему пути «файла нет»:size = nullпри claim, 404 при скачивании. SDLC_HUB_HOME="".paths.home()берётos.environ.get("SDLC_HUB_HOME") or <по умолчанию>. Пустая строка равна незаданной переменной;home_problem/home_warningуже считают так.- Восстановление прерванной публикации. В начале
release.publish, до проверки версии, вызывается_recover(rd). Еслиagent.py.prevесть, аagent.pyнет или его sha256 не совпадает с манифестом, тогда как sha256agent.py.prevсовпадает,agent.py.prevвозвращается на местоagent.pyс предупреждением в лог. Еслиagent.pyсовпадает с манифестом, а.prevлежит,.prevудаляется. Во всех остальных случаях ничего не трогается, а в лог пишется предупреждение. Так закрываются T2.2 и M-6: после_recoverвagent.pyлежит опубликованная версия, иos.replace(agent, prev)не затирает годный.prev. - Устаревшие ключи настроек.
base_jqlиboard_idдобавляются вmodules/jira/settings.OBSOLETE.ensure_defaultsудаляет их при каждом открытии, не меняяsettings_version, какstatus_labels. Запись черезPUT /settingsпо-прежнему даёт 422 с пояснением. Агентуboard_idдавно не передаётся: его нет вAGENT_KEYS.
Risks / Trade-offs
- Нормализация меняет то, что раньше уходило агенту дословно. Пробелы по краям идентификатора в Jira не значимы, а текстовые поля не трогаются.
_recoverсрабатывает только при совпадении sha256 с манифестом, поэтому неизвестное содержимое не перезаписывается.- Удаление
board_idизsettingнеобратимо, но значение нигде не читается. Копия базы есть вbackups/.
Decisions made without discussion
- R-1 (proposal, 26.10.2026): O-3 (
check_confirmedсчитает обратную связь симметричного типа конфликтом) не входит в пакет и переносится в пакет B. Хаб не знает, какие типы симметричны: это знает агент по/issueLinkType. Ручная настройка списка типов в хабе отвергнута, она дублировала бы Jira. Цена ошибки: при потерянном отчёте командаensure_linkк «связанной» задаче, связанной в обратную сторону, подтверждается не по состоянию, а довыдачей агенту, и агент отвечает existed. Лишний вызов Jira, данные не страдают. - R-2 (design #1): обрезаются все строковые параметры, кроме
summary,description,body,goal. Обоснование: пробелы по краям идентификатора всегда ошибка ввода, а в тексте могут быть значимы. Цена ошибки: тема с пробелами по краям уходит в Jira как есть, Jira обрезает её сама. - R-3 (design #2): имя вложения приводится к NFC, а не к NFD. NFC — форма, в которой имена приходят из Jira и набираются с клавиатуры. Цена ошибки: имя вложения в Jira будет в NFC, визуально то же самое.
- R-4 (design #7): ошибка доступа к файлу хранилища трактуется как «файла нет», а не как отдельная ошибка API. Обоснование: путь «файла нет» уже понятен агенту и клиентам. Цена ошибки: причина видна только в логе хаба.
- R-5 (design #9):
_recoverчинит только состояния, однозначно определяемые по sha256 манифеста. Остальные оставляет как есть с предупреждением в лог. Цена ошибки: в редком сочетании сбоев владелец публикует ещё раз. - R-6 (design #10):
base_jqlиboard_idудаляются через механизм устаревших ключей, без новой версии схемы. Это тот же путь, что уstatus_labels, и при каждом старте ключи, вставленные старым процессом, убираются снова. Цена ошибки: нет.