fix(rules): classify run as a full-round action

PF1e CRB: running is a full-round action, not a move action. The budget
filter now classifies run as full-round (consumes the standard AND the
move slot), _FULL_ROUND_KINDS includes it for the staggered filter, and
the nauseated filter drops it (run is no longer move-like). The
moved_this_turn/running flags are unchanged; the _execute_run
moved_this_turn early return stays as defense in depth. default_policy
never emits run, so the golden transcripts are untouched.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-09-11 13:48:58 +02:00
parent 9c6f5e277e
commit e44ec75f2b
4 changed files with 28 additions and 19 deletions
+7 -2
View File
@@ -438,12 +438,17 @@ def test_run_and_aid_without_target_are_rejected() -> None:
eng = _duo(policy, [10, 5], round_cap=1)
t = eng.run().transcript
hero = eng._states[0]
# run is a full-round action: it consumes the standard AND the move slot,
# so the budget filter drops the following aid_another as a surplus
# standard before it can even reach the missing-target gate.
assert hero.last_action_results == [
ActionResult(
kind="aid_another", ok=False, reason="downgraded:action_economy"
),
ActionResult(kind="run", ok=False, reason="missing_target"),
ActionResult(kind="aid_another", ok=False, reason="missing_target"),
]
assert "round 1 hero: run rejected (missing_target)" in t
assert "round 1 hero: aid_another rejected (missing_target)" in t
assert "round 1 hero: aid_another rejected (missing_target)" not in t
assert hero.pos == (0, 0)
assert hero.running is False