textmachine/docs/dev-stand.md

12 KiB
Raw Blame History

Стенд разработки — поднять проект на чистой машине

Отвечает на ОДИН вопрос: что поставить и в каком порядке, чтобы все четыре зоны собрались и их батареи прошли. Версий и рецептов зон здесь НЕТ — каждая строка называет свой носитель и команду, которой номер читается: скопированный сюда номер стал бы вторым носителем и разошёлся бы с первым (D39.112). Что уже построено и что в очереди — CURRENT-STATE в 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) — на этом и останавливается

Ставится одной командой; она же — единственное, что в этом файле просит пароль:

sudo apt-get update && sudo apt-get install -y build-essential python3-venv

3. Порядок подъёма

  1. Go + golangci-lintcd backend && make battery (после шага 2 — make battery-stand).
  2. Postgres по рецепту зоны → cd platform && TM_PLATFORM_TEST_DSN=<из рецепта> make check.
  3. Nodecd 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/... из каталога книги платформы не разрешаются.