Andrey Epifancev 9aaf3cee50 Устаревшие ключи настроек удаляет ensure_defaults; выкатка схемы v8 в документах (#104)
I-1, I-2 финального ревью: старые MCP-сессии возвращали status_labels/transitions_map
после миграции; окно до kickstart описано для v8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:22:44 +04:00

13 KiB
Raw Blame History

Context

Основа — main после sdlc-rename (#97) и web-modules (#98), 5a21825. Схема базы — v7 (core/db.py, SCHEMA_VERSION = 7). Issue #104, ветка feat/104-fact-status-removal.

Где живёт статус по факту (разведка 24.10.2026):

  • база: issue_note.fact_status (modules/jira/schema.py); mirror.NOTE_FIELDS, фильтр fact_status в mirror.list_issues, колонка в выборках list_issues и board_snapshot (modules/jira/mirror.py);
  • API: ISSUE_FILTERS (modules/jira/api.py); PUT /issues/{key}/note принимает поле через NOTE_FIELDS;
  • MCP: issues (параметр и колонка таблицы), notes_set (параметр), issue (строка заметок) — modules/jira/mcp.py;
  • настройки: status_labels, transitions_map в DEFAULTS и AGENT_KEYS (modules/jira/settings.py), перенос из конфига в init --config (там же);
  • импорт: колонка «Статус по факту» в tasks.csv/new_tasks.csv (modules/jira/importer.py);
  • веб: типов с fact_status уже нет (#57); остались фикстуры (board/__fixtures__/hub-basic.board.json, settings.json), тест-страж терминов (boundary.test.ts), тест «параметр из адреса не уходит в запрос» (IssuesPage.test.tsx) и сидер тестового хаба web/scripts/seed-hub.py — он пишет fact_status в заметки через PUT /issues/{key}/note и после change получит 422;
  • тесты хаба и эталоны: tests/fixtures/baseline/{mcp_tools,settings,schema}.expected.json, test_db, test_mirror, test_api, test_mcp, test_importer, test_settings, test_e2e_hub, test_cli, test_queue, test_agents; tests/fixtures/{settings_v6,schema_v6,config.example}.json — входы миграционных тестов, исторические.

jira-agent (../jira-agent/src/agent.py) ни status_labels, ни transitions_map не читает: ensure_status получает путь статусов в параметре target. Потребители MCP в ~/projects поле не упоминают.

Goals / Non-Goals

Goals: в хабе нет ни поля, ни настроек, ни параметров статуса по факту; живая база v7 мигрирует при старте без ручных шагов; прочие заметки целы.

Non-Goals и Anti-Goals: см. proposal.md.

Decisions

  1. Колонка удаляется, а не обнуляется (решение владельца 24.10.2026: «удаляй безвозвратно»). Шаг миграции v7 → v8 — ALTER TABLE issue_note DROP COLUMN fact_status, только если колонка есть (новая база v8 собирается схемой без неё). Сам шаг живёт в модуле jira (функция в modules/jira/, ядро вызывает её ленивым импортом из MIGRATIONS[7], как _project_fields_v7 вызывает projects.migrate_v6): термины jira в ядро не попадают (test_core_has_no_jira_terms). SQLite хаба — 3.50 (Python 3.13 от uv), DROP COLUMN поддерживается с 3.35. Копию базы делает общий механизм миграции (backups/<дата>-schema-v7.sqlite), отдельной выгрузки нет.

  2. Ключи status_labels и transitions_map удаляются из setting той же миграцией и уходят из DEFAULTS и AGENT_KEYS, иначе ensure_defaults создаст их снова. Если удалён хотя бы один ключ — settings_version + 1: набор ключей агента изменился, агент перечитает настройки (на работу агента это не влияет). Строки settings_version может не быть (база без ensure_defaults) — тогда версия не поднимается и не создаётся.

  3. PUT /issues/{key}/note с fact_status — 422 «неизвестные поля заметки: fact_status» — общее правило mirror.set_note для полей вне NOTE_FIELDS, отдельного кода нет.

  4. GET /issues?fact_status=… — параметр игнорируется, как любой неизвестный: h_issues читает только ISSUE_FILTERS. Веб его уже не шлёт, а старые закладки с параметром не ломаются.

  5. init --config не переносит status_labels и transitions, даже если они есть в конфиге.

  6. Импорт пропускает колонку «Статус по факту»; остальные колонки — как раньше.

  7. Веб: только тесты, фикстуры и сидер. seed-hub.py перестаёт писать fact_status в заметки. Из hub-basic.board.json и settings.json поле и ключ убираются; golden-эталоны доски (*.expected.json) MUST NOT измениться — доска поле не читает. fact_status в MODULE_TERMS теста-стража остаётся: ядро веба по-прежнему не должно его содержать. Тест IssuesPage.test.tsx про параметр из адреса остаётся (поведение то же).

  8. Исторические фикстуры (*_v6.json, config.example.json) не правятся: это входы миграций и init, на них проверяется, что поле и ключи пропадают.

  9. Спека data-model: «текущая — 8», сценарии миграций v1–v5 вместо числа говорят «текущая» — число «6» в них отстало от кода ещё в wiki-module (v7) и ломалось бы при каждой новой версии.

  10. Документация и тексты в коде правятся вместе с кодом: README (описание import, строки GET /issues и GET /board), docstring mirror.board, mcp.issues, mcp.notes_set, обе строки чтения CSV в importer.py. Исторические планы docs/superpowers/plans/*.md и архив openspec/changes/archive/ не правятся; итоговая проверка — grep -rn "fact_status\|status_labels\|transitions_map\|по факту" src web/src web/scripts README.md ARCHITECTURE.md openspec/specs даёт только намеренные остатки (страж MODULE_TERMS, тест параметра из адреса, текст спек «статуса по факту нет»).

  11. Устаревшие ключи настроек объявляет модуль (Module.settings_obsolete, у jira — status_labels, transitions_map); core.settings.ensure_defaults удаляет их при каждом вызове, settings_version не поднимает (агенту ключи не передаются). Ядро имён ключей не знает.

Справка: пути переходов из transitions_map

Значение настройки на живом хабе 24.10.2026 — пути по workflow AURORA (статус Jira, в который переводили задачу, по виду работы; default — для видов, которых нет в строке; «—» — пути нет). Ключи — статусы по факту, сами пути пригодятся для спринтов/бэклога.

Статус по факту default аналитика / решение / актуализация организационная
Готово — закрыть Разработка → Готово к тестированию Разработка → Готово Разработка → Готово
В работе Разработка Ожидает анализа → Анализ Разработка (default)
Ожидает решения владельца/заказчика Ожидает анализа Ожидает анализа Ожидает анализа
К актуализации аналитики Ожидает анализа Ожидает анализа Ожидает анализа
Ожидание разработки — Ожидает анализа —
Частично — переформулировать — Ожидает анализа —
Снято Снято Снято Снято

status_labels сопоставлял статусам по факту служебные метки fact-* (fact-done, fact-partial, fact-in-progress, fact-decision, fact-docs, fact-open, fact-roadmap, fact-cancelled).

Risks / Trade-offs

  • Значения статуса по факту теряются — решение владельца; восстановить можно только из backups/.
  • Новый код до kickstart. MCP-сервер и CLI открывают базу сами (HubClient.from_home() → db.connect + ensure_defaults). Новая сессия Claude, /mcp → reconnect или sdlc-hub tokens между git pull и kickstart мигрируют базу до v8, а хаб на прежнем коде отвечает 500 на GET /issues, GET /board, PUT /issues/{key}/note (нет колонки). Порядок выкатки — git pull → сразу kickstart (README, ARCHITECTURE.md, раздел о выкатке схемы).
  • Старый код после kickstart. Долгоживущие MCP-сессии со старым кодом при каждом вызове открывают базу и своим ensure_defaults снова вставляют status_labels/transitions_map ({}); миграция уже прошла и не повторится, а удалить ключ через API нельзя (I-1 финального ревью). Поэтому ключи объявлены устаревшими модулем (Module.settings_obsolete), и ensure_defaults нового кода удаляет их при каждом вызове — при старте хаба и в каждой новой MCP-сессии (design #11). Пока жива старая сессия, ключи могут появляться между её вызовами и вызовами нового кода; агенту они не уходят (AGENT_KEYS нового кода).
  • Сессии MCP со старым кодом до /mcp → reconnect показывают параметр fact_status; вызов с ним вернёт пустой фильтр (хаб параметр игнорирует), notes_set с ним — 422.

Decisions made without discussion

  • 24.10.2026 — R-1 (design #2): transitions_map и status_labels удаляются вместе с полем; пути переходов сохранены в разделе «Справка» этого документа. Обоснование: ключи карты — статусы по факту, читателей нет. Цена ошибки — вернуть настройку из справки одной правкой PUT /settings.
  • 24.10.2026 — R-2: jira-agent не меняется, design-only change в агенте не заводится (агент ключи не читает). Цена ошибки — отдельный PR в агенте.
  • 24.10.2026 — R-3 (design #2): settings_version поднимается, если миграция удалила ключ. Цена ошибки — один лишний перечит настроек агентом.
  • 24.10.2026 — R-4 (design #3, #4): запись поля в заметку — 422, фильтр в GET /issues — игнорируется. Обоснование: общие правила хаба для неизвестных полей тела и параметров. Цена ошибки — правка одного обработчика.
  • 24.10.2026 — R-5: M-3, M-4, M-5 из #60 в change не входят и остаются в #60. Цена ошибки — отдельная мелкая задача.
  • 24.10.2026 — R-7 (design #11): после I-1 финального ревью — устаревшие ключи удаляет каждый ensure_defaults, без подъёма settings_version. Обоснование: старые MCP-сессии возвращают ключи, а удалить их иначе нечем. Цена ошибки — поле контракта модуля, которое придётся убрать.
  • 24.10.2026 — R-6 (design #9): в data-model исправлено отставание номера версии схемы. Цена ошибки — нет.