Andrey Epifancev 76b60e5397 docs(web-modules): T8.3, M-5 README, решения 56–65 в design.md
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 15:38:46 +04:00

40 KiB
Raw Blame History

Context

Основа — main после слияния sdlc-rename (#97): пакет sdlc_hub, бренд «SDLC Hub», ключи sdlc-hub-*. Ветка feat/98-web-modules перебазируется на него до исполнения плана.

Аудит веба 24.10.2026 (сабагент, код + живой хаб, скриншоты в scratchpad сессии) — главное:

  • контракт HubModule (web/src/modules/types.ts): name, pages, nav, Provider, SidebarStatus (компонент), TopbarNotice, useOverlay, projectFields, useOnProjectCreated(batchId);
  • RefreshProvider (модуль jira, 174 строки) — единственный трекер пакетов: подхват пакетов viewer с первой командой refresh (по GET /batches/{id} на каждого кандидата), один опрос, остановка, перечитывание; агент — GET /agent (только jira); время — last_sync из снимка /board (грузится на каждой странице);
  • wiki: SyncStatus — текст из GET /projects + GET /wiki/status, кнопка только в шапке страницы;
  • ядро знает jira: / → /board в модуле jira, типы jira и fact_status в api/types.ts, api/closed.ts, бренд; модуль wiki импортирует fmtStamp из модуля jira;
  • modules/jira/issues/wiki/wiki.css (div.wiki h1…) перебивает заголовки страницы «Вики» (корень div.wiki);
  • POST /projects → один batch_id, оболочка раздаёт его всем модулям;
  • API: GET /agents уже есть (все поля агента), GET /projects уже несёт свежесть wiki, у пакета нет модуля.

Goals / Non-Goals

Goals: оболочка рисует состояние модулей по их описанию; пакеты и агенты отслеживает ядро; навигация и главная страница — модульные; граница ядра и модулей в вебе проверяется тестами; найденные аудитом дефекты страниц исправлены.

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

Decisions

  1. Навигация — группы по модулям + «Обзор» (вариант «А + Б» аудита). Группы оставляют все разделы на виду (их четыре), «Обзор» даёт модульную главную вместо /board и место для сводки. Переключатель модулей (вариант «В») отклонён: лишний щелчок между доской и вики ради масштаба, которого нет.
  2. Адреса с префиксом модуля (/app/jira/…, /app/wiki) и перенаправления со старых. Делается сейчас, пока ломается всё сразу (переименование); пути модулей не пересекаются по построению. Перенаправления объявляет модуль jira (это его прежние адреса). GET / хаба — на /app/.
  3. Состояние модуля — данные (ModuleStatus), рисует ядро. Компонент SidebarStatus убирается: из-за него блок и был разнобойным. Свежесть берётся из уже загруженного GET /projects чистой функцией от проекта — без запросов модуля: jira — jira_synced_at (новое поле, общее для проектов), wiki — wiki_synced_at/wiki_sync_error.
  4. Один трекер пакетов в ядре (shell/activity/): обобщение RefreshProvider — состояние на модуль (event, active, busy), опрос GET /batches/{id}, правила остановки прежние. Подхват — по полю module из GET /batches?module= (новое), любого автора: автообновления хаба и пакеты из MCP теперь видны (С1/В1 аудита), а подхват не делает запрос на каждого кандидата. Прежнее правило «только viewer + refresh» отменено (сценарий «Пакет с другими командами» меняется: пакет показывается, но не блокирует кнопку).
  5. Кнопка недоступна только на время пакета своего действия обновления (jira — первая команда refresh, wiki — wiki_sync; тип виден в GET /batches/{id}, который трекер и так опрашивает). Иначе долгое скачивание вложения блокировало бы «Обновить из Jira».
  6. Обновление: значок в строке модуля + вторичная кнопка в шапке страниц модуля, primary для обновления нет. Сейчас на «Вики» две зелёные кнопки (в панели и в шапке) — против правила AURA «одна primary на экран».
  7. Агенты — один опрос GET /agents раз в 60 с; точка агента: на связи / офлайн / «обновите агента» (warning или update_hint), всегда с текстом.
  8. Узкий экран: в верхней строке «Меню», метка проекта и сводная точка; отдельная кнопка «Обновить из Jira» и TopbarNotice из контракта убираются (событие пакета показывает ядро строкой под верхней строкой). Выезжающая панель — модальная (#73 M-1…M-3).
  9. Пакеты нового проекта по модулям: POST/PATCH /projects отдают batches: [{module, id}]; batch_id и batch_ids остаются для MCP. Оболочка передаёт каждому модулю его пакет (снимает M-14/T5.3 #68 и потерю wiki_sync).
  10. Граница в вебе — тестами: импорты (ядро → только modules/index.ts; модуль → не другой модуль), уникальность имён модулей и nav.to (T7.5/T7.6 #90), пересечение имён классов CSS между модулями и с ядром. Префиксы классов не вводятся: тест на пересечение ловит именно случившийся дефект и не требует переименовывать сотни классов. div.wiki разметки Jira переименовывается в .jira-markup.
  11. Типы jira — в модуль jira (modules/jira/api/types.ts), closed.ts — туда же; fact_status удаляется из веба (веб-часть #60). В api/types.ts ядра остаются Batch, AgentView (полный вид из GET /agents), Project, CreatedProject, UpdatedProject, HubSettings без словарей jira.
  12. Форматтеры дат — ядро (ui/format.ts): fmtStamp («ДД.ММ ЧЧ:ММ»), fmtDate («ДД.ММ», не текущий год — «ДД.ММ.ГГГГ»). Списки и карточка перестают выводить ISO.
  13. «Обзор» берёт сводку у модуля (Summary({project})); счётчики jira — из снимка доски проекта (запрос только на «Обзоре»); вики — wiki_pages из проекта.
  14. Порядок архива: sdlc-rename архивируется раньше web-modules: дельты web-app/hub-api этого change написаны поверх текстов после переименования.

Контракт веб-модуля (после change)

type ModuleStatus = {
  agent?: string;                                   // имя модуля агента в GET /agents
  scope: "all" | "project";                         // охват свежести и обновления
  freshness(p: Project): { available: boolean; at: string | null; error: string | null };
  refresh?: {
    label: string;                                  // «Обновить из Jira», «Обновить вики»
    start(project: string): Promise<{ id: number; estimate_seconds?: number }>;   // 409 → ApiError, ядро подхватит идущий
    isOwn(b: Batch): boolean;                       // пакет этого действия (по commands[0].type)
  };
  invalidate(qc: QueryClient, project: string | null): void;   // что перечитать после пакета модуля
};
type HubModule = {
  name: string; title: string;                      // «jira» / «Jira»
  pages: RouteObject[]; nav: NavItem[];             // nav.to — с префиксом модуля
  status?: ModuleStatus;
  Summary?: ComponentType<{ project: Project }>;    // карточка «Обзора»
  Provider?, useOverlay?, projectFields?;           // как было; SidebarStatus, TopbarNotice, useOnProjectCreated — удалены
};

Risks / Trade-offs

  • Подхват пакетов любого автора покажет и пакеты, поставленные из чата (claude), — это желаемо, но строка «Jira» будет чаще «занята». Кнопка при этом не блокируется (решение 5).
  • Счётчики на «Обзоре» грузят снимок доски — тяжёлый запрос; только на этой странице и с тем же ключом кэша, что у доски.
  • Смена адресов ломает закладки — их держат перенаправления; внешних ссылок на веб нет (MCP веб-адресов не отдаёт).

Decisions made without discussion

Владелец 24.10.2026 ответил «делай» на вопросы brainstorming — решения 1–14 выше приняты агентом по аудиту.

# Дата Решение Обоснование Цена ошибки
1 24.10.2026 Навигация — группы + «Обзор» 4 раздела, 2 модуля; нужна модульная главная переделка панели
2 24.10.2026 Адреса /app/<модуль>/… с перенаправлениями заодно с переименованием, пути не пересекаются вернуть пути, перенаправления наоборот
3 24.10.2026 Состояние модуля — данные, рисует ядро разнобой блоков возник из компонента —
4 24.10.2026 Трекер в ядре, подхват любого автора по module видны автообновления и пакеты MCP вернуть фильтр по автору
5 24.10.2026 Блокирует только пакет своего обновления долгие пакеты не мешают обновлению —
6 24.10.2026 Обновление — значок в панели + secondary в шапке одна primary на экран перекраска кнопок
7 24.10.2026 Один опрос /agents агент wiki не виден сейчас —
8 24.10.2026 Узкий экран: метка проекта + сводная точка проект не виден, две кнопки обновления вернуть кнопку
9 24.10.2026 batches по модулям, старые поля остаются пакет wiki терялся; MCP не ломать —
10 24.10.2026 Тест на пересечение классов CSS вместо префиксов ловит дефект без массового переименования ввести префиксы позже
11 24.10.2026 Типы jira — в модуль, fact_status из веба удалён граница ядра; #60 вернуть поле в тип
12 24.10.2026 Форматтеры дат в ядре три формата дат, импорт wiki → jira —
13 24.10.2026 Сводка «Обзора» от модуля ядро не знает данных модулей —
14 24.10.2026 Архив после sdlc-rename дельты поверх новых имён правка дельт при архиве
15 24.10.2026 last_full_sync(conn, base_jql=None) в modules/jira/mirror.py: базовая JQL необязательна (по умолчанию projects.base_jql), board() передаёт свою; импорт в project_fields.view отложенный интерфейс плана (conn) сохранён, board() не меняет сигнатуру; прямой импорт даёт цикл mirror → history → projects → project_fields вернуть явный параметр
16 24.10.2026 Фильтр module в list_batches применяется до limit перебором пакетов (по типу первой команды), без SQL-колонки у пакета нет колонки модуля, схему не менять; объём пакетов невелик добавить колонку batch.module
17 24.10.2026 Тесты Task 1 лежат в test_wiki_projects.py/test_project_fields.py (нужны оба модуля), а не в test_queue_core.py/test_api.py; правлены старые ожидания в test_db.py (jira_-поля) в test_queue_core модули подменены заглушкой перенести тесты
18 24.10.2026 R-1: трейлер коммитов ветки — Co-Authored-By: Claude Sonnet 5.5, а не Opus 5.5 из плана системная подсказка сессии об атрибуции приоритетнее текста плана переписать трейлеры
19 24.10.2026 R-2: предусловие плана («после слияния #97 в main») считается выполненным базированием на feat/97-sdlc-rename указание владельца; PR #99 ещё не слит ребейз на main после слияния #99
20 24.10.2026 R-3: параметр q страницы «Вики» реализует Task 5, Task 7 только добавляет тест в плане требование задвоено между Task 5 и Task 7 мелкая правка
21 24.10.2026 Task 2: ModuleProviders.tsx перенесён из modules/ в shell/ (импортирует только modules/index.ts) тест-страж границы допускает из ядра лишь modules/index.ts и modules/types.ts; App.tsx импортировал modules/ModuleProviders.tsx вернуть файл и ослабить страж
22 24.10.2026 Task 2: fmtDate доски (board/model/util.ts, принимает не-ISO даты Jira, год не показывает) остаётся в модуле; в ядре ui/format.ts — свой fmtDate, таблица и карточка задач берут его (даты другого года — ДД.ММ.ГГГГ); fmtStamp(null) → «—» задача требует форматтеры в ядре; доска сравнивает строки дат Jira в разных локалях свести две функции в одну
23 24.10.2026 Task 2: словари jira-настроек — тип JiraSettings extends HubSettings в modules/jira/api/types.ts; HubSettings ядра — только project_key и индексная подпись страж запрещает термины jira в ядре вернуть словари в HubSettings
24 24.10.2026 Task 3: ActivityProvider стоит в Layout (внутри ProjectContext), а не в App.tsx; «проект создан» — trackBatch(batchId) ядра (модуль берётся из Batch.module, запасной путь — refresh.isOwn) вместо useOnProjectCreated модуля project провайдера берётся из ProjectContext, он создаётся в Layout; модуль не называется в ядре перенести провайдер выше и передавать проект иначе
25 24.10.2026 Task 3: подхват пакетов — только при монтировании, смене проекта, раз в 60 с и после 409; прежний подхват «после загрузки снимка доски» (skipPickup, T10.1/T4.1) убран ядро не знает ключей данных модуля; правила подхвата заданы спекой; счётчик skipPickup больше не нужен вернуть подписку на кэш по ключу, объявляемому модулем
26 24.10.2026 Task 3: состояние на модуль — хук-трекер на модуль (useTracker, вызывается по константному списку TRACKED) и useQuery пакета в каждом, а не общий useQueries перенос логики остановки опроса без изменений; useQueries потребовал бы переписать эффект завершения заменить на useQueries
27 24.10.2026 Task 3: start берёт агента свежим fetchQuery(["agents"], staleTime 0), а не из кэша; ошибка этого запроса — событие hub-down/error, как у прежнего GET /agent сохраняет поведение прежних сценариев (hub-down, 401 на предпроверке) брать из кэша useAgents()
28 24.10.2026 Task 3: wiki refresh.start приводит ответ {batch_id} к {id}; track() перехватывает отслеживание, если текущий пакет не «свой» (раньше — только если ничего не отслеживалось) контракт ядра единый {id}; пакет нового проекта важнее чужого отдельная форма ответа / прежняя проверка
29 24.10.2026 Task 3: сводка useActivitySummary: error > offline > busy > online — заменено решением 56 ошибка и офлайн агента важнее, чем «идёт пакет» поменять порядок
30 24.10.2026 Task 3: временный shell/activity/StatusBlock.tsx (строки модулей и строка событий узкого экрана) вместо SidebarStatus/TopbarNotice модулей; Task 4 заменяет его; страница вики берёт действие из трекера, уведомление об ошибке постановки (syncError) убрано — ошибка видна событием модуля оболочка должна работать и набор быть зелёным до Task 4 вернуть Notice на странице вики
31 24.10.2026 Task 3, fix T3.I1: подхват после 409 (pickup(true)) заменяет отслеживаемый чужой пакет первым (самым старым) другим незавершённым пакетом модуля; если другого нет — чужой остаётся детали 409 (batch_id) клиент не разбирает, а список без команд не различает типы брать batch_id из ApiError.detail
32 24.10.2026 Task 4: «Обзор» (/) пока рисует shell/OverviewPage.tsx — заглушка с заголовком под ProjectGate; Task 5 заменяет её страницей со сводками пункт «Обзор» и адрес / нужны панели и перенаправлениям уже сейчас оставить / → /jira/board до Task 5
33 24.10.2026 Task 4: пункты панели ядра — shell/nav.tsx (OVERVIEW, GROUPS, NAV); NotFound, Layout и Sidebar берут их оттуда; группа — role="group" с видимым названием модуля (в свёрнутой панели название скрыто) один источник списка разделов для панели, «не найдено» и заголовка вкладки свести в MODULES.flatMap по месту
34 24.10.2026 Task 4: список под окном карточки по прямому/прежнему адресу берёт project из адреса карточки (listBackground(search)), закрытие — /jira/issues?project=… брифом: «закрытие окна — с текущим проектом»; константа LIST_BACKGROUND без проекта теряла выбор вернуть константу, проект подставит Layout
35 24.10.2026 Task 4: модальность выезжающей панели — атрибут inert на соседях aside внутри .shell (страница и верхняя строка), фокус на «Меню» возвращается эффектом после закрытия; Dropdown гасит Escape (preventDefault) только когда сам открыт, а панель закрывается по Escape лишь при !defaultPrevented ловушка Tab на списке фокусируемых хрупка; inert закрывает и чтение с экрана ловушка фокуса вручную
36 24.10.2026 Task 4: --topbar-h удалён из shell.css и из board.css (.drawer на ширине страницы < 852 px статичен, а строка приложения бывает только на < 640 px) M-6 #73: переменная мертва вернуть переменную
37 24.10.2026 Task 4: прокручивается середина панели (.sidebar__scroll: разделы и блок состояния), низ с темой и меню «Ещё» остаётся вне прокрутки; поправка R-1 решения #69 (меню «Ещё» свёрнутой панели выходит за 64 px, при overflow на всей панели обрезалось бы) M-5 #73: на низком окне панель не должна обрезаться прокрутка всей панели и обрезанное меню
38 24.10.2026 Task 4: сводная точка узкого экрана — role="img" с aria-label «Состояние модулей: ошибка / идёт обновление / агент на связи / агент офлайн»; «идёт обновление» — нейтральный цвет (токена «info» нет); событие пакета узкого экрана — постоянный role="status" под строкой (data-testid="topbar-events") цвет не единственный признак; T10.1 #94 вернуть aria-hidden-строку
39 24.10.2026 Task 5: GET /board на / («Обзор» грузит снимок доски для сводки jira, решение 13) — тест no wiki row without root блока состояния проверяет только отсутствие GET /wiki/status open() теста открывает /, а он теперь тянет доску; суть теста — строка вики без корня тест строже, чем нужно; ослабление скрывает запрос статуса вики без корня
40 24.10.2026 Task 5: общий agentText(a) (shell/activity/agentText.ts) — текст, подсказка и признак «на связи» агента; им пользуются блок состояния и карточки «Обзора» текст «агент на связи/офлайн/обновите агента» не должен разойтись между двумя местами рефакторинг блока состояния; тесты блока его держат
41 24.10.2026 Task 5: useRecentBatches(project) опрашивает GET /batches?project=&limit=10 раз в 15 с (refetchInterval) ход пакетов меняется без участия страницы; инвалидация из активности ядра усложнила бы контракт лишние запросы раз в 15 с на «Обзоре»
42 24.10.2026 Task 5: поле поиска вики на «Обзоре» не ведёт на пустой запрос (Enter при пустой строке ничего не делает); q в «Вики» — только начальное значение поля, выбор страницы убирает q из адреса пустой поиск = страница «Вики» без q, для неё есть ссылка «Вики»; hrefOf страницы по контракту Task 4 не несёт поиск пользователь, вставший на ?q= и открывший страницу, теряет в адресе строку поиска (в поле она остаётся)
43 24.10.2026 Task 6: номер доски проверяется в окне сам (/^\d+$/, ≥ 1, текст «нужно целое число»), поле — type="text" с inputMode="numeric", форма noValidate type="number" даёт браузерную подсказку вместо нашего текста и пропускает 51.5/1e3 по-разному в браузерах; T4.1 поле без стрелок счётчика; невалидное значение ловится только по «Создать»
44 24.10.2026 Task 6: в ядре useTrackModuleBatch() (activity.ts) — отслеживание пакета по имени модуля; окно создания вынесено в shell/NewProject.tsx; useTrackBatch остаётся для пакетов без известного модуля пакеты нового проекта привязываются каждому своему модулю по batches[].module (M-14, T5.3 #68); Layout не обязан знать модули пакет неизвестного модуля молча не отслеживается
45 24.10.2026 Task 7: узкий экран «Вики» (страница выше дерева) — через matchMedia("(max-width: 759.98px)") и порядок в разметке (WikiPage), а не CSS order; дерево при поиске скрыто (hidden), а не размонтировано порядок Tab совпадает с видимым; раскрытые вручную узлы переживают поиск (T10.2, T10.6); порог окна — приближение порога контейнера страницы (заменено решением 51: мерится ширина контейнера) CSS order и размонтирование дерева
46 24.10.2026 Task 7: заголовки текста страницы вики сдвинуты ниже заголовка страницы: #/## → h3, ### → h4 … не глубже h6 порядок h1 → h2 → h3 без скачков и без второго h1 (T10.3) оставить h1–h4 как есть
47 24.10.2026 Task 7: .issue-table-wrap{overflow-x:auto} на любой ширине (раньше — только @container page < 1052px) на 1440 px девять столбцов шире панели; цена указана неверно: обёртка-скроллер выключает липкость шапки совсем — см. решение 50 вернуть условие и сжать столбцы
48 24.10.2026 Task 7: проверка T5.2 «ядро не грузит /board и /wiki/status» идёт на странице вне модулей (/app/nowhere), а не на /wiki?project=… страница «Вики» сама запрашивает /wiki/status (это модуль, не ядро) проверять на странице вики с исключением статуса
49 24.10.2026 Task 7: scrollbar-gutter: stable — на html (прокручивается окно, отдельной области страницы нет); «Обновить из Jira» в шапках — общий modules/jira/RefreshButton.tsx страницы разной высоты не двигаются по ширине; одна реализация кнопки на три страницы прокручиваемый контейнер страницы; кнопка в каждой странице
50 24.10.2026 Task 7, fix T7.I1: обёртка таблицы «Задач» при высоте окна ≥ 700 px получает max-height: calc(100vh - 220px) и overflow-y:auto, шапка липнет к обёртке; на низких окнах ограничения нет — шапка уходит со страницей при overflow-x:auto обёртка — скроллер, и position:sticky шапки внутри неё без собственной вертикальной прокрутки не работает (решение 47 ошибочно считало, что шапка липнет к панели); на длинных списках шапка должна оставаться на виду; цена — вложенная вертикальная прокрутка (на телефонах высотой < 700 px её нет) снять sticky/z-index и принять уходящую шапку
51 24.10.2026 Task 7, fix T7.I2: порядок «страница/дерево» в WikiPage определяется ResizeObserver на .wiki__body с порогом ≤ 759.98 px — тем же, что @container page в wiki.css; matchMedia убран окно и контейнер страницы (рядом боковая панель) расходятся, на окне ≈ 760–1050 px CSS уже в одну колонку, а DOM ещё нет; до первого замера (и без ResizeObserver) — широкая раскладка; ключи панелей сохраняют состояние дерева вернуть matchMedia с запасом по ширине панели
52 24.10.2026 Task 7, fix T7.I2: useWikiDownload возвращает объект через useMemo перерисовка WikiPage (замер ширины) пересоздавала {start,status} → набор компонентов Markdown → ссылки-вложения перемонтировались (тест M-15 обнаружил); так же ломали бы их ввод в поиск и опрос статуса не трогать хук и убрать состояние замера
53 24.10.2026 Task 8: проверка «без горизонтальной прокрутки» на 1440 px — document.documentElement.scrollWidth <= window.innerWidth, а не === при классической полосе прокрутки Chromium scrollWidth равен ширине без полосы (1425 против 1440), равенство невозможно; смысл проверки — отсутствие переполнения — сохранён ложное «зелёное» только если переполнение скрыто тем же зазором; на 390 px (оверлейные полосы) проверка прежняя и строгая
54 24.10.2026 Task 8, дефект: у .issue-table-wrap добавлен position: relative скрытый текст «, просрочено» (.visually-hidden, position:absolute) не имел позиционированного предка внутри обёртки и выходил за её прокрутку: на 390 px scrollWidth страницы 778 при окне 390 без правки на узком экране у «Задач» появлялась горизонтальная прокрутка всей страницы
55 24.10.2026 Task 8: «Последние пакеты проекта» проверяются пакетом «Обновить вики» (пакет проекта), а не «Обновить из Jira»; для событий пакета Jira в e2e — хелпер jiraEvent (строка модуля в панели / полоса на узком экране) пакет «Обновить из Jira» не привязан к проекту (охват «все проекты») и в список проекта не попадает; на странице несколько role=status, прежний getByRole("status") неоднозначен только тесты; список пакетов проекта и так фильтруется хабом по project
56 24.10.2026 Final fix wave, I-2: сводная точка — error > busy > offline > online (заменяет решение 29) спека «Оболочка и адреса» — источник истины: ошибка, затем «пакет в работе», затем агенты на связи или нет перепутанный порядок красит точку «офлайн» при идущем пакете; спека и код расходятся
57 24.10.2026 Final fix wave, M-6/T2.3: офлайн-агент модуля сводку не красит, если freshness(project).available === false (вики без корня); проект для проверки провайдер берёт из useProjects() (тот же ключ запроса, без нового запроса); пока проекты не загружены — агент считается значимым ядру нечего показывать и обновлять у модуля без данных проекта; freshness(p: Project) не менялась кратковременно (до загрузки проектов) возможна «офлайн» у проекта без корня вики
58 24.10.2026 Final fix wave, T2.3: jira_synced_at убрано из ядрового Project и перенесено в JiraProject (modules/jira/projectFields.ts); jira/status.ts читает поле через type guard hasJiraSync(p) без as; boundary.test.ts ловит имена полей модулей в ядре (MODULE_TERMS расширен) ядро не должно знать поля модулей; контракт freshness(p: Project) сохранён — минимальное решение без обобщения ModuleStatus проект без поля (старый ответ хаба) показывается как «обновления ещё не было»
59 24.10.2026 Final fix wave, M-11: в agentText.ts предупреждение/update_hint важнее офлайна (офлайн-агент с предупреждением показывается как «обновите агента») предупреждение требует действия человека и объясняет, почему агент не работает, а «офлайн» может пройти сам человек увидит «обновите агента» у агента, который ещё и офлайн; после обновления текст сменится на «офлайн»
60 24.10.2026 Final fix wave, M-9: принято как известное ограничение — jira_synced_at сбрасывается после создания проекта: last_full_sync сравнивает JQL прогона с текущей базовой JQL, а при новом проекте она меняется; до нового полного прогона у всех проектов «обновления ещё не было». Кодом не чинится, follow-up правка — в хабе (Python), вне объёма веб-change у всех проектов после создания нового до следующего «Обновить из Jira» нет даты свежести
61 24.10.2026 Final fix wave, #68 M-2: меню доски названо «Ещё — доска»; меню панели остаётся «Ещё» однозначные доступные имена двух меню на одной странице; тесты больше не зависят от гонки пользовательские сценарии, искавшие «Ещё» на доске, ищут новое имя
62 24.10.2026 Final fix wave, #73 M-2: выезжающая панель обёрнута в div.sidebar-modal[role=dialog][aria-modal][aria-label=Меню] (display: contents), <aside> «Панель приложения» остаётся внутри; прокрутка страницы блокируется overflow:hidden на <html> пока панель открыта роль dialog на самой aside стёрла бы роль complementary и имя «Панель приложения» (тесты, e2e, читалки экрана); scrollbar-gutter: stable исключает сдвиг обёртка не должна менять раскладку; при сбое очистки эффекта прокрутка осталась бы заблокированной (очистка возвращает прежнее значение)
63 24.10.2026 Final fix wave, M-2: Active получает project; track(id, project?) (по умолчанию — текущий проект); смена проекта сбрасывает отслеживаемый пакет проектного модуля, только если он принадлежит другому проекту; «Новый проект» передаёт метку нового проекта пакет вики нового проекта ставится до смены адреса и раньше сбрасывался эффектом смены проекта пакет без указанного проекта считается пакетом текущего
64 24.10.2026 Final fix wave, T10.6: Tree.selectedKnown истинно, только когда полная цепочка предков выбранного узла до корня есть в nodes узел мог прийти раньше родителя, и предки не раскрывались при разорванной цепочке (родителя в дереве нет) предки не раскрываются — раскрывать нечего
65 24.10.2026 Final fix wave, M-1/M-7: start() фиксирует generation вместе с проектом до await; признак «агент офлайн» подхваченного пакета вычисляется при отрисовке (active.agentOffline || agent.online === false) пакет старого проекта не должен появляться в строке нового; снимок на момент подхвата устаревает признак «офлайн» не снимается, пока пакет отслеживается, если был поставлен при офлайн-агенте