Files
clickstream-data-platform/docs/agents/issue-tracker.md
T
ddadminandClaude Opus 5 41d057252e docs(agents): у правки комментария свой путь в API
Зачем: резолюции wayfinder-тикетов живут комментариями, и правка после
ревью идёт в них — а дока описывала только правку тела issue. Путь
неочевидный: без номера issue, по идентификатору из ленты.

Что: абзац в разделе про правку через API и строка в «Что проверено и
когда».

Проверка: снято живыми запросами при закрытии #72 — резолюция правилась
дважды этой командой.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 08:04:38 +03:00

191 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Issue tracker: Gitea
Задачи этого репозитория живут в Gitea на `git.dementev.space`
(`ddmitry/clickstream-data-platform`, это remote `origin`). Все операции —
через CLI [`tea`](https://gitea.com/gitea/tea), официальный клиент Gitea; по
устройству он близок к `gh` и `glab`. Логин и репозиторий `tea` определяет сам
по git remote в текущем каталоге.
## Перед первым запуском
- **Бинарник.** Скачивается с `https://dl.gitea.com/tea/<версия>/` (файл
`tea-<версия>-linux-amd64` и `.sha256` рядом), кладётся в `~/.local/bin/tea`.
Проверка: `tea --version`.
- **Вход.** `tea logins add --name git.dementev.space --url
https://git.dementev.space`, токен передаётся переменной
`GITEA_SERVER_TOKEN` (не аргументом командной строки — он попадёт в историю
оболочки). Логин уже добавлен и назначен по умолчанию, так что `tea` работает
из любого каталога.
- **Скоупы токена:** `read:user` (без него `tea` откажется добавлять логин),
`write:issue`, `write:repository`. Токен выпускается в UI: Settings →
Applications. Нехватка скоупа выглядит не как «нет прав», а как невнятная
ошибка или пустой ответ.
- **Прокси.** Домен `dementev.space` должен быть в `NO_PROXY`, иначе запросы
уходят в прокси и виснут. В обычной оболочке это делает `proxy-client` из
`~/dotfiles`. Если переменная не подхватилась, короткий разовый префикс:
`NO_PROXY='*' tea ...`.
## Команды
- **Создать issue:** `tea issues create --title "..." --description "..."`.
Многострочное тело удобнее собрать heredoc'ом в переменную и подставить
как `--description "$BODY"`.
- **Прочитать issue:** `tea issues <номер> --comments`.
- **Список:** `tea issues list --state open --output json --fields
index,title,labels,assignees`. Фильтры: `--labels`, `--assignee`,
`--keyword`.
- **Комментарий:** `tea comments add <номер> -d "..."`.
- **Метки:** `tea issues edit <номер> --add-labels "..."` / `--remove-labels
"..."`. Список меток репозитория — `tea labels list`, создать новую —
`tea labels create --name "..." --color "..."`.
- **Закрыть:** `tea issues close <номер>`. Комментария при закрытии команда не
принимает — сначала `tea comments add`, потом `close`.
- **Взять в работу:** `tea issues edit <номер> --add-assignees ddmitry`.
Сокращения вида `@me` в `tea` нет, имя пишется целиком.
- **Чего нет в CLI** — через `tea api <path>`: команда ходит в REST API Gitea
уже с сохранённым токеном, например
`tea api repos/ddmitry/clickstream-data-platform/issues/18`.
## Правка тела issue — только через API
Тикнуть чекбокс в критериях приёмки нужно при закрытии каждой задачи, и `tea`
для этого не годится. `tea issues edit --description` принимает тело **целиком
строкой**, а взять эту строку неоткуда: `tea issues <номер>` печатает текст
обёрнутым и разрисованным для терминала, обратно его не скормишь.
Рабочий путь — забрать сырое тело из API, поправить и вернуть:
```sh
# 1. сырой JSON тикета; тело — в поле body
tea api repos/{owner}/{repo}/issues/<n> > issue.json
# 2. правка тела любым удобным способом, например все чекбоксы разом
python3 -c "
import json
d = json.load(open('issue.json'))
json.dump({'body': d['body'].replace('- [ ]', '- [x]')},
open('patch.json', 'w'), ensure_ascii=False)
"
# 3. вернуть
tea api -X PATCH -d @patch.json repos/{owner}/{repo}/issues/<n>
```
Флаги `tea api`: `-X` — метод, `-d` — сырое тело JSON (`@файл` читает из файла,
`@-` из потока ввода), `-f` и `-F` — отдельные поля строкой и с типом. Флага
`--input` нет, хотя рука тянется написать именно его.
Тот же приём — для чек-листа родительской карты: пункт `- [ ] #NN` тикается
правкой её тела, автоматически Gitea этого не делает.
Комментарий правится тем же способом, но путь у него свой — без номера issue:
`tea api -X PATCH -d @patch.json repos/{owner}/{repo}/issues/comments/<id>`.
Идентификатор берётся из `GET .../issues/<n>/comments`; это не порядковый номер
комментария в ленте. Нужно это чаще, чем кажется: резолюции wayfinder-тикетов
живут комментариями, и правка после ревью идёт в них.
**Отсюда общее правило.** `tea` удобен там, где команда создаёт объект или
меняет его свойство: создать issue, добавить комментарий, повесить метку,
назначить исполнителя, закрыть. Как только нужно **изменить уже написанный
текст** — тело issue, тело PR, — CLI мешает: он умеет только заменить всё
целиком, а прочитать это «всё» в пригодном для правки виде не даёт. Такие
операции идут прямо в API.
## Слияние PR не закрывает issue
Gitea понимает только английские ключевые слова автозакрытия: `closes`,
`fixes`, `resolves` (`Closes #13`). Русское «Закрывает #13» в теле PR — обычная
ссылка, issue останется открытым. Наступали не раз: последний случай — слияние
PR #17, где issue #13 пришлось закрывать руками.
Отсюда простое правило: пиши в теле PR английское `Closes #NN` — тогда
слияние закроет задачу само, и ручного шага не остаётся. Всё остальное в PR
по-прежнему на русском: ключевое слово здесь не текст, а команда трекеру.
Если ключевого слова не было, порядок после слияния: закрыть задачу
(`tea issues close <номер>`) и тикнуть её пункт в чек-листе родительского
issue этапа — Gitea чек-листы сама не обновляет. Чем тикать — выше, в разделе
про правку тела.
## Спека — источник истины
- Спецификация фичи — файл в `docs/specs/`, версионируется с кодом.
- Корневой issue фичи — **тонкий**: ссылка на спеку + чек-лист дочерних issues
(`- [ ] #NN`). Содержание спеки в issue не дублируется — истина одна, в git.
- Дочерние issues — полноценные самодостаточные постановки: цель, критерии
приёмки чекбоксами, границы («что трогать нельзя»), «сначала прочитать»,
команды проверки.
- Итоговые резолюции и решения — в спеку или ADR тем же PR; issue — рабочая
переписка, она не обязана переживать фичу.
## Когда скилл говорит «опубликовать в issue tracker»
Создать issue в Gitea: `tea issues create ...`.
## Когда скилл говорит «достать тикет»
`tea issues <номер> --comments`.
## PR как поверхность триажа
**Нет** — одиночный учебный репозиторий, внешних PR не ждём. (Если включить —
`/triage` начнёт гонять PR через те же метки и состояния командами
`tea pulls ...`.)
## Wayfinding-операции
Используются `/wayfinder`. Карта — один issue, тикеты — дочерние issues.
- **Карта**: issue с меткой `wayfinder:map` (Notes / Decisions-so-far / Fog
в теле).
- **Дочерний тикет**: вложенных issues в Gitea нет, поэтому связь держится
двумя ссылками — пункт списка `- [ ] #NN` в теле карты и строка
`Part of #<карта>` в начале тела тикета. Метки: `wayfinder:<тип>`
(`research` / `prototype` / `grilling` / `task`).
- **Блокировки**: нативные зависимости Gitea — единственный источник истины,
текстовых строк `Blocked by:` в телах тикетов нет. В CLI их команд нет,
работаем через `tea api` (`{owner}` и `{repo}` подставляются из текущего
репозитория):
- добавить блокер: `tea api repos/{owner}/{repo}/issues/<n>/dependencies
-F index=<блокер> -f owner=ddmitry -f repo=clickstream-data-platform`
— поля `owner` и `repo` обязательны, без них API отвечает
«repository does not exist»;
- кто блокирует тикет: `GET .../issues/<n>/dependencies`;
- кого блокирует тикет: `GET .../issues/<n>/blocks`;
- снять блокировку: тот же путь методом `DELETE` с тем же телом.
Тикет разблокирован, когда у всех блокеров `state == "closed"`.
- **Фронтир**: открытые дети карты минус заблокированные и назначенные; первый
в порядке карты. Блокеры проверяются запросом `dependencies` по каждому
кандидату.
- **Взять в работу**: `tea issues edit <n> --add-assignees ddmitry` — первая
запись за сессию.
- **Закрыть**: `tea comments add <n> -d "<ответ>"`, затем `tea issues close
<n>`, затем указатель на контекст (суть + ссылка) в Decisions-so-far карты.
## Что проверено и когда
2026-08-13: правка комментария через `repos/{owner}/{repo}/issues/comments/<id>`
снята живыми запросами при закрытии #72 — так дважды правилась резолюция тикета.
2026-08-06: правка тела issue через `tea api -X PATCH -d @файл` снята живыми
запросами при закрытии #37 — так проставлены чекбоксы самого тикета и пункт
в чек-листе карты #4. Тогда же проверено, что `tea issues edit --description`
для этого непригоден, а флага `--input` у `tea api` нет.
2026-07-31: Gitea 1.27.0 (`tea api version`), `tea` 0.15.0. Живыми запросами по
этому репозиторию проверены `tea labels list` и `tea issues list`. Остальной
набор команд, флагов и приёмы с `tea api` перенесены из доки
предшественника — там они снимались с `tea <команда> --help` установленного
бинарника и проверялись живыми запросами 2026-07-29. При обновлении `tea` стоит
перечитать `--help`: набор флагов между версиями менялся.
## Архив
- Трекер предшественника — репозиторий
[`ddmitry/clickstream-ch-kafka-superset-demo`](https://git.dementev.space/ddmitry/clickstream-ch-kafka-superset-demo).
Задачи оттуда сюда не переносились: платформа v2 начата с чистого трекера.
- До 2026-07-26 задачи предшественника жили в GitHub Issues
(`dementev-dev/…`); аккаунт заблокирован, номера воссозданы в Gitea один
в один.