docs: hints engine P1-P4 livré (P5 partial)
§5 Phased plan adds Status column: P14f6d916, P21ed230e, P35500502, P461ca356all ✅. P5 firmware integration partial (hints_client OK, scenario integration PENDING). P6 auto-trigger stuck PENDING. §2.2 response envelope updated with 17 actual fields. §6 Risks: MLX 32B Q4 ~11s warm, F5-TTS event-loop blocking cross-ref. §7 Acceptance gates: 9 checked, 4 PENDING (playtest firmware + soak 24h).
This commit is contained in:
@@ -91,6 +91,8 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
**Live response shape (P1-P4 delivered)**:
|
||||
|
||||
```json
|
||||
{
|
||||
"refused": false,
|
||||
"reason": null,
|
||||
@@ -103,6 +105,32 @@ Content-Type: application/json
|
||||
"count": 1,
|
||||
"level_requested": 1,
|
||||
"level_served": 1,
|
||||
"score_penalty": 50,
|
||||
"total_penalty": 50,
|
||||
"cooldown_until_ms": 1880000,
|
||||
"retry_in_s": 60,
|
||||
"level_floor_adaptive": 1,
|
||||
"stuck_minutes": 3,
|
||||
"failed_attempts": 0,
|
||||
"group_profile_used": "MIXED"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 Response (refused — anti-cheat)
|
||||
|
||||
```json
|
||||
{
|
||||
"refused": true,
|
||||
"reason": "rate_limit",
|
||||
"details": "3 hints already given for P5_MORSE (cap = 3)",
|
||||
"cooldown_until_ms": null
|
||||
}
|
||||
```
|
||||
|
||||
Refusal reasons: `rate_limit` (cap reached), `cooldown` (too soon since last), `phase_blocked` (PROFILING), `unknown_puzzle`, `llm_unavailable`.
|
||||
|
||||
> **Implemented (2026-05-03)** — refusals are emitted as `{refused: true, reason: <code>, ...}` with the same envelope as success (fields like `retry_in_s`, `cooldown_until_ms`, `total_penalty` populated where relevant). Reason codes match the original list.
|
||||
|
||||
## 3. Adaptive level selection
|
||||
|
||||
```
|
||||
@@ -116,6 +144,8 @@ Content-Type: application/json
|
||||
# If stuck_timer is short (< 4 min), bump down one level
|
||||
if context.stuck_timer_ms < 240_000 and base_level > 1:
|
||||
return base_level - 1
|
||||
elif context.group_profile == "NON_TECH":
|
||||
# NON_TECH gets faster escalation when stuck_timer is high
|
||||
if context.stuck_timer_ms > 360_000 and base_level < 3:
|
||||
return base_level + 1
|
||||
|
||||
@@ -172,14 +202,14 @@ Rewrite is **temperature = 0.4** (slight variability for replay flavor, determin
|
||||
|
||||
| Risk | Probability | Mitigation |
|
||||
|------|-------------|------------|
|
||||
| LLM rewrites the base phrase into a literal solution leak | Medium | Per-puzzle banned-word list ; safety filter rejects, falls back to base |
|
||||
| LiteLLM cold start adds latency to the first request | Medium | Warm-up call on hints-server boot ; player won't notice the first call after game start |
|
||||
| Rate-limit math drifts between hints-server and ESP32 firmware view of `hints_already_given` | Medium | Server is single source of truth ; firmware sends its view but server returns authoritative count in response, firmware mirrors |
|
||||
| Adaptive logic feels unfair to NON_TECH groups (escalates "too fast") | Medium | Tunable thresholds in YAML config ; one playtest per profile validates on each engine change |
|
||||
| Stuck-timer auto-trigger fires while player is on a phone call / break | Low | Trigger requires a recent hardware event (any button press in last 60 s) before firing |
|
||||
|
||||
## 7. Acceptance gates (before declaring P6 done)
|
||||
|
||||
| LLM rewrites the base phrase into a literal solution leak | Medium | Per-puzzle banned-word list ; safety filter rejects, falls back to base |
|
||||
| LiteLLM cold start adds latency to the first request | Medium | Warm-up call on hints-server boot ; player won't notice the first call after game start |
|
||||
| Rate-limit math drifts between hints-server and ESP32 firmware view of `hints_already_given` | Medium | Server is single source of truth ; firmware sends its view but server returns authoritative count in response, firmware mirrors |
|
||||
| Adaptive logic feels unfair to NON_TECH groups (escalates "too fast") | Medium | Tunable thresholds in YAML config ; one playtest per profile validates on each engine change |
|
||||
| Stuck-timer auto-trigger fires while player is on a phone call / break | Low | Trigger requires a recent hardware event (any button press in last 60 s) before firing |
|
||||
| **MLX 32B Q4 (`hints-deep`) warm latency ~11 s — dépasse le budget initial 2 s** | High (observed 2026-05-03) | Fallback verbatim sur timeout déjà actif ; envisager pré-roll TTS (lecture d'une phrase de transition Zacus pendant que le rewrite calcule) ; revisit du modèle si budget > 5 s persistant en playtest |
|
||||
| **Event-loop blocking de F5-TTS si le hint final est resynthétisé via le pipeline TTS MacStudio** | Medium | Voir `2026-05-03-tts-stt-llm-macstudio-design.md` §2.5 — le hint doit emprunter la voie Piper Tower (synchrone, latence ~250 ms) plutôt que F5-TTS tant que l'event-loop n'est pas isolé en process worker |
|
||||
|
||||
## 7. Acceptance gates (before declaring P6 done)
|
||||
|
||||
- [x] Static phrase lookup avec couverture audit `/hints/coverage` (P1, commit `4f6d916`)
|
||||
@@ -192,16 +222,25 @@ Rewrite is **temperature = 0.4** (slight variability for replay flavor, determin
|
||||
- [x] LiteLLM-down test: hints server falls back to base phrase (P2, fallback path testé)
|
||||
- [x] `npc_phrases.yaml` schema validator catches a missing `level_3` for a puzzle (refuses startup) (P1)
|
||||
- [x] Suite Python totale : 35 tests verts au 2026-05-03
|
||||
- [ ] Voice loop test: button → hint audio within 5 s p95 — **PENDING playtest firmware réel**
|
||||
- [ ] Safety filter test sur la sortie LLM réelle (synthétique → rejeté) — partiellement couvert par tests unitaires, **PENDING validation playtest**
|
||||
- [ ] At least one playtest in `playtests/` exercises 3 hints across 2 puzzles — **PENDING**
|
||||
- [ ] Soak test 24 h hints-server (mémoire, leaks LiteLLM) — **PENDING**
|
||||
|
||||
|
||||
## 9. Open questions
|
||||
|
||||
None at design stage. All decisions resolved during 2026-05-03 brainstorm:
|
||||
- Trigger: button + auto stuck-timer ✅
|
||||
- Escalation: adaptive per profile + stuck-timer ✅
|
||||
- Anti-cheat: cap 3 + progressive penalty (50/100/200) ✅
|
||||
## 8. Out of scope
|
||||
|
||||
- Hint **generation** (LLM authors fresh hints). The static bank stays canonical.
|
||||
- Multi-language hints. French only.
|
||||
- Hint quality tracking / playtest analytics dashboard. Possible future evolution if needed.
|
||||
- Voice STT for the "more help" phrase. Use the button.
|
||||
- Per-player hint history (multiple players → individual help). Group-level only.
|
||||
|
||||
## 9. Open questions
|
||||
|
||||
None at design stage. All decisions resolved during 2026-05-03 brainstorm:
|
||||
- Trigger: button + auto stuck-timer ✅
|
||||
- Escalation: adaptive per profile + stuck-timer ✅
|
||||
- Anti-cheat: cap 3 + progressive penalty (50/100/200) ✅
|
||||
- Content: hybrid static base + LLM rewrite (Qwen 72B) ✅
|
||||
- Service: dedicated FastAPI server on MacStudio :4100 ✅
|
||||
|
||||
|
||||
Reference in New Issue
Block a user