first cycle lab release
This commit is contained in:
+118
@@ -0,0 +1,118 @@
|
||||
# Backup и восстановление — Phase 5
|
||||
|
||||
`./mcpack backup` работает с полным релизом и runtime, который уже связан
|
||||
с ним через `scripts/server.sh`. Нужны Node/npm dependencies, закреплённый
|
||||
Compose, Docker daemon, GNU tar и zstd. Оператор должен читать весь runtime
|
||||
и сохранять владельцев при распаковке: запускать от владельца данных или
|
||||
с необходимыми правами. Проверка UID/GID не пропускается.
|
||||
|
||||
## Создание snapshot
|
||||
|
||||
```bash
|
||||
export MC_ROOT=/absolute/server-root
|
||||
export MC_RELEASE_DIR=/absolute/full-release
|
||||
# MC_ENV_FILE — необязательный абсолютный путь, по умолчанию MC_ROOT/.env.
|
||||
./mcpack backup --wait-timeout 120
|
||||
```
|
||||
|
||||
Команда удерживает общую `.mcpack-runtime.lock`, проверяет релиз/settings,
|
||||
останавливает сервер через Compose и подтверждает остановку по Docker state.
|
||||
После этого архивирует **весь `MC_ROOT/runtime` без исключений**: world,
|
||||
данные модов вне world, конфиги, server.properties, whitelist/operators,
|
||||
логи, cache, downloads и установленные server/mod JAR. Для NeoForge безопасные
|
||||
исключения пока не подтверждены. Releases, snapshots и host `.env` находятся
|
||||
вне runtime и не входят в архив; внутри snapshot хранится отдельная полная
|
||||
копия исходного релиза, включая его `.env.example`.
|
||||
|
||||
Результат находится в `MC_ROOT/backups/<UTC timestamp>-<UUID>/`:
|
||||
|
||||
```text
|
||||
runtime.tar.zst
|
||||
metadata.json
|
||||
SHA256SUMS
|
||||
release/ # исходный полный релиз с собственными checksums
|
||||
```
|
||||
|
||||
Metadata фиксирует исходный релиз, SHA256 manifest/checksum list, закреплённый
|
||||
image, целевой релиз (если передан `--target-release /absolute/release`),
|
||||
прежнее состояние сервера, подтверждение остановки, время, исключения,
|
||||
архив SHA256/размер и inventory путей/хешей/размеров/mode/UID/GID runtime.
|
||||
`--target-release` только проверяет и записывает назначение будущего deployment;
|
||||
команда backup сама не применяет новый релиз.
|
||||
|
||||
Перед публикацией выполняются tar/zstd listing, проверка типов/путей и
|
||||
пробная распаковка с точным сравнением inventory. Checksums покрывают все
|
||||
файлы snapshot и сохранённого релиза. Каталог публикуется атомарным rename
|
||||
внутри backups; незавершённый snapshot не появляется под окончательным именем.
|
||||
При успехе ранее запущенный сервер возвращается на тот же релиз через
|
||||
`up --wait`. Остановленный сервер или отсутствующий контейнер не запускаются.
|
||||
|
||||
Ошибка backup возвращает non-zero. При ошибке после успешной остановки сервер
|
||||
остаётся остановленным; оператор получает ошибку и status в
|
||||
`MC_ROOT/.mcpack-backup-operation.json`. Ошибка resume сохраняет опубликованный
|
||||
проверенный snapshot и пытается снова остановить сервер. Новый deployment
|
||||
должен использовать `backupBeforeApply` из `platform/backups.mjs`: callback
|
||||
применения допускается только после публикации snapshot и под той же блокировкой.
|
||||
Этот gate проверен тестами и используется SSH deployment Phase 7 под общей
|
||||
блокировкой всей операции: [deploy.md](deploy.md).
|
||||
|
||||
Snapshot не удаляется автоматически. Нужны свободное место под полный runtime,
|
||||
пробную распаковку и копию релиза; операция завершается ошибкой при нехватке места.
|
||||
Символические/жёсткие ссылки и специальные файлы в runtime сейчас отклоняются.
|
||||
Команды вне wrapper не участвуют в блокировке; во время backup не изменять
|
||||
runtime вручную и не запускать контейнер прямым Compose.
|
||||
|
||||
## Восстановление в отдельный каталог
|
||||
|
||||
```bash
|
||||
./mcpack restore \
|
||||
--backup /absolute/server-root/backups/TIMESTAMP-UUID \
|
||||
--destination /absolute/restored-server
|
||||
```
|
||||
|
||||
Destination должен **не существовать**. Команда сначала проверяет snapshot,
|
||||
распаковывает во временный соседний каталог, сверяет bytes/mode/UID/GID,
|
||||
проверяет сохранённый релиз и публикует новый root атомарным rename.
|
||||
Исходный runtime не изменяется. Результат:
|
||||
|
||||
```text
|
||||
restored-server/runtime/
|
||||
restored-server/release/
|
||||
restored-server/.mcpack-runtime.json
|
||||
restored-server/restore-report.json
|
||||
```
|
||||
|
||||
Host settings и EULA acceptance из snapshot не восстанавливаются; сервер
|
||||
автоматически не запускается. Для ручного recovery подготовить `.env` из
|
||||
`release/server/.env.example`, задать прежние UID/GID, подходящие memory/port
|
||||
и принятие EULA. Используется прежний стабильный Compose project из binding.
|
||||
Прежде чем запускать восстановленную копию под тем же project, остановить
|
||||
и удалить **старый контейнер** через wrapper (данные старого root сохраняются):
|
||||
|
||||
```bash
|
||||
MC_ROOT=/absolute/original-server \
|
||||
MC_RELEASE_DIR=/absolute/original-release scripts/server.sh down
|
||||
|
||||
# На данном host settings уже настроены и EULA принята:
|
||||
export MC_ROOT=/absolute/restored-server
|
||||
export MC_RELEASE_DIR="$MC_ROOT/release"
|
||||
export MC_ENV_FILE=/absolute/prepared-host-settings.env
|
||||
scripts/server.sh up -d --wait --wait-timeout 120
|
||||
scripts/server.sh exec -T minecraft mc-health
|
||||
scripts/server.sh logs --tail 100
|
||||
```
|
||||
|
||||
Не заменять binding или release на более новую версию: восстановленный мир
|
||||
нужно запускать с сохранённым исходным релизом. Если прежний контейнер ещё
|
||||
использует другой root, wrapper отклонит запуск. Это ручное восстановление
|
||||
в отдельный root; переключение active release и rollback — последующие фазы.
|
||||
|
||||
## Область проверки
|
||||
|
||||
Проверен local Linux/WSL Docker и NeoForge 21.1.252 / Minecraft 1.21.1.
|
||||
Primary Phase 0 runtime пока управляется старым spike wrapper без full-release
|
||||
binding, поэтому его миграция не выполняется этой командой. Off-host копии,
|
||||
retention, автоматический rollback и защита от внезапного отключения питания
|
||||
во время записи (fsync) остаются последующими улучшениями.
|
||||
|
||||
Реальный опыт восстановления и свидетельства: [phase5-results.md](phase5-results.md).
|
||||
@@ -0,0 +1,94 @@
|
||||
# Build contract — Phase 2
|
||||
|
||||
Из корня проекта, с Node.js 22+ и npm:
|
||||
|
||||
```bash
|
||||
npm ci --ignore-scripts
|
||||
scripts/spike-tools.sh
|
||||
./mcpack build
|
||||
```
|
||||
|
||||
Дополнительные параметры:
|
||||
|
||||
```bash
|
||||
./mcpack build --config platform/config.yaml
|
||||
./mcpack build --release
|
||||
```
|
||||
|
||||
`--config` выбирает YAML manifest; относительные пути pack/output внутри
|
||||
него считаются от корня репозитория. По умолчанию build разрешает dirty
|
||||
worktree и записывает это в manifest. `--release` требует чистого worktree.
|
||||
Команды не делают commit/tag/deploy и не запускают Minecraft.
|
||||
|
||||
Имя, версия, Minecraft и loader читаются из TOML packwiz. Полный релиз
|
||||
создаётся в `<output>/<name>-<version>/` и содержит:
|
||||
|
||||
```text
|
||||
<name>-<version>.mrpack
|
||||
server/compose.yaml
|
||||
server/.env.example
|
||||
server/config/
|
||||
server/README.md
|
||||
manifest.json
|
||||
SHA256SUMS
|
||||
```
|
||||
|
||||
Релиз той же версии не перезаписывается. Для изменённого source нужно выбрать
|
||||
новую версию pack, явно выполнить packwiz refresh, затем build. Для локального
|
||||
эксперимента с прежней версией можно выбрать другой output directory через
|
||||
отдельный config. Не изменять опубликованный release directory вручную.
|
||||
|
||||
## Pipeline
|
||||
|
||||
1. Parse/validate YAML и TOML: обязательные поля, индексы/hash, explicit side,
|
||||
дубликаты mod targets/project IDs, пути, подтверждённый loader/image.
|
||||
2. Проверить SHA256 packwiz/Compose по lock и Git state/известные secret paths.
|
||||
3. Получить lock конкретной версии и временный каталог в output directory.
|
||||
4. Скопировать pack; выполнить packwiz refresh/export. Любое изменение
|
||||
metadata после refresh останавливает build, исходники не исправляются.
|
||||
5. Проверить экспорт, сформировать серверные файлы и выполнить Compose config.
|
||||
6. Записать manifest, покрыть SHA256SUMS все release files кроме SHA256SUMS;
|
||||
проверить checksums и неизменность build inputs.
|
||||
7. Атомарно переименовать готовый временный релиз; убрать временные файлы/lock.
|
||||
|
||||
При обычной ошибке partial release не остаётся. После принудительного убийства
|
||||
процесса может остаться `.build-*.lock`/временный каталог: удалять их только
|
||||
убедившись, что соответствующий build уже не работает.
|
||||
|
||||
Детерминированными являются имя и размещение артефактов. Побайтовая
|
||||
воспроизводимость ZIP не обещается: packwiz может включать timestamps.
|
||||
|
||||
## Server payload
|
||||
|
||||
Compose образ закреплён literal digest из toolchain lock. Memory/port defaults
|
||||
берутся из platform config; local env может переопределять их при запуске.
|
||||
Runtime и release подключаются через абсолютные `MC_ROOT` и `MC_RELEASE_DIR`.
|
||||
Release не зависит от checkout или его `.tools/`. Используется стабильное
|
||||
Compose project name `minecraft-lab-spike`, как в текущем локальном runtime.
|
||||
|
||||
`server/config/` включается в релиз и монтируется как `/config`: его файлы
|
||||
имеют приоритет над соответствующими pack defaults. Локальный исходный
|
||||
Compose spike по-прежнему включает этот слой только явным override.
|
||||
Server properties генерируются environment, отдельного source-файла нет.
|
||||
|
||||
`.env`, активный локальный compose override, SSH target и platform YAML
|
||||
не копируются в release. Публичный `.env.example` имеет EULA=FALSE.
|
||||
Проверка известных secret filenames не является универсальным secret scanner.
|
||||
|
||||
## Manifest v1
|
||||
|
||||
- `pack`: name/version, Minecraft, loader ID/version.
|
||||
- `git`: commit и dirty flag; generated output исключается из dirty check.
|
||||
- `tools`: packwiz commit/hash, Compose version/hash, Node version/npm lock hash.
|
||||
- `server`: image, подтверждённая Java major, defaults и project name.
|
||||
- `source_files`: относительные пути inputs и SHA256, без содержимого config.
|
||||
- `managed_files.client/server`: runtime paths, owner (`pack`/`server`),
|
||||
hashes и политика replace; server override помечает заменённого владельца.
|
||||
- `runtime_policy`: неизвестные файлы preserve, defaultconfigs seed-only.
|
||||
- `release_files`: hashes payload без manifest и SHA256SUMS, чтобы избежать
|
||||
циклического хеширования. SHA256SUMS дополнительно покрывает manifest.
|
||||
|
||||
Ownership описывает контракт для будущего deploy; Phase 2 сама ничего
|
||||
не удаляет из runtime. Совместимость Java проверяется по записи Phase 0
|
||||
в `platform/compatibility.json`, а не новым запуском Docker при каждом build.
|
||||
Новая комбинация требует отдельного spike и записи результата.
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
# SSH deployment — Phase 7
|
||||
|
||||
`./mcpack deploy` применяет готовый полный immutable release через SSH/rsync.
|
||||
Если artifact ещё не создан, команда вызывает clean `build --release`;
|
||||
если уже есть, проверяет его checksums и provenance. Development artifact
|
||||
с `git.dirty=true` отклоняется, даже если текущий worktree уже чистый.
|
||||
|
||||
## Подготовка цели
|
||||
|
||||
На host нужны Linux x86_64, Node.js 22+, доступный Docker daemon, rsync,
|
||||
GNU tar и zstd. Pinned Compose и небольшой Node agent с закреплённым YAML
|
||||
parser передаются из локального bootstrap/dependencies; системный Docker
|
||||
не устанавливается. У оператора должны быть права на весь runtime и его
|
||||
владельцев; выбранные UID/GID согласовать с владельцем каталога.
|
||||
|
||||
В `platform/config.yaml` выбрать SSH host/alias и **отдельный root сборки**:
|
||||
|
||||
```yaml
|
||||
server:
|
||||
host: crab@192.168.1.61
|
||||
directory: /home/crab/workspace/minecraft-lab/minecraft-lab-neoforge-spike
|
||||
memory: 2G
|
||||
port: 25565
|
||||
```
|
||||
|
||||
Host `.env` готовится отдельно, вне releases, с EULA/UID/GID/memory/port
|
||||
и стабильным MC_PROJECT_NAME. Runtime startup читает именно этот файл;
|
||||
build defaults не перезаписывают host settings. Первое применение требует
|
||||
пустого runtime без старого binding; существующий неопознанный мир не
|
||||
принимается автоматически. У разных сборок разные roots, projects и ports.
|
||||
|
||||
SSH host key должен быть известен заранее. Используются BatchMode,
|
||||
StrictHostKeyChecking=yes и keepalive. Ключи/порты задать в SSH config;
|
||||
password-only сессия может использовать заранее аутентифицированный
|
||||
ControlMaster. Пароль не записывается в config, env, artifact или agent.
|
||||
|
||||
```bash
|
||||
./mcpack deploy --artifact /absolute/full-release
|
||||
# Порт/ControlMaster/known_hosts в отдельном SSH config:
|
||||
./mcpack deploy --artifact /absolute/full-release --ssh-config /absolute/ssh-config
|
||||
# Node из nvm, которого нет в non-interactive SSH PATH:
|
||||
./mcpack deploy --artifact /absolute/full-release \
|
||||
--ssh-config /absolute/ssh-config \
|
||||
--remote-node /home/crab/.nvm/versions/node/v26.10.0/bin/node
|
||||
```
|
||||
|
||||
`--config FILE` выбирает другой platform config. Timeout берётся из его
|
||||
`deploy.healthcheck_timeout`; он должен быть больше 10 секунд stability.
|
||||
Первый image/dependency download может требовать 600+ секунд. IPv6 host
|
||||
и другие сложные адреса сейчас задавать через SSH alias.
|
||||
|
||||
## Выполнение и state
|
||||
|
||||
Под SSH удерживается одна `.mcpack-runtime.lock` на всё получение релиза,
|
||||
backup и применение. Перед передачей проверяются незавершённый deployment,
|
||||
source/binding, target version collision, host settings/права и свободное место.
|
||||
Релиз передаётся rsync в `releases/.incoming-*`, проверяется на host и
|
||||
публикуется atomic rename. Сбой передачи не останавливает исходный сервер.
|
||||
Agent в `.mcpack/agent-UUID/` также проверяется по полной checksum coverage.
|
||||
|
||||
Перед применением проверяется каждый replace-managed файл прошлого release.
|
||||
При изменении/missing file или занятом новом managed path возвращается конфликт.
|
||||
Для небольших server-owned text configs выводится content diff, для остальных
|
||||
файлов — expected/actual hash. Неуправляемые файлы не удаляются. Нужно перенести
|
||||
полезные правки в source и построить новую версию; флага force для молчаливого
|
||||
перетирания конфигов нет.
|
||||
|
||||
Если тот же release уже активен, выполняется `health` без restart; успешный
|
||||
повторный deploy возвращает noop. Одинаковая версия с другим manifest/checksums
|
||||
отклоняется до остановки. Если активный release unhealthy, повторный deploy
|
||||
не перезапускает его автоматически.
|
||||
|
||||
При смене релиза исходный сервер останавливается, подтверждается остановка,
|
||||
создаётся verified snapshot всего runtime и исходного release. Только после
|
||||
этого apply callback меняет binding, удаляет отсутствующие в новом релизе
|
||||
известные replace-managed файлы и запускает target. Конфликты проверяются
|
||||
повторно непосредственно перед apply. Image применяет pack/server overrides
|
||||
при запуске; runtime-generated/unmanaged данные сохраняются.
|
||||
|
||||
После стабильного mc-health/status query обновляются previous-release и
|
||||
active-release, каждый через atomic rename. Deployment state записывается
|
||||
перед каждым этапом и связывает source/target identities, прежние pointers,
|
||||
backup path и факт apply. Пара указателей не является единым filesystem
|
||||
transaction: interrupted `committing` требует просмотра state перед recovery.
|
||||
|
||||
## Ошибка и ручное восстановление
|
||||
|
||||
Любой failed/incomplete `deployment-state.json` блокирует следующую операцию.
|
||||
При прерывании SSH во время upload worker сохраняет failed state и освобождает
|
||||
lock; при принудительном убийстве worker/power loss lock может остаться.
|
||||
Не удалять stale lock, пока соответствующий host process действительно жив.
|
||||
|
||||
После ошибки **до apply** source/runtime binding не переключаются. При ошибке
|
||||
backup сервер может остаться остановленным; проверить logs и backup operation.
|
||||
После подтверждения неизменности мира можно запустить исходный release.
|
||||
Failed state нужно сохранить для аудита и явно разрешить только после recovery.
|
||||
|
||||
Если `applied=false`, binding совпадает с active manifest, причина исправлена
|
||||
и исходный сервер проверен health, сохранить failed record под отдельным именем
|
||||
в server root, затем повторить deploy. Для ручного config edit новый clean
|
||||
release должен содержать ровно текущие bytes этого managed файла — такой
|
||||
осознанный перенос разрешается. Любое другое содержимое остаётся конфликтом.
|
||||
Пример архивирования **только после перечисленных проверок на host**:
|
||||
|
||||
```bash
|
||||
mv "$MC_ROOT/deployment-state.json" \
|
||||
"$MC_ROOT/deployment-state-resolved-$(date -u +%Y%m%dT%H%M%SZ).json"
|
||||
```
|
||||
|
||||
Не применять этот способ к `applied=true`, неизвестному binding или
|
||||
interrupted committing: сначала восстановить/завершить реальное состояние.
|
||||
|
||||
После ошибки **apply/startup** target останавливается, source pointers не
|
||||
продвигаются, binding остаётся на фактически применённом target и snapshot
|
||||
сохраняется. Старый pack автоматически не запускается на изменённом мире.
|
||||
Восстановить snapshot в новый root вместе с сохранённым source release по
|
||||
[backups.md](backups.md), подготовить host settings, удалить старый контейнер,
|
||||
запустить восстановленную копию и проверить health. Не менять binding вручную,
|
||||
чтобы обойти защиту существующего мира.
|
||||
|
||||
Для первого неудачного deploy без snapshot использовать state/release/diagnostics:
|
||||
пустой мир можно повторно инициализировать отдельно либо явно завершить запуск
|
||||
того же target. При ошибке `committing` сначала проверить actual binding,
|
||||
Docker health и оба pointer files. Snapshot recovery реализован в
|
||||
[Phase 8](rollback.md). Простое удаление failed state не является recovery.
|
||||
|
||||
## Текущий проверенный host
|
||||
|
||||
На `crab@192.168.1.61:2228` подготовлен root
|
||||
`/home/crab/workspace/minecraft-lab/minecraft-lab-neoforge-spike`.
|
||||
Release 0.0.5 healthy (обновление публикации порта после Phase 7), UID/GID 1000:1000, memory 2G,
|
||||
MC_PROJECT_NAME=minecraft-lab-neoforge-spike. Offline mode включён.
|
||||
|
||||
Clean release собран в отдельном checkout и опубликован локально:
|
||||
|
||||
```bash
|
||||
./mcpack deploy \
|
||||
--artifact dist/minecraft-lab-neoforge-spike-0.0.5 \
|
||||
--ssh-config .tools/phase7-ssh-target/config \
|
||||
--remote-node /home/crab/.nvm/versions/node/v26.10.0/bin/node
|
||||
```
|
||||
|
||||
SSH config хранит только соединение/known_hosts/ControlPath. После окончания
|
||||
ControlMaster для password login сначала заново аутентифицировать сессию:
|
||||
|
||||
```bash
|
||||
ssh -F .tools/phase7-ssh-target/config minecraft-lab-target true
|
||||
```
|
||||
|
||||
Host settings теперь содержат `MC_BIND_ADDRESS=0.0.0.0`; порт 25565
|
||||
публикуется на всех IPv4-интерфейсах host. В Prism подключаться напрямую
|
||||
к **192.168.1.61:25565**, без SSH tunnel. Локальный Phase 0 сервер остаётся
|
||||
отдельным на 127.0.0.1:25565. Default для новых host остаётся 127.0.0.1;
|
||||
LAN bind выбирается явно в host .env. Проверка — [network-results.md](network-results.md).
|
||||
|
||||
Сохранённый remote agent содержит `scripts/server.sh`. Для lifecycle на host
|
||||
выбрать этот agent, задать абсолютные MC_ROOT/MC_RELEASE_DIR, указать nvm Node
|
||||
в PATH и выполнить wrapper:
|
||||
|
||||
```bash
|
||||
export PATH=/home/crab/.nvm/versions/node/v26.10.0/bin:$PATH
|
||||
export MC_ROOT=/home/crab/workspace/minecraft-lab/minecraft-lab-neoforge-spike
|
||||
export MC_RELEASE_DIR="$MC_ROOT/releases/$(cat "$MC_ROOT/active-release")"
|
||||
# Подставить один из проверенных каталогов .mcpack/agent-*:
|
||||
/absolute/agent/scripts/server.sh health
|
||||
/absolute/agent/scripts/server.sh logs --tail 100
|
||||
```
|
||||
|
||||
При failed deployment брать фактически применяемый release из state/binding,
|
||||
а не автоматически active-release. Agents/releases/backups автоматически
|
||||
не удаляются. Свидетельства и границы проверок — [phase7-results.md](phase7-results.md).
|
||||
@@ -0,0 +1,237 @@
|
||||
# Phase 0 — integration spike
|
||||
|
||||
Дата: 2026-10-03. Статус: **предварительный Fabric-эксперимент проверен; целевой Phase 0 должен проверить NeoForge/Forge без аккаунтов**.
|
||||
GUI-проверки не заменяются проверкой ZIP или Minecraft status query.
|
||||
|
||||
## Окружение и версии
|
||||
|
||||
Arch Linux x86_64 в WSL2, kernel `6.18.40.1-microsoft-standard-WSL2`.
|
||||
Изначально отсутствовали Linux packwiz, Docker, Compose, Go и Java.
|
||||
В Windows обнаружен каталог PrismLauncher; аккаунты и существующие instances
|
||||
не читались и не изменялись.
|
||||
|
||||
| Компонент | Зафиксированное значение |
|
||||
| --- | --- |
|
||||
| Minecraft | 1.21.1 |
|
||||
| Fabric Loader | 0.19.5 |
|
||||
| Fabric installer/launcher | 1.1.2, наблюдаемое значение в .fabric-manifest.json |
|
||||
| Fabric API | 0.116.17+1.21.1, Modrinth `Mys3P7lK`, both |
|
||||
| Mod Menu | 11.0.5, Modrinth `6lgOkclV`, client |
|
||||
| Text Placeholder API | 2.4.2+1.21, Modrinth `U5bhVym2`, client в этой сборке |
|
||||
| packwiz commit | `ef87d964f8cbd52b3b13ea42453ef322290e2b9e` |
|
||||
| packwiz GitHub Actions run | `34043101039`, Linux 64-bit x86 |
|
||||
| packwiz binary SHA-256 | `7f8ed641be0c28988895651e3270cc9ad4b40c436e3d5cf9b3bcdb718b4369c6` |
|
||||
| Prism Launcher | 11.0.3-main, commit d393323fdc52ef645c48a04ca73aff2bbe24ffc9 (из локального лога) |
|
||||
| JVM сервера | Temurin 21.0.12.1+1-LTS |
|
||||
| Docker Engine | 29.8.2, storage driver overlayfs |
|
||||
| Compose | v5.6.0, локальный официальный binary |
|
||||
| itzg image digest | `sha256:99dc8b37f97c3b95915452180bbedf29a7ac8252932e372ce6e5b6e383a5d1e2` |
|
||||
| itzg source revision | `beed693663b4c963d1bb4af1101855eccbc6a37b` |
|
||||
| itzg image creation | 2026-10-02T12:03:38.864Z |
|
||||
|
||||
Образ первоначально скачан по тегу java21; Compose использует только digest.
|
||||
JVM проверена без запуска Minecraft: Temurin OpenJDK 21.0.12.1+1-LTS.
|
||||
Команда: `docker run --rm --entrypoint java <закреплённый-image> -version`.
|
||||
|
||||
## Фактически выполнено
|
||||
|
||||
1. Получены точные версии из официальных GitHub, Fabric и Modrinth API.
|
||||
2. Скачан официальный packwiz из привязанного к commit workflow run;
|
||||
SHA-256 архива и binary закреплены в `toolchain.lock.env`.
|
||||
3. Установлен Docker в WSL (`pacman -S --needed --noconfirm docker`),
|
||||
daemon запущен командой `systemctl start docker`, без enable при загрузке.
|
||||
4. Скачан и проверен SHA-256 официального Compose v5.6.0 в `.tools/`.
|
||||
5. Создан source pack и добавлены закреплённые моды через packwiz.
|
||||
6. Для Text Placeholder API сторона явно изменена с both на client:
|
||||
здесь библиотека нужна только client-only Mod Menu.
|
||||
7. Обновлён source index, выполнен export в временной копии source.
|
||||
8. Проверены содержимое ZIP, версии dependencies и env каждой записи.
|
||||
9. `scripts/spike-server.sh config --quiet` и `bash -n scripts/*.sh` успешны.
|
||||
10. После явного принятия EULA пользователем выставлен MC_EULA=TRUE в игнорируемом server/.env.
|
||||
11. Первый запуск, status healthcheck, side filtering и bind mounts проверены на реальном сервере.
|
||||
12. Проверены recreate, смена версии мода, удаление модов, конфиги и datapack на существующем мире.
|
||||
13. Startup с отсутствующим mrpack вернул 1; hash level.dat при ошибке не изменился.
|
||||
14. Исходный snapshot восстановлен в отдельный каталог; world/config совпали до запуска, сервер 0.0.1 снова healthy.
|
||||
15. `git diff --check` успешен; .tools, артефакты, world, backups и .env игнорируются Git.
|
||||
|
||||
Артефакт:
|
||||
|
||||
```text
|
||||
dist/minecraft-lab-spike-0.0.1/minecraft-lab-spike-0.0.1.mrpack
|
||||
SHA-256: 923fa6e5b54921b7b19925bbe634d91e09b113ccd512f1edaaeab818de3a9338
|
||||
```
|
||||
|
||||
ZIP содержит `modrinth.index.json` и `overrides/config/spike-marker.txt`.
|
||||
Fabric API помечен required на обеих сторонах; Mod Menu и Text Placeholder API
|
||||
имеют `server: unsupported`. На установленном сервере подтверждено отсутствие обоих client-only JAR.
|
||||
Маркер проверяет копирование произвольного конфига; его не читает игровой мод.
|
||||
|
||||
## Команды создания и воспроизведения
|
||||
|
||||
Первоначальный init из `pack/`:
|
||||
|
||||
```bash
|
||||
../.tools/packwiz/packwiz --cache ../.tools/packwiz/cache --config ../.tools/packwiz/config.toml init \
|
||||
--name minecraft-lab-spike --version 0.0.1 --author minecraft-lab \
|
||||
--mc-version 1.21.1 --modloader fabric --fabric-version 0.19.5 -y
|
||||
../.tools/packwiz/packwiz --cache ../.tools/packwiz/cache --config ../.tools/packwiz/config.toml modrinth add --project-id P7dR8mSH --version-id Mys3P7lK -y
|
||||
../.tools/packwiz/packwiz --cache ../.tools/packwiz/cache --config ../.tools/packwiz/config.toml modrinth add --project-id mOgUt4GM --version-id 6lgOkclV -y
|
||||
# Явно изменить side в placeholder-api.pw.toml на client.
|
||||
../.tools/packwiz/packwiz --cache ../.tools/packwiz/cache --config ../.tools/packwiz/config.toml refresh
|
||||
```
|
||||
|
||||
В новом checkout достаточно уже закоммиченного source:
|
||||
|
||||
```bash
|
||||
scripts/spike-tools.sh
|
||||
scripts/spike-build.sh
|
||||
scripts/spike-server.sh config --quiet
|
||||
bsdtar -xOf dist/minecraft-lab-spike-0.0.1/minecraft-lab-spike-0.0.1.mrpack modrinth.index.json
|
||||
```
|
||||
|
||||
Для изменения source packwiz запускается из `pack/` с локальными cache/config,
|
||||
как в командах выше. Проверка SHA-256 артефакта выполняется из его каталога:
|
||||
|
||||
```bash
|
||||
cd dist/minecraft-lab-spike-0.0.1
|
||||
sha256sum -c SHA256SUMS
|
||||
```
|
||||
|
||||
Build v0 не создаёт production release manifest, Git tags или удалённый deployment.
|
||||
Игровые версии читаются из pack.toml; выбор MC_PACK — ссылка на готовый артефакт.
|
||||
|
||||
## Матрица проверки
|
||||
|
||||
| Проверка | Статус |
|
||||
| --- | --- |
|
||||
| packwiz описывает и экспортирует сборку | PASS |
|
||||
| ZIP содержит закреплённые dependencies и side metadata | PASS |
|
||||
| Compose config валиден | PASS |
|
||||
| Prism импортирует и запускает pack | PASS: instance 0.0.1, Minecraft/Fabric и три JAR подтверждены |
|
||||
| Сервер устанавливает локальный mrpack и становится healthy | PASS: mc-health, 1.21.1, online=0 |
|
||||
| На сервере нет client-only JAR | PASS: только fabric-api JAR |
|
||||
| World и config находятся в host bind mount | PASS |
|
||||
| World переживает recreation контейнера | PASS: level.dat hash до запуска совпал |
|
||||
| Обновление удаляет старый mod JAR | PASS: 0.116.17 → 0.116.16; затем удалены все JAR |
|
||||
| Конфиги: pack defaults, server override, ручная правка | PASS: override победил; update перезаписал ручную правку |
|
||||
| Backup/restore возвращает world и прежний release | PASS: восстановлен baseline и pack 0.0.1 |
|
||||
| Startup failure возвращает non-zero | PASS: отсутствующий mrpack, exit 1; world не изменён |
|
||||
| Клиент Prism подключается к offline-серверу | PENDING: повторная попытка после online-mode=false |
|
||||
| Datapack на существующем мире | PASS: file/phase0 автоматически загружен в 0.0.2 |
|
||||
| NeoForge/Forge defaultconfigs | НЕ ПРОВЕРЕНО: другой loader |
|
||||
|
||||
## Порядок серверных проверок
|
||||
|
||||
После принятия EULA скопировать `.env.example` в `.env` и выставить MC_EULA=TRUE.
|
||||
Сервер изолирован локальным адресом, без публикации RCON. Первоначально ошибочно требовался online-mode=true; по уточнению пользователя переключён на online-mode=false и enforce-secure-profile=false. Microsoft/Mojang-аккаунт не требуется.
|
||||
|
||||
```bash
|
||||
scripts/spike-server.sh up -d --wait --wait-timeout 600
|
||||
scripts/spike-server.sh ps
|
||||
scripts/spike-server.sh logs --tail 100
|
||||
scripts/spike-server.sh exec -T minecraft java -version
|
||||
scripts/spike-server.sh exec -T minecraft mc-health
|
||||
ls runtime/mods runtime/config runtime/world
|
||||
```
|
||||
|
||||
Затем остановить сервер и записать hash `runtime/world/level.dat`.
|
||||
Recreate выполняется при остановленном сервере:
|
||||
|
||||
```bash
|
||||
scripts/spike-server.sh stop
|
||||
sha256sum runtime/world/level.dat
|
||||
scripts/spike-server.sh create --force-recreate
|
||||
sha256sum runtime/world/level.dat
|
||||
scripts/spike-server.sh start
|
||||
```
|
||||
|
||||
Два hash до запуска должны совпасть. После старта world может штатно измениться;
|
||||
это не потеря данных. Дополнительно проверить UUID/seed и игровой маркер из клиента.
|
||||
|
||||
Для воспроизведения вариантов на новом checkout после исходного build выполнить `scripts/spike-variants.sh`. Скрипт создаёт source-копии в .tools/repro-variants и артефакты 0.0.2/0.0.3; runtime не меняет. Повторный запуск при существующих каталогах прекращается без перезаписи.
|
||||
|
||||
0.0.2: Fabric API fpB2VatZ (0.116.16+1.21.1), marker v2, статический datapack из testdata/spike-datapack. 0.0.3: удалены Mod Menu, Text Placeholder API и Fabric API, остаётся loader и config marker. Исходный pack/ всё время оставался на 0.0.1.
|
||||
Перед сменой MC_PACK обязательно остановить сервер и создать snapshot.
|
||||
Проверить удаление прежнего JAR и фактическое состояние marker.
|
||||
Возврат старого pack выполнять вместе с соответствующим snapshot.
|
||||
|
||||
Минимальная ручная процедура backup (в корне, после stop):
|
||||
|
||||
```bash
|
||||
mkdir -p backups
|
||||
task_snapshot="backups/$(date -u +%Y%m%dT%H%M%SZ)-$(date +%s%N).tar.zst"
|
||||
tar --exclude=./.gitkeep -C runtime -I zstd -cf "$task_snapshot" .
|
||||
tar -I zstd -tf "$task_snapshot" > /dev/null
|
||||
sha256sum "$task_snapshot" > "$task_snapshot.sha256"
|
||||
# Записать рядом исходный MC_PACK и SHA256SUMS релиза.
|
||||
```
|
||||
|
||||
Restore: сервер остановлен; сначала сохранить текущее состояние. Проверить hash
|
||||
архива, распаковать в новый каталог рядом с runtime и проверить файлы.
|
||||
Переименовать текущий runtime в сохранённый каталог, новый — в runtime;
|
||||
выбрать исходный MC_PACK и запустить с healthcheck. Не распаковывать поверх мира.
|
||||
Этот ручной сценарий проверен: snapshot phase0-before-update восстановлен в отдельный каталог, исходный runtime сохранён в .tools/runtime-before-restore, затем запущен pack 0.0.1.
|
||||
|
||||
Prism: импортировать исходный .mrpack, запустить Minecraft, проверить Mod Menu,
|
||||
зайти на localhost:25565, поставить различимый игровой маркер и проверить его
|
||||
после recreation. Записать версию Prism, JVM клиента и фактический результат.
|
||||
|
||||
## Фактические результаты переходов
|
||||
|
||||
- Первый запуск: Minecraft 1.21.1, Fabric 0.19.5, JVM Temurin 21.0.12.1+1; mc-health отвечает version=1.21.1 online=0 max=20.
|
||||
- Docker inspect: /data — rw bind на runtime/, /modpacks — ro bind на dist/. Named volumes отсутствуют.
|
||||
- Recreate: до повторного запуска SHA-256 level.dat остался `32832255e84e2d8b4e324527d21b233b0b0cc4615ae17ee0296e7e8c5d4d9728`.
|
||||
- Update 0.0.1 → 0.0.2: только fabric-api-0.116.16+1.21.1.jar, старый 0.116.17 удалён; manual-runtime-v1 заменён на pack-default-v2.
|
||||
- Datapack: лог «Found new data pack file/phase0, loading it automatically», затем «[Phase0] datapack-v2-loaded».
|
||||
- Optional override: `MC_PACK=minecraft-lab-spike-0.0.2/minecraft-lab-spike-0.0.2.mrpack scripts/spike-server.sh -f server/compose.spike-override.yaml up -d --wait --wait-timeout 120`; marker стал server-override-v1.
|
||||
- Update → 0.0.3 без override: runtime/mods пуст, управляемые файлы прежнего datapack удалены, unmanaged-probe.txt сохранился.
|
||||
- Failure: MC_PACK=missing-phase0.mrpack, Compose --wait вернул 1; контейнер exited(1), hash мира остался прежним.
|
||||
- Restore: sha256sum snapshot проверен, распаковка в .tools/runtime-restored, сравнение world/config с baseline успешно; прежний runtime сохранён, восстановленный переименован в runtime. После запуска исходного pack 0.0.1 сервер healthy.
|
||||
|
||||
Каждый изменяющий тест предварялся корректной остановкой и snapshot. Пять архивов в backups/ имеют SHA-256 и JSON metadata: исходный артефакт, image digest, server override и время; исключений нет. Имена phase0-* относятся к однократному запуску этого эксперимента. Для обычных backups использовать уникальные ID из примера выше.
|
||||
|
||||
Артефакты тестовых переходов (ZIP timestamps могут отличаться при повторном export):
|
||||
|
||||
| Релиз | SHA-256 |
|
||||
| --- | --- |
|
||||
| 0.0.2 | ca10d1faffa8a71ee58431f7f3f2ee88be4c7572e035cac8824331129b701fab |
|
||||
| 0.0.3 | ced6fe830055ce3f0ae2d1c4c14e0fb41b5a8580bdaf5cac3010b0bdc8a9ceba |
|
||||
|
||||
Финальное состояние: сервер запущен с исходным pack 0.0.1 и восстановленным baseline, optional override выключен. Импорт и запуск Prism подтверждены локальными instance metadata и client log. Подключение не завершилось: Failed to log in: The authentication servers are currently not reachable. В client log sessionHost/servicesHost=https://nope.invalid и UnknownHostException: nope.invalid; launcher log содержит четыре -Dminecraft.api.*.host с этим адресом. В pack и instance/global JvmArgs такого override нет, переменные JAVA_TOOL_OPTIONS/JDK_JAVA_OPTIONS/_JAVA_OPTIONS Windows этих overrides не содержат. Для offline-клиента эти параметры не являются ошибкой настройки: изначальное требование online-mode=true противоречило цели пользователя. Требование аккаунта снято; нужен offline-server login. Account files и токены не читались.
|
||||
|
||||
## Обнаруженные ограничения и изменения архитектуры
|
||||
|
||||
- packwiz автоматически добавил Text Placeholder API и выставил both, хотя он
|
||||
нужен этой сборке только на клиенте. Metadata проекта не заменяет проверку
|
||||
конкретного состава зависимостей. Свой resolver не нужен.
|
||||
- В Arch package index Compose 5.5.1 ссылался на отсутствующий файл (HTTP 404).
|
||||
Не обновлялась вся система: Docker установлен отдельно, Compose скачан локально.
|
||||
- В минимальном окружении отсутствует cmp; build сравнивает SHA-256 source и
|
||||
refresh-копии вместо дополнительной системной зависимости.
|
||||
- Network-вызовы sandbox требуют разрешения. Подстановка latest не используется
|
||||
в воспроизводимых командах; закреплены результаты первоначального выбора.
|
||||
- GitHub Actions artifacts имеют ограниченный срок хранения. Bootstrap по run ID
|
||||
пригоден для spike, но не для долговременного release tooling. Для него нужен
|
||||
build packwiz из закреплённого commit или сохранённый binary с checksum.
|
||||
- Пакет содержит ссылки на Modrinth downloads, а не все JAR; offline install
|
||||
не доказан. Образ также загружает Minecraft и loader при первом старте.
|
||||
- Windows Test-NetConnection 127.0.0.1:25565 вернул TcpTestSucceeded=True после восстановления. GET sessionserver hasJoined без сессии возвращает 204 из Windows, WSL и контейнера; GET api.minecraftservices.com/publickeys возвращает 200 из Windows и контейнера. Эти пробы не передавали токены и не подтверждают login, но исключают общую недоступность этих endpoints.
|
||||
- Минимальная сборка использует Fabric API, не добавляя новые блоки/предметы. Она доказывает установку loader и модов; сетевую совместимость content-модов понадобится проверить на реальной сборке.
|
||||
- Fabric был неверно выбран вместо целевых NeoForge/Forge. Его результаты сохраняются только как предварительный эксперимент. Целевой Phase 0 ещё требует modpack на NeoForge/Forge, defaultconfigs и подключения offline-клиента.
|
||||
- При смене mrpack управляемый config заменяется, включая ручную правку. Неуправляемый файл сохраняется. Требуется проверка drift в будущей платформе до применения пакета.
|
||||
- Server override через /config с SYNC_SKIP_NEWER_IN_DESTINATION=false применяется после modpack defaults и побеждает их. Это намеренная политика теста, не универсальная политика production.
|
||||
- Datapacks нужны в world/datapacks, а не в корневом /data/datapacks. В варианте 0.0.2 проверен путь overrides/world/datapacks/phase0. Это статические исходники datapack, не snapshot мира. Если сохранить предложенный pack/datapacks layout, нужен явный перенос в целевой world path; world name должен учитываться.
|
||||
- Важное ограничение воспроизводимости: local mrpack закрепляет loader, но не версию Fabric installer/launcher. В runtime наблюдается 1.1.2. В закреплённом образе TYPE=MODRINTH вызывает install-modrinth-modpack напрямую, не передавая FABRIC_LAUNCHER_VERSION; в help этого helper нет соответствующего параметра. Поэтому простое добавление Fabric env в Compose не доказывает фиксацию installer. Перед production release нужно выбрать проверенный способ фиксировать/сохранять launcher или явно ограничить обещание воспроизводимости. Собственный mod resolver для этого не нужен.
|
||||
- Production deployment и автоматический rollback остаются вне scope Phase 0.
|
||||
|
||||
Официальные источники:
|
||||
|
||||
- [packwiz installation](https://packwiz.infra.link/installation/)
|
||||
- [packwiz Modrinth export](https://packwiz.infra.link/tutorials/hosting/modrinth/)
|
||||
- [itzg local mrpack](https://docker-minecraft-server.readthedocs.io/en/latest/types-and-platforms/mod-platforms/modrinth-modpacks/)
|
||||
- [itzg healthcheck](https://docker-minecraft-server.readthedocs.io/en/latest/misc/healthcheck/)
|
||||
- [Modrinth format](https://support.modrinth.com/en/articles/8802351-modrinth-modpack-format-mrpack)
|
||||
|
||||
## Уточнение цели пользователем
|
||||
|
||||
Собирать пользовательские модпаки NeoForge/Forge, распространять клиентский артефакт и запускать сервер без проверки аккаунтов. ONLINE_MODE=false, ENFORCE_SECURE_PROFILE=false. Смена auth режима предварена backup phase0-before-offline-mode. Проверка Microsoft login не входит в acceptance criteria.
|
||||
@@ -0,0 +1,85 @@
|
||||
# Healthcheck — Phase 6
|
||||
|
||||
Проверенная готовность доступна через `scripts/server.sh` с теми же абсолютными
|
||||
MC_ROOT/MC_RELEASE_DIR и host settings, что описаны в [runtime.md](runtime.md).
|
||||
|
||||
```bash
|
||||
export MC_ROOT=/absolute/server-root
|
||||
export MC_RELEASE_DIR=/absolute/full-release
|
||||
scripts/server.sh up -d --wait --wait-timeout 120
|
||||
# Проверить уже созданный контейнер без запуска/перезапуска:
|
||||
scripts/server.sh health --wait-timeout 120
|
||||
# Первый запуск с загрузкой dependencies может требовать больше времени:
|
||||
scripts/server.sh up --wait --wait-timeout 600
|
||||
```
|
||||
|
||||
`up/start/restart --wait` и `health` возвращают 0 только после штатного Docker
|
||||
healthcheck `mc-health` и свежих успешных Minecraft status queries. Running
|
||||
container и TCP connect сами по себе не подтверждают готовность.
|
||||
|
||||
По умолчанию окно стабильности — 10 секунд. На всём окне должны проходить
|
||||
queries, контейнер не должен меняться или перезапускаться. Неудачный query
|
||||
или health status, отличный от healthy, сбрасывает окно; проверки повторяются
|
||||
до deadline. Пример с явно выбранным окном:
|
||||
|
||||
```bash
|
||||
scripts/server.sh health --wait-timeout 30 --stable-seconds 3
|
||||
scripts/server.sh restart --wait --wait-timeout 120 --stable-seconds 10
|
||||
```
|
||||
|
||||
Timeout — целое положительное число секунд; он должен быть больше окна
|
||||
стабильности. Если флаг не задан, берётся `deploy.healthcheck_timeout` из
|
||||
`platform/config.yaml` (сейчас 120). Timeout учитывает Compose launch и
|
||||
ожидание readiness; проверка входных данных и сбор диагностических логов
|
||||
выполняются отдельно. Docker queries ограничены оставшимся временем, отдельный
|
||||
status query — также максимум 10 секундами. Опрос выполняется примерно раз
|
||||
в секунду. `up --wait` запускается detached; сочетание с attach/abort options
|
||||
отклоняется. Флаги поддерживают и `--wait-timeout=120`.
|
||||
|
||||
Обычный `up -d` без `--wait` по-прежнему означает только запуск Compose и
|
||||
не гарантирует готовность. Backup resume из Phase 5 использует `up --wait`
|
||||
и теперь проходит новую проверку перед возвращением success.
|
||||
|
||||
## Ошибки и сохранённые свидетельства
|
||||
|
||||
Non-zero возвращается для timeout, crash/exited, paused, restart loop,
|
||||
замены контейнера, отсутствующего container/healthcheck, ошибки Docker query
|
||||
и ошибки Compose launch. Наблюдаемый restart или изменение StartedAt/RestartCount
|
||||
во время ожидания считается нестабильным запуском и завершается ошибкой;
|
||||
количество перезапусков до начала проверки используется как baseline.
|
||||
|
||||
На неудачном запуске выводятся пути:
|
||||
|
||||
```text
|
||||
MC_ROOT/diagnostics/health-TIMESTAMP-UUID.json
|
||||
MC_ROOT/diagnostics/health-TIMESTAMP-UUID.log
|
||||
```
|
||||
|
||||
Report содержит причину, elapsed/timeout/stability, последнее Docker state
|
||||
(включая exit code/OOM/restart count), результат последнего status query,
|
||||
project и SHA256 release manifest. При отказе самого Compose сохраняются
|
||||
его exit/error/signal; readiness ещё не проверена. Log содержит последние
|
||||
100 строк Compose logs. Если получение логов тоже не удалось, это записывается
|
||||
в log. Диагностика имеет mode 600, каталог создаётся с mode 700.
|
||||
|
||||
Recovery state сообщает, что runtime и binding сохранены, active release
|
||||
не переключался, automatic rollback не выполнялся. Поле backup_snapshot
|
||||
ссылается на snapshot последней записанной backup operation, если он есть;
|
||||
null не означает, что других snapshots нет. Их можно найти в MC_ROOT/backups.
|
||||
Healthcheck не удаляет runtime, не распаковывает backup и не переключает релиз.
|
||||
После timeout контейнер может продолжать startup; исправить причину/увеличить
|
||||
timeout и повторить `health`. После crash можно запустить тот же релиз через
|
||||
`up --wait`. При restart loop сначала изучить report/log и остановить сервер
|
||||
через `scripts/server.sh stop`. Восстановление — [backups.md](backups.md).
|
||||
|
||||
Startup и отдельный `health` удерживают общую lifecycle lock до завершения
|
||||
проверки. Другой wrapper не сможет одновременно выполнить backup/restart/down.
|
||||
Контейнер другого runtime root отклоняется до запроса игрового протокола.
|
||||
Прямые Docker/Compose команды и ручное изменение данных обходят эту блокировку.
|
||||
|
||||
Это ограниченная проверка готовности после запуска, не постоянно работающий
|
||||
watchdog. Ручное подключение клиента и состав модов проверяются отдельно;
|
||||
SSH deployment и переключение active-release используют эту проверку
|
||||
в Phase 7: [deploy.md](deploy.md).
|
||||
|
||||
Реальные проверки crash/restart loop/timeout — [phase6-results.md](phase6-results.md).
|
||||
@@ -0,0 +1,52 @@
|
||||
# Управление модами — Phase 3
|
||||
|
||||
Из корня репозитория, после установки npm dependencies и packwiz:
|
||||
|
||||
```bash
|
||||
./mcpack add mouse-tweaks
|
||||
./mcpack remove mouse-tweaks
|
||||
./mcpack update sophisticated-backpacks
|
||||
./mcpack update --all
|
||||
```
|
||||
|
||||
`add` использует Modrinth; принимает slug, project ID, URL или одну строку
|
||||
поиска в кавычках. Конкретная версия выбирается штатным version URL:
|
||||
|
||||
```bash
|
||||
./mcpack add https://modrinth.com/mod/sophisticated-backpacks/version/pJxNzk4X
|
||||
```
|
||||
|
||||
`remove` и `update <mod>` используют имя metadata, понятное packwiz, например
|
||||
`sophisticated-backpacks`. Wrapper сохраняет stdin/stdout/stderr packwiz,
|
||||
его prompts и код завершения. По умолчанию автоматического согласия нет.
|
||||
`--yes` или `-y` явно передаёт packwiz `--yes`; при поиске packwiz может
|
||||
выбрать первый результат, поэтому для точного выбора использовать slug/ID/URL.
|
||||
|
||||
Каждая команда поддерживает `--config FILE`. Config выбирает pack directory
|
||||
относительно корня проекта; cwd вызывающей стороны не меняет выбор pack.
|
||||
Проверяются config, пути и SHA256 закреплённого packwiz. Аргументы передаются
|
||||
массивом без shell, строки поиска не исполняются как команды.
|
||||
|
||||
Команды изменяют source metadata/indexes через packwiz. Они не повышают
|
||||
версию сборки, не запускают build, не изменяют готовые релизы и runtime.
|
||||
Перед новым build выбрать новую `version` в `pack/pack.toml`, поскольку
|
||||
существующий релиз той же версии не перезаписывается. Например, следующим
|
||||
после 0.0.4 может быть 0.0.5. Правила build — [build.md](build.md).
|
||||
|
||||
Side metadata и dependencies остаются ответственностью packwiz; wrapper
|
||||
не переписывает resolver и не удаляет автоматически оставшиеся dependencies.
|
||||
Применение модов к уже работающему серверу относится к следующим фазам.
|
||||
|
||||
## Проверка
|
||||
|
||||
```bash
|
||||
npm test
|
||||
bash scripts/verify-phase3.sh
|
||||
```
|
||||
|
||||
Вторая команда требует сети для Modrinth и работает в одноразовом локальном
|
||||
Git clone внутри `.tools/`, с копиями проверенных инструментов и установленными
|
||||
npm dependencies. Удаляет Backpacks, добавляет 3.26.6.2174, обновляет до
|
||||
3.26.7.2182 отдельно и через `--all`. После каждого состояния выпускает
|
||||
полный тестовый релиз с Compose/manifest/checksums. Основной pack и runtime
|
||||
не меняются. Network/provider errors возвращаются как ошибки packwiz.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Remote game port: 0.0.5
|
||||
|
||||
2026-10-03 удалённый NeoForge сервер переведён с loopback на полноценную
|
||||
IPv4-публикацию порта. Подключение клиента теперь **192.168.1.61:25565**,
|
||||
SSH tunnel не нужен.
|
||||
|
||||
- Source pack version поднята до 0.0.5; новый clean immutable release содержит
|
||||
`${MC_BIND_ADDRESS:-127.0.0.1}:${MC_PORT:-25565}:25565` в Compose.
|
||||
- Remote host `.env`: `MC_BIND_ADDRESS=0.0.0.0`; локальный default — 127.0.0.1.
|
||||
Значение проверяется как IPv4 и берётся из host settings, а не ambient shell.
|
||||
- Release построен через `scripts/build-clean-release.sh`: отдельный source
|
||||
snapshot/Git checkout, clean build и проверенная atomic публикация в dist.
|
||||
Основной Git worktree не коммитился; старые immutable releases не изменялись.
|
||||
- Перед update создан verified backup исходного runtime и полного release 0.0.4:
|
||||
`backups/20261003T161610568Z-ca83dc50-0582-4ac7-b98a-353dc957f486`
|
||||
внутри remote server root. В snapshot сохранены 13 файлов мира и остальные
|
||||
persistent данные; host `.env` остаётся вне snapshot.
|
||||
- Deployment complete: active=0.0.5, previous=0.0.4, health=healthy.
|
||||
Тот же `/runtime` bind используется после recreate. Server override marker
|
||||
остался `server-override-v1`; состав/версии модов не менялись.
|
||||
- Docker inspect подтверждает HostIp=0.0.0.0, HostPort=25565.
|
||||
- Прямой Minecraft status query из локального workspace к 192.168.1.61:25565
|
||||
без tunnel вернул Minecraft 1.21.1, protocol 767, online=0/max=20.
|
||||
- Локальный Phase 0 сервер на loopback:25565 остался healthy.
|
||||
|
||||
`npm test`: 58 pass. Проверены build port interpolation, bind validation
|
||||
и приоритет host settings; backup/deployment/health regression tests проходят.
|
||||
Bash/Node syntax и git diff --check пройдены. Дополнительный protocol checker:
|
||||
|
||||
```bash
|
||||
node scripts/query-minecraft.mjs 192.168.1.61 25565
|
||||
```
|
||||
|
||||
Свидетельства: `.tools/lan-port-evidence/deploy.log`, `direct-status.json`,
|
||||
`remote-verification.json`, `primary-server-status.txt`, `.tools/lan-port-tests.log`.
|
||||
Публикация проверена в LAN; router/NAT configuration этим изменением не выполнялась.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Phase 1: каркас проекта
|
||||
|
||||
Phase 1 завершена для рабочей основы NeoForge 21.1.252 / Minecraft 1.21.1.
|
||||
|
||||
## Каркас
|
||||
|
||||
- `platform/config.yaml`: schema version, pack/output paths, server defaults,
|
||||
будущий SSH deployment target. Host/directory не заданы.
|
||||
- `platform/schemas/`: место для будущей схемы вместе с parser в Phase 2.
|
||||
- `pack/`: проверенный packwiz source без изменения версий и состава модов.
|
||||
- `server/`: Compose, `.env.example`, явно подключаемый override template.
|
||||
- `scripts/`: минимальные spike-инструменты; основного CLI пока нет.
|
||||
- `docs/`, `examples/`, `testdata/`: результаты и материалы воспроизведения.
|
||||
- `dist/`, `runtime/`: только `.gitkeep` включается в source.
|
||||
|
||||
`server.properties` генерируется из Compose environment, поэтому отдельный
|
||||
source-файл не создан. Дополнительные pack-директории создаются по мере
|
||||
появления контента; пустые файлы не добавляются в экспорт. Makefile и команды
|
||||
deploy/backup/rollback появятся в соответствующих фазах, без пустых заглушек.
|
||||
|
||||
Platform manifest пока не читается spike-скриптами. Текущий runtime использует
|
||||
env-файлы; подключение manifest и validation относятся к Phase 2.
|
||||
|
||||
## Проверка на чистом clone
|
||||
|
||||
Из неигнорируемых файлов рабочего дерева создан временный Git snapshot в
|
||||
`.tools/phase1-check.0Od3T1/source`, затем выполнен локальный `git clone` в
|
||||
соседний `clone/`. Основной репозиторий не коммитился и не менял index.
|
||||
В clone отсутствовали прежние `.tools/`, runtime state, backups и `.env`.
|
||||
|
||||
Пройдены:
|
||||
|
||||
1. `scripts/spike-tools.sh`: новые downloads packwiz и Compose;
|
||||
архив/бинарники совпали с закреплёнными SHA256, Compose v5.6.0.
|
||||
2. `packwiz refresh`: успешен, `git diff --exit-code -- pack` подтвердил
|
||||
отсутствие изменений metadata после refresh/export/build.
|
||||
3. `packwiz modrinth export`: успешен, ZIP содержит index и pack config.
|
||||
4. `scripts/spike-server.sh config --quiet`: основной Compose валиден.
|
||||
5. То же с `-f server/compose.override.yaml.example`: слой overrides валиден.
|
||||
6. `scripts/spike-build.sh`: экспорт в новый `dist/` с SHA256SUMS успешен.
|
||||
7. Bash syntax и `git diff --check`: успешны.
|
||||
8. `git check-ignore`: runtime, dist, tools, backups, локальные `.env` и
|
||||
активный override игнорируются; `.env.example` не игнорируется.
|
||||
|
||||
Проверка Compose не запускала сервер; активный мир и артефакт не изменены.
|
||||
Точный порядок работы для нового checkout описан в корневом README.
|
||||
|
||||
Bootstrap использует закреплённый GitHub Actions artifact packwiz; такие
|
||||
артефакты имеют ограниченный срок хранения. Для долгосрочного bootstrap
|
||||
потребуется постоянное хранение проверенного бинарника либо сборка
|
||||
закреплённого commit. Текущий URL проверен свежим скачиванием.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Phase 2: build command
|
||||
|
||||
Phase 2 завершена. `./mcpack build` читает platform YAML, валидирует packwiz
|
||||
source и создаёт полный релиз, не меняя source или активный runtime.
|
||||
Node.js 22+ используется для orchestration с закреплёнными YAML/TOML parsers;
|
||||
экспорт и dependency resolution остаются у packwiz.
|
||||
|
||||
## Выпущенный development artifact
|
||||
|
||||
`dist/minecraft-lab-neoforge-spike-0.0.4/` содержит `.mrpack`, `server/`,
|
||||
`manifest.json`, `SHA256SUMS`. Все файлы кроме SHA256SUMS покрыты checksums,
|
||||
включая manifest. Pack version увеличена с 0.0.1 до 0.0.4, чтобы сохранить
|
||||
существующие spike-артефакты 0.0.1–0.0.3 без перезаписи. Состав модов,
|
||||
Minecraft и NeoForge не менялись.
|
||||
|
||||
- `.mrpack` SHA256: `877b34bf582f9d06b9dbd2832db8a1b376a786be21826628229df52a6672cd52`.
|
||||
- Manifest SHA256: `5933ed34f35473026a32f0c3eab9a8b86b6fb484461bac2f670e0a74930aaa0c`.
|
||||
- Git commit: `85f6897365b8d4717d8670808d2223c3024d247f`, `dirty=true`.
|
||||
|
||||
Dirty flag отражает незакоммиченную текущую работу. Main repo не коммитился.
|
||||
Development build допускает это; `--release` требует чистого worktree.
|
||||
|
||||
## Подтверждённые проверки
|
||||
|
||||
- Реальный `./mcpack build` с закреплённым packwiz: refresh/export успешны,
|
||||
metadata в копии не менялась. Перед build версия явно обновлена и refresh
|
||||
выполнен пользователю видимым отдельным шагом.
|
||||
- Compose нового релиза валиден с абсолютными root/release bindings;
|
||||
image literal digest и defaults взяты из lock/platform config.
|
||||
- Checksums всех шести release files успешны.
|
||||
- Manifest содержит Minecraft/loader, provenance инструментов, исходные
|
||||
hashes и управляемые пути клиента/сервера. Mouse Tweaks отсутствует в
|
||||
server ownership; server marker явно overrides pack marker.
|
||||
- 12 автоматических тестов успешны. Используют настоящий Git и Compose,
|
||||
контролируемый packwiz substitute для отказов и ZIP fixtures. Проверяют
|
||||
чистый/dirty build, configurable output/defaults, checksums, отсутствие
|
||||
local secrets/target, повторную сборку, stale source, export failure,
|
||||
неподтверждённый loader, дубликаты, invalid YAML/paths, tracked secrets,
|
||||
symlinks и tampered tool hash.
|
||||
- Bash/Node syntax, `git diff --check` успешны.
|
||||
- Активный NeoForge-сервер после build остаётся healthy на 0.0.1;
|
||||
контейнер не пересоздавался, мир не менялся командой build.
|
||||
|
||||
Контракт и воспроизведение — [build.md](build.md). Full release Compose
|
||||
проверен через `config`, запуск нового релиза в Phase 2 не выполнялся.
|
||||
Deployment/cleanup/rollback по ownership manifest относятся к следующим
|
||||
фазам. Build лишь фиксирует контракт.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Phase 3: mod wrappers
|
||||
|
||||
Phase 3 завершена: `mcpack add`, `remove`, `update <mod>`, `update --all`
|
||||
делегируют операции закреплённому packwiz. Config/путь source/бинарник
|
||||
проверяются до вызова; оригинальные prompts, stdout/stderr и exit code
|
||||
packwiz сохраняются. Add поддерживает штатные Modrinth version URLs.
|
||||
|
||||
## Реальная integration-проверка
|
||||
|
||||
`bash scripts/verify-phase3.sh` успешно выполнен в тестовом clone
|
||||
`.tools/phase3-check.m9vdq6/clone`. Лог: `.tools/phase3-integration.log`;
|
||||
diff source: `.tools/phase3-check.m9vdq6/source-changes.diff`.
|
||||
|
||||
1. Remove Backpacks удалил `.pw.toml` и обновил index.
|
||||
2. Add version URL создал metadata для 3.26.6.2174 / `pJxNzk4X`;
|
||||
уже установленный Core сохранился.
|
||||
3. Update одного мода заменил Backpacks на 3.26.7.2182 / `Igmp9PwW`.
|
||||
4. Для update --all снова установлена старая версия. Команда реально
|
||||
обновила её, после чего metadata вернулась к 3.26.7.2182.
|
||||
5. После каждого состояния успешен full build: `phase3-remove`,
|
||||
`phase3-add`, `phase3-update`, `phase3-all`. Для всех прошли Compose
|
||||
config и SHA256SUMS, source metadata осталась консистентной.
|
||||
|
||||
Тестовые versions менялись только в clone, чтобы сохранить неизменяемые
|
||||
готовые релизы. Основной pack остаётся 0.0.4 с прежними тремя модами;
|
||||
активный сервер и мир не изменялись и не перезапускались.
|
||||
|
||||
## Автоматические проверки
|
||||
|
||||
`npm test`: 16/16 успешны. Помимо 12 build-тестов проверены:
|
||||
|
||||
- точное отображение команд/аргументов packwiz, включая --all и --yes;
|
||||
- отклонение неверных комбинаций до запуска tool;
|
||||
- выбор source directory через config при вызове из другого cwd;
|
||||
- literal search argv без shell execution;
|
||||
- сохранение stdout/stderr и тестового exit code 17;
|
||||
- отказ при изменённом hash packwiz.
|
||||
|
||||
Bash/Node syntax и `git diff --check` успешны. Реальные GUI/server проверки
|
||||
новых модов не входят в Phase 3; wrappers меняют source, не deployment.
|
||||
Пользовательские команды и контракт — [mods.md](mods.md).
|
||||
@@ -0,0 +1,43 @@
|
||||
# Phase 4: server runtime
|
||||
|
||||
Phase 4 завершена для NeoForge 21.1.252 / Minecraft 1.21.1. Full release
|
||||
0.0.4 реально запущен с пустой директорией данных через `scripts/server.sh`.
|
||||
|
||||
## Реальная Docker-проверка
|
||||
|
||||
- Server root: `.tools/phase4-server`, project: `minecraft-lab-phase4`.
|
||||
- Настройки: EULA=TRUE по ранее полученному принятию, UID/GID=1000:1000,
|
||||
memory=2G, IPv4 loopback port=25566.
|
||||
- Первый `up -d --wait --wait-timeout 600` завершился healthy. Лог подтвердил
|
||||
создание нового мира, Minecraft 1.21.1, NeoForge 21.1.252, Backpacks 3.26.7
|
||||
и Core 1.5.5. Mouse Tweaks отсутствовал в серверных JAR.
|
||||
- Docker inspect подтвердил обычные абсолютные bind mounts: host runtime
|
||||
→ `/data` rw, release → `/modpacks` ro, server/config → `/config` ro.
|
||||
- `world/level.dat` принадлежит 1000:1000. Pack загружен из `.mrpack`,
|
||||
server override marker=`server-override-v1`, `online-mode=false` и
|
||||
`enforce-secure-profile=false` подтверждены.
|
||||
- Restart того же контейнера завершился healthy.
|
||||
- После остановки и `create --force-recreate` все 23 файла мира совпали
|
||||
по путям/SHA256 до нового запуска. Неуправляемый config marker сохранился.
|
||||
- Вновь запущенный контейнер healthy; mc-health отвечает Minecraft 1.21.1.
|
||||
- Финальная версия wrapper дополнительно проверена реальным up/exec/down
|
||||
после добавления проверки принадлежности Compose project.
|
||||
- Тестовый контейнер/network удалены через down, runtime и binding сохранены.
|
||||
Основной сервер на 25565 не пересоздавался и остался healthy.
|
||||
|
||||
Свидетельства: `.tools/phase4-evidence/first-start.log`, `mounts.json`,
|
||||
`before-recreate-world.json`, `recreate-verification.txt`,
|
||||
`recreated-start.log`. Test root остаётся пригодным для последующих проверок.
|
||||
|
||||
## Автоматические проверки
|
||||
|
||||
`npm test`: 25 тестов. Новые runtime tests используют controlled Compose/Docker
|
||||
substitutes и проверяют integrity/coverage, EULA/UID/GID, immutable binding,
|
||||
смену release/project, защиту существующего мира, failed startup/exit code,
|
||||
operation lock, offline/bind contract, paths и конфликт project другого root.
|
||||
Build/mod regression tests также проходят. Реальная Docker-проверка выше
|
||||
подтверждает integration, которую substitutes сами по себе не доказывают.
|
||||
|
||||
Bash/Node syntax и `git diff --check` пройдены. Backup, миграция существующего
|
||||
мира, remote deployment и расширенная диагностика healthcheck не реализуются
|
||||
этим этапом. Контракт и команды — [runtime.md](runtime.md).
|
||||
@@ -0,0 +1,74 @@
|
||||
# Phase 5: backups и восстановление
|
||||
|
||||
Phase 5 завершена для NeoForge 21.1.252 / Minecraft 1.21.1. Реализованы
|
||||
`./mcpack backup`, `./mcpack restore` и обязательный gate `backupBeforeApply`
|
||||
для будущего deployment. Контракт и проверенная инструкция: [backups.md](backups.md).
|
||||
|
||||
## Проверка с реальным Docker
|
||||
|
||||
Проверка 2026-10-03 выполнялась на отдельном root `.tools/phase4-server`,
|
||||
project `minecraft-lab-phase4`, port 25566, full release 0.0.4. Основной
|
||||
Phase 0 сервер на 25565 не останавливался и остался healthy.
|
||||
|
||||
- Запущенный сервер был корректно остановлен; backup всего runtime
|
||||
опубликован после tar/zstd listing и пробной распаковки.
|
||||
- Snapshot содержит runtime archive, metadata, полную копию release 0.0.4
|
||||
и checksums всех файлов. Исключений нет.
|
||||
- После backup сервер автоматически вернулся на исходный release в healthy;
|
||||
`mc-health` подтвердил Minecraft 1.21.1.
|
||||
- Затем намеренно подставлена команда tar с exit 42. Backup вернул non-zero,
|
||||
оставил сервер остановленным, не создал дополнительный окончательный
|
||||
snapshot и удалил временный staging. Metadata операции фиксирует failed.
|
||||
- Старый тестовый контейнер удалён через down. Snapshot восстановлен в новый
|
||||
`.tools/phase5-restored-server` без распаковки поверх существующего root.
|
||||
- До запуска совпали все 416 inventory entries (160 файлов, включая 23 файла
|
||||
world): пути, bytes/SHA256, mode, UID и GID. В наборе есть владельцы
|
||||
1000:1000 и 0:0; обе группы сохранились.
|
||||
- Подтверждены `mod-state/phase5.json` и unmanaged config вне world,
|
||||
server.properties, ops.json, whitelist.json. Локальный host `.env` не
|
||||
копировался: при запуске использован уже настроенный файл прежнего test root.
|
||||
- Восстановленная копия запущена с собственным сохранённым `release/`:
|
||||
NeoForge 21.1.252, Minecraft 1.21.1, статус healthy и успешный `mc-health`.
|
||||
- После проверки восстановленный контейнер/network удалены через down.
|
||||
Оба тестовых runtime и snapshot сохранены для дальнейших проверок.
|
||||
|
||||
Проверенный snapshot:
|
||||
|
||||
```text
|
||||
.tools/phase4-server/backups/20261003T134409150Z-edd387d7-f947-4c3d-8ffc-bc02649cdfdc
|
||||
archive bytes: 162695375
|
||||
archive SHA256: e52c82adb379942ed2b63fb0cd361dd7d2cfd153314b26b026bafd942c87c9ce
|
||||
release manifest SHA256: 5933ed34f35473026a32f0c3eab9a8b86b6fb484461bac2f670e0a74930aaa0c
|
||||
```
|
||||
|
||||
Свидетельства: `.tools/phase5-evidence/backup.log`, `failed-backup.log`,
|
||||
`failure-verification.txt`, `restore-verification.txt`, `resumed-health.txt`,
|
||||
`restored-health.txt`, `restored-start.log`, `primary-server-status.txt`,
|
||||
`integration.log`. Сценарий — `scripts/verify-phase5.sh`; он требует специально
|
||||
подготовленного test root Phase 4 и ещё не существующего restore destination.
|
||||
Его нельзя запускать как универсальную команду на primary сервере.
|
||||
|
||||
## Автоматические проверки
|
||||
|
||||
`npm test`: 37 tests pass. Backup/restore tests проверяют общий lifecycle lock,
|
||||
stop/archive/verify/resume, stopped/absent state, разные snapshot ID,
|
||||
восстановление bytes/modes/ownership и связанного release, запрет существующей
|
||||
цели, повреждённый archive, неполное checksum coverage, ошибку tar/stop/resume,
|
||||
unsupported links, проверку target до остановки и отказ применения до backup.
|
||||
|
||||
Gate test доказывает, что callback будущего apply не вызывается при ошибке
|
||||
архива и вызывается только после verified snapshot под той же блокировкой.
|
||||
При ошибке callback status учитывает текущее состояние контейнера и не
|
||||
запускает старую сборку автоматически. SSH apply сам пока не реализован.
|
||||
Build, mod commands и runtime regression tests также проходят. Node/Bash
|
||||
syntax и `git diff --check` пройдены.
|
||||
|
||||
## Оставшиеся границы
|
||||
|
||||
Автоматическое удаление snapshot, off-host копии, retention, rollback и
|
||||
переключение active release — последующие фазы. Пока runtime не поддерживает
|
||||
links/special files в backup. Atomic publication защищает от обычной ошибки
|
||||
процесса, но fsync для гарантии при отключении питания не реализован.
|
||||
Primary старого spike wrapper не мигрирован на full-release binding.
|
||||
Следующая Phase 6 — расширенная диагностика healthcheck, crash/restart-loop
|
||||
и timeout с полезными logs.
|
||||
@@ -0,0 +1,61 @@
|
||||
# Phase 6: healthcheck и диагностика startup
|
||||
|
||||
Phase 6 завершена: ожидание готовности проверяет pinned image healthcheck,
|
||||
Minecraft status query и стабильность контейнера; отказ возвращает non-zero
|
||||
и пути к сохранённым logs/report. Контракт — [health.md](health.md).
|
||||
|
||||
## Реальная Docker-проверка 2026-10-03
|
||||
|
||||
Исходный snapshot Phase 5 восстановлен в отдельный `.tools/phase6-server`.
|
||||
Использован сохранённый полный NeoForge release 0.0.4, Minecraft 1.21.1,
|
||||
NeoForge 21.1.252, pinned image, host UID/GID 1000:1000 и port 25566.
|
||||
Project — свободный после Phase 5 `minecraft-lab-phase4`.
|
||||
|
||||
- `up --wait --wait-timeout 2 --stable-seconds 1` на холодном JVM старте
|
||||
вернул timeout/non-zero через 2000 ms ожидания. Container оставлен для
|
||||
диагностики; runtime/binding сохранились.
|
||||
- `health --wait-timeout 120 --stable-seconds 3` затем вернул 0 после
|
||||
Docker healthy и стабильных свежих Minecraft queries. TCP не использован
|
||||
как достаточное свидетельство готовности.
|
||||
- Только тестовый контейнер аварийно завершён `docker kill --signal KILL`.
|
||||
Следующий health вернул crash/non-zero, report сохранил exit code 137
|
||||
и OOMKilled=false; elapsed около 230 ms.
|
||||
- Повторный `up --wait --wait-timeout 120 --stable-seconds 3` поднял тот же
|
||||
NeoForge release и подтвердил готовность. Исходный модпак не заменялся.
|
||||
- Для restart loop создан отдельный `.tools/phase6-loop-server` и намеренно
|
||||
повреждённая Compose fixture: pinned image, entrypoint с exit 42 и
|
||||
restart=on-failure:5. Это тестовая копия полного релиза с отдельной версией
|
||||
`phase6-failure-fixture` в manifest и пересчитанными checksums;
|
||||
опубликованный immutable release 0.0.4 не менялся. Fixture не доказывает
|
||||
загрузку NeoForge: её назначение — реальный Docker restart loop.
|
||||
- Docker inspect подтвердил RestartCount=1 до проверки. Health затем
|
||||
вернул restart-loop/non-zero за около 1476 ms с RestartCount=2 и новым
|
||||
StartedAt, сохранив logs с intentional failure marker.
|
||||
- Для всех ошибок есть JSON report и файл последних logs, binding сохранился,
|
||||
lifecycle lock освободилась, automatic rollback не выполнялся.
|
||||
- Test containers/network удалены через down. Их runtime/release/diagnostics
|
||||
оставлены для просмотра. Primary Phase 0 сервер на 25565 не останавливался,
|
||||
не пересоздавался и остался healthy.
|
||||
|
||||
Сценарий: `scripts/verify-phase6.sh`. Он требует Phase 5 snapshot и новых
|
||||
fixture roots, использует только копии test runtime. Свидетельства:
|
||||
`.tools/phase6-evidence/{integration.log,timeout.txt,healthy.txt,healthy-start.log,
|
||||
crash.txt,recovered.txt,restart-loop.txt,loop-docker-state.txt,assertions.txt,
|
||||
primary-server-status.txt}`. Подробные reports/logs находятся в diagnostics
|
||||
соответствующих test roots.
|
||||
|
||||
## Автоматические проверки
|
||||
|
||||
`npm test`: 46 тестов. Deterministic health tests проверяют успешные
|
||||
последовательные queries, провал протокола при running/healthy state,
|
||||
starting/unhealthy, сброс окна после transient failure, crash/OOM/paused,
|
||||
RestartCount/StartedAt/container identity, missing container/healthcheck,
|
||||
inspection error, deadlines включая launch и слишком поздний query, строгие
|
||||
флаги и диагностику Compose failure с сохранением binding/lock cleanup.
|
||||
|
||||
Regression tests Phase 2–5 проходят; backup resume теперь действительно
|
||||
ожидает стабильную готовность. Bash/Node syntax и `git diff --check` пройдены.
|
||||
|
||||
SSH transport, switching active-release, automatic recovery/rollback и
|
||||
continuous watchdog не добавляются в эту фазу. Следующая Phase 7 — SSH deployment
|
||||
с уже готовыми backup gate и healthcheck.
|
||||
@@ -0,0 +1,94 @@
|
||||
# Phase 7: SSH deployment
|
||||
|
||||
Phase 7 завершена для подтверждённой NeoForge 1.21.1 / 21.1.252 комбинации.
|
||||
Добавлены `mcpack deploy`, SSH worker и host deployment state. Подробный
|
||||
контракт и подготовка/recovery — [deploy.md](deploy.md).
|
||||
|
||||
## Реальный host пользователя
|
||||
|
||||
2026-10-03 выполнен deployment на `crab@192.168.1.61:2228` (minipc):
|
||||
|
||||
- Отдельный root: `/home/crab/workspace/minecraft-lab/minecraft-lab-neoforge-spike`.
|
||||
Базовый каталог для других сборок не используется как runtime.
|
||||
- Подтверждены Docker 27.4.1, Node 26.10.0 через nvm, rsync, GNU tar и zstd.
|
||||
Новые системные зависимости на remote host не устанавливались.
|
||||
- Создан host `.env` с ранее принятой EULA, UID/GID 1000:1000, memory 2G,
|
||||
port 25565, project minecraft-lab-neoforge-spike. Mode env=600, root=700.
|
||||
- SSH key host закреплён в локальном known_hosts. Password authentication
|
||||
использован для ControlMaster; пароль нигде не записан. Worker/rsync
|
||||
используют BatchMode и StrictHostKeyChecking=yes.
|
||||
- Clean release **0.0.4** построен в отдельном Git checkout, поскольку root
|
||||
development release 0.0.4 имеет dirty=true и намеренно не допускается deploy.
|
||||
Source repository пользователя не коммитился и immutable старый dist не менялся.
|
||||
- Release manifest SHA256:
|
||||
`4b9a060ecb74329c0c10ca8c24954f87f4b137dfb5240f844bb93208780a694f`.
|
||||
- Первый deploy создал runtime без backup (first deploy), загрузил pinned
|
||||
image/dependencies, запустил NeoForge и подтвердил status query + 10 s stability.
|
||||
- Повторный deploy завершился healthy noop. Deployment state complete,
|
||||
applied=false, noop=true; container StartedAt остаётся временем первого
|
||||
запуска `2026-10-03T15:40:01.458777215Z`.
|
||||
- Remote status query возвращает Minecraft 1.21.1. `online-mode=false` и
|
||||
`enforce-secure-profile=false`; world принадлежит 1000:1000, Backpacks/Core
|
||||
присутствуют, client-only Mouse Tweaks в server JAR нет.
|
||||
- Сервер оставлен запущенным. Game port остаётся на remote IPv4 loopback;
|
||||
инструкция SSH tunnel для клиента находится в deploy.md.
|
||||
- Локальный primary Phase 0 сервер на 25565 не останавливался и остался healthy.
|
||||
|
||||
Свидетельства: `.tools/phase7-target-evidence/deploy-first.log`,
|
||||
`deploy-noop.log`, `verification.txt`, `primary-server-status.txt`.
|
||||
SSH config — `.tools/phase7-ssh-target/config`, только параметры соединения.
|
||||
|
||||
## Реальный изолированный SSH/rsync стенд
|
||||
|
||||
`scripts/verify-phase7.sh` создал loopback SSH server на 22227 с временными
|
||||
ключами и новым Docker project minecraft-lab-phase7, port 25566. Полный
|
||||
source snapshot помещён в отдельный Git clone, dependencies скопированы как
|
||||
обычный ignored каталог (symlink node_modules делал worktree dirty).
|
||||
|
||||
Проверены реальные операции:
|
||||
|
||||
1. Clean build `0.0.4`, первая передача rsync и запуск healthy.
|
||||
2. Повторная передача команды deploy той же версии: ID и StartedAt контейнера
|
||||
совпали до/после, release не передавался повторно и restart не было.
|
||||
3. Общий host lock заблокировал параллельный deploy до остановки сервера.
|
||||
4. Clean build `0.0.5` с новым server override marker; update создал проверенный
|
||||
backup исходного runtime/release, запустил target и обновил active/previous.
|
||||
5. World/level.dat и persistent mod-state вне world сохранились; новый marker
|
||||
применился после backup, unknown файлы не удалялись.
|
||||
6. Ручное изменение managed config затем вызвало conflict/non-zero до stop/apply.
|
||||
Изменённый файл сохранён, state failed/applied=false.
|
||||
7. Test container/network и временный SSH daemon остановлены; snapshots,
|
||||
оба releases/runtime/state/evidence сохранены.
|
||||
|
||||
Стенд: `.tools/phase7-check.6dbBak`, свидетельства в его `evidence/`:
|
||||
`build-first.log`, `build-second.log`, `deploy-first.log`, `deploy-noop.log`,
|
||||
`noop-container.txt`, `locked.log`, `deploy-second.log`, `update-assertions.txt`,
|
||||
`manual-conflict.log`, `conflict-assertions.txt`, `primary-server-status.txt`.
|
||||
|
||||
## Автоматические проверки
|
||||
|
||||
`npm test`: 57 tests pass. Deployment tests используют controlled Compose/Docker
|
||||
и проверяют first deploy, no-op, immutable version collision, backup-gated
|
||||
update/world/mod-state, manual conflicts/diff, точный перенос ручной правки
|
||||
в clean target, failure передачи/backup/startup, unresolved state, async lock
|
||||
во время upload, dirty provenance, unsafe SSH arguments и CLI option scope.
|
||||
|
||||
При failure передачи source не останавливается. При failure backup target
|
||||
не запускается. Failed startup оставляет target binding, source pointers,
|
||||
verified snapshot и stopped state; старый pack не запускается автоматически.
|
||||
Это unit fault injection, а не имитация сбоев на пользовательском live host.
|
||||
Health failures с живым Docker проверены отдельно в Phase 6; tar failure и
|
||||
restore — в Phase 5. Обычный SSH update выше подтверждает интеграцию gate.
|
||||
|
||||
## Границы
|
||||
|
||||
Первый реальный remote deploy и no-op проверены на host пользователя;
|
||||
обновление и ручной conflict — на loopback стенде. Forge остаётся непроверенным.
|
||||
Аккаунты отключены; LAN game port не открывался, используется tunnel.
|
||||
Новый unknown существующий мир не принимается автоматически.
|
||||
|
||||
Failed/incomplete state блокирует следующий deploy до ручного recovery.
|
||||
Указатели каждый atomic, общая пара не transaction; state содержит этап
|
||||
committing и прежние значения. fsync, retention, off-host backup и автоматический
|
||||
recovery не реализованы. Remote agents автоматически не удаляются.
|
||||
Следующая Phase 8 — rollback с восстановлением snapshot и исходного release.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Phase 8 — завершена
|
||||
|
||||
Проверено 4 октября 2026 (Asia/Novosibirsk): rollback по SSH без повторного build.
|
||||
Оба режима автоматизированы; команды и условия описаны в [rollback.md](rollback.md).
|
||||
|
||||
На изолированном SSH/Docker-стенде восстановлен snapshot Phase 7, применён
|
||||
чистый release 0.0.5, затем выполнен pack-only rollback на retained 0.0.4.
|
||||
Маркеры мира и состояния модов сохранили текущий прогресс. Следующий snapshot
|
||||
rollback восстановил исходные маркеры, убрал появившийся позже файл из активного
|
||||
runtime и сохранил его вместе с текущим прогрессом в retired runtime.
|
||||
|
||||
Для обеих операций проверены backup текущего состояния, успешный health,
|
||||
сохранение `.env` и публикации `0.0.0.0:25566`, правильные pointers и освобождение
|
||||
общей блокировки. Просмотр планов сохранил список файлов root, ID контейнера и
|
||||
время его запуска. Финальный Minecraft status query прошёл. Контейнер стенда удалён.
|
||||
|
||||
68 unit tests прошли: CLI подтверждения, readonly plan, corrupt snapshot до stop,
|
||||
ошибка current backup, startup failure без автоматического возврата, snapshot
|
||||
recovery после failed deploy по фактическому binding, lock и безопасные ID.
|
||||
Старый immutable Compose проверен настоящим pinned Compose без зависимости от dist.
|
||||
Обнаруженные права `700` у опубликованного release исправлены на `755`, чтобы
|
||||
контейнер UID 1000 мог читать bind-mounted `.mrpack`; добавлена регрессионная проверка.
|
||||
|
||||
Доказательства: `.tools/phase8-check.Hgc1oL/evidence/`,
|
||||
`.tools/phase8-unit-tests.log`, `.tools/phase8-integration.log`.
|
||||
Рабочий host не откатывался: прямой query `192.168.1.61:25565` прошёл;
|
||||
результат `.tools/phase8-target-evidence/direct-status.json`.
|
||||
|
||||
Ограничения: world compatibility подтверждает оператор; аварийное завершение
|
||||
между обновлениями двух pointer files требует сверки state/binding. Незавершённый
|
||||
rollback требует документированного ручного recovery. Retired runtime и backups
|
||||
сохраняются без автоматической очистки. Forge остаётся непроверенной веткой.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Phase 9 — завершена
|
||||
|
||||
Проверено 4 октября 2026: `mcpack release VERSION` реализует workflow из §22 плана.
|
||||
Требует clean Git worktree, проверяет SemVer без build metadata, отсутствие
|
||||
release/tag и Git identity; обновляет только версию pack, выполняет candidate build,
|
||||
коммитит версию, собирает полный release из чистого commit, проверяет SHA256SUMS
|
||||
и provenance, создаёт annotated tag. Push, публикация и deploy не выполняются.
|
||||
|
||||
76 тестов прошли. Новые проверки покрывают успешный выпуск, грязное дерево,
|
||||
занятые release/tag, некорректные аргументы/версии, lock, candidate export failure,
|
||||
final build failure, отклонённый Git commit hook и сохранение concurrent source edit.
|
||||
Общий build fixture выделен без изменения прежних проверок build.
|
||||
|
||||
`scripts/verify-phase9.sh` проверил настоящий pinned packwiz/Compose в отдельном
|
||||
Git clone: обе сборки 0.0.6, чистый финальный manifest, полные checksums, отдельный
|
||||
version commit только для `pack.toml`, annotated `v0.0.6` на manifest commit,
|
||||
отказ повторного выпуска и удаление временного output/lock. HEAD и status
|
||||
основного workspace до/после совпали.
|
||||
|
||||
Артефакт:
|
||||
`.tools/phase9-check.FX8NZe/clone/dist/minecraft-lab-neoforge-spike-0.0.6/`.
|
||||
Доказательства: `.tools/phase9-check.FX8NZe/evidence/`,
|
||||
`.tools/phase9-unit-tests.log`, `.tools/phase9-integration.log`.
|
||||
|
||||
Основной workspace по-прежнему содержит uncommitted исходники; его выпуск
|
||||
корректно заблокирован до обычного коммита проекта. Версия исходного pack остаётся
|
||||
0.0.5, основной Git не получил release commit/tag, рабочий сервер не изменён.
|
||||
Recovery и ограничения описаны в [releases.md](releases.md). Синхронизация
|
||||
удалённых tags остаётся обязанностью оператора; автоматического push нет.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Выпуск релиза — Phase 9
|
||||
|
||||
```bash
|
||||
./mcpack release 0.0.6
|
||||
# Дополнительная конфигурация:
|
||||
./mcpack release 0.0.6 --config platform/config.yaml
|
||||
```
|
||||
|
||||
Команда требует чистый Git worktree, включая untracked files, активную ветку,
|
||||
полный локальный clone и настроенные Git author/committer. Подготовьте исходники
|
||||
обычным Git-коммитом заранее. Команда не коммитит остальные изменения проекта.
|
||||
Версия — `MAJOR.MINOR.PATCH`, допускается prerelease (`0.1.0-rc.1`). Build metadata
|
||||
с `+` пока не поддерживается форматом имён deployment. Версия должна отличаться
|
||||
от текущей и не быть занята каталогом релиза или локальным tag `vVERSION`.
|
||||
Удалённые tags автоматически не загружаются: синхронизация refs остаётся задачей оператора.
|
||||
|
||||
Workflow:
|
||||
|
||||
1. Проверяет Git, конфигурацию, версию и наличие release/tag; берёт локальный lock.
|
||||
2. Меняет только top-level `version` в `pack.toml`, сохраняя остальной текст.
|
||||
3. Собирает пробный артефакт в отдельном временном output с pinned packwiz/Compose.
|
||||
4. При успехе коммитит только `pack.toml` с сообщением `Release VERSION`.
|
||||
5. Собирает финальный полный release из чистого коммита, проверяет checksums и provenance.
|
||||
6. Создаёт annotated tag `vVERSION` на тот же commit и выводит каталог/commit/tag.
|
||||
|
||||
Пробный output удаляется. Ошибка до коммита восстанавливает точный исходный
|
||||
`pack.toml`; параллельные изменения сохраняются для разбора. Если финальная сборка
|
||||
или создание tag завершается ошибкой, version commit остаётся, tag не создаётся
|
||||
этой операцией. Финальный артефакт, если уже создан, остаётся для проверки.
|
||||
Автоматического Git reset коммита, перезаписи существующего release/tag, push,
|
||||
публикации или deployment нет.
|
||||
|
||||
После прерывания изучите HEAD, status, refs, `dist/` и `.tools/release.lock`.
|
||||
Убедитесь, что процесс закончился, прежде чем убрать stale lock. После ошибки
|
||||
финальной сборки исправьте причину и осознанно завершите выпуск из чистого коммита:
|
||||
`./mcpack build --release`, затем проверьте manifest/SHA256SUMS и создайте annotated
|
||||
`vVERSION` на manifest commit. Если артефакт уже существует, проверьте его целиком,
|
||||
не запускайте повторный build поверх него. Tag создавайте только после проверки.
|
||||
|
||||
В текущем workspace пока незакоммиченные исходники: `release` корректно откажет.
|
||||
Phase 9 проверена на отдельном source snapshot, с настоящими packwiz/Compose,
|
||||
version commit и tag; основной Git, версия pack и рабочий сервер не менялись.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Rollback — Phase 8
|
||||
|
||||
Команды работают по SSH с root из `platform/config.yaml`. При необходимости
|
||||
передайте `--ssh-config FILE` и `--remote-node /absolute/path/to/node`.
|
||||
|
||||
```bash
|
||||
./mcpack rollback
|
||||
./mcpack rollback-pack 0.0.4
|
||||
```
|
||||
|
||||
Без подтверждения это только чтение: active/previous, actual binding, состояния
|
||||
операций и список snapshots с временем и исходным релизом. Нет загрузки agent,
|
||||
блокировки, остановки сервера или сборки. Список не заменяет проверку snapshot.
|
||||
|
||||
```bash
|
||||
./mcpack rollback-pack 0.0.4 --confirm-compatible
|
||||
./mcpack rollback --backup SNAPSHOT_ID --accept-progress-loss
|
||||
```
|
||||
|
||||
Первый режим запускает сохранённый полный релиз с текущим миром. Оператор
|
||||
подтверждает совместимость модов и мира; SemVer её не доказывает. Ручные изменения
|
||||
managed configs блокируют перезапись, если target не содержит ровно эти изменения.
|
||||
|
||||
Второй режим восстанавливает весь runtime и исходный релиз snapshot. Прогресс
|
||||
после указанного времени исчезает из активного runtime, включая данные модов.
|
||||
Архив, inventory и release проверяются до остановки; распаковка происходит в
|
||||
отдельном каталоге. Текущий runtime переносится в `retired-runtimes/UUID/runtime`,
|
||||
а не удаляется. Дополнительно перед обоими режимами создаётся проверенный backup
|
||||
текущего состояния при остановленном сервере под общей блокировкой.
|
||||
|
||||
`.env` и секреты сохраняются. Явный `MC_BIND_ADDRESS` действует и для старого
|
||||
Compose через временный port overlay; immutable release не переписывается.
|
||||
Pointers обновляются только после успешного startup/health. Состояние записывается
|
||||
в `rollback-state.json`, предыдущий deployment — в `operation-history/`.
|
||||
|
||||
После неудачного deploy snapshot recovery определяет применённый релиз по binding,
|
||||
даже если active ещё указывает на предыдущий. Pack-only в таком состоянии запрещён.
|
||||
При ошибке rollback сервер останавливается; автоматического запуска старой сборки
|
||||
на изменённом мире нет. Незавершённый rollback блокирует следующие операции.
|
||||
|
||||
Для ручного восстановления после ошибки сначала изучите state, binding,
|
||||
diagnostics и оба pointers. Сохраните current backup, retired runtime и staged
|
||||
restore. Восстановите проверенный snapshot в отдельный root по [backups.md](backups.md),
|
||||
с host settings этого сервера; удалите остановленный старый контейнер и проверьте
|
||||
source release и health восстановленной копии. Завершать failed state можно лишь
|
||||
после сверки фактического binding и pointers; удаление state само по себе не recovery.
|
||||
Backups и retired runtime автоматически не очищаются.
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
# Server runtime — Phase 4
|
||||
|
||||
Полный релиз содержит готовый Docker Compose. `scripts/server.sh` управляет
|
||||
им локально, проверяя artifact checksums, manifest, pinned Compose и
|
||||
подтверждённую Minecraft/loader/image/Java комбинацию. Wrapper требует
|
||||
Node/npm dependencies, Docker daemon и локальный Compose из bootstrap.
|
||||
Сам payload можно запускать обычным Docker Compose на подготовленном host.
|
||||
|
||||
## Первоначальная настройка
|
||||
|
||||
Выбрать отдельный server root и готовый full release. Пример для второго
|
||||
локального сервера, пока основной работает на 25565:
|
||||
|
||||
```bash
|
||||
mkdir -p .tools/local-server
|
||||
cp server/.env.example .tools/local-server/.env
|
||||
chmod 600 .tools/local-server/.env
|
||||
```
|
||||
|
||||
В локальном `.env` явно задать:
|
||||
|
||||
```dotenv
|
||||
MC_EULA=TRUE
|
||||
MC_MEMORY=2G
|
||||
MC_PORT=25566
|
||||
MC_BIND_ADDRESS=127.0.0.1
|
||||
MC_UID=1000
|
||||
MC_GID=1000
|
||||
MC_PROJECT_NAME=minecraft-lab-local
|
||||
```
|
||||
|
||||
`MC_EULA=TRUE` означает ваше принятие https://www.minecraft.net/en-us/eula.
|
||||
Для текущего эксперимента оно уже получено. На новом host EULA принять
|
||||
самостоятельно. UID/GID выбрать для владельца runtime на host; image
|
||||
инициализирует права данных с этими значениями. Оператор должен иметь
|
||||
доступ к Docker, server root и локальному `.env`.
|
||||
|
||||
Файл использует простые `KEY=value` без кавычек/interpolation. Пока разрешены
|
||||
только перечисленные ключи. Его значения имеют приоритет над случайными
|
||||
ambient MC_EULA/MEMORY/PORT/UID/GID из shell. Project можно выбрать также
|
||||
через `MC_PROJECT_NAME` в shell; он должен оставаться стабильным для этого root.
|
||||
|
||||
```bash
|
||||
export MC_ROOT="$PWD/.tools/local-server"
|
||||
export MC_RELEASE_DIR="$PWD/dist/minecraft-lab-neoforge-spike-0.0.4"
|
||||
scripts/server.sh config --quiet
|
||||
scripts/server.sh up -d --wait --wait-timeout 600
|
||||
scripts/server.sh ps
|
||||
scripts/server.sh logs --tail 100
|
||||
scripts/server.sh exec -T minecraft mc-health
|
||||
```
|
||||
|
||||
Пути должны быть абсолютными; cwd не влияет на mounts. `MC_ENV_FILE` может
|
||||
выбрать другой абсолютный файл настроек вне immutable release; по умолчанию
|
||||
используется `MC_ROOT/.env`. Для второго runtime нужен отдельный стабильный
|
||||
project и свободный порт. Wrapper отклоняет project, чьи существующие
|
||||
контейнеры подключают другой `/data`.
|
||||
|
||||
## Lifecycle и данные
|
||||
|
||||
```bash
|
||||
scripts/server.sh restart --timeout 120
|
||||
scripts/server.sh up -d --wait --wait-timeout 120
|
||||
scripts/server.sh stop
|
||||
scripts/server.sh create --force-recreate
|
||||
scripts/server.sh up -d --wait --wait-timeout 120
|
||||
scripts/server.sh down
|
||||
```
|
||||
|
||||
Restart/create/stop/down относятся к тому же выбранному релизу. `down`
|
||||
удаляет контейнер и network, но сохраняет host runtime. Данные не находятся
|
||||
в named volume: `MC_ROOT/runtime` монтируется в `/data` read-write.
|
||||
Release и его `server/config` монтируются read-only. Онлайн-проверка аккаунтов
|
||||
выключена. `MC_BIND_ADDRESS` в host `.env` выбирает IPv4 интерфейс:
|
||||
по умолчанию 127.0.0.1; для remote LAN задать 0.0.0.0.
|
||||
|
||||
Первая инициализация разрешена только с пустым runtime (или `.gitkeep`).
|
||||
В root создаётся `.mcpack-runtime.json`: project и SHA256 manifest выбранного
|
||||
релиза. Binding записывается перед запуском и сохраняется даже при его
|
||||
неудаче, чтобы повторный up продолжал ту же попытку. Это не active-release
|
||||
и не отметка успешного deployment.
|
||||
|
||||
Смена релиза/project на связанном runtime и неявное принятие существующего
|
||||
мира без binding запрещены. Backup/restore реализованы в Phase 5;
|
||||
смена релиза требует будущего deploy workflow. Текущий старый Phase 0 мир управляется `scripts/spike-server.sh`;
|
||||
миграция на новый wrapper в Phase 4 не выполняется.
|
||||
|
||||
Lifecycle-операции и весь цикл backup используют общую `.mcpack-runtime.lock`
|
||||
в server root. Snapshot/recovery procedure — [backups.md](backups.md). После
|
||||
принудительного убийства процесса lock может остаться; удалять только когда
|
||||
соответствующий процесс точно завершён. `config` проверяет контракт без
|
||||
запуска Docker и без создания runtime/binding. `up --wait` теперь проверяет
|
||||
Minecraft status query и окно стабильной работы, включая restart loops.
|
||||
Отдельная проверка — `scripts/server.sh health`; timeout/report/logs описаны
|
||||
в [health.md](health.md).
|
||||
|
||||
Обычный Compose также работает с release payload:
|
||||
|
||||
```bash
|
||||
MC_ROOT=/absolute/server-root MC_RELEASE_DIR=/absolute/full-release \
|
||||
docker compose --project-name minecraft-lab-local \
|
||||
--env-file /absolute/server-root/.env \
|
||||
-f /absolute/full-release/server/compose.yaml up -d --wait
|
||||
```
|
||||
|
||||
При прямом вызове Compose проверки/binding/lock wrapper не выполняются;
|
||||
для локального lifecycle используйте `scripts/server.sh`.
|
||||
@@ -0,0 +1,118 @@
|
||||
# Phase 0: NeoForge, Minecraft 1.21.1
|
||||
|
||||
Целевая сборка работает без онлайн-проверки аккаунта. Пользователь выбрал
|
||||
NeoForge на Minecraft 1.21.1; EULA принята для локального эксперимента.
|
||||
Phase 0 завершена для NeoForge 21.1.252 на Minecraft 1.21.1. Импорт и вход
|
||||
клиента пользователь подтвердил; оставшиеся серверные сценарии проверены
|
||||
на том же loader. Это не подтверждает поддержку Forge.
|
||||
|
||||
## Закреплённая сборка
|
||||
|
||||
- Minecraft 1.21.1, NeoForge 21.1.252.
|
||||
- Sophisticated Backpacks 3.26.7.2182 и Sophisticated Core 1.5.5.2363: обе стороны.
|
||||
- Mouse Tweaks 2.26.1: только клиент.
|
||||
- Source: `pack/`; версии и download hashes находятся в packwiz metadata.
|
||||
- Инструменты и digest Docker image закреплены в `toolchain.lock.env`.
|
||||
- Артефакт: `dist/minecraft-lab-neoforge-spike-0.0.1/minecraft-lab-neoforge-spike-0.0.1.mrpack`.
|
||||
- SHA256: `67d6802ae30a1d42413dc44d76f3cc7f0a77885dbbea5329ab9c2e288bda2d4e`.
|
||||
|
||||
## Подтверждённые результаты
|
||||
|
||||
`scripts/spike-build.sh` экспортировал `.mrpack`. В `modrinth.index.json`
|
||||
указаны зависимости Minecraft 1.21.1 и NeoForge 21.1.252; для Mouse Tweaks
|
||||
записано `server: unsupported`.
|
||||
|
||||
`scripts/spike-server.sh up -d --wait --wait-timeout 600` успешно запустил
|
||||
сервер. Первый запуск закончился таймаутом загрузки Maven-зависимостей;
|
||||
повторный запуск того же артефакта завершился успешно. Это внешняя ошибка
|
||||
загрузки, воспроизводимость установки без сети пока не подтверждена.
|
||||
|
||||
Сервер стал healthy; `mc-health` ответил с версией Minecraft 1.21.1.
|
||||
Лог подтвердил NeoForge 21.1.252 и загрузку Backpacks/Core. В `runtime/mods/`
|
||||
ровно два соответствующих JAR: клиентский Mouse Tweaks исключён.
|
||||
|
||||
В `runtime/server.properties` подтверждены `online-mode=false` и
|
||||
`enforce-secure-profile=false`. Порт привязан к `127.0.0.1:25565`.
|
||||
Windows TCP-проверка `127.0.0.1:25565` успешна. При первой попытке клиент
|
||||
разрешил `localhost` в IPv6 `::1` и получил Connection refused; для текущей
|
||||
публикации порта подключаться к `127.0.0.1:25565`.
|
||||
После смены адреса пользователь подтвердил успешный вход в мир. Импорт в
|
||||
Prism, запуск клиента с NeoForge и подключение без проверки аккаунта пройдены.
|
||||
Мир, моды и сгенерированные конфиги доступны как обычные файлы в bind-mounted
|
||||
`runtime/`.
|
||||
|
||||
Сгенерированные серверные конфиги NeoForge и Backpacks находятся в
|
||||
`runtime/config/`, включая `neoforge-server.toml` и
|
||||
`sophisticatedbackpacks-server.toml`. Нельзя предполагать, что серверный
|
||||
конфиг обязательно создаётся в `world/serverconfig/`; политика конфигов
|
||||
должна учитывать выбранную версию loader.
|
||||
|
||||
Локальные свидетельства (не коммитятся):
|
||||
|
||||
- `.tools/neoforge-evidence/mrpack-index.json`;
|
||||
- `.tools/neoforge-evidence/first-start.log`;
|
||||
- `.tools/neoforge-evidence/healthy-start.log`.
|
||||
|
||||
## Оставшиеся серверные сценарии: пройдены
|
||||
|
||||
Перед тестами сервер остановлен. Полный `runtime/` сохранён в
|
||||
`backups/phase0-neoforge-baseline.tar.zst`; архив проверен чтением и SHA256.
|
||||
Backup содержит мир после подтверждённого пользовательского входа.
|
||||
Часть файлов мира принадлежит UID контейнера и недоступна в sandbox;
|
||||
backup и чтение этих файлов выполнены с разрешённым повышением доступа.
|
||||
Ошибка чтения файла должна прерывать backup, а не оставлять частичный архив
|
||||
как успешный результат.
|
||||
|
||||
| Проверка | Результат |
|
||||
| --- | --- |
|
||||
| Recreate | `create --force-recreate` не изменил SHA256 `world/level.dat` до запуска; затем сервер healthy. |
|
||||
| Смена версии | Релиз 0.0.2 заменил Backpacks 3.26.7.2182 на 3.26.6.2174; старый JAR отсутствовал, новая версия загружена. Это проверка замены версии, включая downgrade. |
|
||||
| Удаление модов | Релиз 0.0.3 без модов запустился healthy; `runtime/mods/` пуст. |
|
||||
| Pack config | Ручной `manual-runtime-edit` в управляемом `config/spike-marker.txt` заменён на `neoforge-pack-v2` при смене релиза. |
|
||||
| Server override | С дополнительным Compose marker стал `server-override-v1`, несмотря на pack default и ручную правку. |
|
||||
| Неуправляемые файлы | `config/unmanaged-probe.txt` сохранил `preserve-me` после смены релиза и удаления модов. |
|
||||
| Defaultconfigs | Шаблон `removeErroringEntities=true` не заменил существующий `config/neoforge-server.toml` со значением false. После переноса текущего конфига вне runtime и запуска 0.0.2 на том же мире новый конфиг получил true. |
|
||||
| Datapack | Добавленный в 0.0.2 `world/datapacks/phase0` выполнил load-функцию на существующем мире: в логе есть `[Phase0] datapack-v2-loaded`. В 0.0.3 управляемые файлы datapack удалены. |
|
||||
| Startup failure | Отсутствующий `missing-neoforge-phase0.mrpack` привёл к exit 1; SHA256 остановленного `level.dat` до/после совпал. |
|
||||
| Restore | Backup извлечён в отдельную директорию. Все 28 файлов мира совпали по путям и SHA256 с архивом до запуска; восстановленный `level.dat` совпал с исходным. Возвращён релиз 0.0.1, сервер healthy. |
|
||||
|
||||
Тестовые варианты воспроизводятся `bash scripts/spike-neoforge-variants.sh`
|
||||
из корня на чистом checkout после bootstrap. Скрипт не меняет canonical
|
||||
`pack/`, не запускает сервер и отказывается перезаписывать готовые релизы.
|
||||
|
||||
Артефакты проверки:
|
||||
|
||||
- 0.0.2 SHA256: `4f26f91f7b6e2db80caf522d370db37607ab46de5951e9cd8178f709b9e12ffd`.
|
||||
- 0.0.3 SHA256: `ba0e2476ac7f095f13f5feed73584f38042f93457563dd00920c0211422494a2`.
|
||||
- `.tools/neoforge-evidence/v2-start.log`, `v2-override-start.log`, `v3-start.log`.
|
||||
- `.tools/neoforge-evidence/config-results.txt`, `controlled-failure.log`.
|
||||
- `.tools/neoforge-evidence/baseline-level.sha256`, `before-failure-level.sha256`.
|
||||
- `.tools/neoforge-evidence/restored-world-manifest.json`, `restore-verification.txt`, `restored-start.log`.
|
||||
|
||||
После тестов сохранённое исходное состояние вновь находится в `runtime/`,
|
||||
промежуточное — в `.tools/neoforge-runtime-after-tests`. Активен 0.0.1 с
|
||||
Backpacks 3.26.7.2182 и Core 1.5.5.2363, marker `neoforge-pack-v1`,
|
||||
`online-mode=false`, `enforce-secure-profile=false`. Подключение:
|
||||
`127.0.0.1:25565`; повторный импорт instance не требуется.
|
||||
|
||||
## Выводы для следующих фаз
|
||||
|
||||
Управляемые pack-конфиги заменяются при смене релиза, поэтому ручные правки
|
||||
не являются устойчивым источником настроек. Серверные overrides должны быть
|
||||
явными. Defaultconfigs в проверенной версии служат seed, а не механизмом
|
||||
обновления существующего конфига. Runtime-generated конфиги сохраняются,
|
||||
пока явно не включены в управляемые пути.
|
||||
|
||||
Политики replace/seed-only/preserve и ownership manifest пока не реализованы
|
||||
в CLI: spike подтвердил поведение закреплённых компонентов. Контролируемая
|
||||
ошибка проверена до старта игры; сохранность мира при произвольном сбое
|
||||
мода или миграции формата мира этим тестом не подтверждается.
|
||||
|
||||
## Предварительный Fabric-эксперимент
|
||||
|
||||
Результаты предыдущего эксперимента сохранены в `fabric-spike-results.md`,
|
||||
source — в `examples/fabric-spike/`. Они не заменяют проверки NeoForge/Forge.
|
||||
Перед сменой loader Fabric-сервер остановлен, создан и проверен архив
|
||||
`backups/phase0-fabric-before-neoforge.tar.zst`; старый runtime сохранён в
|
||||
`.tools/fabric-runtime`. NeoForge запущен с новым миром.
|
||||
Forge требует отдельного integration spike.
|
||||
Reference in New Issue
Block a user