Files
pinball-duel/playtest-protocol.md
aevgarik bfdb24294a Implement defensive setup scoring v3.10
Реализует финальную модель scoring из data-contracts.md v3.10:
fixed center bumpers — по last-touch; setup-bumpers — defensive trap
(награждают владельца только когда мяч принадлежит сопернику).
Self-farm запрещён. Neutral ball не даёт очков нигде.

Code changes:
- types/index.ts: BumperScoreSource union ('fixed_last_touch' |
  'player_setup' | 'ai_setup'); MatchResult.aiBumperPointsEarned +
  aiBumperHitsCount.
- Bumper.ts: новый required field source: BumperScoreSource;
  передаётся в onHit callback через bumper.source.
- scoring/MatchTracker.ts: pure helper computeCreditedTo(source, ballOwner)
  → реализует 9-cell credit matrix; recordBumperHit принимает
  (rawPoints, source, ballOwner, type, ...) и возвращает {creditedTo,
  pointsEarned}; новые getter'ы getAIBumperHits + getUncreditedBumperHits.
- scenes/MatchScene.ts:
  * Fixed bumpers создаются с source='fixed_last_touch'
  * placeSetupBumpers передаёт source per side
  * handleBumperHit (новая сигнатура: bumper, points) рутит в tracker,
    emit'ит spawn-particles + telemetry bumper_hit event с полным
    набором полей per telemetry-spec.md v3.10
  * MatchResult заполняется с AI BP/hits
  * match_end telemetry также включает aiBumperPointsEarned/HitsCount
  * HUD: BP теперь сравнительный «P x / AI y»
- scenes/ResultScene.ts: breakdown показывает обе стороны BP и hits.

Particle effects (DoD v3.10):
- 12 псевдо-частиц радиально от bumper'а (cubic ease-out, 320ms)
- цвет: player=magenta, ai=cyan, null=grey
- screenshake 80ms/0.0025 ТОЛЬКО на credited hit
  (иначе экран дрожит на каждом нейтральном отскоке)

Tests: scoring/MatchTracker.test.ts — 21 теста:
- 9-cell credit matrix (computeCreditedTo, все source × ballOwner)
- recordBumperHit с counter assertions
- многократные hits (накопление BP per сторона)
- симметрия player/AI defensive trap scenarios
- fixed bumpers через смену владения
- events log для telemetry
- recordGoal с autogoal-flag

Итого 50/50 unit-тестов (16 calculateScores + 13 flipperGeometry +
21 MatchTracker). typecheck/lint/build все зелёные.

Несоответствия с docs остающиеся:
- DoD: «12 частиц per credited side» — done; SFX bumper hit (DoD line 247)
  — TODO Phase 4 (asset pack).
- Particle effects через psecdoupartials (Arc + tween), не через
  ParticleEmitter — упрощение, визуально эквивалентно.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 07:27:01 +03:00

133 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Playtest Protocol — Phase 2 AI Distinguishability
**Цель.** Закрыть Phase 2 DoD «тестер различает 4 AI-личности после 5 матчей»
через blind attribution. Требуется внешний тестер (НЕ разработчик и НЕ автор AI кода).
**Pass-bar:** ≥ 75 % правильных attribution-ответов (≥ 15 / 20) ИЛИ ≥ 1 distinct tell
per личность, названный тестером без подсказки.
---
## Подготовка
| Шаг | Команда / действие |
|---|---|
| Build | `npm run build && npm run preview` (production build на `localhost:4173`) |
| Difficulty | **Medium** — Easy скрывает поведение за reaction-задержкой; Hard не реализован (Phase 3) |
| Mode | Quick Match → выбор личности → Medium |
| Device | Минимум 1 desktop + 1 mobile session (mobile важно — touch zones там единственный input) |
| Telemetry | Mock adapter логирует `trackEvent` в консоль — оставить открытой DevTools для пост-анализа |
---
## Per-match observation rubric
После каждого матча тестер заполняет строку:
| Поле | Что фиксировать | Источник |
|---|---|---|
| `match_index` | 1..20 | manual |
| `setup_pattern` | Какие bumper-типы AI поставил, где (углы / центр / далеко) | визуально, AI половина |
| `reaction_distance` | «early / normal / late» — насколько близко мяч долетает до AI-флипперов | субъективно |
| `miss_rate` | «низкий / средний / высокий» — как часто AI пропускает свой удар | визуально |
| `special_behaviour` | Любой характерный приём (двойной свинг, странный угол отскока, агрессивная атака центром) | free-text |
| `final_score` | Player : AI | HUD post-match |
| `duration_sec` | Длина матча | HUD timer / `match_end` telemetry |
| `personality_guess` | Бэтти / Турбо / Хитрый Хо / Эхо | blind по завершению ВСЕХ 20 матчей |
---
## Expected tells (для оценщика; тестеру НЕ показывать до конца сессии)
| Личность | Tells |
|---|---|
| **Defensive (Бэтти)** | Setup: 2 slingshot в углах ворот + 1 турбо центр + 1 curve + 1 пусто. Поведение: реакция надёжная (`reliabilityMul: 1.1`, capped 1.0 = почти 100 %), чуть быстрее (`reactionMul: 0.9`). AI пропускает редко; матчи длиннее обычного. |
| **Aggressive (Турбо)** | Setup: 2 турбо в своей зоне (defensive trap против мяча игрока) + 1 slingshot угол + 1 curve + 1 standard. Поведение: реагирует с большего расстояния (`triggerDistBonus: +80px`), чаще промахивается (`reliabilityMul: 0.85`). Быстрые матчи; игрок, застрявший в setup Турбо, быстро отдаёт ему очки. |
| **Trickster (Хитрый Хо)** | Setup: 4 curve bumper'а (лабиринт) + 1 турбо центр. Поведение: 15 % случайный спайк jitter (×1.3) — реакция «дёргается». Непредсказуемый счёт; необычные траектории мяча. |
| **Ghost (Эхо)** | Setup: balanced (2 slingshot + 1 турбо + 1 curve + 1 standard). Поведение: 15 % «echo double-swing» — обе стороны активируются одновременно, даже если мяч идёт только в одну. Медианный счёт; характерный двойной flip. |
---
## Процедура
1. **Randomize order.** Использовать random.org pick из `[defensive, aggressive, trickster, ghost]`,
5 раз для каждой → 20 матчей. **Не группировать по личности** — рассыпать.
Пример последовательности: `[T, D, G, A, T, A, D, G, T, A, D, G, A, T, D, G, A, D, G, T]`.
2. **Играть в выбранном порядке.** После каждого матча — заполнить строку рубрики.
НЕ смотреть expected tells между матчами.
3. **Blind attribution.** По завершении всех 20 матчей — для каждой строки заполнить
`personality_guess` без обращения к памяти о выборе перед матчем.
4. **Score.** Сравнить `personality_guess` с фактическим выбором. Подсчитать accuracy.
5. **Subjective rating.** Тестер ставит общую оценку «AI feels different» по 5-балльной
шкале (≥ 4 = pass).
6. **Report.** Заполнить шаблон ниже, приложить к Phase 2 sign-off.
---
## Failure modes & follow-ups
| Результат | Что делать |
|---|---|
| Accuracy < 50 % | Модификаторы слишком слабые. Удвоить `triggerDistBonus`, опустить `reliabilityMul` ниже 0.7. |
| Accuracy 50-74 % | Две личности путаются между собой. Развести их setup'ом сильнее (например, поменять Defensive curve → second slingshot для большего «защитного» паттерна). |
| Accuracy ≥ 75 %, subjective < 4 | Поведение различимо, но не интересно. Это не блокер Phase 2, но завести задачу на «character polish» в Phase 4. |
| Тестер жалуется «AI слишком сложный/лёгкий на Medium» | Тюнить `reactionMs` в `src/config/defaults.ts` — не personality-specific. |
---
## Codex automation (опционально)
`codex exec` потенциально может прогнать матчи через headless Phaser
и replay-log; но для Phase 2 sign-off **достаточно ручного playtest'а**.
Маппинг рубрики в telemetry events:
| Поле рубрики | Telemetry source |
|---|---|
| `setup_pattern` (AI) | `MatchResult.aiSetup.slots` |
| `reaction_distance` | derivable: ball trajectory + `goal_scored.ballOwnershipBeforeGoal` |
| `miss_rate` | `1 (AI flipper hit count / ball-passes-through-AI-zone count)` (нужен новый event `flipper_hit` — не в Phase 2 scope) |
| `final_score` | `match_end.goalsScored / goalsAgainst` |
| `duration_sec` | `match_end.durationSeconds` |
Автоматизация — backlog Phase 5+.
---
## Report template
```markdown
# Playtest Report — Phase 2 AI Distinguishability
**Tester:** <имя / handle>
**Date:** <YYYY-MM-DD>
**Build:** HEAD <git-sha>
**Devices:** desktop=<browser/os>, mobile=<browser/os>
## Match log
| # | Personality (actual) | Setup observed | Reaction | Miss rate | Special | Score | Duration | Guess | Match? |
|---|---|---|---|---|---|---|---|---|---|
| 1 | trickster | 4 curve + turbo | normal | medium | hectic angles | 5:3 | 4m12s | trickster | ✅ |
| 2 | ... | | | | | | | | |
## Results
- Accuracy: __ / 20 = __ %
- Subjective rating: __ / 5
- Per-personality breakdown:
- Defensive: __ / 5
- Aggressive: __ / 5
- Trickster: __ / 5
- Ghost: __ / 5
## Free-text observations
<распознанные tells, неожиданные моменты, баги>
## Verdict
- [ ] Phase 2 AI DoD PASS (≥75% accuracy + ≥4/5 subjective)
- [ ] Phase 2 AI DoD FAIL — see follow-ups
```