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 starting any game task, before writing tests - find out which editors and runners exist on this machine, keep gameplay rules in engine-independent classes with an injected clock and seeded RNG, and report exactly what could not run.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
You run headless on the user's machine. A web game or a Bevy crate can always be built and tested; a Unity, Unreal or Godot editor may or may not be installed, licensed and at the right version. The answer is the same in every engine: gameplay rules live in plain classes that a plain runner can drive, and engine callbacks are thin adapters that feed them input, time and randomness.
Core principle: If a rule can only be tested by pressing Play, it is in the wrong class. And a test you wrote but could not run is reported as exactly that — never as a pass.
Run these first, in one step, and keep the answers for the plan.
# Unity: the exact editor version the project pins
grep m_EditorVersion ProjectSettings/ProjectVersion.txt
ls "/Applications/Unity/Hub/Editor/" 2>/dev/null # macOS
ls "$HOME/Unity/Hub/Editor/" 2>/dev/null # Linux
echo "$UNITY_PATH"
# macOS binary: /Applications/Unity/Hub/Editor/<ver>/Unity.app/Contents/MacOS/Unity
# Windows: C:\Program Files\Unity\Hub\Editor\<ver>\Editor\Unity.exe ; Linux: ~/Unity/Hub/Editor/<ver>/Editor/Unity
# Godot: binary and version must match config/features (major.minor); .NET projects need the .NET build
which godot godot4 2>/dev/null; godot --version 2>/dev/null
ls /Applications/Godot*.app/Contents/MacOS/ 2>/dev/null
# Unreal: EngineAssociation in the .uproject names the install
grep EngineAssociation *.uproject
ls "/Users/Shared/Epic Games/" 2>/dev/null # macOS; Windows: C:\Program Files\Epic Games\UE_5.x
# binary: <engine>/Engine/Binaries/<Mac|Win64|Linux>/UnrealEditor-Cmd
node -v; cargo --version; dotnet --version; python3 --version 2>/dev/null
Rules:
project.godot.run_terminal a long timeout, or run detached to /tmp/tt-<task key>/<step>.log and read the log.Rules (plain C# / GDScript RefCounted / C++ struct / TS module / Rust fn) ← unit tests, any runner
↑ called by
Engine adapter (MonoBehaviour / Node / Actor component / Phaser scene / Bevy system) ← engine tests
↑ wired in
Scenes, prefabs, Blueprints, data assets ← looked at (game-visual-self-review)
The adapter reads input and deltaTime, calls the rule, and applies the result to the engine (transform, animation, UI event). It contains no if about game rules.
// ❌ rule welded to the engine: untestable without Play mode, reads global time
public class Dash : MonoBehaviour {
float _lastDash;
void Update() {
if (Input.GetKeyDown(KeyCode.Space) && Time.time - _lastDash > 1.5f) {
_lastDash = Time.time;
GetComponent<Rigidbody>().AddForce(transform.forward * 20, ForceMode.Impulse);
}
}
}
// ✅ rule in a plain class (assembly with noEngineReferences), time passed in
public sealed class Cooldown {
readonly float _duration; float _remaining;
public Cooldown(float duration) => _duration = duration;
public bool IsReady => _remaining <= 0f;
public void Tick(float dt) => _remaining = MathF.Max(0f, _remaining - dt);
public bool TryConsume() { if (!IsReady) return false; _remaining = _duration; return true; }
}
[Test] public void TryConsume_WhileCoolingDown_ReturnsFalse() {
var c = new Cooldown(1.5f);
Assert.That(c.TryConsume(), Is.True);
c.Tick(1.0f);
Assert.That(c.TryConsume(), Is.False);
c.Tick(0.5f);
Assert.That(c.TryConsume(), Is.True);
}
The adapter DashAbility : MonoBehaviour caches its Rigidbody in Awake, ticks the cooldown in Update with Time.deltaTime, and applies the impulse in FixedUpdate when an input flag is set — three lines with no rule in them.
| Engine | Runs without the editor | How |
|---|---|---|
| Unity | Rules in an asmdef with "noEngineReferences": true | A throwaway net8.0 NUnit project in /tmp/tt-<task key>/ that compiles those sources: <Compile Include="<repo>/Assets/Scripts/Core/**/*.cs" />, then dotnet test. Commit the EditMode test in the repo either way. |
| Godot (C#) | Plain C# classes with no Godot namespace | A class-library project referenced by an xUnit/NUnit project, dotnet test |
| Godot (GDScript) | Nothing — GDScript needs the Godot binary | Write the gdUnit4/GUT test anyway and report it as not run |
| Unreal | Nothing — even pure C++ in a module needs the engine build | Write the Automation Spec anyway and report it as not run |
| Web, Bevy, MonoGame, pygame | Everything | Vitest, cargo test, dotnet test, pytest |
If the repository already has such a plain-runner project (a Tests.Core.csproj, a logic/ crate), use it instead of a throwaway one.
dt (or an IClock), never read Time.time, OS.get_ticks_msec(), performance.now() or Instant::now() themselves.new System.Random(seed), RandomNumberGenerator with .seed, a mulberry32(seed) in TS, ChaCha8Rng::seed_from_u64(seed) in Rust. A test fixes the seed; the game seeds from the clock or the save.MoveIntent(x, y), Jump), not key codes. Rebinding then never touches a rule.Naming follows the repository; without a convention: NUnit Method_Scenario_Expected, gdUnit4/GUT test_<scenario>_<expected>, Unreal Project.System.Scenario, Vitest/cargo test a sentence describing the behaviour.
One line per command in the closing message, verbatim:
NOT RUN: Unity 6000.3.2f1 not installed (Hub has 6000.0.40f1 only) — EditMode tests in Assets/Tests/EditMode/CooldownTests.cs written, not executed.
RAN: dotnet test /tmp/tt-T-42/core-tests → 12 passed, 0 failed (Core sources compiled without UnityEngine).
Random inside a rule, then fighting flaky tests.UnityEngine, Godot, Phaser or bevy::prelude without needing it.RAN:/NOT RUN: accounting on an engine project.まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
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 deciding whether a request needs an analiz task before implementation - the conditions that require the architect's analysis versus going straight to implementation
日本語の概要は準備中です。原文の説明を表示しています。