12 KiB
Стенд разработки — поднять проект на чистой машине
Отвечает на ОДИН вопрос: что поставить и в каком порядке, чтобы все четыре зоны собрались и их батареи прошли. Версий и рецептов зон здесь НЕТ — каждая строка называет свой носитель и команду, которой номер читается: скопированный сюда номер стал бы вторым носителем и разошёлся бы с первым (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. Порядок подъёма
- Go + golangci-lint →
cd backend && make battery(после шага 2 —make battery-stand). - Postgres по рецепту зоны →
cd platform && TM_PLATFORM_TEST_DSN=<из рецепта> make check. - 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. - Python-окружение полигона — по
eval/README.mdп.5. - Данные книг — раздел 4 ниже.
- Дев-стенд платформы целиком (демон + сид через живой интейк + дев-прокси фронта) — рецепт в
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/...из каталога книги платформы не разрешаются.