textmachine/docs/dev-stand.md

106 lines
12 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.

# Стенд разработки — поднять проект на чистой машине
> Отвечает на ОДИН вопрос: что поставить и в каком порядке, чтобы все четыре зоны собрались и их
> батареи прошли. **Версий и рецептов зон здесь НЕТ** — каждая строка называет свой носитель и
> команду, которой номер читается: скопированный сюда номер стал бы вторым носителем и разошёлся
> бы с первым (D39.112). Что уже построено и что в очереди — CURRENT-STATE в [PROGRESS.md](PROGRESS.md),
> здесь только «как поднять».
>
> ⚠ **Проверено исполнением 24.08.2026** на чистой Ubuntu 26.04 LTS (WSL2), пользователь `ubuntu-26`,
> репозиторий `~/projects/textmachine`. Результаты прогонов — в теле; всё, что не прогнано, названо
> вслух в разделе «Чего этот стенд не проверяет».
## 1. Что ставится БЕЗ root, и где оно живёт
Схема одна для всех: дистрибутив разворачивается в `~/.local/opt/<инструмент>`, а исполняемое
симлинкуется в `~/.local/bin` — он уже в `PATH` из `~/.profile` Ubuntu, поэтому rc-файлы править не
надо. Каждый архив ставится ТОЛЬКО после сверки sha256 с подписью вендора.
| Инструмент | Кто требует и какой версии (носитель) | Как ставится |
|---|---|---|
| **Go** | `backend/Makefile` `GO_MIN_VERSION` и `platform/Makefile` `GO_MIN_VERSION` (у платформы выше — она сетевая, разбор — комментарий `toolchain` в `platform/go.mod`). Прочесть: `grep -h GO_MIN_VERSION backend/Makefile platform/Makefile` | тарбол с `go.dev/dl``~/.local/opt/go`, симлинки `go`/`gofmt`. ⚠ Брать ПОСЛЕДНИЙ ПАТЧ ПИНОВАННОГО МИНОРА, а не следующий минор: линтер пинован и его находки версионно-зависимы |
| **golangci-lint** | `GOLANGCI_VERSION` в обоих Makefile, точным равенством (`tools-check` сверяет строку версии). Прочесть: `grep -h GOLANGCI_VERSION backend/Makefile platform/Makefile` | release-бинарь с GitHub → `~/.local/bin/golangci-lint`; чексуммы — `golangci-lint-<v>-checksums.txt` того же релиза |
| **Node + npm** | `frontend/package.json` `engines.node`; менеджер — npm из поставки Node (`frontend/docs/STACK_DECISIONS.md` §1). Прочесть: `python3 -c "import json;print(json.load(open('frontend/package.json'))['engines'])"` | тарбол с `nodejs.org/dist``~/.local/opt/node`; чексуммы — `SHASUMS256.txt` того же каталога. ⚠ `frontend/.npmrc` ставит `engine-strict=true` — Node ниже пола это ОШИБКА установки, а не предупреждение |
| **PostgreSQL** | `platform/README.md` (мажор) — рецепт целиком, включая порт и DSN, живёт в `platform/docs/STACK_DECISIONS.md` §«Postgres на стенде без root» | ровно по тому рецепту: micromamba + conda-forge в `~/.local/pgsql`, кластер в `~/.local/share/tmstand/pgdata`, сокет в `/tmp`. Рецепт ратифицирован зоной и sudo не требует |
| **micromamba** | нужен только предыдущей строке | один статический бинарь; ⚠ на чистой Ubuntu 26 НЕТ `bzip2`, поэтому `tar -xjf` падает — архив распаковывается модулем `tarfile` питона (`bz2` в stdlib есть) |
## 2. Что БЕЗ root не ставится — и почему обход недопустим
| Пакет | Кто без него не работает | Почему нельзя обойти |
|---|---|---|
| **`build-essential`** (`gcc` + `make`) | `make test`/`make battery`/`make check` ОБЕИХ Go-зон | Обе цели гоняют `go test -race`, а `-race` требует cgo, то есть C-компилятора. Комментарий над целью в `backend/Makefile` говорит прямо: снять `-race` значит превратить отсутствие тулчейна в зелёный прогон, доказывающий меньше, чем он заявляет. `make` нужен и сам по себе: `platform` `TestTheToolchainGateComparesVersionsRatherThanMatchingThem` зовёт `make version-check` и без `make` СКИПАЕТСЯ |
| **`python3-venv`** | вся зона `eval/` | В системном питоне Ubuntu 26 нет `ensurepip`, поэтому `python3 -m venv .venv` создаёт окружение БЕЗ pip. Ратифицированная зоной установка — `python3 -m venv .venv && .venv/bin/pip install -r requirements.txt` (`eval/README.md` п.5) — на этом и останавливается |
Ставится одной командой; она же — единственное, что в этом файле просит пароль:
```sh
sudo apt-get update && sudo apt-get install -y build-essential python3-venv
```
## 3. Порядок подъёма
1. **Go + golangci-lint**`cd backend && make battery` (после шага 2 — `make battery-stand`).
2. **Postgres** по рецепту зоны → `cd platform && TM_PLATFORM_TEST_DSN=<из рецепта> make check`.
3. **Node**`cd frontend && npm ci && npm run check`. ⚠ `npm ci` через `prepare` ставит
pre-commit-диспетчер в `.git/hooks/` — **это единственный путь, которым включается гейт якорей
доков** (`docs/scripts/githooks/pre-commit`). На клоне, где во фронте не ставили зависимости, гейт
МОЛЧА выключен. Поставить его отдельно, без установки зависимостей:
`node frontend/scripts/githooks/install.mjs`.
4. **Python-окружение полигона** — по `eval/README.md` п.5.
5. **Данные книг** — раздел 4 ниже.
6. **Дев-стенд платформы целиком** (демон + сид через живой интейк + дев-прокси фронта) — рецепт в
`platform/deploy/README.md` §«Дев-стенд». Он же — самая дешёвая сквозная проверка: сид гоняет
движковый бинарь настоящим вызовом.
## 4. Каталог книг
Книги и производные лежат в **`<репозиторий>/books`** и версионируются ОТДЕЛЬНЫМ git-репозиторием
(свой `origin`, свой лог); внешний репозиторий держит `books/` в `.gitignore` и о нём ничего не знает.
Инвариант канона «книга и производные вне git» этим не нарушен — вне ЭТОГО git, — но следствия
новые:
- `git clean -xdf` во внешнем репозитории снёс бы весь каталог вместе с его историей. `clean` и так
запрещён каноном (`CLAUDE.md` §Гардрейлы); здесь у запрета появилась вторая цена.
- `git status` внешнего репозитория НЕ показывает правки книг. Состояние книг читается только
`git -C books status`.
- ⚠ Прежний адрес каталога был `~/books`, и он захардкожен в трёх местах движка и в скриптах
полигона. Диспозиция — строки бэклога; до их закрытия корпус-гейченные тесты движка запускаются с
переопределениями (`TM_CHECKER_LABELS_DIR`, `TM_MINER_PARITY_{RECORDS,SEED}`), которые в коде уже
предусмотрены.
## 5. Чего этот стенд не проверяет
Гейт обязан печатать, чего он не смотрит, — иначе его молчание читается как покрытие.
- **`-race` не гонялся ни в одной зоне** (нет C-тулчейна, раздел 2). Все зелёные прогоны ниже —
БЕЗ детектора гонок, и это не «батарея прошла».
- **`make` не гонялся** — цели исполнялись командами из самих Makefile. Расхождение цели и того, что
запускали, этим не поймано.
- **Ни одного платного вызова.** Всё зелёное — $0-пути: сборки, юнит-тесты, `tmctl manifest/status`,
интейк платформы. `tmctl translate` не запускался.
- **`TestMinerFullBookParity` СКИПАЕТСЯ на любом клоне**: ему нужен `eval/exp16/data/jieba_dict_general_zh.txt`,
который в git не попадает (`.gitignore`) и пересобирается — носитель диспозиции — строка бэклога 123.
- **Браузеры Playwright не скачаны** ⇒ `npm run check:full` (цели `shot`/`scenes`, оси axe) не гонялся;
`npm run check` их не включает.
- **Локальной модели нет:** ни `ollama`, ни GPU (`nvidia-smi` отсутствует). Замеры полигона, которым
нужна локальная модель, на этой машине не воспроизводимы.
- **OIDC-провайдера нет** — вход на стенде идёт дев-логином; боевой путь входа не проверялся.
## 6. Ловушки, подтверждённые на этой машине
- **`no_proxy=<local>` в окружении WSL — это Windows-синтаксис, и curl его не понимает.**
`curl http://127.0.0.1:8080/healthz` отдаёт **403** от прокси, и это читается как дефект кода,
которого нет. Лечится по месту: `curl --noproxy '*'` (так и записано в
`platform/docs/STACK_DECISIONS.md` §«Грабли стенда») или `NO_PROXY=127.0.0.1,localhost,::1`.
**Go-бинари проекта эта грабля НЕ задевает, и не потому, что понимают `<local>`:** пробой
`http.ProxyFromEnvironment` показано, что loopback не проксируется и при `no_proxy=""` вовсе —
это встроенное правило, а не заслуга переменной. Значит симптом асимметричен: ручная проверка
curl'ом краснеет там, где сам сервис зелёный.
- **`tmctl` берёт глагол ПЕРВЫМ аргументом, флаги после**: `tmctl manifest --config book.yaml`.
Обратный порядок печатает `--config book.yaml is required` — сообщение выглядит как «флаг не
передан», хотя флаг передан.
- **`tmplatformctl seed` требует и `TM_PLATFORM_DSN`, и `TM_PLATFORM_DEV_LOGIN`** в СВОЁМ окружении,
а не только в окружении демона: он ходит и в базу, и в HTTP.
- **Шаблон книги для платформы (`TM_PLATFORM_BOOK_TEMPLATE`) обязан нести АБСОЛЮТНЫЕ пути** к
`pipeline:`/`models:`. `backend/example/book.yaml` годится как заготовка, но его относительные
`../configs/...` из каталога книги платформы не разрешаются.