Добавить испытания и прогрессию по LevelID

This commit is contained in:
2026-08-19 09:25:32 +03:00
parent 259fcd316b
commit 3de8d45039
37 changed files with 968 additions and 63 deletions
+10 -4
View File
@@ -161,10 +161,11 @@ baseline-задачи также имели явного владельца по
`STAGE5_HUMAN_PLAYTEST_RESULT.md`. Stage 6 разблокирован.
Текущий статус Stage 6: foundation, production hazards, burned/crushed corpse
states и weighted objects приняты. Каталог содержит 17 уровней; последний exact
candidate прошёл `108` app JVM, `2` content-tool JVM и нефильтрованную Android 16
матрицу `48/48` за `2,223.695 s`. Следующий dependency-order slice — challenges
и production progression, после него начинается массовое производство четырёх
states, weighted objects и challenge/progression приняты. Каталог содержит 18
уровней. Stable `levelId`/`worldId`, casualty/time/cache challenges, progress-v3
migration, session-v5 collectible state и persistent three-star result прошли
`116` app JVM, `2` content-tool JVM и нефильтрованную Android 16 матрицу `52/52`
за `551.773 s`. Следующий dependency-order slice — массовое производство четырёх
миров.
### Этап 6. Production content — P1, несколько итераций
@@ -202,6 +203,11 @@ data-driven модель. Завершён первый mechanics slice: product
Box/Rock/Ball/IceBlock/Counterweight, save v4 и обучающий уровень 17 прошли clean
gate `108` app JVM + `2` content-tool JVM и unfiltered Android matrix `48/48`
(`2,223.695 s`). Evidence зафиксирован в `STAGE6_WEIGHTED_OBJECTS.md`.
Challenge/progression slice также принят: stable level/world IDs, три независимых
challenge-критерия, optional collectible, накопительные лучшие звёзды по `levelId`,
progress v1/v2 → v3 и active-session v4 → v5 migration, result UI и обучающий
уровень 18 прошли clean gate `116` app JVM + `2` content-tool JVM и unfiltered
Android matrix `52/52` (`551.773 s`). Evidence — `STAGE6_CHALLENGES.md`.
### Этап 7. Техническая стабилизация и release engineering — P0, 4–8 дней
+30 -2
View File
@@ -1,8 +1,8 @@
# Графы решений уровней 1–17
# Графы решений уровней 1–18
Документ фиксирует **авторский маршрут** каждого уровня текущего vertical slice. Он получен из `LevelCatalog`, моделей `LevelDefinition` и фактической логики `GameView`, затем проверен device-level ботами через production-команды движения и прыжка. `targetDeaths` ниже — целевое число жертв для результата уровня, но оно не доказывает минимальность решения.
На 19 августа 2026 года intended route всех уровней 1–17 автоматически выполнен по три раза подряд без retry masking. Device-тесты управляют production `GameView` через те же флаги, что и touch-контролы. Для уровня 8 отдельно проверено восстановление после истечения таймера на дальней стороне `PIT`.
На 19 августа 2026 года intended route всех уровней 1–18 автоматически выполнен по три раза подряд без retry masking. Device-тесты управляют production `GameView` через те же флаги, что и touch-контролы. Для уровня 8 отдельно проверено восстановление после истечения таймера на дальней стороне `PIT`.
## Семантика, общая для графов
@@ -434,6 +434,34 @@ save-v4 состояние. V1–v3 active sessions мигрируют с пус
до push `allDoorsOpen=false`; после push `firstPhysicalObjectX≥920` и Door open;
после release Door остаётся open; затем два отдельных jump edge и `completed=true`.
## Уровень 18 — `Threefold Proof`
**Статус:** доказан production-input ботом, 3/3 последовательных прохождения.
**Ожидаемые и доказанные смерти:** `0`; обязательный challenge-route получает
casualty, time и collectible stars.
```text
LevelID="foundations.threefold-proof", WorldID="foundations"
→ игрок проходит безопасный teaching floor без смертей
→ у x≈650 начинает прыжок к cache=(850,650,58,58)
→ пересекает cache: collectibleFound=true, cache исчезает только для этой попытки
→ продолжает вправо и достигает goal x=2000..2086
→ COMPLETE с deaths=0 и time≤30 s
→ ChallengeResult выдаёт casualty/time/collectible = true, stars=3
→ ProgressStore сохраняет лучшие критерии по стабильному LevelID
→ три последовательных restart-free прохождения воспроизводят 3/3 stars
```
**Контракт:** collectible является опциональным world-space объектом и сохраняется
в active session v5. Restart сбрасывает состояние текущей попытки; завершённый
collectible challenge накапливается в progress v3 независимо от лучших casualty и
time runs. Legacy levels без collectible получают третью звезду за core completion.
**Bot checkpoints:** `deaths=0`; после прыжка `collectibleFound=true` и
`collectibleVisible=false`; затем `completed=true`; `CompletionResult.stars=3`,
`bestStars=3`; новый `ProgressStore` после трёх запусков возвращает 3 звезды для
`foundations.threefold-proof`.
## Проверки, следующие из графов
1. Сохранять полный integrated device-regression: intended route принятых уровней по три раза и отдельный recovery route уровня 8.
+12 -3
View File
@@ -39,6 +39,8 @@ desktop-команды используют один и тот же JSON parser,
{
"formatVersion": 1,
"physicsVersion": 1,
"id": "foundations.dead-weight",
"worldId": "foundations",
"number": 3,
"copy": {
"en": {"title": "Dead Weight", "hint": "Leave a body on the plate."},
@@ -47,6 +49,7 @@ desktop-команды используют один и тот же JSON parser,
"world": {"width": 2050, "height": 1080},
"spawn": {"x": 130, "y": 760},
"goal": {"x": 1810, "y": 770, "width": 86, "height": 110},
"collectible": {"x": 850, "y": 650, "width": 58, "height": 58},
"targets": {"deaths": 1, "seconds": 50},
"objects": [
{"type": "COUNTERWEIGHT", "box": {"x": 300, "y": 780, "width": 80, "height": 100}, "mass": 3}
@@ -71,6 +74,11 @@ desktop-команды используют один и тот же JSON parser,
Поддерживаемые значения:
- `id` — стабильный lowercase level ID; `worldId` — стабильный lowercase world ID.
Legacy JSON без этих полей получает `legacy.level-NN` и `legacy`, поэтому старые
сохранения мигрируют без потери;
- `collectible` — опциональный world-space `box`. Его отсутствие означает, что
третья звезда выдаётся за основное прохождение, а не становится недостижимой;
- hazards: `SPIKES`, `SAW`, `FREEZER`, `ELECTRIC`, `PIT`, `CRUSHER`, `FIRE`,
`PROJECTILE`, `EXPLOSION`;
- physical objects: `BOX`, `ROCK`, `BALL`, `ICE_BLOCK`, `COUNTERWEIGHT`; каждый
@@ -88,7 +96,7 @@ desktop-команды используют один и тот же JSON parser,
- известные format/physics versions;
- конечные положительные размеры мира и объектов;
- spawn, goal, physical objects, платформы, hazards, switches, doors и конечную позицию moving
- стабильные `id`/`worldId`, spawn, goal, optional collectible, physical objects, платформы, hazards, switches, doors и конечную позицию moving
platform внутри мира;
- наличие хотя бы одной платформы;
- неотрицательный target deaths и положительный target seconds;
@@ -96,7 +104,8 @@ desktop-команды используют один и тот же JSON parser,
`TIMED`;
- существование каждого `door.requiredSignals` и `platform.controlId` среди
сигналов switches/relays;
- целостность index, уникальность ресурсов и последовательную нумерацию.
- целостность index, уникальность ресурсов и stable level IDs, последовательную
нумерацию.
Ошибка содержит путь, например:
@@ -122,7 +131,7 @@ level-03.json.doors[0].requiredSignals[0] references missing signal 'missing'
Результат находится в `level-format/build/level-previews`:
- `level-01.svg` … последний уровень каталога — world-space схема spawn/goal,
objects, платформ, hazards, switches и doors;
collectible, objects, платформ, hazards, switches и doors;
- `catalog.tsv` — координаты, размеры, object mass, travel и signal/control references.
Вывод использует стабильный порядок и locale-independent числа. Два запуска на
+70
View File
@@ -0,0 +1,70 @@
# Stage 6: challenges, collectibles и production progression
## Принятый результат
Срез добавляет стабильную идентичность уровня и три независимых production
challenge-критерия: целевое число жертв, целевое время и collectible. Лучший
результат накапливается между разными прохождениями и отображается как 0–3 звезды.
Каталог расширен до 18 уровней. `Threefold Proof` обучает всем трём критериям на
одном безопасном маршруте; intended route выполняется production-input ботом три
раза подряд без teleport, прямой мутации completion или retry masking.
## Контракты
- `LevelDefinition.levelId` и `worldId` являются стабильными lowercase ID.
Legacy-контент без полей получает `legacy.level-NN` / `legacy`.
- Optional `collectible` — world-space box. После пересечения он исчезает в текущей
попытке, сохраняется при Activity recreation и сбрасывается restart.
- `ChallengeResult` независимо вычисляет casualty, time и collectible criteria.
На legacy-уровне без collectible третья звезда означает core completion.
- `ProgressStore` save v3 хранит completion, лучшие deaths/time и collectible по
`levelId`. V1/V2 numeric keys мигрируют в ID keys без потери данных.
- Active session v5 сохраняет `collectibleFound`; V4 и более старые snapshots
восстанавливаются с безопасным `false`.
- Result UI и level cards показывают лучший star row. Complete screen сохраняет
Stage 3 строки Current/Best/Targets, добавляет три challenge rows и следующую
цель. RU/EN и non-color labels являются частью контракта.
- SVG/TSV exporter публикует collectible и LevelID; validator проверяет ID и
границы collectible до упаковки APK.
## TDD и найденные регрессии
RED сначала зафиксировали отсутствующие `ChallengeResult`, stable IDs, JSON schema,
ID-based persistence, session collectible, completion/UI copy, catalog level 18 и
exporter output. Review добавил отдельный RED на duplicate stable LevelID: catalog
loader теперь отклоняет конфликт до того, как два уровня разделят progress key.
Каждый контракт проводился в GREEN отдельно.
Первый полный Android run (`52` tests) нашёл ещё два интеграционных RED:
1. Stage 3 result snapshot потерял локализованный prefix `Цели` после добавления
challenge rows. Prefix и видимая строка targets восстановлены.
2. Real-time late-level driver мог пропустить узкое окно пилы уровня 10 между
двумя AVD polls. Late-level acceptance переведён на существующие fixed production
physics ticks: обычное решение принимает решения каждые 16 ms симуляции, stress
сохраняет 96 ms. Физика, input, collision, точные смерти и geometry не менялись.
После исправления вся late-level matrix прошла `6/6`; level 10 normal выполняется
три раза, отдельный stress route — один раз.
Один предварительный повтор после нескольких непрерывных full runs получил
environmental `frameP95=41.02 ms`; тот же неизменённый APK сразу прошёл
изолированный 34-ms gate. Финальный exact run выполнен после cold AVD restart на
host GPU и прошёл performance test внутри полного порядка. Бюджет не ослаблялся.
## Финальные gates
На Android 16 ARM64 candidate:
- `:level-format:test`: `2/2`;
- `testDebugUnitTest`: `116/116`;
- `lintDebug`, `assembleDebug`, `assembleDebugAndroidTest`: GREEN после `clean`;
- validator: `18` levels, `formatVersion=1`, `physicsVersion=1`;
- focused challenge/restore/result matrix: `9/9`;
- exact unfiltered instrumentation: `OK (52 tests)`, `551.773 s`;
- APK ZIP integrity: no errors; внутри APK `18` level JSON;
- debug APK SHA-256:
`0b70a0a1a508425c311d7de473318e3bb83407f5f27e9dd4a8e1876b2eb25344`.
APK: `app/build/outputs/apk/debug/app-debug.apk`.
+1 -1
View File
@@ -65,7 +65,7 @@ Snapshot на 19 августа 2026 года:
| 3 | 5 | 0 |
| 4 | 4 | 0 |
| 5 | 15 | 0 |
| 6 | 18 | 8 |
| 6 | 18 | 6 |
| 7 | 9 | 9 |
| 8 | 1 | 1 |
| 9 | 1 | 1 |