Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when adding or changing save games, settings or progression storage - a versioned save format with a tested migration chain, atomic writes with backup and checksum, per-engine storage locations, safe serializers, and the round-trip/migration/corruption tests.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
A save file outlives the code that wrote it. Players carry saves across updates, crashes happen mid-write, and a lost 40-hour save is the bug players remember. Every save has a version, every older version has a tested migration, and a write never destroys the last good save.
Core principle: Versioned, migrated, written atomically, checked on load — and never deserialized with a format that can execute code.
{
"version": 3,
"savedAtUtc": "2026-10-08T12:00:00Z",
"player": { "levelId": "forest_02", "position": [12.5, 0, -4.0], "hp": 72 },
"inventory": [{ "itemId": "sword_iron", "count": 1 }],
"flags": ["met_blacksmith", "boss_forest_defeated"]
}
GameObject, Node or AActor references, no array indices into data tables — stable IDs only (data-driven-gameplay-design).store_var without objects) is fine when size matters — the version field stays first.type Migration = (save: any) => any;
const migrations: Record<number, Migration> = {
1: (s) => ({ ...s, version: 2, inventory: s.items.map((id: string) => ({ itemId: id, count: 1 })) }),
2: (s) => ({ ...s, version: 3, flags: Object.keys(s.questState ?? {}).filter((k) => s.questState[k] === "done") }),
};
export function upgrade(raw: any): SaveV3 {
if (typeof raw?.version !== "number") throw new SaveError("unversioned");
if (raw.version > CURRENT) throw new SaveError("from a newer game version"); // refuse, never guess
let s = raw;
while (s.version < CURRENT) s = migrations[s.version](s);
return SaveV3Schema.parse(s);
}
tests/fixtures/saves/v1.json, v2.json).save.json.tmp, flush to disk.save.json.bak.save.json (atomic on the same volume).On load: verify the checksum and parse; on failure fall back to .bak, tell the player, and never crash or silently start a new game over the old one.
Serialize on the main thread if the engine requires it, but do file I/O off it (or between frames at a checkpoint) — a save must not hitch gameplay. Autosave at checkpoints, not every frame.
| Engine | Location / API |
|---|---|
| Unity | Application.persistentDataPath + System.IO; PlayerPrefs only for tiny settings |
| Godot | user:// with FileAccess; ConfigFile for settings |
| Unreal | USaveGame subclass + UGameplayStatics::AsyncSaveGameToSlot / LoadGameFromSlot; keep a version UPROPERTY in it |
| Web | IndexedDB for saves (async, larger; e.g. idb-keyval), localStorage only for small settings — it is synchronous, ~5 MB and can throw in private mode or when full |
| Bevy / Rust | serde to the platform data dir (directories crate) |
| pygame / MonoGame | the OS user data directory, never the install folder |
Consoles and some stores impose their own save APIs and size limits — follow the platform layer the repository already has.
BinaryFormatter: obsolete and insecure; do not use it in Unity, MonoGame or Godot C#.bytes_to_var_with_objects / str_to_var on untrusted data, and loading a user-supplied .tres/.res, can instantiate scripts — use JSON, ConfigFile, or FileAccess.get_var(false) (objects disallowed).pickle for pygame saves: a shared or downloaded save becomes code execution — use JSON.vN.json → upgrade → matches the expected current-version object..bak and reports; no exception escapes.BinaryFormatter, pickle, or object-enabled Godot variant decoding in a save path.아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.