104 lines
13 KiB
Markdown
104 lines
13 KiB
Markdown
## Context
|
||
|
||
`main` 9f4bb75. Устройство, на которое опираются правки:
|
||
|
||
- **Настройки** — `src/jira_hub/settings.py`: `DEFAULTS` (ключ → значение по умолчанию), `ensure_defaults` при открытии
|
||
базы добавляет недостающие ключи (`INSERT OR IGNORE`), `validate` проверяет тип по значению по умолчанию,
|
||
`AGENT_KEYS` — что уходит агенту. `GET /settings` отдаёт всё, кроме токенов.
|
||
- **Список на сервере** — `api.ISSUE_FILTERS` → `mirror.list_issues(conn, filters, limit, offset)`: `_FILTERS`
|
||
(точное совпадение по колонке) плюс отдельные ветки для `label`, `neighbor`, `q`.
|
||
- **Список в приложении** — `web/src/issues/IssuesPage.tsx`: фильтры из query-строки по `ISSUE_FILTER_NAMES`
|
||
(`web/src/api/queries.ts`), все уходят в `GET /issues` как есть; `SELECTS` — выпадающие списки, варианты —
|
||
`filterOptions` (`web/src/issues/options.ts`), «только соседи» — флажок `neighbor=1`. Порции по 50 (`useIssues`).
|
||
- **Доска** — `web/src/board/`: модель из `GET /board` / CSV / JSON → видимая выборка (`analysis/visible.ts`, `VisNode`
|
||
с `dim` — сосед, класс карточки `out`) → `BoardCanvas` → `Card.tsx` (класс `card`, `out`, `crit`, `focus`) и
|
||
`Edges.tsx` (`<path>` на каждую связь). Настройки — `useSettings()` в `BoardPage.tsx`, словари — `dicts.ts`.
|
||
Golden-тесты сравнивают модель, выборку, критический путь и проблемы с `links.html@3931a88`.
|
||
- **Карточка** — `web/src/issues/IssueCard.tsx`: шапка с бейджем статуса по факту (`factClass` по `status_labels`),
|
||
«просрочено» — `isOverdue(due, fact, statusLabels, today)` (`card.ts`, R-2 #37). `Notes.tsx` — строки заметки,
|
||
`NoteForm.tsx` — форма, поле `fact_status` с подсказками из `status_labels`; сохраняются только изменённые поля.
|
||
- **Живые данные** (17.10.2026): закрытые статусы AURORA — «Готово» и «Снято»; `transitions_map` и `status_labels`
|
||
в настройках ключуются статусами по факту — это касается будущего полного удаления, не этой задачи.
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:** в списке по умолчанию только незакрытые задачи, закрытые — одним флажком; на доске закрытые не отвлекают, но
|
||
связи через них видны; «статуса по факту» в веб-приложении нет.
|
||
|
||
**Non-Goals:** см. proposal.md.
|
||
|
||
## Decisions
|
||
|
||
1. **Набор закрытых статусов — настройка хаба `closed_statuses`**, список строк, по умолчанию `["Готово", "Снято"]`.
|
||
Приложение по правилу «Справочники из настроек хаба» своих копий словарей не держит, а сервер нужен для фильтра
|
||
списка. В `DEFAULTS`, поэтому на живом хабе ключ появится при первом открытии базы после выкатки (`ensure_defaults`);
|
||
тип проверяет `validate` (список). В `AGENT_KEYS` не входит. Сравнение — точное совпадение строки статуса.
|
||
2. **Фильтр списка — на сервере:** `GET /issues?hide_closed=1` добавляет условие `i.status IS NULL OR i.status NOT IN
|
||
(…closed_statuses)` (задача без статуса — не закрыта). Клиентский фильтр поверх порций по 50 ломал бы «Показать
|
||
ещё» (порция могла бы прийти пустой). Значение `1` / `true` — включено, иное или отсутствие — выключено (как
|
||
`neighbor`). Пустой `closed_statuses` — фильтр ничего не скрывает.
|
||
3. **Адрес списка:** по умолчанию закрытые скрыты, в адресе ничего нет; снятый флажок «скрыть закрытые» — `closed=1`.
|
||
Приложение отправляет `hide_closed=1`, пока `closed` не `1`. `closed` — параметр приложения, в `GET /issues` не
|
||
уходит. Флажок — рядом с «только соседи».
|
||
4. **Явный выбор статуса сильнее флажка:** если в фильтре «Статус Jira» выбран статус из `closed_statuses`,
|
||
`hide_closed` не отправляется — иначе выборка всегда пуста. Флажок при этом остаётся как есть.
|
||
5. **Доска:** признак закрытости вычисляется при отрисовке, а не в модели — модель, выборка, критический путь и
|
||
проблемы остаются как у `links.html` (golden-тесты не трогаются). Карточка получает класс `closed`
|
||
(`opacity: .4`), под указателем и с фокусом внутри — полная яркость (`.card.closed:hover`, `.card.closed:focus-within`;
|
||
признак `VisNode.focus` нигде не включается, выделения карточек на доске нет). Стрелка, у которой хотя бы один конец —
|
||
закрытая задача, — класс/атрибут с той же прозрачностью. Сосед (`out`) и закрытая — признаки независимые, вместе
|
||
— оба стиля. Набор закрытых — из `useSettings()`; карточки из CSV и JSON приглушаются по тому же правилу (статус у
|
||
них есть).
|
||
6. **Нет `closed_statuses` в настройках** (хаб старее приложения) — ничего не считается закрытым: список без фильтра,
|
||
доска без приглушения, ошибки «нет словаря» нет. Хаб и приложение выкатываются вместе, это окно короткое.
|
||
7. **«Просрочено» в карточке** — по статусу Jira: срок раньше сегодня и статус не из `closed_statuses` (было — по
|
||
классу статуса по факту, R-2 #37). Без статуса по факту прежнее правило не на чем считать.
|
||
8. **«Статус по факту» из приложения:** убрать из `ISSUE_FILTER_NAMES` и `SELECTS`, колонку таблицы, вариант из
|
||
`filterOptions`, бейдж в шапке карточки (`factClass`, стили `.badge.fact*`), строку в `Notes.tsx`, поле и подсказки
|
||
в `NoteForm.tsx`. Тип `NoteFields` / `NOTE_FIELDS` приложения — без `fact_status`; так форма не может отправить его
|
||
и в `PUT` значение не трогается. Тип ответа API (`IssueRow.fact_status`, `Note.fact_status`) — поле остаётся
|
||
необязательным, приложение его не читает. Старый адрес с `fact_status=` — параметр игнорируется (нет в
|
||
`ISSUE_FILTER_NAMES`).
|
||
|
||
## Risks / Trade-offs
|
||
|
||
- Новый статус Jira закрытого смысла (например, «Отклонено») не будет скрыт, пока его не добавят в `closed_statuses`
|
||
— осознанно: владелец назвал ровно два статуса.
|
||
- Пока хаб не перезапущен после выкатки, сборка приложения новее хаба: `hide_closed` хаб старой версии игнорирует, и
|
||
список покажет закрытые — безвредно.
|
||
|
||
## Decisions made without discussion
|
||
|
||
1. 2026-10-17 — **набор закрытых статусов в настройке хаба `closed_statuses`**, а не константой в коде. Обоснование:
|
||
правило «Справочники из настроек хаба», фильтр нужен и серверу, и приложению. Цена ошибки: лишний ключ настроек;
|
||
убрать — правка `DEFAULTS` и двух мест чтения.
|
||
2. 2026-10-17 — **фильтр `hide_closed` на сервере**, а не в браузере. Обоснование: порции по 50. Цена ошибки: один
|
||
параметр API; поведение MCP не меняется.
|
||
3. 2026-10-17 — **адрес: `closed=1` — показать закрытые; по умолчанию параметра нет.** Обоснование: умолчание владельца
|
||
«скрыты», адрес без лишних параметров. Цена ошибки: переименование параметра.
|
||
4. 2026-10-17 — **выбранный в «Статус Jira» закрытый статус отменяет скрытие.** Обоснование: иначе выборка всегда пуста.
|
||
Цена ошибки: поведение одного сочетания фильтров.
|
||
5. 2026-10-17 — **приглушение: `opacity .4`, полная яркость под указателем и с фокусом клавиатуры внутри; стрелки — если закрыт хотя бы один
|
||
конец.** Обоснование: владелец подтвердил «связи тоже бледнеют»; степень прозрачности — на глаз, отличается от
|
||
соседа (`.7`, пунктир). Цена ошибки: правка CSS.
|
||
6. 2026-10-17 — **без `closed_statuses` — ничего не закрыто, без сообщения об ошибке.** Обоснование: это не словарь
|
||
подписей, без него страница работает как раньше. Цена ошибки: нет.
|
||
7. 2026-10-17 — **«просрочено» — по статусу Jira из `closed_statuses`.** Обоснование: статус по факту из приложения
|
||
убран. Цена ошибки: пометка «просрочено» у задачи, закрытой по факту, но не в Jira, — теперь видна (это и есть
|
||
статус Jira).
|
||
|
||
Решения исполнения (маркеры по ledger SDD):
|
||
|
||
8. 2026-10-17 — **R-1: e2e-шаг флажка — `click()` + `not.toBeChecked()` вместо `uncheck()`.** Обоснование: флажок
|
||
управляется адресом, React Router меняет его навигацией асинхронно, `uncheck()` проверяет состояние сразу после
|
||
щелчка; так же устроен «только соседи». Цена ошибки: нет, поведение то же.
|
||
9. 2026-10-17 — **R-2: «PUT заметки не шлёт `fact_status`» отдельным тестом не дублируется.** Обоснование: тест
|
||
сохранения в `IssueCard.test.tsx` идёт на фикстуре с `fact_status` и сравнивает тело целиком. Цена ошибки: нет.
|
||
10. 2026-10-17 — **R-3: в заметке без данных — 4 прочерка вместо 5.** Обоснование: полей заметки в приложении
|
||
четыре по спеке. Цена ошибки: нет.
|
||
11. 2026-10-17 — **R-4: тест приглушения на доске считает закрытые по статусам выборки.** Обоснование: в фикстуре
|
||
`hub-basic` уже есть AURORA-9006 «Готово». Цена ошибки: нет.
|
||
12. 2026-10-17 — **R-5: находки финального ревью M-1 (README описывал статус по факту в карточке) и M-2 (формат даты в
|
||
сценарии спеки) исправлены, а не отложены.** Обоснование: документация и спека — источник истины — противоречили
|
||
поведению; тестом не проверяются. Цена ошибки: нет.
|