Skill 寫法圖鑑

soak-test

Donchitos | 遊戲開發 | 原文 | MIT

產出長時間遊玩的觀察流程,用來抓記憶體洩漏和樂趣疲勞

中文翻譯

---
name: soak-test
description: "長時間遊玩的 soak test 流程:要觀察和記錄什麼,才抓得到慢性洩漏、疲勞,以及很晚才出現的邊界情況。"
argument-hint: "[duration: 30m | 1h | 2h | 4h] [focus: memory | stability | balance | all]"
user-invocable: true
allowed-tools: Read, Glob, Grep, Write, Bash(bash "*/.claude/skills/soak-test/../../hooks/yaml-helper.sh" resolve_config *)
model: sonnet
---

!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation,workflow`

**自動化模式**:解析 `modes.automation`(`project.local.yaml` →
`project.yaml` → 預設 `collaborative`)。每一次 `AskUserQuestion` 呼叫和
每一次寫檔,都要遵守 `.claude/docs/automation-modes.md`
(collaborative 一律詢問 · guided 只問重大事項 · autonomous 記錄後直接進行;
屬於 `automation_always_ask` 的類別一律要詢問)。

# Soak Test

soak test(也叫耐久測試)是帶著特定觀察目標、
延長時間的遊玩 session。跟 smoke check(涵蓋面廣的關鍵路徑,
約 10 分鐘)或單一功能的 playtest(約 30 分鐘)不一樣,soak test 會跑 **30
分鐘到數小時**,用來找出:

- **記憶體洩漏**:只會在場景切換之後才出現的 heap 緩慢成長
- **效能漂移**:隨時間越來越糟的 frame time 退化
- **狀態累積的 bug**:只會在某個機制重複 N 次之後才出現的問題
  (背包滿了、分數溢位、AI 狀態損毀)
- **樂趣疲勞**:第一次玩感覺很棒,但長時間遊玩後
  變得重複的機制
- **內容耗盡**:玩家用完新鮮內容的那個時間點

**這個 skill 產生的是觀察流程和分析框架,實際
玩遊戲的是人。**

**輸出:** `production/qa/soak-test-[date]-[duration].md`

**什麼時候跑:**
- Polish 階段:在 `/gate-check release` 之前
- 修好記憶體或穩定性問題之後(回歸 soak)
- 長時間遊玩還沒被正式追蹤過的時候

---

## 1. Parse Arguments

**Duration**(預設:`1h`):
- `30m`:短時間 soak;適合測試單一機制或場景
- `1h`:標準 soak;涵蓋大部分常見的洩漏類別
- `2h`:延長 soak;建議用在第一次完整的 Polish soak
- `4h`:深度 soak;遊戲設計是長 session(RPG、模擬遊戲)時必須做

**Focus**(預設:`all`):
- `memory`:聚焦在 heap 大小、物件數量、洩漏模式
- `stability`:聚焦在偵測 crash/凍結/卡死
- `balance`:聚焦在樂趣疲勞、內容耗盡、難度感受
- `all`:以上全部

---

## 2. Load Context

讀取:
- `project.yaml`:`engine.name`(用於各引擎專屬的記憶體監控
  指引)和 `performance.*` 預算(記憶體上限、目標 FPS);任何
  不存在或是空的 key(包括 `project.yaml` 沒有 `performance` 或
  `engine` 區塊時),退而用 `.claude/docs/technical-preferences.md`
- `design/gdd/game-concept.md`:預期的 session 長度(用來跟 soak 時長比較)、
  核心循環描述(或是 `design/game-brief.md`,也就是
  在 `rigor: minimal` 時取代它的一頁 brief:核心循環,而 session 長度只有在
  它的 "Who it's for" 那一行有寫時才有)。要分段讀:用 Grep 工具
  (pattern `^#`、content mode)找出你需要的標題,再用 offset 和 limit 讀那些範圍。
- `production/qa/playtests/` 裡最新的檔案:先前的 playtest 發現
  (避免重複記錄已知問題)
- `production/qa/qa-plan-*.md` 裡最新的檔案:目前 sprint 的測試涵蓋
  (了解哪些是正式測過的,哪些是 soak 涵蓋的)

記下任何效能預算目標(`project.yaml` 的 `performance.*`,沒有的話用 `.claude/docs/technical-preferences.md`):
- 記憶體上限:[N MB,或 "not set"]
- 目標 FPS:[N,或 "not set"]
- Frame 預算:[N ms,或 "not set"]

---

## 3. Define Observation Checkpoints

依時長,產生定時的檢查點:

**30m soak**:T+0、T+10、T+20、T+30
**1h soak**:T+0、T+15、T+30、T+45、T+60
**2h soak**:T+0、T+20、T+40、T+60、T+80、T+100、T+120
**4h soak**:T+0、T+30、T+60、T+90、T+120、T+180、T+240

在每個檢查點,觀察者要記錄 Phase 4 定義的觀察項目。

---

## 4. Generate the Soak Test Protocol

### Memory / Stability observation items (if focus = memory or all)

各引擎專屬的監控指引。

> **記錄工具顯示的單位;絕對不要換算,也絕對不要假設單位。**
> soak test 找的是**成長**,所以下面每個門檻都是對這次 session 自己 T+0 基準的
> *比例或差值*:這跟單位無關,
> 不管編輯器怎麼顯示數字都維持正確。在 T+0 把單位
> 照顯示的樣子寫下來,並在剩下的執行中一致地使用。

> **NOT SOURCEABLE:下面的工具、面板和計數器名稱,`docs/engine-reference/`
> 沒有涵蓋**:Godot 的 Debugger → Monitors 和它的記憶體
> 計數器、Unity 的 Memory Profiler 和它的欄位、Unreal 的 `stat memory`。要在
> 流程裡這樣標示:它們是讓測試者在 T+0 於自己的編輯器裡確認的指引,
> 不是驗證過的路徑。如果找不到任何記憶體工具,就等於什麼都沒量,
> 適用 Verdict 段落的 NOT ASSESSED。

**Godot 4:**
- 打開 Debugger → Monitors 分頁;在各檢查點追蹤 `Memory → Static Memory` 和
  `Object Count → Objects`
- 記錄:Static Memory(**依顯示的單位**)、Object Count、Orphan Nodes 數量
- 警示門檻:在最初 15 分鐘之後,記憶體比 T+0 成長 > 20%
  (載入時會有一些成長是預期的;持續成長代表有洩漏)
- **Orphan Nodes 是唯一值得看絕對值的數字**:場景卸載之後,它應該回到
  T+0 的值。比例會把這點藏起來;一個持續上升的非零底線,
  不管單位是什麼,都是洩漏

**Unity:**
- 打開 Memory Profiler(Window → Analysis → Memory Profiler)
- 記錄:每個檢查點的 Total Reserved Memory、GC Allocated、Object Count
  (**依顯示的單位**)
- 警示門檻:GC Allocated 在 3 個以上的檢查點單調成長:
  這是單調性檢查,刻意與單位無關

**Unreal Engine:**
- 在每個檢查點使用 `stat memory` console 指令
- 記錄:Physical Memory Used、Physical Memory Available(**依顯示的單位**)
- 警示門檻:Physical Memory Used **在整個 soak 期間成長 > 20%**,
  以這次執行的 T+0 為基準。像 "> 50MB" 這種絕對門檻,
  會悄悄假設單位*和*專案規模:50MB 對某個遊戲來說只是四捨五入的誤差,
  對另一個遊戲卻是災難

### Stability observation items (if focus = stability or all)

在每個檢查點,記下:
- [ ] 自上個檢查點以來沒有發生 crash、卡死或凍結
- [ ] 幀率仍在目標預算內([target FPS] fps)
- [ ] 音訊仍然正常播放(沒有不同步或無聲)
- [ ] 所有 HUD 元素仍然正確渲染
- [ ] 輸入反應正常(沒有輸入遺失或延遲尖峰)

### Balance / fatigue observation items (if focus = balance or all)

在每個檢查點收集主觀的觀察:
- [ ] 核心機制仍然讓人感到有回報(Y/N)
- [ ] 感受到的難度等級:[too easy / appropriate / too hard]
- [ ] 自上個檢查點以來,有沒有任何「這個我看過了」的時刻?(新鮮內容耗盡)
- [ ] 自上個檢查點以來,有沒有任何感到挫折的時刻?記下原因。
- [ ] 自上個檢查點以來,有沒有任何投入度最高的時刻?記下原因。

---

## 5. Generate the Protocol Document

```markdown
# Soak Test Protocol

> **Date**: [date]
> **Duration**: [duration]
> **Focus**: [memory | stability | balance | all]
> **Engine**: [engine]
> **Generated by**: /soak-test

---

## Pre-Session Setup

Before starting the soak:

- [ ] Game is running from a **fresh launch** (not resumed from a prior session)
- [ ] All background applications closed (minimise OS memory interference)
- [ ] Performance monitoring tool open and recording:
  - **Godot**: Debugger → Monitors tab → Memory section visible
  - **Unity**: Memory Profiler window open
  - **Unreal**: `stat memory` ready in console
  - Tool actually used, as named in this editor: [record it — the names above
    are NOT SOURCEABLE from `docs/engine-reference/`; none found → NOT ASSESSED]
- [ ] Soak target confirmed: [session design intent from game concept]
- [ ] Prior known issues to watch for: [from most recent playtest / qa-plan]

---

## Baseline (T+0) — Record Before Playing

| Metric | Baseline Value |
|--------|---------------|
| Memory / Heap | [record before first frame of gameplay] |
| Object Count | [record] |
| FPS (first 30 seconds) | [record] |
| [Engine-specific metric] | [record] |

---

## Checkpoint Log

### T+[N] minutes

**Memory / Stability** *(if applicable)*:

| Metric | Value | Δ from Baseline | Alert? |
|--------|-------|-----------------|--------|
| Memory / Heap | | | |
| Object Count | | | |
| FPS | | | |
| Crashes / Hangs | | | |

**Stability checks**:
- [ ] No crash or hang since last checkpoint
- [ ] Frame rate within budget ([N] fps target)
- [ ] Audio correct
- [ ] HUD rendering correctly
- [ ] Input responding correctly

**Balance / Fatigue** *(if applicable)*:
- Core mechanic still rewarding: Y / N
- Difficulty perception: too easy / appropriate / too hard
- Notable moments: [note any peak engagement or frustration]
- Content exhaustion signs: Y / N — [describe]

**Free observations**:
*(Note anything unexpected observed since the last checkpoint)*

---

[Repeat Checkpoint Log section for each timed checkpoint]

---

## Post-Session Analysis

### Memory Trend

| Checkpoint | Memory | Δ/hr extrapolated |
|------------|--------|-------------------|
| T+0 | | |
| [T+N] | | |

**Leak detected?** Y / N
**Estimated time to OOM at current rate**: [N hours / not applicable]

### Stability Summary

Total crashes: [N]
Total hangs: [N]
Worst FPS observed: [N] fps at [checkpoint]
Performance degradation: stable / mild / severe

### Balance / Fatigue Summary

Fun curve: [engaged throughout / fatigue onset at T+N / repetitive from start]
Content exhaustion point: [never / at T+N / early]
Difficulty arc: [appropriate / too easy throughout / difficulty spike at T+N]

### Issues Found

| ID | Severity | Checkpoint | Description |
|----|----------|------------|-------------|
| SOAK-001 | S[1-4] | T+[N] | [description] |

---

## Verdict: PASS / PASS WITH CONCERNS / NOT ASSESSED / FAIL

**PASS**: No leaks detected, stability maintained, fun factor consistent
**PASS WITH CONCERNS**: Minor drift or fatigue noted; addressable in Polish
**NOT ASSESSED**: The soak did not run to a length that could show what it looks
for — say how far it got and which checkpoints were never reached
**FAIL**: Memory leak confirmed, stability breach, or severe fun fatigue

> **A short soak cannot return PASS.** Everything this protocol exists to detect
> — slow leaks, fatigue, late-appearing edge cases — is by definition invisible
> early, so a session that ended before the checkpoints it was built around has
> not shown stability; it has shown nothing yet. Record `NOT ASSESSED — reached
> T+[N] of [duration]; checkpoints [list] not reached`. Ranks **above both pass
> values** and **below FAIL**: a crash observed at T+20 is a real finding no
> matter how short the run, and must not be demoted behind the run's length.
> The same applies when the build crashed for reasons unrelated to the soak, when
> no memory instrumentation was available (nothing was measured, so "no leaks
> detected" means "no leaks could have been detected"), or when the protocol was
> written but never executed — a protocol document is not a result.

---

## Sign-Off

- **Tester**: [name] — [date]
- **QA Lead review**: [name] — [date]
```

---

## 6. Write Output

在對話中呈現流程摘要,然後詢問:

"May I write this soak test protocol to
`production/qa/soak-test-[date]-[duration].md`?"

核准後才寫。

寫完之後:

"Protocol written. To run the soak:
1. Open the file and follow the Pre-Session Setup checklist
2. Record each checkpoint as you play
3. Complete the Post-Session Analysis section when done
4. File bugs from 'Issues Found' to `production/qa/bugs/`
5. Run `/bug-triage sprint` after the session to integrate any S1/S2 issues (at `workflow: minimal`, which has no sprints: `/bug-triage full`)

If the verdict is FAIL, run `/smoke-check` again after fixing the issues."

---

## Collaborative Protocol

- **這個 skill 產生的是流程,由人來執行**:絕對不要嘗試
  自動執行 soak test。這些觀察需要人類觀察者。
- **時長應該配合遊戲的 session 設計**:5 分鐘的遊戲
  不需要 4 小時的 soak;城市建造遊戲可能需要。自行判斷,不確定就問。
- **第一次 soak 應該用 `all` 聚焦**:狹窄的聚焦(只看記憶體)是用在
  修好某個特定問題之後的回歸 soak,不是第一輪
- **寫之前先問**:建立流程檔案之前一定要先確認

英文原文

---
name: soak-test
description: "Soak test protocol for extended play — what to observe and log for slow leaks, fatigue, late-appearing edge cases."
argument-hint: "[duration: 30m | 1h | 2h | 4h] [focus: memory | stability | balance | all]"
user-invocable: true
allowed-tools: Read, Glob, Grep, Write, Bash(bash "*/.claude/skills/soak-test/../../hooks/yaml-helper.sh" resolve_config *)
model: sonnet
---

!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation,workflow`

**Automation mode**: Resolve `modes.automation` (`project.local.yaml` →
`project.yaml` → default `collaborative`). Every `AskUserQuestion` call and
every file write follows `.claude/docs/automation-modes.md`
(collaborative asks always · guided major-only · autonomous logs and proceeds;
`automation_always_ask` categories always prompt).

# Soak Test

A soak test (also called an endurance test) is an extended play session run
with specific observation goals. Unlike a smoke check (broad critical path,
~10 min) or a single-feature playtest (~30 min), a soak test runs for **30
minutes to several hours** to surface:

- **Memory leaks** — gradual heap growth that only appears after scene transitions
- **Performance drift** — frame time degradation that worsens over time
- **State accumulation bugs** — issues that only appear after N repetitions
  of a mechanic (inventory full, score overflow, AI state corruption)
- **Fun fatigue** — mechanics that feel good in a first session but grow
  repetitive over extended play
- **Content exhaustion** — the point where players run out of novel content

**This skill generates the observation protocol and analysis harness — the
human does the actual playing.**

**Output:** `production/qa/soak-test-[date]-[duration].md`

**When to run:**
- Polish phase — before `/gate-check release`
- After fixing a memory or stability issue (regression soak)
- When extended play has not been formally tracked

---

## 1. Parse Arguments

**Duration** (default: `1h`):
- `30m` — short soak; suitable for testing a single mechanic or scene
- `1h` — standard soak; covers most common leak categories
- `2h` — extended soak; recommended for first full Polish soak
- `4h` — deep soak; required for games with long session design (RPGs, sims)

**Focus** (default: `all`):
- `memory` — focus on heap size, object count, leak patterns
- `stability` — focus on crash/freeze/hang detection
- `balance` — focus on fun fatigue, content exhaustion, difficulty perception
- `all` — all of the above

---

## 2. Load Context

Read:
- `project.yaml` — `engine.name` (for engine-specific memory monitoring
  guidance) and `performance.*` budgets (memory ceiling, target FPS); for any
  key absent or empty (including when `project.yaml` has no `performance` or
  `engine` block), fall back to `.claude/docs/technical-preferences.md`
- `design/gdd/game-concept.md` — intended session length (for comparison against
  soak duration), core loop description (or `design/game-brief.md`, the one-page
  brief that replaces it at `rigor: minimal` — core loop, and session length only
  if its "Who it's for" line states one). Read it by section: find the headings you
  need with the Grep tool (pattern `^#`, content mode) and Read those ranges
  with offset and limit.
- Most recent file in `production/qa/playtests/` — prior playtest findings
  (to avoid re-documenting known issues)
- Most recent file in `production/qa/qa-plan-*.md` — current sprint test coverage
  (to understand what has been formally tested vs. what the soak covers)

Note any performance budget targets (`performance.*` from `project.yaml`, else `.claude/docs/technical-preferences.md`):
- Memory ceiling: [N MB, or "not set"]
- Target FPS: [N, or "not set"]
- Frame budget: [N ms, or "not set"]

---

## 3. Define Observation Checkpoints

Based on duration, generate timed checkpoints:

**30m soak**: T+0, T+10, T+20, T+30
**1h soak**: T+0, T+15, T+30, T+45, T+60
**2h soak**: T+0, T+20, T+40, T+60, T+80, T+100, T+120
**4h soak**: T+0, T+30, T+60, T+90, T+120, T+180, T+240

At each checkpoint, the observer records the observation items defined in
Phase 4.

---

## 4. Generate the Soak Test Protocol

### Memory / Stability observation items (if focus = memory or all)

Engine-specific monitoring guidance.

> **Record the unit the tool shows; never convert, and never assume one.**
> A soak test looks for **growth**, so every threshold below is a *ratio or a
> delta against this session's own T+0 baseline* — which is unit-agnostic and
> stays correct however the editor reports the number. Write the unit down at
> T+0 exactly as displayed and use it consistently for the rest of the run.

> **NOT SOURCEABLE — the tool, panel and counter names below are not covered by
> `docs/engine-reference/`**: Godot's Debugger → Monitors and its memory
> counters, Unity's Memory Profiler and its fields, Unreal's `stat memory`. Mark
> them so in the protocol: they are pointers for the tester to confirm in their
> own editor at T+0, not verified paths. If no memory tool can be found, nothing
> was measured, and the Verdict section's NOT ASSESSED applies.

**Godot 4:**
- Open Debugger → Monitors tab; track `Memory → Static Memory` and
  `Object Count → Objects` across checkpoints
- Record: Static Memory (**unit as displayed**), Object Count, Orphan Nodes count
- Alert threshold: Memory growth > 20% from T+0 after the first 15 minutes
  (some growth on load is expected; sustained growth indicates a leak)
- **Orphan Nodes is the one absolute number worth watching**: it should return to
  its T+0 value after a scene unload. A ratio hides that; a non-zero floor that
  keeps rising is a leak regardless of units

**Unity:**
- Open Memory Profiler (Window → Analysis → Memory Profiler)
- Record: Total Reserved Memory, GC Allocated, Object Count at each checkpoint
  (**units as displayed**)
- Alert threshold: GC Allocated growing monotonically across 3+ checkpoints —
  a monotonicity check, deliberately unit-free

**Unreal Engine:**
- Use `stat memory` console command at each checkpoint
- Record: Physical Memory Used, Physical Memory Available (**units as displayed**)
- Alert threshold: Physical Memory Used growth **> 20% over the full soak**,
  measured against this run's T+0. An absolute threshold such as "> 50MB"
  silently assumes both the unit *and* a project scale — 50MB is a rounding
  error for one game and a catastrophe for another

### Stability observation items (if focus = stability or all)

At each checkpoint, note:
- [ ] No crash, hang, or freeze occurred since last checkpoint
- [ ] Frame rate still within target budget ([target FPS] fps)
- [ ] Audio still playing correctly (no desync or silence)
- [ ] All HUD elements still rendering correctly
- [ ] Input responding as expected (no input loss or lag spike)

### Balance / fatigue observation items (if focus = balance or all)

Collect subjective observations at each checkpoint:
- [ ] Core mechanic still feels rewarding (Y/N)
- [ ] Perceived difficulty level: [too easy / appropriate / too hard]
- [ ] Any "I've seen this before" moments since last checkpoint? (novel content exhaustion)
- [ ] Any moment of frustration since last checkpoint? Note cause.
- [ ] Any moment of peak engagement since last checkpoint? Note cause.

---

## 5. Generate the Protocol Document

```markdown
# Soak Test Protocol

> **Date**: [date]
> **Duration**: [duration]
> **Focus**: [memory | stability | balance | all]
> **Engine**: [engine]
> **Generated by**: /soak-test

---

## Pre-Session Setup

Before starting the soak:

- [ ] Game is running from a **fresh launch** (not resumed from a prior session)
- [ ] All background applications closed (minimise OS memory interference)
- [ ] Performance monitoring tool open and recording:
  - **Godot**: Debugger → Monitors tab → Memory section visible
  - **Unity**: Memory Profiler window open
  - **Unreal**: `stat memory` ready in console
  - Tool actually used, as named in this editor: [record it — the names above
    are NOT SOURCEABLE from `docs/engine-reference/`; none found → NOT ASSESSED]
- [ ] Soak target confirmed: [session design intent from game concept]
- [ ] Prior known issues to watch for: [from most recent playtest / qa-plan]

---

## Baseline (T+0) — Record Before Playing

| Metric | Baseline Value |
|--------|---------------|
| Memory / Heap | [record before first frame of gameplay] |
| Object Count | [record] |
| FPS (first 30 seconds) | [record] |
| [Engine-specific metric] | [record] |

---

## Checkpoint Log

### T+[N] minutes

**Memory / Stability** *(if applicable)*:

| Metric | Value | Δ from Baseline | Alert? |
|--------|-------|-----------------|--------|
| Memory / Heap | | | |
| Object Count | | | |
| FPS | | | |
| Crashes / Hangs | | | |

**Stability checks**:
- [ ] No crash or hang since last checkpoint
- [ ] Frame rate within budget ([N] fps target)
- [ ] Audio correct
- [ ] HUD rendering correctly
- [ ] Input responding correctly

**Balance / Fatigue** *(if applicable)*:
- Core mechanic still rewarding: Y / N
- Difficulty perception: too easy / appropriate / too hard
- Notable moments: [note any peak engagement or frustration]
- Content exhaustion signs: Y / N — [describe]

**Free observations**:
*(Note anything unexpected observed since the last checkpoint)*

---

[Repeat Checkpoint Log section for each timed checkpoint]

---

## Post-Session Analysis

### Memory Trend

| Checkpoint | Memory | Δ/hr extrapolated |
|------------|--------|-------------------|
| T+0 | | |
| [T+N] | | |

**Leak detected?** Y / N
**Estimated time to OOM at current rate**: [N hours / not applicable]

### Stability Summary

Total crashes: [N]
Total hangs: [N]
Worst FPS observed: [N] fps at [checkpoint]
Performance degradation: stable / mild / severe

### Balance / Fatigue Summary

Fun curve: [engaged throughout / fatigue onset at T+N / repetitive from start]
Content exhaustion point: [never / at T+N / early]
Difficulty arc: [appropriate / too easy throughout / difficulty spike at T+N]

### Issues Found

| ID | Severity | Checkpoint | Description |
|----|----------|------------|-------------|
| SOAK-001 | S[1-4] | T+[N] | [description] |

---

## Verdict: PASS / PASS WITH CONCERNS / NOT ASSESSED / FAIL

**PASS**: No leaks detected, stability maintained, fun factor consistent
**PASS WITH CONCERNS**: Minor drift or fatigue noted; addressable in Polish
**NOT ASSESSED**: The soak did not run to a length that could show what it looks
for — say how far it got and which checkpoints were never reached
**FAIL**: Memory leak confirmed, stability breach, or severe fun fatigue

> **A short soak cannot return PASS.** Everything this protocol exists to detect
> — slow leaks, fatigue, late-appearing edge cases — is by definition invisible
> early, so a session that ended before the checkpoints it was built around has
> not shown stability; it has shown nothing yet. Record `NOT ASSESSED — reached
> T+[N] of [duration]; checkpoints [list] not reached`. Ranks **above both pass
> values** and **below FAIL**: a crash observed at T+20 is a real finding no
> matter how short the run, and must not be demoted behind the run's length.
> The same applies when the build crashed for reasons unrelated to the soak, when
> no memory instrumentation was available (nothing was measured, so "no leaks
> detected" means "no leaks could have been detected"), or when the protocol was
> written but never executed — a protocol document is not a result.

---

## Sign-Off

- **Tester**: [name] — [date]
- **QA Lead review**: [name] — [date]
```

---

## 6. Write Output

Present the protocol summary in conversation, then ask:

"May I write this soak test protocol to
`production/qa/soak-test-[date]-[duration].md`?"

Write only after approval.

After writing:

"Protocol written. To run the soak:
1. Open the file and follow the Pre-Session Setup checklist
2. Record each checkpoint as you play
3. Complete the Post-Session Analysis section when done
4. File bugs from 'Issues Found' to `production/qa/bugs/`
5. Run `/bug-triage sprint` after the session to integrate any S1/S2 issues (at `workflow: minimal`, which has no sprints: `/bug-triage full`)

If the verdict is FAIL, run `/smoke-check` again after fixing the issues."

---

## Collaborative Protocol

- **This skill generates a protocol — humans run it** — never attempt to
  run a soak test automatically. The observations require a human observer.
- **Duration should match the game's session design** — a 5-minute game
  doesn't need a 4h soak; a city-builder might. Use judgment and ask if unclear.
- **First soak should be `all` focus** — narrow focus (memory-only) is for
  regression soaks after a specific fix, not the first pass
- **Ask before writing** — always confirm before creating the protocol file