Добавить испытания и прогрессию по 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
+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`.