docs: bootstrap repo — CLAUDE.md, spec, ADR, TenVex-style workflow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 14:36:33 +03:00
co-authored by Claude Opus 5.5
commit cf2cc8b5f4
15 changed files with 1671 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
# Gitea API — шпаргалка
> **⛔ Кириллица в JSON:** `curl -d '{...}'` ломает кодировку. Тело собирать в файл (python/node `json.dumps(..., ensure_ascii=False)`) и слать через `--data-binary @file` с `Content-Type: application/json; charset=utf-8`.
> **⛔ Обратные кавычки:** markdown-тексты не передавать внутри `"..."` в shell — бэктики выполнятся как команды. Только через файл / heredoc `<<'EOF'`.
```bash
set -a; . ./.env 2>/dev/null; set +a # GITEA_URL, GITEA_REPO, GITEA_USER, GITEA_TOKEN
API="$GITEA_URL/api/v1/repos/$GITEA_REPO"
H=(-H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json; charset=utf-8")
```
## Issues
```bash
# Мои открытые
curl -s "${H[@]}" "$API/issues?state=open&type=issues&assigned_by=$GITEA_USER"
# Открытые по зоне
curl -s "${H[@]}" "$API/issues?state=open&type=issues&labels=core"
# Создать (тело из файла)
python3 - <<'EOF' > /tmp/issue.json
import json; print(json.dumps({"title":"...","body":open("body.md").read(),"labels":[1,2],"milestone":1}, ensure_ascii=False))
EOF
curl -s -X POST "${H[@]}" "$API/issues" --data-binary @/tmp/issue.json
# Дописать лог выполнения в тело
curl -s "${H[@]}" "$API/issues/NN" | python3 -c '
import json,sys,datetime; b=json.load(sys.stdin)["body"]
b+=f"\n### {datetime.date.today()}\n- **Что сделано:** ...\n- **Результат:** ...\n"
print(json.dumps({"body":b},ensure_ascii=False))' > /tmp/patch.json
curl -s -X PATCH "${H[@]}" "$API/issues/NN" --data-binary @/tmp/patch.json >/dev/null
# Комментарий
curl -s -X POST "${H[@]}" "$API/issues/NN/comments" --data-binary @/tmp/comment.json
```
## Зависимости (только через API)
```bash
# #NN зависит от #MM
curl -s -X POST "${H[@]}" "$API/issues/NN/dependencies" \
-d "{\"owner\":\"${GITEA_REPO%%/*}\",\"repo\":\"${GITEA_REPO##*/}\",\"index\":MM}"
curl -s "${H[@]}" "$API/issues/NN/dependencies"
```
## Pull Requests
```bash
# base = dev, не main
curl -s -X POST "${H[@]}" "$API/pulls" --data-binary @/tmp/pr.json # {"head":"feat/NN-slug","base":"dev","title":"...","body":"Closes #NN ..."}
# Смержить (после зелёного CI)
curl -s -X POST "${H[@]}" "$API/pulls/PP/merge" -d '{"Do":"merge","delete_branch_after_merge":true}'
# Статусы CI коммита
curl -s "${H[@]}" "$API/commits/<sha>/statuses"
```
## Ветки
```bash
git ls-remote --heads origin <ветка> # пусто = PR уже смержен, не пушить
B="feat/NN-slug"; curl -s -X DELETE "${H[@]}" "$API/branches/${B//\//%2F}"
```
+34
View File
@@ -0,0 +1,34 @@
# Шаблон тела issue
Задача самодостаточна: агент, открывший её без контекста, понимает, что делать. Не хватает информации — дополни issue до начала работы.
```markdown
## Описание
Почему задача возникла, какую проблему решает, к какой части продукта относится. Ссылки на ADR / SPEC / CLINICAL_MODULES.
## Желаемый результат
Конкретно и проверяемо.
## Подзадачи
- [ ] шаг — файл/модуль
## Анализ
### Затрагиваемые файлы
| Файл | Что меняется |
|---|---|
### Ограничения и риски
152-ФЗ, safety, детерминизм, демо-часы, офлайн-режим.
### Архитектурный выбор
Если есть развилка — варианты и выбор.
## Как проверить
Команды / сценарий в демо-консоли / ожидаемый результат.
---
## Лог выполнения
```
> Зависимости — только через API. Лог — секция `### YYYY-MM-DD` за каждую сессию. Issue закрывается мержем PR с `Closes #N`.
+116
View File
@@ -0,0 +1,116 @@
# Регламент работы: зоны, задачи, git, коммиты
> Основан на регламенте TenVex/vobot, облегчён под хакатон (ADR-009). Дедлайн: **пн 05.10.2026, 13:00 МСК**.
## Зоны и файлы
| Зона (`label`) | Пути | Отвечает за | Владелец |
|---|---|---|---|
| `core` | `app/core/` | privacy, шкалы и скоринг, safety, движок правил, демо-часы | dev |
| `bot` | `app/dialog/`, `app/channels/`, `app/llm/` | FSM диалога, Telegram-адаптер, LLM-шлюз (GigaChat/mock) | Егор |
| `backend` | `app/db/`, `app/api/`, `app/scheduler/`, `app/integrations/` | БД, API, шедулер, моки МИС/ЕСИА/ГРЛС, уведомления | dev |
| `dashboard` | `dashboard/` | дашборд врача, демо-консоль (Streamlit) | dev |
| `devops` | `docker-compose.yml`, `Dockerfile`, `Makefile`, `.gitea/`, `pyproject.toml` | окружение, CI, запуск на чистой машине | dev |
| `clinical` | `config/` (содержимое), `data/eval/` | шкалы, пороги, тексты, лексикон, кризисный скрипт | психиатр |
| `pitch` | `docs/pitch/` | презентация, клинико-экономика, CJM, правовые слайды | медик |
| `docs` | `docs/`, `README.md`, `CLAUDE.md` | регламенты, ADR, README | все |
**Замок зоны:** пока на зону есть открытый issue с активной веткой, файлы зоны принадлежат ему до мержа. Перед правкой: `git fetch origin && git branch -r`.
**Схемы `config/*.yaml`** задаёт `core` (pydantic-модели), а **значения** в них — `clinical`.
---
## Откуда задачи
- Только из Gitea `$GITEA_REPO`. Нет issue — нет кода. Нет подходящего issue — заведи его на себя.
- Атрибуты: **метка зоны**, **тип** (`feature`/`fix`/`refactor`/`docs`/`chore`), **размер** (`size/0.5` ≈ 2 ч, `size/1` ≈ 4 ч, `size/2` ≈ день), **milestone** (M1/M2/M3), приоритет `P0`/`P1`/`P2`.
- **Одна задача = одна зона.** Нужно несколько зон → несколько issue, связанных зависимостью через API ([`GITEA_API.md`](GITEA_API.md)).
- Тело issue — по шаблону [`ISSUE_TEMPLATE.md`](ISSUE_TEMPLATE.md).
### Milestones
| Milestone | Срок | Смысл |
|---|---|---|
| M1 Каркас | сб 03.10, 23:59 | ядро, БД, LLM-шлюз, конфиги; тесты зелёные |
| M2 Демо-сценарий | вс 04.10, 23:59 | весь сценарий проходит end-to-end в демо-консоли |
| M3 Сдача | пн 05.10, 13:00 | README, презентация PDF, репетиция, `dev → main` |
---
## Жизненный цикл задачи
```
1. Взял issue (assignee = $GITEA_USER), зона свободна
2. git fetch origin
3. git worktree add .claude/worktrees/<issue#>-<slug> -b <type>/<issue#>-<slug> origin/dev ← ДО первого изменения
4. cp .env в worktree; uv sync
5. Код по модулям; коммиты с Refs #N
6. git ls-remote --heads origin <ветка> ← пусто после первого пуша = PR смержен, стоп
7. git fetch && git rebase origin/dev
8. make lint && make test
9. Лог в тело issue: ### YYYY-MM-DD
10. PR в dev с Closes #N → после зелёного CI мержит автор (облегчение хакатона)
11. git worktree remove .claude/worktrees/<issue#>-<slug>
```
**Задача завершена → сам: коммит → push → PR.** Не запушено — не сделано.
## Git
```
main ← сдаваемая версия, мержит только человек (пн утром)
dev ← интеграция, сюда все PR
<type>/<issue#>-<slug> ← от dev
```
## Коммиты — Conventional Commits
```
feat(core): add PHQ-9 scoring with item-9 escalation
Refs #3
```
scope = зона. `Closes #N` — только в описании PR.
## Шаблон PR
```markdown
## Что меняется
1–3 предложения.
Closes #<N>
## Зона
core | bot | backend | dashboard | devops | clinical | pitch | docs
## Как проверить
шаги/команды
## Чек-лист
- [ ] rebase на origin/dev
- [ ] make lint + make test зелёные
- [ ] лог в issue (### YYYY-MM-DD)
- [ ] нет ПДн в логах, нет реальных данных, нет секретов
- [ ] общие файлы (CLAUDE.md, docker-compose, pyproject) — отдельный мелкий PR с пингом
```
---
## Guardrails (проверяются в каждом PR)
1. **В LLM — только `scrub()`-текст.** Прямой вызов клиента GigaChat в обход `app/llm/gateway.py` запрещён.
2. **Safety до LLM.** При `acute` LLM не вызывается вообще.
3. **Алерты и скоринг детерминированы** — LLM не решает (ADR-007).
4. **Время — только из `app.core.clock`** (ADR-005).
5. **identity ↔ clinical — только через токен.** Модули clinical не импортируют `app.db.identity`.
6. **Доступ врача → `audit_log`.**
7. **Пороги, тексты и лексикон — в `config/`**, не в коде.
8. **Только синтетика.** Логи без ПДн и без сырого текста.
9. **Никаких зарубежных API в контуре.**
## Факапы
| Ситуация | Действие |
|---|---|
| Начал в основной копии | `git stash` → worktree → `git stash pop` |
| `git push` дал `[new branch]` после мержа | удалить ветку через API, новый issue + cherry-pick |
| Конфликт при rebase в чужой зоне | спросить владельца |
| Утёк секрет | отозвать ключ, вычистить историю |
| Битая кириллица в issue/PR | см. [`GITEA_API.md`](GITEA_API.md): только `--data-binary @файл` |